mirror of
https://github.com/imgproxy/imgproxy.git
synced 2024-11-29 08:22:11 +02:00
4944dfab30
* Always return Last-Modified and support If-Modified-Since. * IMGPROXY_USE_LAST_MODIFIED config setting. IMGPROXY_USE_LAST_MODIFIED (default false) when enabled will return the Last-Modified time of the upstream image and also allow the support of the If-Modified-Since request header (returning a 304 if the image hasn't been modified). If-Modified-Since allows If-None-Match to take precedence. * Fixes based on DarthSim's feedback. 1. Don't worry about nil maps. 2. Fix a test now that we use the config.LastModifiedEnabled (and move it's location it he test file to a more sane place). 3. Update GCS transport code based on the refactoring of DarthSim. In this iteration, we pull the Updated time from the GCS object attributes and format them as a string. We then parse it in the notmodified module. Seems a bit silly to do it this way. If we agree on the approach here, then AWS and Azure can follow. * Support azure, fs, s3, and swift. * Grab the headers for If-Modified-Since and Last-Modified before parsing them. * Add tests for last-modified for fs. * Support Last-Modified being passed when streaming an upstream file. * Tests for Last-Modified for GCS and Azure * Support s3 and swift tests. Sadly fakes3 doesn't support Last-Modified * Test against forked gofakes3
709 lines
20 KiB
Go
709 lines
20 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/imgproxy/imgproxy/v3/config"
|
|
"github.com/imgproxy/imgproxy/v3/config/configurators"
|
|
"github.com/imgproxy/imgproxy/v3/etag"
|
|
"github.com/imgproxy/imgproxy/v3/imagedata"
|
|
"github.com/imgproxy/imgproxy/v3/imagemeta"
|
|
"github.com/imgproxy/imgproxy/v3/imagetype"
|
|
"github.com/imgproxy/imgproxy/v3/options"
|
|
"github.com/imgproxy/imgproxy/v3/router"
|
|
"github.com/imgproxy/imgproxy/v3/svg"
|
|
"github.com/imgproxy/imgproxy/v3/vips"
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
type ProcessingHandlerTestSuite struct {
|
|
suite.Suite
|
|
|
|
router *router.Router
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) SetupSuite() {
|
|
config.Reset()
|
|
|
|
wd, err := os.Getwd()
|
|
require.Nil(s.T(), err)
|
|
|
|
config.LocalFileSystemRoot = filepath.Join(wd, "/testdata")
|
|
// Disable keep-alive to test connection restrictions
|
|
config.ClientKeepAliveTimeout = 0
|
|
|
|
err = initialize()
|
|
require.Nil(s.T(), err)
|
|
|
|
logrus.SetOutput(io.Discard)
|
|
|
|
s.router = buildRouter()
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TeardownSuite() {
|
|
shutdown()
|
|
logrus.SetOutput(os.Stdout)
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) SetupTest() {
|
|
// We don't need config.LocalFileSystemRoot anymore as it is used
|
|
// only during initialization
|
|
config.Reset()
|
|
config.AllowLoopbackSourceAddresses = true
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) send(path string, header ...http.Header) *httptest.ResponseRecorder {
|
|
req := httptest.NewRequest(http.MethodGet, path, nil)
|
|
rw := httptest.NewRecorder()
|
|
|
|
if len(header) > 0 {
|
|
req.Header = header[0]
|
|
}
|
|
|
|
s.router.ServeHTTP(rw, req)
|
|
|
|
return rw
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) readTestFile(name string) []byte {
|
|
wd, err := os.Getwd()
|
|
require.Nil(s.T(), err)
|
|
|
|
data, err := os.ReadFile(filepath.Join(wd, "testdata", name))
|
|
require.Nil(s.T(), err)
|
|
|
|
return data
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) readBody(res *http.Response) []byte {
|
|
data, err := io.ReadAll(res.Body)
|
|
require.Nil(s.T(), err)
|
|
return data
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) sampleETagData(imgETag string) (string, *imagedata.ImageData, string) {
|
|
poStr := "rs:fill:4:4"
|
|
|
|
po := options.NewProcessingOptions()
|
|
po.ResizingType = options.ResizeFill
|
|
po.Width = 4
|
|
po.Height = 4
|
|
|
|
imgdata := imagedata.ImageData{
|
|
Type: imagetype.PNG,
|
|
Data: s.readTestFile("test1.png"),
|
|
}
|
|
|
|
if len(imgETag) != 0 {
|
|
imgdata.Headers = map[string]string{"ETag": imgETag}
|
|
}
|
|
|
|
var h etag.Handler
|
|
|
|
h.SetActualProcessingOptions(po)
|
|
h.SetActualImageData(&imgdata)
|
|
return poStr, &imgdata, h.GenerateActualETag()
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestRequest() {
|
|
rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png")
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 200, res.StatusCode)
|
|
require.Equal(s.T(), "image/png", res.Header.Get("Content-Type"))
|
|
|
|
meta, err := imagemeta.DecodeMeta(res.Body)
|
|
|
|
require.Nil(s.T(), err)
|
|
require.Equal(s.T(), imagetype.PNG, meta.Format())
|
|
require.Equal(s.T(), 4, meta.Width())
|
|
require.Equal(s.T(), 4, meta.Height())
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestSignatureValidationFailure() {
|
|
config.Keys = [][]byte{[]byte("test-key")}
|
|
config.Salts = [][]byte{[]byte("test-salt")}
|
|
|
|
rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png")
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 403, res.StatusCode)
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestSignatureValidationSuccess() {
|
|
config.Keys = [][]byte{[]byte("test-key")}
|
|
config.Salts = [][]byte{[]byte("test-salt")}
|
|
|
|
rw := s.send("/My9d3xq_PYpVHsPrCyww0Kh1w5KZeZhIlWhsa4az1TI/rs:fill:4:4/plain/local:///test1.png")
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 200, res.StatusCode)
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestSourceValidation() {
|
|
imagedata.RedirectAllRequestsTo("local:///test1.png")
|
|
defer imagedata.StopRedirectingRequests()
|
|
|
|
tt := []struct {
|
|
name string
|
|
allowedSources []string
|
|
requestPath string
|
|
expectedError bool
|
|
}{
|
|
{
|
|
name: "match http URL without wildcard",
|
|
allowedSources: []string{"local://", "http://images.dev/"},
|
|
requestPath: "/unsafe/plain/http://images.dev/lorem/ipsum.jpg",
|
|
expectedError: false,
|
|
},
|
|
{
|
|
name: "match http URL with wildcard in hostname single level",
|
|
allowedSources: []string{"local://", "http://*.mycdn.dev/"},
|
|
requestPath: "/unsafe/plain/http://a-1.mycdn.dev/lorem/ipsum.jpg",
|
|
expectedError: false,
|
|
},
|
|
{
|
|
name: "match http URL with wildcard in hostname multiple levels",
|
|
allowedSources: []string{"local://", "http://*.mycdn.dev/"},
|
|
requestPath: "/unsafe/plain/http://a-1.b-2.mycdn.dev/lorem/ipsum.jpg",
|
|
expectedError: false,
|
|
},
|
|
{
|
|
name: "no match s3 URL with allowed local and http URLs",
|
|
allowedSources: []string{"local://", "http://images.dev/"},
|
|
requestPath: "/unsafe/plain/s3://images/lorem/ipsum.jpg",
|
|
expectedError: true,
|
|
},
|
|
{
|
|
name: "no match http URL with wildcard in hostname including slash",
|
|
allowedSources: []string{"local://", "http://*.mycdn.dev/"},
|
|
requestPath: "/unsafe/plain/http://other.dev/.mycdn.dev/lorem/ipsum.jpg",
|
|
expectedError: true,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tt {
|
|
s.T().Run(tc.name, func(t *testing.T) {
|
|
exps := make([]*regexp.Regexp, len(tc.allowedSources))
|
|
for i, pattern := range tc.allowedSources {
|
|
exps[i] = configurators.RegexpFromPattern(pattern)
|
|
}
|
|
config.AllowedSources = exps
|
|
|
|
rw := s.send(tc.requestPath)
|
|
res := rw.Result()
|
|
|
|
if tc.expectedError {
|
|
require.Equal(s.T(), 404, res.StatusCode)
|
|
} else {
|
|
require.Equal(s.T(), 200, res.StatusCode)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestSourceNetworkValidation() {
|
|
data := s.readTestFile("test1.png")
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
rw.WriteHeader(200)
|
|
rw.Write(data)
|
|
}))
|
|
defer server.Close()
|
|
|
|
var rw *httptest.ResponseRecorder
|
|
|
|
u := fmt.Sprintf("/unsafe/rs:fill:4:4/plain/%s/test1.png", server.URL)
|
|
fmt.Println(u)
|
|
|
|
rw = s.send(u)
|
|
require.Equal(s.T(), 200, rw.Result().StatusCode)
|
|
|
|
config.AllowLoopbackSourceAddresses = false
|
|
rw = s.send(u)
|
|
require.Equal(s.T(), 404, rw.Result().StatusCode)
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestSourceFormatNotSupported() {
|
|
vips.DisableLoadSupport(imagetype.PNG)
|
|
defer vips.ResetLoadSupport()
|
|
|
|
rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png")
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 422, res.StatusCode)
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestResultingFormatNotSupported() {
|
|
vips.DisableSaveSupport(imagetype.PNG)
|
|
defer vips.ResetSaveSupport()
|
|
|
|
rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png@png")
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 422, res.StatusCode)
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestSkipProcessingConfig() {
|
|
config.SkipProcessingFormats = []imagetype.Type{imagetype.PNG}
|
|
|
|
rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png")
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 200, res.StatusCode)
|
|
|
|
actual := s.readBody(res)
|
|
expected := s.readTestFile("test1.png")
|
|
|
|
require.True(s.T(), bytes.Equal(expected, actual))
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestSkipProcessingPO() {
|
|
rw := s.send("/unsafe/rs:fill:4:4/skp:png/plain/local:///test1.png")
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 200, res.StatusCode)
|
|
|
|
actual := s.readBody(res)
|
|
expected := s.readTestFile("test1.png")
|
|
|
|
require.True(s.T(), bytes.Equal(expected, actual))
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestSkipProcessingSameFormat() {
|
|
config.SkipProcessingFormats = []imagetype.Type{imagetype.PNG}
|
|
|
|
rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png@png")
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 200, res.StatusCode)
|
|
|
|
actual := s.readBody(res)
|
|
expected := s.readTestFile("test1.png")
|
|
|
|
require.True(s.T(), bytes.Equal(expected, actual))
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestSkipProcessingDifferentFormat() {
|
|
config.SkipProcessingFormats = []imagetype.Type{imagetype.PNG}
|
|
|
|
rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png@jpg")
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 200, res.StatusCode)
|
|
|
|
actual := s.readBody(res)
|
|
expected := s.readTestFile("test1.png")
|
|
|
|
require.False(s.T(), bytes.Equal(expected, actual))
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestSkipProcessingSVG() {
|
|
rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.svg")
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 200, res.StatusCode)
|
|
|
|
actual := s.readBody(res)
|
|
expected, err := svg.Satitize(&imagedata.ImageData{Data: s.readTestFile("test1.svg")})
|
|
|
|
require.Nil(s.T(), err)
|
|
|
|
require.True(s.T(), bytes.Equal(expected.Data, actual))
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestNotSkipProcessingSVGToJPG() {
|
|
rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.svg@jpg")
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 200, res.StatusCode)
|
|
|
|
actual := s.readBody(res)
|
|
expected := s.readTestFile("test1.svg")
|
|
|
|
require.False(s.T(), bytes.Equal(expected, actual))
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestErrorSavingToSVG() {
|
|
rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png@svg")
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 422, res.StatusCode)
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestCacheControlPassthrough() {
|
|
config.CacheControlPassthrough = true
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
rw.Header().Set("Cache-Control", "fake-cache-control")
|
|
rw.Header().Set("Expires", "fake-expires")
|
|
rw.WriteHeader(200)
|
|
rw.Write(s.readTestFile("test1.png"))
|
|
}))
|
|
defer ts.Close()
|
|
|
|
rw := s.send("/unsafe/rs:fill:4:4/plain/" + ts.URL)
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), "fake-cache-control", res.Header.Get("Cache-Control"))
|
|
require.Equal(s.T(), "fake-expires", res.Header.Get("Expires"))
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestCacheControlPassthroughDisabled() {
|
|
config.CacheControlPassthrough = false
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
rw.Header().Set("Cache-Control", "fake-cache-control")
|
|
rw.Header().Set("Expires", "fake-expires")
|
|
rw.WriteHeader(200)
|
|
rw.Write(s.readTestFile("test1.png"))
|
|
}))
|
|
defer ts.Close()
|
|
|
|
rw := s.send("/unsafe/rs:fill:4:4/plain/" + ts.URL)
|
|
res := rw.Result()
|
|
|
|
require.NotEqual(s.T(), "fake-cache-control", res.Header.Get("Cache-Control"))
|
|
require.NotEqual(s.T(), "fake-expires", res.Header.Get("Expires"))
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestETagDisabled() {
|
|
config.ETagEnabled = false
|
|
|
|
rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png")
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 200, res.StatusCode)
|
|
require.Empty(s.T(), res.Header.Get("ETag"))
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestETagReqNoIfNotModified() {
|
|
config.ETagEnabled = true
|
|
|
|
poStr, imgdata, etag := s.sampleETagData("loremipsumdolor")
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
require.Empty(s.T(), r.Header.Get("If-None-Match"))
|
|
|
|
rw.Header().Set("ETag", imgdata.Headers["ETag"])
|
|
rw.WriteHeader(200)
|
|
rw.Write(s.readTestFile("test1.png"))
|
|
}))
|
|
defer ts.Close()
|
|
|
|
rw := s.send(fmt.Sprintf("/unsafe/%s/plain/%s", poStr, ts.URL))
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 200, res.StatusCode)
|
|
require.Equal(s.T(), etag, res.Header.Get("ETag"))
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestETagDataNoIfNotModified() {
|
|
config.ETagEnabled = true
|
|
|
|
poStr, imgdata, etag := s.sampleETagData("")
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
require.Empty(s.T(), r.Header.Get("If-None-Match"))
|
|
|
|
rw.WriteHeader(200)
|
|
rw.Write(imgdata.Data)
|
|
}))
|
|
defer ts.Close()
|
|
|
|
rw := s.send(fmt.Sprintf("/unsafe/%s/plain/%s", poStr, ts.URL))
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 200, res.StatusCode)
|
|
require.Equal(s.T(), etag, res.Header.Get("ETag"))
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestETagReqMatch() {
|
|
config.ETagEnabled = true
|
|
|
|
poStr, imgdata, etag := s.sampleETagData(`"loremipsumdolor"`)
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
require.Equal(s.T(), imgdata.Headers["ETag"], r.Header.Get("If-None-Match"))
|
|
|
|
rw.WriteHeader(304)
|
|
}))
|
|
defer ts.Close()
|
|
|
|
header := make(http.Header)
|
|
header.Set("If-None-Match", etag)
|
|
|
|
rw := s.send(fmt.Sprintf("/unsafe/%s/plain/%s", poStr, ts.URL), header)
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 304, res.StatusCode)
|
|
require.Equal(s.T(), etag, res.Header.Get("ETag"))
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestETagDataMatch() {
|
|
config.ETagEnabled = true
|
|
|
|
poStr, imgdata, etag := s.sampleETagData("")
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
require.Empty(s.T(), r.Header.Get("If-None-Match"))
|
|
|
|
rw.WriteHeader(200)
|
|
rw.Write(imgdata.Data)
|
|
}))
|
|
defer ts.Close()
|
|
|
|
header := make(http.Header)
|
|
header.Set("If-None-Match", etag)
|
|
|
|
rw := s.send(fmt.Sprintf("/unsafe/%s/plain/%s", poStr, ts.URL), header)
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 304, res.StatusCode)
|
|
require.Equal(s.T(), etag, res.Header.Get("ETag"))
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestETagReqNotMatch() {
|
|
config.ETagEnabled = true
|
|
|
|
poStr, imgdata, actualETag := s.sampleETagData(`"loremipsumdolor"`)
|
|
_, _, expectedETag := s.sampleETagData(`"loremipsum"`)
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
require.Equal(s.T(), `"loremipsum"`, r.Header.Get("If-None-Match"))
|
|
|
|
rw.Header().Set("ETag", imgdata.Headers["ETag"])
|
|
rw.WriteHeader(200)
|
|
rw.Write(imgdata.Data)
|
|
}))
|
|
defer ts.Close()
|
|
|
|
header := make(http.Header)
|
|
header.Set("If-None-Match", expectedETag)
|
|
|
|
rw := s.send(fmt.Sprintf("/unsafe/%s/plain/%s", poStr, ts.URL), header)
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 200, res.StatusCode)
|
|
require.Equal(s.T(), actualETag, res.Header.Get("ETag"))
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestETagDataNotMatch() {
|
|
config.ETagEnabled = true
|
|
|
|
poStr, imgdata, actualETag := s.sampleETagData("")
|
|
// Change the data hash
|
|
expectedETag := actualETag[:strings.IndexByte(actualETag, '/')] + "/Dasdbefj"
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
require.Empty(s.T(), r.Header.Get("If-None-Match"))
|
|
|
|
rw.WriteHeader(200)
|
|
rw.Write(imgdata.Data)
|
|
}))
|
|
defer ts.Close()
|
|
|
|
header := make(http.Header)
|
|
header.Set("If-None-Match", expectedETag)
|
|
|
|
rw := s.send(fmt.Sprintf("/unsafe/%s/plain/%s", poStr, ts.URL), header)
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 200, res.StatusCode)
|
|
require.Equal(s.T(), actualETag, res.Header.Get("ETag"))
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestETagProcessingOptionsNotMatch() {
|
|
config.ETagEnabled = true
|
|
|
|
poStr, imgdata, actualETag := s.sampleETagData("")
|
|
// Change the processing options hash
|
|
expectedETag := "abcdefj" + actualETag[strings.IndexByte(actualETag, '/'):]
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
require.Empty(s.T(), r.Header.Get("If-None-Match"))
|
|
|
|
rw.Header().Set("ETag", imgdata.Headers["ETag"])
|
|
rw.WriteHeader(200)
|
|
rw.Write(imgdata.Data)
|
|
}))
|
|
defer ts.Close()
|
|
|
|
header := make(http.Header)
|
|
header.Set("If-None-Match", expectedETag)
|
|
|
|
rw := s.send(fmt.Sprintf("/unsafe/%s/plain/%s", poStr, ts.URL), header)
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 200, res.StatusCode)
|
|
require.Equal(s.T(), actualETag, res.Header.Get("ETag"))
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestLastModifiedEnabled() {
|
|
config.LastModifiedEnabled = true
|
|
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
rw.Header().Set("Last-Modified", "Wed, 21 Oct 2015 07:28:00 GMT")
|
|
rw.WriteHeader(200)
|
|
rw.Write(s.readTestFile("test1.png"))
|
|
}))
|
|
defer ts.Close()
|
|
|
|
rw := s.send("/unsafe/rs:fill:4:4/plain/" + ts.URL)
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), "Wed, 21 Oct 2015 07:28:00 GMT", res.Header.Get("Last-Modified"))
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestLastModifiedDisabled() {
|
|
config.LastModifiedEnabled = false
|
|
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
rw.Header().Set("Last-Modified", "Wed, 21 Oct 2015 07:28:00 GMT")
|
|
rw.WriteHeader(200)
|
|
rw.Write(s.readTestFile("test1.png"))
|
|
}))
|
|
defer ts.Close()
|
|
|
|
rw := s.send("/unsafe/rs:fill:4:4/plain/" + ts.URL)
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), "", res.Header.Get("Last-Modified"))
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqExactMatchLastModifiedDisabled() {
|
|
config.LastModifiedEnabled = false
|
|
data := s.readTestFile("test1.png")
|
|
lastModified := "Wed, 21 Oct 2015 07:28:00 GMT"
|
|
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
modifiedSince := r.Header.Get("If-Modified-Since")
|
|
require.Equal(s.T(), "", modifiedSince)
|
|
rw.WriteHeader(200)
|
|
rw.Write(data)
|
|
|
|
}))
|
|
defer ts.Close()
|
|
|
|
header := make(http.Header)
|
|
header.Set("If-Modified-Since", lastModified)
|
|
rw := s.send(fmt.Sprintf("/unsafe/plain/%s", ts.URL), header)
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 200, res.StatusCode)
|
|
}
|
|
func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqExactMatchLastModifiedEnabled() {
|
|
config.LastModifiedEnabled = true
|
|
lastModified := "Wed, 21 Oct 2015 07:28:00 GMT"
|
|
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
modifiedSince := r.Header.Get("If-Modified-Since")
|
|
require.Equal(s.T(), lastModified, modifiedSince)
|
|
rw.WriteHeader(304)
|
|
}))
|
|
defer ts.Close()
|
|
|
|
header := make(http.Header)
|
|
header.Set("If-Modified-Since", lastModified)
|
|
rw := s.send(fmt.Sprintf("/unsafe/plain/%s", ts.URL), header)
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 304, res.StatusCode)
|
|
}
|
|
|
|
func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareMoreRecentLastModifiedDisabled() {
|
|
data := s.readTestFile("test1.png")
|
|
config.LastModifiedEnabled = false
|
|
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
modifiedSince := r.Header.Get("If-Modified-Since")
|
|
require.Equal(s.T(), modifiedSince, "")
|
|
rw.WriteHeader(200)
|
|
rw.Write(data)
|
|
}))
|
|
defer ts.Close()
|
|
|
|
recentTimestamp := "Thu, 25 Feb 2021 01:45:00 GMT"
|
|
|
|
header := make(http.Header)
|
|
header.Set("If-Modified-Since", recentTimestamp)
|
|
rw := s.send(fmt.Sprintf("/unsafe/plain/%s", ts.URL), header)
|
|
res := rw.Result()
|
|
|
|
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) {
|
|
fileLastModified, _ := time.Parse(http.TimeFormat, "Wed, 21 Oct 2015 07:28:00 GMT")
|
|
modifiedSince := r.Header.Get("If-Modified-Since")
|
|
parsedModifiedSince, err := time.Parse(http.TimeFormat, modifiedSince)
|
|
require.Nil(s.T(), err)
|
|
require.True(s.T(), fileLastModified.Before(parsedModifiedSince))
|
|
rw.WriteHeader(304)
|
|
}))
|
|
defer ts.Close()
|
|
|
|
recentTimestamp := "Thu, 25 Feb 2021 01:45:00 GMT"
|
|
|
|
header := make(http.Header)
|
|
header.Set("If-Modified-Since", recentTimestamp)
|
|
rw := s.send(fmt.Sprintf("/unsafe/plain/%s", ts.URL), header)
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 304, res.StatusCode)
|
|
}
|
|
func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareTooOldLastModifiedDisabled() {
|
|
config.LastModifiedEnabled = false
|
|
data := s.readTestFile("test1.png")
|
|
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
modifiedSince := r.Header.Get("If-Modified-Since")
|
|
require.Equal(s.T(), modifiedSince, "")
|
|
rw.WriteHeader(200)
|
|
rw.Write(data)
|
|
}))
|
|
defer ts.Close()
|
|
|
|
oldTimestamp := "Tue, 01 Oct 2013 17:31:00 GMT"
|
|
|
|
header := make(http.Header)
|
|
header.Set("If-Modified-Since", oldTimestamp)
|
|
rw := s.send(fmt.Sprintf("/unsafe/plain/%s", ts.URL), header)
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 200, res.StatusCode)
|
|
}
|
|
func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareTooOldLastModifiedEnabled() {
|
|
config.LastModifiedEnabled = true
|
|
data := s.readTestFile("test1.png")
|
|
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
fileLastModified, _ := time.Parse(http.TimeFormat, "Wed, 21 Oct 2015 07:28:00 GMT")
|
|
modifiedSince := r.Header.Get("If-Modified-Since")
|
|
parsedModifiedSince, err := time.Parse(http.TimeFormat, modifiedSince)
|
|
require.Nil(s.T(), err)
|
|
require.True(s.T(), fileLastModified.After(parsedModifiedSince))
|
|
rw.WriteHeader(200)
|
|
rw.Write(data)
|
|
}))
|
|
defer ts.Close()
|
|
|
|
oldTimestamp := "Tue, 01 Oct 2013 17:31:00 GMT"
|
|
|
|
header := make(http.Header)
|
|
header.Set("If-Modified-Since", oldTimestamp)
|
|
rw := s.send(fmt.Sprintf("/unsafe/plain/%s", ts.URL), header)
|
|
res := rw.Result()
|
|
|
|
require.Equal(s.T(), 200, res.StatusCode)
|
|
}
|
|
func TestProcessingHandler(t *testing.T) {
|
|
suite.Run(t, new(ProcessingHandlerTestSuite))
|
|
}
|