| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 |
- package middleware
- import (
- "compress/gzip"
- "io"
- "net/http"
- "github.com/QuantumNous/new-api/constant"
- "github.com/andybalholm/brotli"
- "github.com/gin-gonic/gin"
- )
- type readCloser struct {
- io.Reader
- closeFn func() error
- }
- func (rc *readCloser) Close() error {
- if rc.closeFn != nil {
- return rc.closeFn()
- }
- return nil
- }
- func DecompressRequestMiddleware() gin.HandlerFunc {
- return func(c *gin.Context) {
- if c.Request.Body == nil || c.Request.Method == http.MethodGet {
- c.Next()
- return
- }
- maxMB := constant.MaxRequestBodyMB
- if maxMB <= 0 {
- maxMB = 32
- }
- maxBytes := int64(maxMB) << 20
- origBody := c.Request.Body
- wrapMaxBytes := func(body io.ReadCloser) io.ReadCloser {
- return http.MaxBytesReader(c.Writer, body, maxBytes)
- }
- switch c.GetHeader("Content-Encoding") {
- case "gzip":
- gzipReader, err := gzip.NewReader(origBody)
- if err != nil {
- _ = origBody.Close()
- c.AbortWithStatus(http.StatusBadRequest)
- return
- }
- // Replace the request body with the decompressed data, and enforce a max size (post-decompression).
- c.Request.Body = wrapMaxBytes(&readCloser{
- Reader: gzipReader,
- closeFn: func() error {
- _ = gzipReader.Close()
- return origBody.Close()
- },
- })
- c.Request.Header.Del("Content-Encoding")
- case "br":
- reader := brotli.NewReader(origBody)
- c.Request.Body = wrapMaxBytes(&readCloser{
- Reader: reader,
- closeFn: func() error {
- return origBody.Close()
- },
- })
- c.Request.Header.Del("Content-Encoding")
- default:
- // Even for uncompressed bodies, enforce a max size to avoid huge request allocations.
- c.Request.Body = wrapMaxBytes(origBody)
- }
- // Continue processing the request
- c.Next()
- }
- }
|