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 }