1
0

processing_handler_test.go 18 KB

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