processing_handler_test.go 18 KB

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