read.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package imagedata
  2. import (
  3. "io"
  4. "github.com/imgproxy/imgproxy/v3/bufpool"
  5. "github.com/imgproxy/imgproxy/v3/bufreader"
  6. "github.com/imgproxy/imgproxy/v3/config"
  7. "github.com/imgproxy/imgproxy/v3/ierrors"
  8. "github.com/imgproxy/imgproxy/v3/imagemeta"
  9. "github.com/imgproxy/imgproxy/v3/security"
  10. )
  11. var (
  12. ErrSourceFileTooBig = ierrors.New(422, "Source image file is too big", "Invalid source image")
  13. ErrSourceImageTypeNotSupported = ierrors.New(422, "Source image type not supported", "Invalid source image")
  14. )
  15. var downloadBufPool *bufpool.Pool
  16. func initRead() {
  17. downloadBufPool = bufpool.New("download", config.Concurrency, config.DownloadBufferSize)
  18. }
  19. type hardLimitReader struct {
  20. r io.Reader
  21. left int
  22. }
  23. func (lr *hardLimitReader) Read(p []byte) (n int, err error) {
  24. if lr.left <= 0 {
  25. return 0, ErrSourceFileTooBig
  26. }
  27. if len(p) > lr.left {
  28. p = p[0:lr.left]
  29. }
  30. n, err = lr.r.Read(p)
  31. lr.left -= n
  32. return
  33. }
  34. func readAndCheckImage(r io.Reader, contentLength int) (*ImageData, error) {
  35. if config.MaxSrcFileSize > 0 && contentLength > config.MaxSrcFileSize {
  36. return nil, ErrSourceFileTooBig
  37. }
  38. buf := downloadBufPool.Get(contentLength, false)
  39. cancel := func() { downloadBufPool.Put(buf) }
  40. if config.MaxSrcFileSize > 0 {
  41. r = &hardLimitReader{r: r, left: config.MaxSrcFileSize}
  42. }
  43. br := bufreader.New(r, buf)
  44. meta, err := imagemeta.DecodeMeta(br)
  45. if err != nil {
  46. buf.Reset()
  47. cancel()
  48. if err == imagemeta.ErrFormat {
  49. return nil, ErrSourceImageTypeNotSupported
  50. }
  51. return nil, checkTimeoutErr(err)
  52. }
  53. if err = security.CheckDimensions(meta.Width(), meta.Height()); err != nil {
  54. buf.Reset()
  55. cancel()
  56. return nil, err
  57. }
  58. if contentLength > buf.Cap() {
  59. buf.Grow(contentLength - buf.Len())
  60. }
  61. if err = br.Flush(); err != nil {
  62. cancel()
  63. return nil, checkTimeoutErr(err)
  64. }
  65. return &ImageData{
  66. Data: buf.Bytes(),
  67. Type: meta.Format(),
  68. cancel: cancel,
  69. }, nil
  70. }