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