gzip_test.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. package gzip
  2. import (
  3. "compress/gzip"
  4. "fmt"
  5. "io/ioutil"
  6. "net/http"
  7. "net/http/httptest"
  8. "net/http/httputil"
  9. "net/url"
  10. "strconv"
  11. "testing"
  12. "github.com/gin-gonic/gin"
  13. "github.com/stretchr/testify/assert"
  14. )
  15. const (
  16. testResponse = "Gzip Test Response "
  17. testReverseResponse = "Gzip Test Reverse Response "
  18. )
  19. func init() {
  20. gin.SetMode(gin.ReleaseMode)
  21. }
  22. type rServer struct{}
  23. func (s *rServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
  24. fmt.Fprint(rw, testReverseResponse)
  25. }
  26. type closeNotifyingRecorder struct {
  27. *httptest.ResponseRecorder
  28. closed chan bool
  29. }
  30. func newCloseNotifyingRecorder() *closeNotifyingRecorder {
  31. return &closeNotifyingRecorder{
  32. httptest.NewRecorder(),
  33. make(chan bool, 1),
  34. }
  35. }
  36. func (c *closeNotifyingRecorder) close() {
  37. c.closed <- true
  38. }
  39. func (c *closeNotifyingRecorder) CloseNotify() <-chan bool {
  40. return c.closed
  41. }
  42. func newServer() *gin.Engine {
  43. // init reverse proxy server
  44. rServer := httptest.NewServer(new(rServer))
  45. target, _ := url.Parse(rServer.URL)
  46. rp := httputil.NewSingleHostReverseProxy(target)
  47. router := gin.New()
  48. router.Use(Gzip(DefaultCompression))
  49. router.GET("/", func(c *gin.Context) {
  50. c.Header("Content-Length", strconv.Itoa(len(testResponse)))
  51. c.String(200, testResponse)
  52. })
  53. router.Any("/reverse", func(c *gin.Context) {
  54. rp.ServeHTTP(c.Writer, c.Request)
  55. })
  56. return router
  57. }
  58. func TestGzip(t *testing.T) {
  59. req, _ := http.NewRequest("GET", "/", nil)
  60. req.Header.Add("Accept-Encoding", "gzip")
  61. w := httptest.NewRecorder()
  62. r := newServer()
  63. r.ServeHTTP(w, req)
  64. assert.Equal(t, w.Code, 200)
  65. assert.Equal(t, w.Header().Get("Content-Encoding"), "gzip")
  66. assert.Equal(t, w.Header().Get("Vary"), "Accept-Encoding")
  67. assert.NotEqual(t, w.Header().Get("Content-Length"), "0")
  68. assert.NotEqual(t, w.Body.Len(), 19)
  69. assert.Equal(t, fmt.Sprint(w.Body.Len()), w.Header().Get("Content-Length"))
  70. gr, err := gzip.NewReader(w.Body)
  71. assert.NoError(t, err)
  72. defer gr.Close()
  73. body, _ := ioutil.ReadAll(gr)
  74. assert.Equal(t, string(body), testResponse)
  75. }
  76. func TestGzipPNG(t *testing.T) {
  77. req, _ := http.NewRequest("GET", "/image.png", nil)
  78. req.Header.Add("Accept-Encoding", "gzip")
  79. router := gin.New()
  80. router.Use(Gzip(DefaultCompression))
  81. router.GET("/image.png", func(c *gin.Context) {
  82. c.String(200, "this is a PNG!")
  83. })
  84. w := httptest.NewRecorder()
  85. router.ServeHTTP(w, req)
  86. assert.Equal(t, w.Code, 200)
  87. assert.Equal(t, w.Header().Get("Content-Encoding"), "")
  88. assert.Equal(t, w.Header().Get("Vary"), "")
  89. assert.Equal(t, w.Body.String(), "this is a PNG!")
  90. }
  91. func TestExcludedExtensions(t *testing.T) {
  92. req, _ := http.NewRequest("GET", "/index.html", nil)
  93. req.Header.Add("Accept-Encoding", "gzip")
  94. router := gin.New()
  95. router.Use(Gzip(DefaultCompression, WithExcludedExtensions([]string{".html"})))
  96. router.GET("/index.html", func(c *gin.Context) {
  97. c.String(200, "this is a HTML!")
  98. })
  99. w := httptest.NewRecorder()
  100. router.ServeHTTP(w, req)
  101. assert.Equal(t, http.StatusOK, w.Code)
  102. assert.Equal(t, "", w.Header().Get("Content-Encoding"))
  103. assert.Equal(t, "", w.Header().Get("Vary"))
  104. assert.Equal(t, "this is a HTML!", w.Body.String())
  105. assert.Equal(t, "", w.Header().Get("Content-Length"))
  106. }
  107. func TestExcludedPaths(t *testing.T) {
  108. req, _ := http.NewRequest("GET", "/api/books", nil)
  109. req.Header.Add("Accept-Encoding", "gzip")
  110. router := gin.New()
  111. router.Use(Gzip(DefaultCompression, WithExcludedPaths([]string{"/api/"})))
  112. router.GET("/api/books", func(c *gin.Context) {
  113. c.String(200, "this is books!")
  114. })
  115. w := httptest.NewRecorder()
  116. router.ServeHTTP(w, req)
  117. assert.Equal(t, http.StatusOK, w.Code)
  118. assert.Equal(t, "", w.Header().Get("Content-Encoding"))
  119. assert.Equal(t, "", w.Header().Get("Vary"))
  120. assert.Equal(t, "this is books!", w.Body.String())
  121. assert.Equal(t, "", w.Header().Get("Content-Length"))
  122. }
  123. func TestNoGzip(t *testing.T) {
  124. req, _ := http.NewRequest("GET", "/", nil)
  125. w := httptest.NewRecorder()
  126. r := newServer()
  127. r.ServeHTTP(w, req)
  128. assert.Equal(t, w.Code, 200)
  129. assert.Equal(t, w.Header().Get("Content-Encoding"), "")
  130. assert.Equal(t, w.Header().Get("Content-Length"), "19")
  131. assert.Equal(t, w.Body.String(), testResponse)
  132. }
  133. func TestGzipWithReverseProxy(t *testing.T) {
  134. req, _ := http.NewRequest("GET", "/reverse", nil)
  135. req.Header.Add("Accept-Encoding", "gzip")
  136. w := newCloseNotifyingRecorder()
  137. r := newServer()
  138. r.ServeHTTP(w, req)
  139. assert.Equal(t, w.Code, 200)
  140. assert.Equal(t, w.Header().Get("Content-Encoding"), "gzip")
  141. assert.Equal(t, w.Header().Get("Vary"), "Accept-Encoding")
  142. assert.NotEqual(t, w.Header().Get("Content-Length"), "0")
  143. assert.NotEqual(t, w.Body.Len(), 19)
  144. assert.Equal(t, fmt.Sprint(w.Body.Len()), w.Header().Get("Content-Length"))
  145. gr, err := gzip.NewReader(w.Body)
  146. assert.NoError(t, err)
  147. defer gr.Close()
  148. body, _ := ioutil.ReadAll(gr)
  149. assert.Equal(t, string(body), testReverseResponse)
  150. }