limit.go 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  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. // Read reads data from the underlying reader, limiting the number of bytes read
  14. func (lr *hardLimitReadCloser) Read(p []byte) (n int, err error) {
  15. if lr.left <= 0 {
  16. return 0, newFileSizeError()
  17. }
  18. if len(p) > lr.left {
  19. p = p[0:lr.left]
  20. }
  21. n, err = lr.r.Read(p)
  22. lr.left -= n
  23. return
  24. }
  25. // Close closes the underlying reader
  26. func (lr *hardLimitReadCloser) Close() error {
  27. return lr.r.Close()
  28. }
  29. // LimitFileSize limits the size of the file to MaxSrcFileSize (if set).
  30. // It calls f.Stat() to get the file to get its size and returns an error
  31. // if the size exceeds MaxSrcFileSize.
  32. func LimitFileSize(f *os.File, opts Options) (*os.File, error) {
  33. if opts.MaxSrcFileSize == 0 {
  34. return f, nil
  35. }
  36. s, err := f.Stat()
  37. if err != nil {
  38. return nil, err
  39. }
  40. if int(s.Size()) > opts.MaxSrcFileSize {
  41. return nil, newFileSizeError()
  42. }
  43. return f, nil
  44. }
  45. // LimitResponseSize limits the size of the response body to MaxSrcFileSize (if set).
  46. // First, it tries to use Content-Length header to check the limit.
  47. // If Content-Length is not set, it limits the size of the response body by wrapping
  48. // body reader with hard limit reader.
  49. func LimitResponseSize(r *http.Response, opts Options) (*http.Response, error) {
  50. if opts.MaxSrcFileSize == 0 {
  51. return r, nil
  52. }
  53. // If Content-Length was set, limit the size of the response body before reading it
  54. size := int(r.ContentLength)
  55. if size > opts.MaxSrcFileSize {
  56. return nil, newFileSizeError()
  57. }
  58. // hard-limit the response body reader
  59. r.Body = &hardLimitReadCloser{r: r.Body, left: opts.MaxSrcFileSize}
  60. return r, nil
  61. }