github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/gorilla/handlers/compress.go (about)

     1  // Copyright 2013 The Gorilla Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package handlers
     6  
     7  import (
     8  	"compress/flate"
     9  	"compress/gzip"
    10  	"github.com/hellobchain/newcryptosm/http"
    11  	"io"
    12  	"strings"
    13  )
    14  
    15  type compressResponseWriter struct {
    16  	io.Writer
    17  	http.ResponseWriter
    18  	http.Hijacker
    19  	http.Flusher
    20  	http.CloseNotifier
    21  }
    22  
    23  func (w *compressResponseWriter) WriteHeader(c int) {
    24  	w.ResponseWriter.Header().Del("Content-Length")
    25  	w.ResponseWriter.WriteHeader(c)
    26  }
    27  
    28  func (w *compressResponseWriter) Header() http.Header {
    29  	return w.ResponseWriter.Header()
    30  }
    31  
    32  func (w *compressResponseWriter) Write(b []byte) (int, error) {
    33  	h := w.ResponseWriter.Header()
    34  	if h.Get("Content-Type") == "" {
    35  		h.Set("Content-Type", http.DetectContentType(b))
    36  	}
    37  	h.Del("Content-Length")
    38  
    39  	return w.Writer.Write(b)
    40  }
    41  
    42  type flusher interface {
    43  	Flush() error
    44  }
    45  
    46  func (w *compressResponseWriter) Flush() {
    47  	// Flush compressed data if compressor supports it.
    48  	if f, ok := w.Writer.(flusher); ok {
    49  		f.Flush()
    50  	}
    51  	// Flush HTTP response.
    52  	if w.Flusher != nil {
    53  		w.Flusher.Flush()
    54  	}
    55  }
    56  
    57  // CompressHandler gzip compresses HTTP responses for clients that support it
    58  // via the 'Accept-Encoding' header.
    59  //
    60  // Compressing TLS traffic may leak the page contents to an attacker if the
    61  // page contains user input: http://security.stackexchange.com/a/102015/12208
    62  func CompressHandler(h http.Handler) http.Handler {
    63  	return CompressHandlerLevel(h, gzip.DefaultCompression)
    64  }
    65  
    66  // CompressHandlerLevel gzip compresses HTTP responses with specified compression level
    67  // for clients that support it via the 'Accept-Encoding' header.
    68  //
    69  // The compression level should be gzip.DefaultCompression, gzip.NoCompression,
    70  // or any integer value between gzip.BestSpeed and gzip.BestCompression inclusive.
    71  // gzip.DefaultCompression is used in case of invalid compression level.
    72  func CompressHandlerLevel(h http.Handler, level int) http.Handler {
    73  	if level < gzip.DefaultCompression || level > gzip.BestCompression {
    74  		level = gzip.DefaultCompression
    75  	}
    76  
    77  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    78  	L:
    79  		for _, enc := range strings.Split(r.Header.Get("Accept-Encoding"), ",") {
    80  			switch strings.TrimSpace(enc) {
    81  			case "gzip":
    82  				w.Header().Set("Content-Encoding", "gzip")
    83  				w.Header().Add("Vary", "Accept-Encoding")
    84  
    85  				gw, _ := gzip.NewWriterLevel(w, level)
    86  				defer gw.Close()
    87  
    88  				h, hok := w.(http.Hijacker)
    89  				if !hok { /* w is not Hijacker... oh well... */
    90  					h = nil
    91  				}
    92  
    93  				f, fok := w.(http.Flusher)
    94  				if !fok {
    95  					f = nil
    96  				}
    97  
    98  				cn, cnok := w.(http.CloseNotifier)
    99  				if !cnok {
   100  					cn = nil
   101  				}
   102  
   103  				w = &compressResponseWriter{
   104  					Writer:         gw,
   105  					ResponseWriter: w,
   106  					Hijacker:       h,
   107  					Flusher:        f,
   108  					CloseNotifier:  cn,
   109  				}
   110  
   111  				break L
   112  			case "deflate":
   113  				w.Header().Set("Content-Encoding", "deflate")
   114  				w.Header().Add("Vary", "Accept-Encoding")
   115  
   116  				fw, _ := flate.NewWriter(w, level)
   117  				defer fw.Close()
   118  
   119  				h, hok := w.(http.Hijacker)
   120  				if !hok { /* w is not Hijacker... oh well... */
   121  					h = nil
   122  				}
   123  
   124  				f, fok := w.(http.Flusher)
   125  				if !fok {
   126  					f = nil
   127  				}
   128  
   129  				cn, cnok := w.(http.CloseNotifier)
   130  				if !cnok {
   131  					cn = nil
   132  				}
   133  
   134  				w = &compressResponseWriter{
   135  					Writer:         fw,
   136  					ResponseWriter: w,
   137  					Hijacker:       h,
   138  					Flusher:        f,
   139  					CloseNotifier:  cn,
   140  				}
   141  
   142  				break L
   143  			}
   144  		}
   145  
   146  		h.ServeHTTP(w, r)
   147  	})
   148  }