processing_handler_test.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. package main
  2. import (
  3. "bytes"
  4. "io"
  5. "net/http"
  6. "net/http/httptest"
  7. "os"
  8. "path/filepath"
  9. "testing"
  10. "github.com/imgproxy/imgproxy/v2/config"
  11. "github.com/imgproxy/imgproxy/v2/imagemeta"
  12. "github.com/imgproxy/imgproxy/v2/imagetype"
  13. "github.com/imgproxy/imgproxy/v2/router"
  14. "github.com/imgproxy/imgproxy/v2/vips"
  15. "github.com/sirupsen/logrus"
  16. "github.com/stretchr/testify/assert"
  17. "github.com/stretchr/testify/suite"
  18. )
  19. type ProcessingHandlerTestSuite struct {
  20. suite.Suite
  21. router *router.Router
  22. }
  23. func (s *ProcessingHandlerTestSuite) SetupSuite() {
  24. config.Reset()
  25. wd, err := os.Getwd()
  26. assert.Nil(s.T(), err)
  27. config.LocalFileSystemRoot = filepath.Join(wd, "/testdata")
  28. logrus.SetOutput(io.Discard)
  29. initialize()
  30. s.router = buildRouter()
  31. }
  32. func (s *ProcessingHandlerTestSuite) TeardownSuite() {
  33. shutdown()
  34. logrus.SetOutput(os.Stdout)
  35. }
  36. func (s *ProcessingHandlerTestSuite) SetupTest() {
  37. // We don't need config.LocalFileSystemRoot anymore as it is used
  38. // only during initialization
  39. config.Reset()
  40. }
  41. func (s *ProcessingHandlerTestSuite) send(path string, header ...http.Header) *httptest.ResponseRecorder {
  42. req := httptest.NewRequest(http.MethodGet, path, nil)
  43. rw := httptest.NewRecorder()
  44. if len(header) > 0 {
  45. req.Header = header[0]
  46. }
  47. s.router.ServeHTTP(rw, req)
  48. return rw
  49. }
  50. func (s *ProcessingHandlerTestSuite) readTestFile(name string) []byte {
  51. wd, err := os.Getwd()
  52. assert.Nil(s.T(), err)
  53. data, err := os.ReadFile(filepath.Join(wd, "testdata", name))
  54. assert.Nil(s.T(), err)
  55. return data
  56. }
  57. func (s *ProcessingHandlerTestSuite) readBody(res *http.Response) []byte {
  58. data, err := io.ReadAll(res.Body)
  59. assert.Nil(s.T(), err)
  60. return data
  61. }
  62. func (s *ProcessingHandlerTestSuite) TestRequest() {
  63. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png")
  64. res := rw.Result()
  65. assert.Equal(s.T(), 200, res.StatusCode)
  66. assert.Equal(s.T(), "image/png", res.Header.Get("Content-Type"))
  67. meta, err := imagemeta.DecodeMeta(res.Body)
  68. assert.Nil(s.T(), err)
  69. assert.Equal(s.T(), imagetype.PNG, meta.Format())
  70. assert.Equal(s.T(), 4, meta.Width())
  71. assert.Equal(s.T(), 4, meta.Height())
  72. }
  73. func (s *ProcessingHandlerTestSuite) TestSignatureValidationFailure() {
  74. config.Keys = [][]byte{[]byte("test-key")}
  75. config.Salts = [][]byte{[]byte("test-salt")}
  76. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png")
  77. res := rw.Result()
  78. assert.Equal(s.T(), 403, res.StatusCode)
  79. }
  80. func (s *ProcessingHandlerTestSuite) TestSignatureValidationSuccess() {
  81. config.Keys = [][]byte{[]byte("test-key")}
  82. config.Salts = [][]byte{[]byte("test-salt")}
  83. rw := s.send("/My9d3xq_PYpVHsPrCyww0Kh1w5KZeZhIlWhsa4az1TI/rs:fill:4:4/plain/local:///test1.png")
  84. res := rw.Result()
  85. assert.Equal(s.T(), 200, res.StatusCode)
  86. }
  87. func (s *ProcessingHandlerTestSuite) TestSourceValidationFailure() {
  88. config.AllowedSources = []string{"https://"}
  89. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png")
  90. res := rw.Result()
  91. assert.Equal(s.T(), 404, res.StatusCode)
  92. }
  93. func (s *ProcessingHandlerTestSuite) TestSourceValidationSuccess() {
  94. config.AllowedSources = []string{"local:///"}
  95. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png")
  96. res := rw.Result()
  97. assert.Equal(s.T(), 200, res.StatusCode)
  98. }
  99. func (s *ProcessingHandlerTestSuite) TestSourceFormatNotSupported() {
  100. vips.DisableLoadSupport(imagetype.PNG)
  101. defer vips.ResetLoadSupport()
  102. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png")
  103. res := rw.Result()
  104. assert.Equal(s.T(), 422, res.StatusCode)
  105. }
  106. func (s *ProcessingHandlerTestSuite) TestResultingFormatNotSupported() {
  107. vips.DisableSaveSupport(imagetype.PNG)
  108. defer vips.ResetSaveSupport()
  109. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png@png")
  110. res := rw.Result()
  111. assert.Equal(s.T(), 422, res.StatusCode)
  112. }
  113. func (s *ProcessingHandlerTestSuite) TestSkipProcessingConfig() {
  114. config.SkipProcessingFormats = []imagetype.Type{imagetype.PNG}
  115. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png")
  116. res := rw.Result()
  117. assert.Equal(s.T(), 200, res.StatusCode)
  118. actual := s.readBody(res)
  119. expected := s.readTestFile("test1.png")
  120. assert.True(s.T(), bytes.Equal(expected, actual))
  121. }
  122. func (s *ProcessingHandlerTestSuite) TestSkipProcessingPO() {
  123. rw := s.send("/unsafe/rs:fill:4:4/skp:png/plain/local:///test1.png")
  124. res := rw.Result()
  125. assert.Equal(s.T(), 200, res.StatusCode)
  126. actual := s.readBody(res)
  127. expected := s.readTestFile("test1.png")
  128. assert.True(s.T(), bytes.Equal(expected, actual))
  129. }
  130. func (s *ProcessingHandlerTestSuite) TestSkipProcessingSameFormat() {
  131. config.SkipProcessingFormats = []imagetype.Type{imagetype.PNG}
  132. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png@png")
  133. res := rw.Result()
  134. assert.Equal(s.T(), 200, res.StatusCode)
  135. actual := s.readBody(res)
  136. expected := s.readTestFile("test1.png")
  137. assert.True(s.T(), bytes.Equal(expected, actual))
  138. }
  139. func (s *ProcessingHandlerTestSuite) TestSkipProcessingDifferentFormat() {
  140. config.SkipProcessingFormats = []imagetype.Type{imagetype.PNG}
  141. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png@jpg")
  142. res := rw.Result()
  143. assert.Equal(s.T(), 200, res.StatusCode)
  144. actual := s.readBody(res)
  145. expected := s.readTestFile("test1.png")
  146. assert.False(s.T(), bytes.Equal(expected, actual))
  147. }
  148. func (s *ProcessingHandlerTestSuite) TestSkipProcessingSVG() {
  149. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.svg")
  150. res := rw.Result()
  151. assert.Equal(s.T(), 200, res.StatusCode)
  152. actual := s.readBody(res)
  153. expected := s.readTestFile("test1.svg")
  154. assert.True(s.T(), bytes.Equal(expected, actual))
  155. }
  156. func (s *ProcessingHandlerTestSuite) TestNotSkipProcessingSVGToJPG() {
  157. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.svg@jpg")
  158. res := rw.Result()
  159. assert.Equal(s.T(), 200, res.StatusCode)
  160. actual := s.readBody(res)
  161. expected := s.readTestFile("test1.svg")
  162. assert.False(s.T(), bytes.Equal(expected, actual))
  163. }
  164. func (s *ProcessingHandlerTestSuite) TestErrorSavingToSVG() {
  165. rw := s.send("/unsafe/rs:fill:4:4/plain/local:///test1.png@svg")
  166. res := rw.Result()
  167. assert.Equal(s.T(), 422, res.StatusCode)
  168. }
  169. func (s *ProcessingHandlerTestSuite) TestCacheControlPassthrough() {
  170. config.CacheControlPassthrough = true
  171. ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  172. data := s.readTestFile("test1.png")
  173. rw.Header().Set("Cache-Control", "fake-cache-control")
  174. rw.Header().Set("Expires", "fake-expires")
  175. rw.WriteHeader(200)
  176. rw.Write(data)
  177. }))
  178. defer ts.Close()
  179. rw := s.send("/unsafe/rs:fill:4:4/plain/" + ts.URL)
  180. res := rw.Result()
  181. assert.Equal(s.T(), "fake-cache-control", res.Header.Get("Cache-Control"))
  182. assert.Equal(s.T(), "fake-expires", res.Header.Get("Expires"))
  183. }
  184. func (s *ProcessingHandlerTestSuite) TestCacheControlPassthroughDisabled() {
  185. config.CacheControlPassthrough = false
  186. ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  187. data := s.readTestFile("test1.png")
  188. rw.Header().Set("Cache-Control", "fake-cache-control")
  189. rw.Header().Set("Expires", "fake-expires")
  190. rw.WriteHeader(200)
  191. rw.Write(data)
  192. }))
  193. defer ts.Close()
  194. rw := s.send("/unsafe/rs:fill:4:4/plain/" + ts.URL)
  195. res := rw.Result()
  196. assert.NotEqual(s.T(), "fake-cache-control", res.Header.Get("Cache-Control"))
  197. assert.NotEqual(s.T(), "fake-expires", res.Header.Get("Expires"))
  198. }
  199. func TestProcessingHandler(t *testing.T) {
  200. suite.Run(t, new(ProcessingHandlerTestSuite))
  201. }