response_limit.go 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. package security
  2. import (
  3. "io"
  4. "net/http"
  5. "os"
  6. )
  7. // hardLimitReadCloser is a wrapper around io.ReadCloser
  8. // that limits the number of bytes it can read from the upstream reader.
  9. type hardLimitReadCloser struct {
  10. r io.ReadCloser
  11. left int
  12. }
  13. func (lr *hardLimitReadCloser) Read(p []byte) (n int, err error) {
  14. if lr.left <= 0 {
  15. return 0, newFileSizeError()
  16. }
  17. if len(p) > lr.left {
  18. p = p[0:lr.left]
  19. }
  20. n, err = lr.r.Read(p)
  21. lr.left -= n
  22. return
  23. }
  24. func (lr *hardLimitReadCloser) Close() error {
  25. return lr.r.Close()
  26. }
  27. // LimitResponseSize limits the size of the response body to MaxSrcFileSize (if set).
  28. // First, it tries to use Content-Length header to check the limit.
  29. // If Content-Length is not set, it limits the size of the response body by wrapping
  30. // body reader with hard limit reader.
  31. func LimitResponseSize(r *http.Response, opts Options) (*http.Response, error) {
  32. if opts.MaxSrcFileSize == 0 {
  33. return r, nil
  34. }
  35. // If Content-Length was set, limit the size of the response body before reading it
  36. size := int(r.ContentLength)
  37. if size > opts.MaxSrcFileSize {
  38. return nil, newFileSizeError()
  39. }
  40. // hard-limit the response body reader
  41. r.Body = &hardLimitReadCloser{r: r.Body, left: opts.MaxSrcFileSize}
  42. return r, nil
  43. }
  44. // LimitFileSize limits the size of the file to MaxSrcFileSize (if set).
  45. // It calls f.Stat() to get the file to get its size and returns an error
  46. // if the size exceeds MaxSrcFileSize.
  47. func LimitFileSize(f *os.File, opts Options) (*os.File, error) {
  48. if opts.MaxSrcFileSize == 0 {
  49. return f, nil
  50. }
  51. s, err := f.Stat()
  52. if err != nil {
  53. return nil, err
  54. }
  55. if int(s.Size()) > opts.MaxSrcFileSize {
  56. return nil, newFileSizeError()
  57. }
  58. return f, nil
  59. }