1
0
Fork 0

Merge 'v1.3.5'

This commit is contained in:
Fernandez Ludovic 2017-08-01 19:32:44 +02:00
commit d456c2ce6a
23 changed files with 1833 additions and 138 deletions

View file

@ -1,13 +1,11 @@
package middlewares
import (
"compress/gzip"
"net/http"
"github.com/NYTimes/gziphandler"
)
const (
contentEncodingHeader = "Content-Encoding"
"github.com/containous/traefik/log"
)
// Compress is a middleware that allows redirection
@ -15,17 +13,13 @@ type Compress struct{}
// ServerHTTP is a function used by Negroni
func (c *Compress) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
if isEncoded(r.Header) {
next.ServeHTTP(rw, r)
} else {
newGzipHandler := gziphandler.GzipHandler(next)
newGzipHandler.ServeHTTP(rw, r)
}
gzipHandler(next).ServeHTTP(rw, r)
}
func isEncoded(headers http.Header) bool {
header := headers.Get(contentEncodingHeader)
// According to https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding,
// content is not encoded if the header 'Content-Encoding' is empty or equals to 'identity'.
return header != "" && header != "identity"
func gzipHandler(h http.Handler) http.Handler {
wrapper, err := gziphandler.NewGzipHandler(gzip.DefaultCompression, gziphandler.DefaultMinSize, &gziphandler.GzipResponseWriterWrapper{})
if err != nil {
log.Error(err)
}
return wrapper(h)
}

View file

@ -1,6 +1,7 @@
package middlewares
import (
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
@ -8,29 +9,31 @@ import (
"github.com/NYTimes/gziphandler"
"github.com/containous/traefik/testhelpers"
"github.com/stretchr/testify/assert"
"github.com/urfave/negroni"
)
const (
acceptEncodingHeader = "Accept-Encoding"
varyHeader = "Vary"
gzip = "gzip"
acceptEncodingHeader = "Accept-Encoding"
contentEncodingHeader = "Content-Encoding"
varyHeader = "Vary"
gzipValue = "gzip"
)
func TestShouldCompressWhenNoContentEncodingHeader(t *testing.T) {
handler := &Compress{}
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost", nil)
req.Header.Add(acceptEncodingHeader, gzip)
req.Header.Add(acceptEncodingHeader, gzipValue)
baseBody := generateBytes(gziphandler.DefaultMinSize)
next := func(rw http.ResponseWriter, r *http.Request) {
rw.Write(baseBody)
}
rw := httptest.NewRecorder()
rw := httptest.NewRecorder()
handler.ServeHTTP(rw, req, next)
assert.Equal(t, gzip, rw.Header().Get(contentEncodingHeader))
assert.Equal(t, gzipValue, rw.Header().Get(contentEncodingHeader))
assert.Equal(t, acceptEncodingHeader, rw.Header().Get(varyHeader))
if assert.ObjectsAreEqualValues(rw.Body.Bytes(), baseBody) {
@ -42,28 +45,105 @@ func TestShouldNotCompressWhenContentEncodingHeader(t *testing.T) {
handler := &Compress{}
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost", nil)
req.Header.Add(acceptEncodingHeader, gzip)
req.Header.Add(contentEncodingHeader, gzip)
baseBody := generateBytes(gziphandler.DefaultMinSize)
req.Header.Add(acceptEncodingHeader, gzipValue)
fakeCompressedBody := generateBytes(gziphandler.DefaultMinSize)
next := func(rw http.ResponseWriter, r *http.Request) {
rw.Write(baseBody)
rw.Header().Add(contentEncodingHeader, gzipValue)
rw.Header().Add(varyHeader, acceptEncodingHeader)
rw.Write(fakeCompressedBody)
}
rw := httptest.NewRecorder()
handler.ServeHTTP(rw, req, next)
assert.Equal(t, "", rw.Header().Get(contentEncodingHeader))
assert.Equal(t, "", rw.Header().Get(varyHeader))
assert.Equal(t, gzipValue, rw.Header().Get(contentEncodingHeader))
assert.Equal(t, acceptEncodingHeader, rw.Header().Get(varyHeader))
assert.EqualValues(t, rw.Body.Bytes(), baseBody)
assert.EqualValues(t, rw.Body.Bytes(), fakeCompressedBody)
}
func TestShouldNotCompressWhenNoAcceptEncodingHeader(t *testing.T) {
handler := &Compress{}
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost", nil)
fakeBody := generateBytes(gziphandler.DefaultMinSize)
next := func(rw http.ResponseWriter, r *http.Request) {
rw.Write(fakeBody)
}
rw := httptest.NewRecorder()
handler.ServeHTTP(rw, req, next)
assert.Empty(t, rw.Header().Get(contentEncodingHeader))
assert.EqualValues(t, rw.Body.Bytes(), fakeBody)
}
func TestIntegrationShouldNotCompressWhenContentAlreadyCompressed(t *testing.T) {
fakeCompressedBody := generateBytes(100000)
handler := func(rw http.ResponseWriter, r *http.Request) {
rw.Header().Add(contentEncodingHeader, gzipValue)
rw.Header().Add(varyHeader, acceptEncodingHeader)
rw.Write(fakeCompressedBody)
}
comp := &Compress{}
negro := negroni.New(comp)
negro.UseHandlerFunc(handler)
ts := httptest.NewServer(negro)
defer ts.Close()
client := &http.Client{}
req := testhelpers.MustNewRequest(http.MethodGet, ts.URL, nil)
req.Header.Add(acceptEncodingHeader, gzipValue)
resp, err := client.Do(req)
assert.NoError(t, err, "there should be no error")
assert.Equal(t, gzipValue, resp.Header.Get(contentEncodingHeader))
assert.Equal(t, acceptEncodingHeader, resp.Header.Get(varyHeader))
body, err := ioutil.ReadAll(resp.Body)
assert.EqualValues(t, fakeCompressedBody, body)
}
func TestIntegrationShouldCompressWhenAcceptEncodingHeaderIsPresent(t *testing.T) {
fakeBody := generateBytes(100000)
handler := func(rw http.ResponseWriter, r *http.Request) {
rw.Write(fakeBody)
}
comp := &Compress{}
negro := negroni.New(comp)
negro.UseHandlerFunc(handler)
ts := httptest.NewServer(negro)
defer ts.Close()
client := &http.Client{}
req := testhelpers.MustNewRequest(http.MethodGet, ts.URL, nil)
req.Header.Add(acceptEncodingHeader, gzipValue)
resp, err := client.Do(req)
assert.NoError(t, err, "there should be no error")
assert.Equal(t, gzipValue, resp.Header.Get(contentEncodingHeader))
assert.Equal(t, acceptEncodingHeader, resp.Header.Get(varyHeader))
body, err := ioutil.ReadAll(resp.Body)
if assert.ObjectsAreEqualValues(body, fakeBody) {
assert.Fail(t, "expected a compressed body", "got %v", body)
}
}
func generateBytes(len int) []byte {
var value []byte
for i := 0; i < len; i++ {
value = append(value, 0x61)
value = append(value, 0x61+byte(i))
}
return value
}

View file

@ -16,5 +16,6 @@ type ReplacePath struct {
func (s *ReplacePath) ServeHTTP(w http.ResponseWriter, r *http.Request) {
r.Header.Add(ReplacedPathHeader, r.URL.Path)
r.URL.Path = s.Path
r.RequestURI = r.URL.RequestURI()
s.Handler.ServeHTTP(w, r)
}

View file

@ -19,20 +19,23 @@ func TestReplacePath(t *testing.T) {
for _, path := range paths {
t.Run(path, func(t *testing.T) {
var expectedPath, actualHeader string
var expectedPath, actualHeader, requestURI string
handler := &ReplacePath{
Path: replacementPath,
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
expectedPath = r.URL.Path
actualHeader = r.Header.Get(ReplacedPathHeader)
requestURI = r.RequestURI
}),
}
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost"+path, nil)
handler.ServeHTTP(nil, req)
assert.Equal(t, expectedPath, replacementPath, "Unexpected path.")
assert.Equal(t, path, actualHeader, "Unexpected '%s' header.", ReplacedPathHeader)
assert.Equal(t, expectedPath, requestURI, "Unexpected request URI.")
})
}
}