Skip to content

Commit 438926d

Browse files
alexdyukovAlex Dyukovappleboy
authored
fix: default auto decompressor on uncompressed or double compressed bodies (#91)
* fix: default auto decompressor on uncompressed or double compressed bodies * Update options.go --------- Co-authored-by: Alex Dyukov <[email protected]> Co-authored-by: Bo-Yi Wu <[email protected]>
1 parent 3529136 commit 438926d

File tree

1 file changed

+56
-10
lines changed

1 file changed

+56
-10
lines changed

options.go

+56-10
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,24 @@ package gzip
22

33
import (
44
"compress/gzip"
5+
"errors"
6+
"io"
57
"net/http"
68
"regexp"
79
"strings"
810

911
"github.com/gin-gonic/gin"
1012
)
1113

12-
// DefaultExcludedExtentions is a predefined list of file extensions that should be excluded from gzip compression.
13-
// These extensions typically represent image files that are already compressed
14-
// and do not benefit from additional compression.
15-
var DefaultExcludedExtentions = NewExcludedExtensions([]string{
16-
".png", ".gif", ".jpeg", ".jpg",
17-
})
14+
var (
15+
// DefaultExcludedExtentions is a predefined list of file extensions that should be excluded from gzip compression.
16+
// These extensions typically represent image files that are already compressed
17+
// and do not benefit from additional compression.
18+
DefaultExcludedExtentions = NewExcludedExtensions([]string{
19+
".png", ".gif", ".jpeg", ".jpg",
20+
})
21+
UnsupportedContentEncoding = errors.New("Unsupported content encoding")
22+
)
1823

1924
// Option is an interface that defines a method to apply a configuration
2025
// to a given config instance. Implementations of this interface can be
@@ -210,12 +215,53 @@ func DefaultDecompressHandle(c *gin.Context) {
210215
if c.Request.Body == nil {
211216
return
212217
}
213-
r, err := gzip.NewReader(c.Request.Body)
214-
if err != nil {
215-
_ = c.AbortWithError(http.StatusBadRequest, err)
218+
219+
contentEncodingField := strings.Split(strings.ToLower(c.GetHeader("Content-Encoding")), ",")
220+
if len(contentEncodingField) == 0 { // nothing to decompress
221+
c.Next()
222+
216223
return
217224
}
225+
226+
toClose := make([]io.Closer, 0, len(contentEncodingField))
227+
defer func() {
228+
for i := len(toClose); i > 0; i-- {
229+
toClose[i-1].Close()
230+
}
231+
}()
232+
233+
// parses multiply gzips like
234+
// Content-Encoding: gzip, gzip, gzip
235+
// allowed by RFC
236+
for i := 0; i < len(contentEncodingField); i++ {
237+
trimmedValue := strings.TrimSpace(contentEncodingField[i])
238+
239+
if trimmedValue == "" {
240+
continue
241+
}
242+
243+
if trimmedValue != "gzip" {
244+
// https://www.rfc-editor.org/rfc/rfc7231#section-3.1.2.2
245+
// An origin server MAY respond with a status code of 415 (Unsupported
246+
// Media Type) if a representation in the request message has a content
247+
// coding that is not acceptable.
248+
_ = c.AbortWithError(http.StatusUnsupportedMediaType, UnsupportedContentEncoding)
249+
}
250+
251+
r, err := gzip.NewReader(c.Request.Body)
252+
if err != nil {
253+
_ = c.AbortWithError(http.StatusBadRequest, err)
254+
255+
return
256+
}
257+
258+
toClose = append(toClose, c.Request.Body)
259+
260+
c.Request.Body = r
261+
}
262+
218263
c.Request.Header.Del("Content-Encoding")
219264
c.Request.Header.Del("Content-Length")
220-
c.Request.Body = r
265+
266+
c.Next()
221267
}

0 commit comments

Comments
 (0)