processing_handler_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. package main
  2. import (
  3. "fmt"
  4. "io"
  5. "net/http"
  6. "net/http/httptest"
  7. "os"
  8. "path/filepath"
  9. "regexp"
  10. "testing"
  11. "time"
  12. "github.com/sirupsen/logrus"
  13. "github.com/stretchr/testify/suite"
  14. "github.com/imgproxy/imgproxy/v3/config"
  15. "github.com/imgproxy/imgproxy/v3/config/configurators"
  16. "github.com/imgproxy/imgproxy/v3/httpheaders"
  17. "github.com/imgproxy/imgproxy/v3/imagedata"
  18. "github.com/imgproxy/imgproxy/v3/imagetype"
  19. "github.com/imgproxy/imgproxy/v3/server"
  20. "github.com/imgproxy/imgproxy/v3/svg"
  21. "github.com/imgproxy/imgproxy/v3/testutil"
  22. "github.com/imgproxy/imgproxy/v3/vips"
  23. )
  24. type ProcessingHandlerTestSuite struct {
  25. suite.Suite
  26. router *server.Router
  27. }
  28. func (s *ProcessingHandlerTestSuite) SetupSuite() {
  29. config.Reset()
  30. wd, err := os.Getwd()
  31. s.Require().NoError(err)
  32. s.T().Setenv("IMGPROXY_LOCAL_FILESYSTEM_ROOT", filepath.Join(wd, "/testdata"))
  33. s.T().Setenv("IMGPROXY_CLIENT_KEEP_ALIVE_TIMEOUT", "0")
  34. err = initialize()
  35. s.Require().NoError(err)
  36. logrus.SetOutput(io.Discard)
  37. cfg := server.NewDefaultConfig()
  38. r, err := server.NewRouter(cfg)
  39. s.Require().NoError(err)
  40. s.router = buildRouter(r)
  41. }
  42. func (s *ProcessingHandlerTestSuite) TeardownSuite() {
  43. shutdown()
  44. logrus.SetOutput(os.Stdout)
  45. }
  46. func (s *ProcessingHandlerTestSuite) SetupTest() {
  47. // We don't need config.LocalFileSystemRoot anymore as it is used
  48. // only during initialization
  49. config.Reset()
  50. config.AllowLoopbackSourceAddresses = true
  51. }
  52. func (s *ProcessingHandlerTestSuite) send(path string, header ...http.Header) *httptest.ResponseRecorder {
  53. req := httptest.NewRequest(http.MethodGet, path, nil)
  54. rw := httptest.NewRecorder()
  55. if len(header) > 0 {
  56. req.Header = header[0]
  57. }
  58. s.router.ServeHTTP(rw, req)
  59. return rw
  60. }
  61. func (s *ProcessingHandlerTestSuite) readTestFile(name string) []byte {
  62. wd, err := os.Getwd()
  63. s.Require().NoError(err)
  64. data, err := os.ReadFile(filepath.Join(wd, "testdata", name))
  65. s.Require().NoError(err)
  66. return data
  67. }
  68. func (s *ProcessingHandlerTestSuite) readTestImageData(name string) imagedata.ImageData {
  69. wd, err := os.Getwd()
  70. s.Require().NoError(err)
  71. data, err := os.ReadFile(filepath.Join(wd, "testdata", name))
  72. s.Require().NoError(err)
  73. imgdata, err := imagedata.NewFromBytes(data)
  74. s.Require().NoError(err)
  75. return imgdata
  76. }
  77. func (s *ProcessingHandlerTestSuite) TestRequest() {
  78. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png")
  79. res := rw.Result()
  80. s.Require().Equal(200, res.StatusCode)
  81. s.Require().Equal("image/png", res.Header.Get("Content-Type"))
  82. format, err := imagetype.Detect(res.Body)
  83. s.Require().NoError(err)
  84. s.Require().Equal(imagetype.PNG, format)
  85. }
  86. func (s *ProcessingHandlerTestSuite) TestSignatureValidationFailure() {
  87. config.Keys = [][]byte{[]byte("test-key")}
  88. config.Salts = [][]byte{[]byte("test-salt")}
  89. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png")
  90. res := rw.Result()
  91. s.Require().Equal(403, res.StatusCode)
  92. }
  93. func (s *ProcessingHandlerTestSuite) TestSignatureValidationSuccess() {
  94. config.Keys = [][]byte{[]byte("test-key")}
  95. config.Salts = [][]byte{[]byte("test-salt")}
  96. rw := s.send("/My9d3xq_PYpVHsPrCyww0Kh1w5KZeZhIlWhsa4az1TI/rs:fill:4:4/plain/local:///test1.png")
  97. res := rw.Result()
  98. s.Require().Equal(200, res.StatusCode)
  99. }
  100. func (s *ProcessingHandlerTestSuite) TestSourceValidation() {
  101. imagedata.RedirectAllRequestsTo("local:///test1.png")
  102. defer imagedata.StopRedirectingRequests()
  103. tt := []struct {
  104. name string
  105. allowedSources []string
  106. requestPath string
  107. expectedError bool
  108. }{
  109. {
  110. name: "match http URL without wildcard",
  111. allowedSources: []string{"local://", "http://images.dev/"},
  112. requestPath: "/unsafe/plain/http://images.dev/lorem/ipsum.jpg",
  113. expectedError: false,
  114. },
  115. {
  116. name: "match http URL with wildcard in hostname single level",
  117. allowedSources: []string{"local://", "http://*.mycdn.dev/"},
  118. requestPath: "/unsafe/plain/http://a-1.mycdn.dev/lorem/ipsum.jpg",
  119. expectedError: false,
  120. },
  121. {
  122. name: "match http URL with wildcard in hostname multiple levels",
  123. allowedSources: []string{"local://", "http://*.mycdn.dev/"},
  124. requestPath: "/unsafe/plain/http://a-1.b-2.mycdn.dev/lorem/ipsum.jpg",
  125. expectedError: false,
  126. },
  127. {
  128. name: "no match s3 URL with allowed local and http URLs",
  129. allowedSources: []string{"local://", "http://images.dev/"},
  130. requestPath: "/unsafe/plain/s3://images/lorem/ipsum.jpg",
  131. expectedError: true,
  132. },
  133. {
  134. name: "no match http URL with wildcard in hostname including slash",
  135. allowedSources: []string{"local://", "http://*.mycdn.dev/"},
  136. requestPath: "/unsafe/plain/http://other.dev/.mycdn.dev/lorem/ipsum.jpg",
  137. expectedError: true,
  138. },
  139. }
  140. for _, tc := range tt {
  141. s.Run(tc.name, func() {
  142. exps := make([]*regexp.Regexp, len(tc.allowedSources))
  143. for i, pattern := range tc.allowedSources {
  144. exps[i] = configurators.RegexpFromPattern(pattern)
  145. }
  146. config.AllowedSources = exps
  147. rw := s.send(tc.requestPath)
  148. res := rw.Result()
  149. if tc.expectedError {
  150. s.Require().Equal(404, res.StatusCode)
  151. } else {
  152. s.Require().Equal(200, res.StatusCode)
  153. }
  154. })
  155. }
  156. }
  157. func (s *ProcessingHandlerTestSuite) TestSourceNetworkValidation() {
  158. data := s.readTestFile("test1.png")
  159. server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  160. rw.WriteHeader(200)
  161. rw.Write(data)
  162. }))
  163. defer server.Close()
  164. var rw *httptest.ResponseRecorder
  165. u := fmt.Sprintf("/unsafe/rs:fill:4:4/plain/%s/test1.png", server.URL)
  166. rw = s.send(u)
  167. s.Require().Equal(200, rw.Result().StatusCode)
  168. config.AllowLoopbackSourceAddresses = false
  169. rw = s.send(u)
  170. s.Require().Equal(404, rw.Result().StatusCode)
  171. }
  172. func (s *ProcessingHandlerTestSuite) TestSourceFormatNotSupported() {
  173. vips.DisableLoadSupport(imagetype.PNG)
  174. defer vips.ResetLoadSupport()
  175. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png")
  176. res := rw.Result()
  177. s.Require().Equal(422, res.StatusCode)
  178. }
  179. func (s *ProcessingHandlerTestSuite) TestResultingFormatNotSupported() {
  180. vips.DisableSaveSupport(imagetype.PNG)
  181. defer vips.ResetSaveSupport()
  182. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png@png")
  183. res := rw.Result()
  184. s.Require().Equal(422, res.StatusCode)
  185. }
  186. func (s *ProcessingHandlerTestSuite) TestSkipProcessingConfig() {
  187. config.SkipProcessingFormats = []imagetype.Type{imagetype.PNG}
  188. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png")
  189. res := rw.Result()
  190. s.Require().Equal(200, res.StatusCode)
  191. expected := s.readTestImageData("test1.png")
  192. s.Require().True(testutil.ReadersEqual(s.T(), expected.Reader(), res.Body))
  193. }
  194. func (s *ProcessingHandlerTestSuite) TestSkipProcessingPO() {
  195. rw := s.send("/unsafe/rs:fill:4:4/skp:png/plain/local:///test1.png")
  196. res := rw.Result()
  197. s.Require().Equal(200, res.StatusCode)
  198. expected := s.readTestImageData("test1.png")
  199. s.Require().True(testutil.ReadersEqual(s.T(), expected.Reader(), res.Body))
  200. }
  201. func (s *ProcessingHandlerTestSuite) TestSkipProcessingSameFormat() {
  202. config.SkipProcessingFormats = []imagetype.Type{imagetype.PNG}
  203. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png@png")
  204. res := rw.Result()
  205. s.Require().Equal(200, res.StatusCode)
  206. expected := s.readTestImageData("test1.png")
  207. s.Require().True(testutil.ReadersEqual(s.T(), expected.Reader(), res.Body))
  208. }
  209. func (s *ProcessingHandlerTestSuite) TestSkipProcessingDifferentFormat() {
  210. config.SkipProcessingFormats = []imagetype.Type{imagetype.PNG}
  211. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png@jpg")
  212. res := rw.Result()
  213. s.Require().Equal(200, res.StatusCode)
  214. expected := s.readTestImageData("test1.png")
  215. s.Require().False(testutil.ReadersEqual(s.T(), expected.Reader(), res.Body))
  216. }
  217. func (s *ProcessingHandlerTestSuite) TestSkipProcessingSVG() {
  218. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.svg")
  219. res := rw.Result()
  220. s.Require().Equal(200, res.StatusCode)
  221. expected, err := svg.Sanitize(s.readTestImageData("test1.svg"))
  222. s.Require().NoError(err)
  223. s.Require().True(testutil.ReadersEqual(s.T(), expected.Reader(), res.Body))
  224. }
  225. func (s *ProcessingHandlerTestSuite) TestNotSkipProcessingSVGToJPG() {
  226. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.svg@jpg")
  227. res := rw.Result()
  228. s.Require().Equal(200, res.StatusCode)
  229. expected := s.readTestImageData("test1.svg")
  230. s.Require().False(testutil.ReadersEqual(s.T(), expected.Reader(), res.Body))
  231. }
  232. func (s *ProcessingHandlerTestSuite) TestErrorSavingToSVG() {
  233. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png@svg")
  234. res := rw.Result()
  235. s.Require().Equal(422, res.StatusCode)
  236. }
  237. func (s *ProcessingHandlerTestSuite) TestCacheControlPassthroughCacheControl() {
  238. config.CacheControlPassthrough = true
  239. ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  240. rw.Header().Set("Cache-Control", "max-age=1234, public")
  241. rw.Header().Set("Expires", time.Now().Add(time.Hour).UTC().Format(http.TimeFormat))
  242. rw.WriteHeader(200)
  243. rw.Write(s.readTestFile("test1.png"))
  244. }))
  245. defer ts.Close()
  246. rw := s.send("/unsafe/rs:fill:4:4/plain/" + ts.URL)
  247. res := rw.Result()
  248. s.Require().Equal("max-age=1234, public", res.Header.Get("Cache-Control"))
  249. s.Require().Empty(res.Header.Get("Expires"))
  250. }
  251. func (s *ProcessingHandlerTestSuite) TestCacheControlPassthroughExpires() {
  252. config.CacheControlPassthrough = true
  253. ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  254. rw.Header().Set("Expires", time.Now().Add(1239*time.Second).UTC().Format(http.TimeFormat))
  255. rw.WriteHeader(200)
  256. rw.Write(s.readTestFile("test1.png"))
  257. }))
  258. defer ts.Close()
  259. rw := s.send("/unsafe/rs:fill:4:4/plain/" + ts.URL)
  260. res := rw.Result()
  261. // Use regex to allow some delay
  262. s.Require().Regexp("max-age=123[0-9], public", res.Header.Get("Cache-Control"))
  263. s.Require().Empty(res.Header.Get("Expires"))
  264. }
  265. func (s *ProcessingHandlerTestSuite) TestCacheControlPassthroughDisabled() {
  266. config.CacheControlPassthrough = false
  267. ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  268. rw.Header().Set("Cache-Control", "max-age=1234, public")
  269. rw.Header().Set("Expires", time.Now().Add(time.Hour).UTC().Format(http.TimeFormat))
  270. rw.WriteHeader(200)
  271. rw.Write(s.readTestFile("test1.png"))
  272. }))
  273. defer ts.Close()
  274. rw := s.send("/unsafe/rs:fill:4:4/plain/" + ts.URL)
  275. res := rw.Result()
  276. s.Require().NotEqual("max-age=1234, public", res.Header.Get("Cache-Control"))
  277. s.Require().Empty(res.Header.Get("Expires"))
  278. }
  279. func (s *ProcessingHandlerTestSuite) TestETagDisabled() {
  280. config.ETagEnabled = false
  281. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png")
  282. res := rw.Result()
  283. s.Require().Equal(200, res.StatusCode)
  284. s.Require().Empty(res.Header.Get("ETag"))
  285. }
  286. func (s *ProcessingHandlerTestSuite) TestETagDataMatch() {
  287. config.ETagEnabled = true
  288. etag := `"loremipsumdolor"`
  289. ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  290. s.NotEmpty(r.Header.Get(httpheaders.IfNoneMatch))
  291. rw.Header().Set(httpheaders.Etag, etag)
  292. rw.WriteHeader(http.StatusNotModified)
  293. }))
  294. defer ts.Close()
  295. header := make(http.Header)
  296. header.Set(httpheaders.IfNoneMatch, etag)
  297. rw := s.send(fmt.Sprintf("/unsafe/plain/%s", ts.URL), header)
  298. res := rw.Result()
  299. s.Require().Equal(304, res.StatusCode)
  300. s.Require().Equal(etag, res.Header.Get(httpheaders.Etag))
  301. }
  302. func (s *ProcessingHandlerTestSuite) TestLastModifiedEnabled() {
  303. config.LastModifiedEnabled = true
  304. ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  305. rw.Header().Set("Last-Modified", "Wed, 21 Oct 2015 07:28:00 GMT")
  306. rw.WriteHeader(200)
  307. rw.Write(s.readTestFile("test1.png"))
  308. }))
  309. defer ts.Close()
  310. rw := s.send("/unsafe/rs:fill:4:4/plain/" + ts.URL)
  311. res := rw.Result()
  312. s.Require().Equal("Wed, 21 Oct 2015 07:28:00 GMT", res.Header.Get("Last-Modified"))
  313. }
  314. func (s *ProcessingHandlerTestSuite) TestLastModifiedDisabled() {
  315. config.LastModifiedEnabled = false
  316. ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  317. rw.Header().Set("Last-Modified", "Wed, 21 Oct 2015 07:28:00 GMT")
  318. rw.WriteHeader(200)
  319. rw.Write(s.readTestFile("test1.png"))
  320. }))
  321. defer ts.Close()
  322. rw := s.send("/unsafe/rs:fill:4:4/plain/" + ts.URL)
  323. res := rw.Result()
  324. s.Require().Empty(res.Header.Get("Last-Modified"))
  325. }
  326. func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqExactMatchLastModifiedDisabled() {
  327. config.LastModifiedEnabled = false
  328. data := s.readTestFile("test1.png")
  329. lastModified := "Wed, 21 Oct 2015 07:28:00 GMT"
  330. ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  331. modifiedSince := r.Header.Get("If-Modified-Since")
  332. s.Empty(modifiedSince)
  333. rw.WriteHeader(200)
  334. rw.Write(data)
  335. }))
  336. defer ts.Close()
  337. header := make(http.Header)
  338. header.Set("If-Modified-Since", lastModified)
  339. rw := s.send(fmt.Sprintf("/unsafe/plain/%s", ts.URL), header)
  340. res := rw.Result()
  341. s.Require().Equal(200, res.StatusCode)
  342. }
  343. func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqExactMatchLastModifiedEnabled() {
  344. config.LastModifiedEnabled = true
  345. lastModified := "Wed, 21 Oct 2015 07:28:00 GMT"
  346. ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  347. modifiedSince := r.Header.Get("If-Modified-Since")
  348. s.Equal(lastModified, modifiedSince)
  349. rw.WriteHeader(304)
  350. }))
  351. defer ts.Close()
  352. header := make(http.Header)
  353. header.Set("If-Modified-Since", lastModified)
  354. rw := s.send(fmt.Sprintf("/unsafe/plain/%s", ts.URL), header)
  355. res := rw.Result()
  356. s.Require().Equal(304, res.StatusCode)
  357. }
  358. func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareMoreRecentLastModifiedDisabled() {
  359. data := s.readTestFile("test1.png")
  360. config.LastModifiedEnabled = false
  361. ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  362. modifiedSince := r.Header.Get("If-Modified-Since")
  363. s.Empty(modifiedSince)
  364. rw.WriteHeader(200)
  365. rw.Write(data)
  366. }))
  367. defer ts.Close()
  368. recentTimestamp := "Thu, 25 Feb 2021 01:45:00 GMT"
  369. header := make(http.Header)
  370. header.Set("If-Modified-Since", recentTimestamp)
  371. rw := s.send(fmt.Sprintf("/unsafe/plain/%s", ts.URL), header)
  372. res := rw.Result()
  373. s.Require().Equal(200, res.StatusCode)
  374. }
  375. func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareMoreRecentLastModifiedEnabled() {
  376. config.LastModifiedEnabled = true
  377. ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  378. fileLastModified, _ := time.Parse(http.TimeFormat, "Wed, 21 Oct 2015 07:28:00 GMT")
  379. modifiedSince := r.Header.Get("If-Modified-Since")
  380. parsedModifiedSince, err := time.Parse(http.TimeFormat, modifiedSince)
  381. s.NoError(err)
  382. s.True(fileLastModified.Before(parsedModifiedSince))
  383. rw.WriteHeader(304)
  384. }))
  385. defer ts.Close()
  386. recentTimestamp := "Thu, 25 Feb 2021 01:45:00 GMT"
  387. header := make(http.Header)
  388. header.Set("If-Modified-Since", recentTimestamp)
  389. rw := s.send(fmt.Sprintf("/unsafe/plain/%s", ts.URL), header)
  390. res := rw.Result()
  391. s.Require().Equal(304, res.StatusCode)
  392. }
  393. func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareTooOldLastModifiedDisabled() {
  394. config.LastModifiedEnabled = false
  395. data := s.readTestFile("test1.png")
  396. ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  397. modifiedSince := r.Header.Get("If-Modified-Since")
  398. s.Empty(modifiedSince)
  399. rw.WriteHeader(200)
  400. rw.Write(data)
  401. }))
  402. defer ts.Close()
  403. oldTimestamp := "Tue, 01 Oct 2013 17:31:00 GMT"
  404. header := make(http.Header)
  405. header.Set("If-Modified-Since", oldTimestamp)
  406. rw := s.send(fmt.Sprintf("/unsafe/plain/%s", ts.URL), header)
  407. res := rw.Result()
  408. s.Require().Equal(200, res.StatusCode)
  409. }
  410. func (s *ProcessingHandlerTestSuite) TestModifiedSinceReqCompareTooOldLastModifiedEnabled() {
  411. config.LastModifiedEnabled = true
  412. data := s.readTestFile("test1.png")
  413. ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  414. fileLastModified, _ := time.Parse(http.TimeFormat, "Wed, 21 Oct 2015 07:28:00 GMT")
  415. modifiedSince := r.Header.Get("If-Modified-Since")
  416. parsedModifiedSince, err := time.Parse(http.TimeFormat, modifiedSince)
  417. s.NoError(err)
  418. s.True(fileLastModified.After(parsedModifiedSince))
  419. rw.WriteHeader(200)
  420. rw.Write(data)
  421. }))
  422. defer ts.Close()
  423. oldTimestamp := "Tue, 01 Oct 2013 17:31:00 GMT"
  424. header := make(http.Header)
  425. header.Set("If-Modified-Since", oldTimestamp)
  426. rw := s.send(fmt.Sprintf("/unsafe/plain/%s", ts.URL), header)
  427. res := rw.Result()
  428. s.Require().Equal(200, res.StatusCode)
  429. }
  430. func (s *ProcessingHandlerTestSuite) TestAlwaysRasterizeSvg() {
  431. config.AlwaysRasterizeSvg = true
  432. rw := s.send("/unsafe/rs:fill:40:40/plain/local:///test1.svg")
  433. res := rw.Result()
  434. s.Require().Equal(200, res.StatusCode)
  435. s.Require().Equal("image/png", res.Header.Get("Content-Type"))
  436. }
  437. func (s *ProcessingHandlerTestSuite) TestAlwaysRasterizeSvgWithEnforceAvif() {
  438. config.AlwaysRasterizeSvg = true
  439. config.EnforceWebp = true
  440. rw := s.send("/unsafe/plain/local:///test1.svg", http.Header{"Accept": []string{"image/webp"}})
  441. res := rw.Result()
  442. s.Require().Equal(200, res.StatusCode)
  443. s.Require().Equal("image/webp", res.Header.Get("Content-Type"))
  444. }
  445. func (s *ProcessingHandlerTestSuite) TestAlwaysRasterizeSvgDisabled() {
  446. config.AlwaysRasterizeSvg = false
  447. config.EnforceWebp = true
  448. rw := s.send("/unsafe/plain/local:///test1.svg")
  449. res := rw.Result()
  450. s.Require().Equal(200, res.StatusCode)
  451. s.Require().Equal("image/svg+xml", res.Header.Get("Content-Type"))
  452. }
  453. func (s *ProcessingHandlerTestSuite) TestAlwaysRasterizeSvgWithFormat() {
  454. config.AlwaysRasterizeSvg = true
  455. config.SkipProcessingFormats = []imagetype.Type{imagetype.SVG}
  456. rw := s.send("/unsafe/plain/local:///test1.svg@svg")
  457. res := rw.Result()
  458. s.Require().Equal(200, res.StatusCode)
  459. s.Require().Equal("image/svg+xml", res.Header.Get("Content-Type"))
  460. }
  461. func (s *ProcessingHandlerTestSuite) TestMaxSrcFileSizeGlobal() {
  462. config.MaxSrcFileSize = 1
  463. ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  464. rw.WriteHeader(200)
  465. rw.Write(s.readTestFile("test1.png"))
  466. }))
  467. defer ts.Close()
  468. rw := s.send("/unsafe/rs:fill:4:4/plain/" + ts.URL)
  469. res := rw.Result()
  470. s.Require().Equal(422, res.StatusCode)
  471. }
  472. func TestProcessingHandler(t *testing.T) {
  473. suite.Run(t, new(ProcessingHandlerTestSuite))
  474. }