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  }