mirror of
https://github.com/imgproxy/imgproxy.git
synced 2025-10-10 12:12:40 +02:00
feat: Implement AlwaysRasterizeSvg (#1257)
Implement AlwaysRasterizeSvg Add sanitize to skip processing Add tests Refactoring skipProcessing
This commit is contained in:
@@ -93,7 +93,8 @@ var (
|
|||||||
AllowLinkLocalSourceAddresses bool
|
AllowLinkLocalSourceAddresses bool
|
||||||
AllowPrivateSourceAddresses bool
|
AllowPrivateSourceAddresses bool
|
||||||
|
|
||||||
SanitizeSvg bool
|
SanitizeSvg bool
|
||||||
|
AlwaysRasterizeSvg bool
|
||||||
|
|
||||||
CookiePassthrough bool
|
CookiePassthrough bool
|
||||||
CookieBaseURL string
|
CookieBaseURL string
|
||||||
@@ -288,6 +289,7 @@ func Reset() {
|
|||||||
AllowPrivateSourceAddresses = true
|
AllowPrivateSourceAddresses = true
|
||||||
|
|
||||||
SanitizeSvg = true
|
SanitizeSvg = true
|
||||||
|
AlwaysRasterizeSvg = false
|
||||||
|
|
||||||
CookiePassthrough = false
|
CookiePassthrough = false
|
||||||
CookieBaseURL = ""
|
CookieBaseURL = ""
|
||||||
@@ -429,6 +431,7 @@ func Configure() error {
|
|||||||
configurators.Bool(&AllowPrivateSourceAddresses, "IMGPROXY_ALLOW_PRIVATE_SOURCE_ADDRESSES")
|
configurators.Bool(&AllowPrivateSourceAddresses, "IMGPROXY_ALLOW_PRIVATE_SOURCE_ADDRESSES")
|
||||||
|
|
||||||
configurators.Bool(&SanitizeSvg, "IMGPROXY_SANITIZE_SVG")
|
configurators.Bool(&SanitizeSvg, "IMGPROXY_SANITIZE_SVG")
|
||||||
|
configurators.Bool(&AlwaysRasterizeSvg, "IMGPROXY_ALWAYS_RASTERIZE_SVG")
|
||||||
|
|
||||||
configurators.Bool(&AllowSecurityOptions, "IMGPROXY_ALLOW_SECURITY_OPTIONS")
|
configurators.Bool(&AllowSecurityOptions, "IMGPROXY_ALLOW_SECURITY_OPTIONS")
|
||||||
|
|
||||||
@@ -680,7 +683,6 @@ func Configure() error {
|
|||||||
|
|
||||||
if LocalFileSystemRoot != "" {
|
if LocalFileSystemRoot != "" {
|
||||||
stat, err := os.Stat(LocalFileSystemRoot)
|
stat, err := os.Stat(LocalFileSystemRoot)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Cannot use local directory: %s", err)
|
return fmt.Errorf("Cannot use local directory: %s", err)
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -372,32 +373,28 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
checkErr(ctx, "timeout", router.CheckTimeout(ctx))
|
checkErr(ctx, "timeout", router.CheckTimeout(ctx))
|
||||||
|
|
||||||
if originData.Type == po.Format || po.Format == imagetype.Unknown {
|
// Skip processing svg with unknown or the same destination imageType
|
||||||
// Don't process SVG
|
// if it's not forced by AlwaysRasterizeSvg option
|
||||||
if originData.Type == imagetype.SVG {
|
// Also skip processing if the format is in SkipProcessingFormats
|
||||||
if config.SanitizeSvg {
|
shouldSkipProcessing := (originData.Type == po.Format || po.Format == imagetype.Unknown) &&
|
||||||
sanitized, svgErr := svg.Sanitize(originData)
|
(slices.Contains(po.SkipProcessingFormats, originData.Type) ||
|
||||||
checkErr(ctx, "svg_processing", svgErr)
|
originData.Type == imagetype.SVG && !config.AlwaysRasterizeSvg)
|
||||||
|
|
||||||
// Since we'll replace origin data, it's better to close it to return
|
if shouldSkipProcessing {
|
||||||
// it's buffer to the pool
|
if originData.Type == imagetype.SVG && config.SanitizeSvg {
|
||||||
originData.Close()
|
sanitized, svgErr := svg.Sanitize(originData)
|
||||||
|
checkErr(ctx, "svg_processing", svgErr)
|
||||||
|
|
||||||
originData = sanitized
|
// Since we'll replace origin data, it's better to close it to return
|
||||||
}
|
// it's buffer to the pool
|
||||||
|
originData.Close()
|
||||||
|
|
||||||
|
originData = sanitized
|
||||||
|
|
||||||
respondWithImage(reqID, r, rw, statusCode, originData, po, imageURL, originData)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(po.SkipProcessingFormats) > 0 {
|
respondWithImage(reqID, r, rw, statusCode, originData, po, imageURL, originData)
|
||||||
for _, f := range po.SkipProcessingFormats {
|
return
|
||||||
if f == originData.Type {
|
|
||||||
respondWithImage(reqID, r, rw, statusCode, originData, po, imageURL, originData)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !vips.SupportsLoad(originData.Type) {
|
if !vips.SupportsLoad(originData.Type) {
|
||||||
|
@@ -608,7 +608,6 @@ func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqExactMatchLastModifiedD
|
|||||||
require.Equal(s.T(), "", modifiedSince)
|
require.Equal(s.T(), "", modifiedSince)
|
||||||
rw.WriteHeader(200)
|
rw.WriteHeader(200)
|
||||||
rw.Write(data)
|
rw.Write(data)
|
||||||
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
@@ -619,6 +618,7 @@ func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqExactMatchLastModifiedD
|
|||||||
|
|
||||||
require.Equal(s.T(), 200, res.StatusCode)
|
require.Equal(s.T(), 200, res.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqExactMatchLastModifiedEnabled() {
|
func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqExactMatchLastModifiedEnabled() {
|
||||||
config.LastModifiedEnabled = true
|
config.LastModifiedEnabled = true
|
||||||
lastModified := "Wed, 21 Oct 2015 07:28:00 GMT"
|
lastModified := "Wed, 21 Oct 2015 07:28:00 GMT"
|
||||||
@@ -657,6 +657,7 @@ func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareMoreRecentLastMo
|
|||||||
|
|
||||||
require.Equal(s.T(), 200, res.StatusCode)
|
require.Equal(s.T(), 200, res.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareMoreRecentLastModifiedEnabled() {
|
func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareMoreRecentLastModifiedEnabled() {
|
||||||
config.LastModifiedEnabled = true
|
config.LastModifiedEnabled = true
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
@@ -678,6 +679,7 @@ func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareMoreRecentLastMo
|
|||||||
|
|
||||||
require.Equal(s.T(), 304, res.StatusCode)
|
require.Equal(s.T(), 304, res.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareTooOldLastModifiedDisabled() {
|
func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareTooOldLastModifiedDisabled() {
|
||||||
config.LastModifiedEnabled = false
|
config.LastModifiedEnabled = false
|
||||||
data := s.readTestFile("test1.png")
|
data := s.readTestFile("test1.png")
|
||||||
@@ -698,6 +700,7 @@ func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareTooOldLastModifi
|
|||||||
|
|
||||||
require.Equal(s.T(), 200, res.StatusCode)
|
require.Equal(s.T(), 200, res.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareTooOldLastModifiedEnabled() {
|
func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareTooOldLastModifiedEnabled() {
|
||||||
config.LastModifiedEnabled = true
|
config.LastModifiedEnabled = true
|
||||||
data := s.readTestFile("test1.png")
|
data := s.readTestFile("test1.png")
|
||||||
@@ -721,6 +724,49 @@ func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareTooOldLastModifi
|
|||||||
|
|
||||||
require.Equal(s.T(), 200, res.StatusCode)
|
require.Equal(s.T(), 200, res.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ProcessingHandlerTestSuite) TestAlwaysRasterizeSvg() {
|
||||||
|
config.AlwaysRasterizeSvg = true
|
||||||
|
|
||||||
|
rw := s.send("/unsafe/rs:fill:40:40/plain/local:///test1.svg")
|
||||||
|
res := rw.Result()
|
||||||
|
|
||||||
|
require.Equal(s.T(), 200, res.StatusCode)
|
||||||
|
require.Equal(s.T(), "image/png", res.Header.Get("Content-Type"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProcessingHandlerTestSuite) TestAlwaysRasterizeSvgWithEnforceAvif() {
|
||||||
|
config.AlwaysRasterizeSvg = true
|
||||||
|
config.EnforceWebp = true
|
||||||
|
|
||||||
|
rw := s.send("/unsafe/plain/local:///test1.svg", http.Header{"Accept": []string{"image/webp"}})
|
||||||
|
res := rw.Result()
|
||||||
|
|
||||||
|
require.Equal(s.T(), 200, res.StatusCode)
|
||||||
|
require.Equal(s.T(), "image/webp", res.Header.Get("Content-Type"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProcessingHandlerTestSuite) TestAlwaysRasterizeSvgDisabled() {
|
||||||
|
config.AlwaysRasterizeSvg = false
|
||||||
|
config.EnforceWebp = true
|
||||||
|
|
||||||
|
rw := s.send("/unsafe/plain/local:///test1.svg")
|
||||||
|
res := rw.Result()
|
||||||
|
|
||||||
|
require.Equal(s.T(), 200, res.StatusCode)
|
||||||
|
require.Equal(s.T(), "image/svg+xml", res.Header.Get("Content-Type"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProcessingHandlerTestSuite) TestAlwaysRasterizeSvgWithFormat() {
|
||||||
|
config.AlwaysRasterizeSvg = true
|
||||||
|
config.SkipProcessingFormats = []imagetype.Type{imagetype.SVG}
|
||||||
|
rw := s.send("/unsafe/plain/local:///test1.svg@svg")
|
||||||
|
res := rw.Result()
|
||||||
|
|
||||||
|
require.Equal(s.T(), 200, res.StatusCode)
|
||||||
|
require.Equal(s.T(), "image/svg+xml", res.Header.Get("Content-Type"))
|
||||||
|
}
|
||||||
|
|
||||||
func TestProcessingHandler(t *testing.T) {
|
func TestProcessingHandler(t *testing.T) {
|
||||||
suite.Run(t, new(ProcessingHandlerTestSuite))
|
suite.Run(t, new(ProcessingHandlerTestSuite))
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user