summaryrefslogtreecommitdiff
path: root/vendor/github.com/gin-contrib/gzip/options.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/gin-contrib/gzip/options.go')
-rw-r--r--vendor/github.com/gin-contrib/gzip/options.go208
1 files changed, 181 insertions, 27 deletions
diff --git a/vendor/github.com/gin-contrib/gzip/options.go b/vendor/github.com/gin-contrib/gzip/options.go
index c0953e08a..67607f51b 100644
--- a/vendor/github.com/gin-contrib/gzip/options.go
+++ b/vendor/github.com/gin-contrib/gzip/options.go
@@ -2,6 +2,8 @@ package gzip
import (
"compress/gzip"
+ "errors"
+ "io"
"net/http"
"regexp"
"strings"
@@ -10,58 +12,134 @@ import (
)
var (
+ // DefaultExcludedExtentions is a predefined list of file extensions that should be excluded from gzip compression.
+ // These extensions typically represent image files that are already compressed
+ // and do not benefit from additional compression.
DefaultExcludedExtentions = NewExcludedExtensions([]string{
".png", ".gif", ".jpeg", ".jpg",
})
- DefaultOptions = &Options{
- ExcludedExtensions: DefaultExcludedExtentions,
- }
+ // ErrUnsupportedContentEncoding is an error that indicates the content encoding
+ // is not supported by the application.
+ ErrUnsupportedContentEncoding = errors.New("unsupported content encoding")
)
-type Options struct {
- ExcludedExtensions ExcludedExtensions
- ExcludedPaths ExcludedPaths
- ExcludedPathesRegexs ExcludedPathesRegexs
- DecompressFn func(c *gin.Context)
+// Option is an interface that defines a method to apply a configuration
+// to a given config instance. Implementations of this interface can be
+// used to modify the configuration settings of the logger.
+type Option interface {
+ apply(*config)
+}
+
+// Ensures that optionFunc implements the Option interface at compile time.
+// If optionFunc does not implement Option, a compile-time error will occur.
+var _ Option = (*optionFunc)(nil)
+
+type optionFunc func(*config)
+
+func (o optionFunc) apply(c *config) {
+ o(c)
}
-type Option func(*Options)
+type config struct {
+ excludedExtensions ExcludedExtensions
+ excludedPaths ExcludedPaths
+ excludedPathesRegexs ExcludedPathesRegexs
+ decompressFn func(c *gin.Context)
+ decompressOnly bool
+ customShouldCompressFn func(c *gin.Context) bool
+}
+// WithExcludedExtensions returns an Option that sets the ExcludedExtensions field of the Options struct.
+// Parameters:
+// - args: []string - A slice of file extensions to exclude from gzip compression.
func WithExcludedExtensions(args []string) Option {
- return func(o *Options) {
- o.ExcludedExtensions = NewExcludedExtensions(args)
- }
+ return optionFunc(func(o *config) {
+ o.excludedExtensions = NewExcludedExtensions(args)
+ })
}
+// WithExcludedPaths returns an Option that sets the ExcludedPaths field of the Options struct.
+// Parameters:
+// - args: []string - A slice of paths to exclude from gzip compression.
func WithExcludedPaths(args []string) Option {
- return func(o *Options) {
- o.ExcludedPaths = NewExcludedPaths(args)
- }
+ return optionFunc(func(o *config) {
+ o.excludedPaths = NewExcludedPaths(args)
+ })
}
+// WithExcludedPathsRegexs returns an Option that sets the ExcludedPathesRegexs field of the Options struct.
+// Parameters:
+// - args: []string - A slice of regex patterns to exclude paths from gzip compression.
func WithExcludedPathsRegexs(args []string) Option {
- return func(o *Options) {
- o.ExcludedPathesRegexs = NewExcludedPathesRegexs(args)
- }
+ return optionFunc(func(o *config) {
+ o.excludedPathesRegexs = NewExcludedPathesRegexs(args)
+ })
}
+// WithDecompressFn returns an Option that sets the DecompressFn field of the Options struct.
+// Parameters:
+// - decompressFn: func(c *gin.Context) - A function to handle decompression of incoming requests.
func WithDecompressFn(decompressFn func(c *gin.Context)) Option {
- return func(o *Options) {
- o.DecompressFn = decompressFn
- }
+ return optionFunc(func(o *config) {
+ o.decompressFn = decompressFn
+ })
+}
+
+// WithDecompressOnly is an option that configures the gzip middleware to only
+// decompress incoming requests without compressing the responses. When this
+// option is enabled, the middleware will set the DecompressOnly field of the
+// Options struct to true.
+func WithDecompressOnly() Option {
+ return optionFunc(func(o *config) {
+ o.decompressOnly = true
+ })
+}
+
+// WithCustomShouldCompressFn returns an Option that sets the CustomShouldCompressFn field of the Options struct.
+// Parameters:
+// - fn: func(c *gin.Context) bool - A function to determine if a request should be compressed.
+// The function should return true if the request should be compressed, false otherwise.
+// If the function returns false, the middleware will not compress the response.
+// If the function is nil, the middleware will use the default logic to determine
+// if the response should be compressed.
+//
+// Returns:
+// - Option - An option that sets the CustomShouldCompressFn field of the Options struct.
+//
+// Example:
+//
+// router.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithCustomShouldCompressFn(func(c *gin.Context) bool {
+// return c.Request.URL.Path != "/no-compress"
+// })))
+func WithCustomShouldCompressFn(fn func(c *gin.Context) bool) Option {
+ return optionFunc(func(o *config) {
+ o.customShouldCompressFn = fn
+ })
}
// Using map for better lookup performance
type ExcludedExtensions map[string]struct{}
+// NewExcludedExtensions creates a new ExcludedExtensions map from a slice of file extensions.
+// Parameters:
+// - extensions: []string - A slice of file extensions to exclude from gzip compression.
+//
+// Returns:
+// - ExcludedExtensions - A map of excluded file extensions.
func NewExcludedExtensions(extensions []string) ExcludedExtensions {
- res := make(ExcludedExtensions)
+ res := make(ExcludedExtensions, len(extensions))
for _, e := range extensions {
res[e] = struct{}{}
}
return res
}
+// Contains checks if a given file extension is in the ExcludedExtensions map.
+// Parameters:
+// - target: string - The file extension to check.
+//
+// Returns:
+// - bool - True if the extension is excluded, false otherwise.
func (e ExcludedExtensions) Contains(target string) bool {
_, ok := e[target]
return ok
@@ -69,10 +147,22 @@ func (e ExcludedExtensions) Contains(target string) bool {
type ExcludedPaths []string
+// NewExcludedPaths creates a new ExcludedPaths slice from a slice of paths.
+// Parameters:
+// - paths: []string - A slice of paths to exclude from gzip compression.
+//
+// Returns:
+// - ExcludedPaths - A slice of excluded paths.
func NewExcludedPaths(paths []string) ExcludedPaths {
return ExcludedPaths(paths)
}
+// Contains checks if a given request URI starts with any of the excluded paths.
+// Parameters:
+// - requestURI: string - The request URI to check.
+//
+// Returns:
+// - bool - True if the URI starts with an excluded path, false otherwise.
func (e ExcludedPaths) Contains(requestURI string) bool {
for _, path := range e {
if strings.HasPrefix(requestURI, path) {
@@ -84,14 +174,26 @@ func (e ExcludedPaths) Contains(requestURI string) bool {
type ExcludedPathesRegexs []*regexp.Regexp
+// NewExcludedPathesRegexs creates a new ExcludedPathesRegexs slice from a slice of regex patterns.
+// Parameters:
+// - regexs: []string - A slice of regex patterns to exclude paths from gzip compression.
+//
+// Returns:
+// - ExcludedPathesRegexs - A slice of excluded path regex patterns.
func NewExcludedPathesRegexs(regexs []string) ExcludedPathesRegexs {
- result := make([]*regexp.Regexp, len(regexs))
+ result := make(ExcludedPathesRegexs, len(regexs))
for i, reg := range regexs {
result[i] = regexp.MustCompile(reg)
}
return result
}
+// Contains checks if a given request URI matches any of the excluded path regex patterns.
+// Parameters:
+// - requestURI: string - The request URI to check.
+//
+// Returns:
+// - bool - True if the URI matches an excluded path regex pattern, false otherwise.
func (e ExcludedPathesRegexs) Contains(requestURI string) bool {
for _, reg := range e {
if reg.MatchString(requestURI) {
@@ -101,16 +203,68 @@ func (e ExcludedPathesRegexs) Contains(requestURI string) bool {
return false
}
+// DefaultDecompressHandle is a middleware function for the Gin framework that
+// decompresses the request body if it is gzip encoded. It checks if the request
+// body is nil and returns immediately if it is. Otherwise, it attempts to create
+// a new gzip reader from the request body. If an error occurs during this process,
+// it aborts the request with a 400 Bad Request status and the error. If successful,
+// it removes the "Content-Encoding" and "Content-Length" headers from the request
+// and replaces the request body with the decompressed reader.
+//
+// Parameters:
+// - c: *gin.Context - The Gin context for the current request.
func DefaultDecompressHandle(c *gin.Context) {
if c.Request.Body == nil {
return
}
- r, err := gzip.NewReader(c.Request.Body)
- if err != nil {
- _ = c.AbortWithError(http.StatusBadRequest, err)
+
+ contentEncodingField := strings.Split(strings.ToLower(c.GetHeader("Content-Encoding")), ",")
+ if len(contentEncodingField) == 0 { // nothing to decompress
+ c.Next()
+
return
}
+
+ toClose := make([]io.Closer, 0, len(contentEncodingField))
+ defer func() {
+ for i := len(toClose); i > 0; i-- {
+ toClose[i-1].Close()
+ }
+ }()
+
+ // parses multiply gzips like
+ // Content-Encoding: gzip, gzip, gzip
+ // allowed by RFC
+ for i := 0; i < len(contentEncodingField); i++ {
+ trimmedValue := strings.TrimSpace(contentEncodingField[i])
+
+ if trimmedValue == "" {
+ continue
+ }
+
+ if trimmedValue != "gzip" {
+ // According to RFC 7231, Section 3.1.2.2:
+ // https://www.rfc-editor.org/rfc/rfc7231#section-3.1.2.2
+ // An origin server MAY respond with a status code of 415 (Unsupported
+ // Media Type) if a representation in the request message has a content
+ // coding that is not acceptable.
+ _ = c.AbortWithError(http.StatusUnsupportedMediaType, ErrUnsupportedContentEncoding)
+ }
+
+ r, err := gzip.NewReader(c.Request.Body)
+ if err != nil {
+ _ = c.AbortWithError(http.StatusBadRequest, err)
+
+ return
+ }
+
+ toClose = append(toClose, c.Request.Body)
+
+ c.Request.Body = r
+ }
+
c.Request.Header.Del("Content-Encoding")
c.Request.Header.Del("Content-Length")
- c.Request.Body = r
+
+ c.Next()
}