@@ -54,7 +54,7 @@ type GzipResponseWriter struct {
5454 buf []byte // Holds the first part of the write before reaching the minSize or the end of the write.
5555 ignore bool // If true, then we immediately passthru writes to the underlying ResponseWriter.
5656
57- contentTypes [] parsedContentType // Only compress if the response is one of these content-types. All are accepted if empty.
57+ contentTypeFilter func ( ct string ) bool // Only compress if the response is one of these content-types. All are accepted if empty.
5858}
5959
6060type GzipResponseWriterWithCloseNotify struct {
@@ -87,7 +87,7 @@ func (w *GzipResponseWriter) Write(b []byte) (int, error) {
8787 ce = w .Header ().Get (contentEncoding )
8888 )
8989 // Only continue if they didn't already choose an encoding or a known unhandled content length or type.
90- if ce == "" && (cl == 0 || cl >= w .minSize ) && (ct == "" || handleContentType ( w . contentTypes , ct )) {
90+ if ce == "" && (cl == 0 || cl >= w .minSize ) && (ct == "" || w . contentTypeFilter ( ct )) {
9191 // If the current buffer is less than minSize and a Content-Length isn't set, then wait until we have more data.
9292 if len (w .buf ) < w .minSize && cl == 0 {
9393 return len (b ), nil
@@ -106,7 +106,7 @@ func (w *GzipResponseWriter) Write(b []byte) (int, error) {
106106 w .Header ().Set (contentType , ct )
107107 }
108108 // If the Content-Type is acceptable to GZIP, initialize the GZIP writer.
109- if handleContentType ( w . contentTypes , ct ) {
109+ if w . contentTypeFilter ( ct ) {
110110 if err := w .startGzip (); err != nil {
111111 return 0 , err
112112 }
@@ -273,6 +273,9 @@ func NewGzipHandler(opts ...option) (func(http.Handler) http.Handler, error) {
273273 Levels : gzkp .Levels ,
274274 New : gzkp .NewWriter ,
275275 },
276+ contentTypes : func (ct string ) bool {
277+ return true
278+ },
276279 }
277280
278281 for _ , o := range opts {
@@ -288,11 +291,11 @@ func NewGzipHandler(opts ...option) (func(http.Handler) http.Handler, error) {
288291 w .Header ().Add (vary , acceptEncoding )
289292 if acceptsGzip (r ) {
290293 gw := & GzipResponseWriter {
291- ResponseWriter : w ,
292- gwFactory : c .writer ,
293- level : c .level ,
294- minSize : c .minSize ,
295- contentTypes : c .contentTypes ,
294+ ResponseWriter : w ,
295+ gwFactory : c .writer ,
296+ level : c .level ,
297+ minSize : c .minSize ,
298+ contentTypeFilter : c .contentTypes ,
296299 }
297300 defer gw .Close ()
298301
@@ -344,7 +347,7 @@ type config struct {
344347 minSize int
345348 level int
346349 writer writer.GzipWriterFactory
347- contentTypes [] parsedContentType
350+ contentTypes func ( ct string ) bool
348351}
349352
350353func (c * config ) validate () error {
@@ -403,31 +406,72 @@ func Implementation(writer writer.GzipWriterFactory) option {
403406//
404407// By default, responses are gzipped regardless of
405408// Content-Type.
409+ //
410+ // Setting this will override any previous Content Type settings.
406411func ContentTypes (types []string ) option {
407412 return func (c * config ) {
408- c . contentTypes = []parsedContentType {}
413+ var contentTypes []parsedContentType
409414 for _ , v := range types {
410415 mediaType , params , err := mime .ParseMediaType (v )
411416 if err == nil {
412- c . contentTypes = append (c . contentTypes , parsedContentType {mediaType , params })
417+ contentTypes = append (contentTypes , parsedContentType {mediaType , params })
413418 }
414419 }
420+ c .contentTypes = func (ct string ) bool {
421+ return handleContentType (contentTypes , ct )
422+ }
415423 }
416424}
417425
418- /*
419- func ContentTypeFilter(func(contentType string) bool) {
426+ // ExceptContentTypes specifies a list of content types to compare
427+ // the Content-Type header to before compressing. If none
428+ // match, the response will be compressed.
429+ //
430+ // Content types are compared in a case-insensitive, whitespace-ignored
431+ // manner.
432+ //
433+ // A MIME type without any other directive will match a content type
434+ // that has the same MIME type, regardless of that content type's other
435+ // directives. I.e., "text/html" will match both "text/html" and
436+ // "text/html; charset=utf-8".
437+ //
438+ // A MIME type with any other directive will only match a content type
439+ // that has the same MIME type and other directives. I.e.,
440+ // "text/html; charset=utf-8" will only match "text/html; charset=utf-8".
441+ //
442+ // By default, responses are gzipped regardless of
443+ // Content-Type.
444+ //
445+ // Setting this will override any previous Content Type settings.
446+ func ExceptContentTypes (types []string ) option {
420447 return func (c * config ) {
421- c. contentTypes = []parsedContentType{}
448+ var contentTypes []parsedContentType
422449 for _ , v := range types {
423450 mediaType , params , err := mime .ParseMediaType (v )
424451 if err == nil {
425- c. contentTypes = append(c. contentTypes, parsedContentType{mediaType, params})
452+ contentTypes = append (contentTypes , parsedContentType {mediaType , params })
426453 }
427454 }
455+ c .contentTypes = func (ct string ) bool {
456+ return ! handleContentType (contentTypes , ct )
457+ }
458+ }
459+ }
460+
461+ // ContentTypeFilter allows adding a custom content type filter.
462+ //
463+ // The supplied function must return true/false to indicate if content
464+ // should be compressed.
465+ //
466+ // When called no parsing of the content type 'ct' has been done.
467+ // It may have been set or auto-detected.
468+ //
469+ // Setting this will override any previous Content Type settings.
470+ func ContentTypeFilter (compress func (ct string ) bool ) option {
471+ return func (c * config ) {
472+ c .contentTypes = compress
428473 }
429474}
430- */
431475
432476// GzipHandler wraps an HTTP handler, to transparently gzip the response body if
433477// the client supports it (via the Accept-Encoding header). This will compress at
0 commit comments