feat: Implement AlwaysRasterizeSvg (#1257)

Implement AlwaysRasterizeSvg
Add sanitize to skip processing
Add tests
Refactoring skipProcessing
This commit is contained in:
Frezyy
2024-03-25 19:53:43 +05:00
committed by GitHub
parent 59ca483aa7
commit 923b32a1b4
3 changed files with 69 additions and 24 deletions

View File

@@ -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)
} }

View File

@@ -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) {

View File

@@ -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))
} }