gzip.go 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. package middleware
  2. import (
  3. "compress/gzip"
  4. "io"
  5. "net/http"
  6. "github.com/QuantumNous/new-api/constant"
  7. "github.com/andybalholm/brotli"
  8. "github.com/gin-gonic/gin"
  9. )
  10. type readCloser struct {
  11. io.Reader
  12. closeFn func() error
  13. }
  14. func (rc *readCloser) Close() error {
  15. if rc.closeFn != nil {
  16. return rc.closeFn()
  17. }
  18. return nil
  19. }
  20. func DecompressRequestMiddleware() gin.HandlerFunc {
  21. return func(c *gin.Context) {
  22. if c.Request.Body == nil || c.Request.Method == http.MethodGet {
  23. c.Next()
  24. return
  25. }
  26. maxMB := constant.MaxRequestBodyMB
  27. if maxMB <= 0 {
  28. maxMB = 32
  29. }
  30. maxBytes := int64(maxMB) << 20
  31. origBody := c.Request.Body
  32. wrapMaxBytes := func(body io.ReadCloser) io.ReadCloser {
  33. return http.MaxBytesReader(c.Writer, body, maxBytes)
  34. }
  35. switch c.GetHeader("Content-Encoding") {
  36. case "gzip":
  37. gzipReader, err := gzip.NewReader(origBody)
  38. if err != nil {
  39. _ = origBody.Close()
  40. c.AbortWithStatus(http.StatusBadRequest)
  41. return
  42. }
  43. // Replace the request body with the decompressed data, and enforce a max size (post-decompression).
  44. c.Request.Body = wrapMaxBytes(&readCloser{
  45. Reader: gzipReader,
  46. closeFn: func() error {
  47. _ = gzipReader.Close()
  48. return origBody.Close()
  49. },
  50. })
  51. c.Request.Header.Del("Content-Encoding")
  52. case "br":
  53. reader := brotli.NewReader(origBody)
  54. c.Request.Body = wrapMaxBytes(&readCloser{
  55. Reader: reader,
  56. closeFn: func() error {
  57. return origBody.Close()
  58. },
  59. })
  60. c.Request.Header.Del("Content-Encoding")
  61. default:
  62. // Even for uncompressed bodies, enforce a max size to avoid huge request allocations.
  63. c.Request.Body = wrapMaxBytes(origBody)
  64. }
  65. // Continue processing the request
  66. c.Next()
  67. }
  68. }