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
AllowPrivateSourceAddresses bool
SanitizeSvg bool
SanitizeSvg bool
AlwaysRasterizeSvg bool
CookiePassthrough bool
CookieBaseURL string
@@ -288,6 +289,7 @@ func Reset() {
AllowPrivateSourceAddresses = true
SanitizeSvg = true
AlwaysRasterizeSvg = false
CookiePassthrough = false
CookieBaseURL = ""
@@ -429,6 +431,7 @@ func Configure() error {
configurators.Bool(&AllowPrivateSourceAddresses, "IMGPROXY_ALLOW_PRIVATE_SOURCE_ADDRESSES")
configurators.Bool(&SanitizeSvg, "IMGPROXY_SANITIZE_SVG")
configurators.Bool(&AlwaysRasterizeSvg, "IMGPROXY_ALWAYS_RASTERIZE_SVG")
configurators.Bool(&AllowSecurityOptions, "IMGPROXY_ALLOW_SECURITY_OPTIONS")
@@ -680,7 +683,6 @@ func Configure() error {
if LocalFileSystemRoot != "" {
stat, err := os.Stat(LocalFileSystemRoot)
if err != nil {
return fmt.Errorf("Cannot use local directory: %s", err)
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"net/http"
"slices"
"strconv"
"strings"
"time"
@@ -372,32 +373,28 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
checkErr(ctx, "timeout", router.CheckTimeout(ctx))
if originData.Type == po.Format || po.Format == imagetype.Unknown {
// Don't process SVG
if originData.Type == imagetype.SVG {
if config.SanitizeSvg {
sanitized, svgErr := svg.Sanitize(originData)
checkErr(ctx, "svg_processing", svgErr)
// Skip processing svg with unknown or the same destination imageType
// if it's not forced by AlwaysRasterizeSvg option
// Also skip processing if the format is in SkipProcessingFormats
shouldSkipProcessing := (originData.Type == po.Format || po.Format == imagetype.Unknown) &&
(slices.Contains(po.SkipProcessingFormats, originData.Type) ||
originData.Type == imagetype.SVG && !config.AlwaysRasterizeSvg)
// Since we'll replace origin data, it's better to close it to return
// it's buffer to the pool
originData.Close()
if shouldSkipProcessing {
if originData.Type == imagetype.SVG && config.SanitizeSvg {
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 {
for _, f := range po.SkipProcessingFormats {
if f == originData.Type {
respondWithImage(reqID, r, rw, statusCode, originData, po, imageURL, originData)
return
}
}
}
respondWithImage(reqID, r, rw, statusCode, originData, po, imageURL, originData)
return
}
if !vips.SupportsLoad(originData.Type) {

View File

@@ -608,7 +608,6 @@ func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqExactMatchLastModifiedD
require.Equal(s.T(), "", modifiedSince)
rw.WriteHeader(200)
rw.Write(data)
}))
defer ts.Close()
@@ -619,6 +618,7 @@ func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqExactMatchLastModifiedD
require.Equal(s.T(), 200, res.StatusCode)
}
func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqExactMatchLastModifiedEnabled() {
config.LastModifiedEnabled = true
lastModified := "Wed, 21 Oct 2015 07:28:00 GMT"
@@ -657,6 +657,7 @@ func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareMoreRecentLastMo
require.Equal(s.T(), 200, res.StatusCode)
}
func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareMoreRecentLastModifiedEnabled() {
config.LastModifiedEnabled = true
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)
}
func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareTooOldLastModifiedDisabled() {
config.LastModifiedEnabled = false
data := s.readTestFile("test1.png")
@@ -698,6 +700,7 @@ func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareTooOldLastModifi
require.Equal(s.T(), 200, res.StatusCode)
}
func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareTooOldLastModifiedEnabled() {
config.LastModifiedEnabled = true
data := s.readTestFile("test1.png")
@@ -721,6 +724,49 @@ func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareTooOldLastModifi
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) {
suite.Run(t, new(ProcessingHandlerTestSuite))
}