github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/handlers/compress_test.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 "bufio" 9 "bytes" 10 "compress/gzip" 11 "io" 12 "io/ioutil" 13 "net" 14 "net/url" 15 "os" 16 "path/filepath" 17 "strconv" 18 "testing" 19 20 http "github.com/hxx258456/ccgo/gmhttp" 21 "github.com/hxx258456/ccgo/gmhttp/httptest" 22 ) 23 24 var contentType = "text/plain; charset=utf-8" 25 26 func compressedRequest(w *httptest.ResponseRecorder, compression string) { 27 CompressHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 28 w.Header().Set("Content-Length", strconv.Itoa(9*1024)) 29 w.Header().Set("Content-Type", contentType) 30 for i := 0; i < 1024; i++ { 31 io.WriteString(w, "Gorilla!\n") 32 } 33 })).ServeHTTP(w, &http.Request{ 34 Method: "GET", 35 Header: http.Header{ 36 acceptEncoding: []string{compression}, 37 }, 38 }) 39 } 40 41 func TestCompressHandlerNoCompression(t *testing.T) { 42 w := httptest.NewRecorder() 43 compressedRequest(w, "") 44 if enc := w.HeaderMap.Get("Content-Encoding"); enc != "" { 45 t.Errorf("wrong content encoding, got %q want %q", enc, "") 46 } 47 if ct := w.HeaderMap.Get("Content-Type"); ct != contentType { 48 t.Errorf("wrong content type, got %q want %q", ct, contentType) 49 } 50 if w.Body.Len() != 1024*9 { 51 t.Errorf("wrong len, got %d want %d", w.Body.Len(), 1024*9) 52 } 53 if l := w.HeaderMap.Get("Content-Length"); l != "9216" { 54 t.Errorf("wrong content-length. got %q expected %d", l, 1024*9) 55 } 56 if v := w.HeaderMap.Get("Vary"); v != acceptEncoding { 57 t.Errorf("wrong vary. got %s expected %s", v, acceptEncoding) 58 } 59 } 60 61 func TestAcceptEncodingIsDropped(t *testing.T) { 62 tCases := []struct { 63 name, 64 compression, 65 expect string 66 isPresent bool 67 }{ 68 { 69 "accept-encoding-gzip", 70 "gzip", 71 "", 72 false, 73 }, 74 { 75 "accept-encoding-deflate", 76 "deflate", 77 "", 78 false, 79 }, 80 { 81 "accept-encoding-gzip,deflate", 82 "gzip,deflate", 83 "", 84 false, 85 }, 86 { 87 "accept-encoding-gzip,deflate,something", 88 "gzip,deflate,something", 89 "", 90 false, 91 }, 92 { 93 "accept-encoding-unknown", 94 "unknown", 95 "unknown", 96 true, 97 }, 98 } 99 100 for _, tCase := range tCases { 101 ch := CompressHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 102 acceptEnc := r.Header.Get(acceptEncoding) 103 if acceptEnc == "" && tCase.isPresent { 104 t.Fatalf("%s: expected 'Accept-Encoding' header to be present but was not", tCase.name) 105 } 106 if acceptEnc != "" { 107 if !tCase.isPresent { 108 t.Fatalf("%s: expected 'Accept-Encoding' header to be dropped but was still present having value %q", tCase.name, acceptEnc) 109 } 110 if acceptEnc != tCase.expect { 111 t.Fatalf("%s: expected 'Accept-Encoding' to be %q but was %q", tCase.name, tCase.expect, acceptEnc) 112 } 113 } 114 })) 115 116 w := httptest.NewRecorder() 117 ch.ServeHTTP(w, &http.Request{ 118 Method: "GET", 119 Header: http.Header{ 120 acceptEncoding: []string{tCase.compression}, 121 }, 122 }) 123 } 124 } 125 126 func TestCompressHandlerGzip(t *testing.T) { 127 w := httptest.NewRecorder() 128 compressedRequest(w, "gzip") 129 if w.HeaderMap.Get("Content-Encoding") != "gzip" { 130 t.Errorf("wrong content encoding, got %q want %q", w.HeaderMap.Get("Content-Encoding"), "gzip") 131 } 132 if w.HeaderMap.Get("Content-Type") != "text/plain; charset=utf-8" { 133 t.Errorf("wrong content type, got %s want %s", w.HeaderMap.Get("Content-Type"), "text/plain; charset=utf-8") 134 } 135 if w.Body.Len() != 72 { 136 t.Errorf("wrong len, got %d want %d", w.Body.Len(), 72) 137 } 138 if l := w.HeaderMap.Get("Content-Length"); l != "" { 139 t.Errorf("wrong content-length. got %q expected %q", l, "") 140 } 141 } 142 143 func TestCompressHandlerDeflate(t *testing.T) { 144 w := httptest.NewRecorder() 145 compressedRequest(w, "deflate") 146 if w.HeaderMap.Get("Content-Encoding") != "deflate" { 147 t.Fatalf("wrong content encoding, got %q want %q", w.HeaderMap.Get("Content-Encoding"), "deflate") 148 } 149 if w.HeaderMap.Get("Content-Type") != "text/plain; charset=utf-8" { 150 t.Fatalf("wrong content type, got %s want %s", w.HeaderMap.Get("Content-Type"), "text/plain; charset=utf-8") 151 } 152 if w.Body.Len() != 54 { 153 t.Fatalf("wrong len, got %d want %d", w.Body.Len(), 54) 154 } 155 } 156 157 func TestCompressHandlerGzipDeflate(t *testing.T) { 158 w := httptest.NewRecorder() 159 compressedRequest(w, "gzip, deflate ") 160 if w.HeaderMap.Get("Content-Encoding") != "gzip" { 161 t.Fatalf("wrong content encoding, got %q want %q", w.HeaderMap.Get("Content-Encoding"), "gzip") 162 } 163 if w.HeaderMap.Get("Content-Type") != "text/plain; charset=utf-8" { 164 t.Fatalf("wrong content type, got %s want %s", w.HeaderMap.Get("Content-Type"), "text/plain; charset=utf-8") 165 } 166 } 167 168 // Make sure we can compress and serve an *os.File properly. We need 169 // to use a real http server to trigger the net/http sendfile special 170 // case. 171 func TestCompressFile(t *testing.T) { 172 dir, err := ioutil.TempDir("", "gorilla_compress") 173 if err != nil { 174 t.Fatal(err) 175 } 176 defer os.RemoveAll(dir) 177 178 err = ioutil.WriteFile(filepath.Join(dir, "hello.txt"), []byte("hello"), 0644) 179 if err != nil { 180 t.Fatal(err) 181 } 182 183 s := httptest.NewServer(CompressHandler(http.FileServer(http.Dir(dir)))) 184 defer s.Close() 185 186 url := &url.URL{Scheme: "http", Host: s.Listener.Addr().String(), Path: "/hello.txt"} 187 req, err := http.NewRequest("GET", url.String(), nil) 188 if err != nil { 189 t.Fatal(err) 190 } 191 req.Header.Set(acceptEncoding, "gzip") 192 res, err := http.DefaultClient.Do(req) 193 if err != nil { 194 t.Fatal(err) 195 } 196 197 if res.StatusCode != http.StatusOK { 198 t.Fatalf("expected OK, got %q", res.Status) 199 } 200 201 var got bytes.Buffer 202 gr, err := gzip.NewReader(res.Body) 203 if err != nil { 204 t.Fatal(err) 205 } 206 _, err = io.Copy(&got, gr) 207 if err != nil { 208 t.Fatal(err) 209 } 210 211 if got.String() != "hello" { 212 t.Errorf("expected hello, got %q", got.String()) 213 } 214 } 215 216 type fullyFeaturedResponseWriter struct{} 217 218 // Header/Write/WriteHeader implement the http.ResponseWriter interface. 219 func (fullyFeaturedResponseWriter) Header() http.Header { 220 return http.Header{} 221 } 222 223 func (fullyFeaturedResponseWriter) Write([]byte) (int, error) { 224 return 0, nil 225 } 226 func (fullyFeaturedResponseWriter) WriteHeader(int) {} 227 228 // Flush implements the http.Flusher interface. 229 func (fullyFeaturedResponseWriter) Flush() {} 230 231 // Hijack implements the http.Hijacker interface. 232 func (fullyFeaturedResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { 233 return nil, nil, nil 234 } 235 236 // CloseNotify implements the http.CloseNotifier interface. 237 func (fullyFeaturedResponseWriter) CloseNotify() <-chan bool { 238 return nil 239 } 240 241 func TestCompressHandlerPreserveInterfaces(t *testing.T) { 242 // Compile time validation fullyFeaturedResponseWriter implements all the 243 // interfaces we're asserting in the test case below. 244 var ( 245 _ http.Flusher = fullyFeaturedResponseWriter{} 246 _ http.CloseNotifier = fullyFeaturedResponseWriter{} 247 _ http.Hijacker = fullyFeaturedResponseWriter{} 248 ) 249 var h http.Handler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { 250 comp := r.Header.Get(acceptEncoding) 251 if _, ok := rw.(http.Flusher); !ok { 252 t.Errorf("ResponseWriter lost http.Flusher interface for %q", comp) 253 } 254 if _, ok := rw.(http.CloseNotifier); !ok { 255 t.Errorf("ResponseWriter lost http.CloseNotifier interface for %q", comp) 256 } 257 if _, ok := rw.(http.Hijacker); !ok { 258 t.Errorf("ResponseWriter lost http.Hijacker interface for %q", comp) 259 } 260 }) 261 h = CompressHandler(h) 262 var rw fullyFeaturedResponseWriter 263 r, err := http.NewRequest("GET", "/", nil) 264 if err != nil { 265 t.Fatalf("Failed to create test request: %v", err) 266 } 267 r.Header.Set(acceptEncoding, "gzip") 268 h.ServeHTTP(rw, r) 269 270 r.Header.Set(acceptEncoding, "deflate") 271 h.ServeHTTP(rw, r) 272 } 273 274 type paltryResponseWriter struct{} 275 276 func (paltryResponseWriter) Header() http.Header { 277 return http.Header{} 278 } 279 280 func (paltryResponseWriter) Write([]byte) (int, error) { 281 return 0, nil 282 } 283 func (paltryResponseWriter) WriteHeader(int) {} 284 285 func TestCompressHandlerDoesntInventInterfaces(t *testing.T) { 286 var h http.Handler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { 287 if _, ok := rw.(http.Hijacker); ok { 288 t.Error("ResponseWriter shouldn't implement http.Hijacker") 289 } 290 }) 291 292 h = CompressHandler(h) 293 294 var rw paltryResponseWriter 295 r, err := http.NewRequest("GET", "/", nil) 296 if err != nil { 297 t.Fatalf("Failed to create test request: %v", err) 298 } 299 r.Header.Set(acceptEncoding, "gzip") 300 h.ServeHTTP(rw, r) 301 }