Этот коммит содержится в:
Christopher Speller
2017-08-17 17:19:06 -07:00
коммит произвёл GitHub
родитель 2c895ee66e
Коммит 96eab12027
400 изменённых файлов: 45331 добавлений и 11832 удалений

91
vendor/github.com/NYTimes/gziphandler/gzip.go сгенерированный поставляемый
Просмотреть файл

@@ -80,6 +80,8 @@ type GzipResponseWriter struct {
minSize int // Specifed the minimum response size to gzip. If the response length is bigger than this value, it is compressed.
buf []byte // Holds the first part of the write before reaching the minSize or the end of the write.
contentTypes []string // Only compress if the response is one of these content-types. All are accepted if empty.
}
// Write appends data to the gzip writer.
@@ -100,8 +102,10 @@ func (w *GzipResponseWriter) Write(b []byte) (int, error) {
// On the first write, w.buf changes from nil to a valid slice
w.buf = append(w.buf, b...)
// If the global writes are bigger than the minSize, compression is enable.
if len(w.buf) >= w.minSize {
// If the global writes are bigger than the minSize and we're about to write
// a response containing a content type we want to handle, enable
// compression.
if len(w.buf) >= w.minSize && handleContentType(w.contentTypes, w) {
err := w.startGzip()
if err != nil {
return 0, err
@@ -230,14 +234,25 @@ func NewGzipLevelHandler(level int) (func(http.Handler) http.Handler, error) {
// NewGzipLevelAndMinSize behave as NewGzipLevelHandler except it let the caller
// specify the minimum size before compression.
func NewGzipLevelAndMinSize(level, minSize int) (func(http.Handler) http.Handler, error) {
if level != gzip.DefaultCompression && (level < gzip.BestSpeed || level > gzip.BestCompression) {
return nil, fmt.Errorf("invalid compression level requested: %d", level)
return GzipHandlerWithOpts(CompressionLevel(level), MinSize(minSize))
}
func GzipHandlerWithOpts(opts ...option) (func(http.Handler) http.Handler, error) {
c := &config{
level: gzip.DefaultCompression,
minSize: DefaultMinSize,
}
if minSize < 0 {
return nil, fmt.Errorf("minimum size must be more than zero")
for _, o := range opts {
o(c)
}
if err := c.validate(); err != nil {
return nil, err
}
return func(h http.Handler) http.Handler {
index := poolIndex(level)
index := poolIndex(c.level)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add(vary, acceptEncoding)
@@ -246,7 +261,8 @@ func NewGzipLevelAndMinSize(level, minSize int) (func(http.Handler) http.Handler
gw := &GzipResponseWriter{
ResponseWriter: w,
index: index,
minSize: minSize,
minSize: c.minSize,
contentTypes: c.contentTypes,
}
defer gw.Close()
@@ -258,6 +274,48 @@ func NewGzipLevelAndMinSize(level, minSize int) (func(http.Handler) http.Handler
}, nil
}
// Used for functional configuration.
type config struct {
minSize int
level int
contentTypes []string
}
func (c *config) validate() error {
if c.level != gzip.DefaultCompression && (c.level < gzip.BestSpeed || c.level > gzip.BestCompression) {
return fmt.Errorf("invalid compression level requested: %d", c.level)
}
if c.minSize < 0 {
return fmt.Errorf("minimum size must be more than zero")
}
return nil
}
type option func(c *config)
func MinSize(size int) option {
return func(c *config) {
c.minSize = size
}
}
func CompressionLevel(level int) option {
return func(c *config) {
c.level = level
}
}
func ContentTypes(types []string) option {
return func(c *config) {
c.contentTypes = []string{}
for _, v := range types {
c.contentTypes = append(c.contentTypes, strings.ToLower(v))
}
}
}
// GzipHandler wraps an HTTP handler, to transparently gzip the response body if
// the client supports it (via the Accept-Encoding header). This will compress at
// the default compression level.
@@ -273,6 +331,23 @@ func acceptsGzip(r *http.Request) bool {
return acceptedEncodings["gzip"] > 0.0
}
// returns true if we've been configured to compress the specific content type.
func handleContentType(contentTypes []string, w http.ResponseWriter) bool {
// If contentTypes is empty we handle all content types.
if len(contentTypes) == 0 {
return true
}
ct := strings.ToLower(w.Header().Get(contentType))
for _, c := range contentTypes {
if c == ct {
return true
}
}
return false
}
// parseEncodings attempts to parse a list of codings, per RFC 2616, as might
// appear in an Accept-Encoding header. It returns a map of content-codings to
// quality values, and an error containing the errors encountered. It's probably

60
vendor/github.com/NYTimes/gziphandler/gzip_test.go сгенерированный поставляемый
Просмотреть файл

@@ -319,6 +319,66 @@ func TestDontWriteWhenNotWrittenTo(t *testing.T) {
}
}
var contentTypeTests = []struct {
name string
contentType string
acceptedContentTypes []string
expectedGzip bool
}{
{
name: "Always gzip when content types are empty",
contentType: "",
acceptedContentTypes: []string{},
expectedGzip: true,
},
{
name: "Exact content-type match",
contentType: "application/json",
acceptedContentTypes: []string{"application/json"},
expectedGzip: true,
},
{
name: "Case insensitive content-type matching",
contentType: "Application/Json",
acceptedContentTypes: []string{"application/json"},
expectedGzip: true,
},
{
name: "Non-matching content-type",
contentType: "text/xml",
acceptedContentTypes: []string{"application/json"},
expectedGzip: false,
},
}
func TestContentTypes(t *testing.T) {
for _, tt := range contentTypeTests {
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", tt.contentType)
io.WriteString(w, testBody)
})
wrapper, err := GzipHandlerWithOpts(ContentTypes(tt.acceptedContentTypes))
if !assert.Nil(t, err, "NewGzipHandlerWithOpts returned error", tt.name) {
continue
}
req, _ := http.NewRequest("GET", "/whatever", nil)
req.Header.Set("Accept-Encoding", "gzip")
resp := httptest.NewRecorder()
wrapper(handler).ServeHTTP(resp, req)
res := resp.Result()
assert.Equal(t, 200, res.StatusCode)
if tt.expectedGzip {
assert.Equal(t, "gzip", res.Header.Get("Content-Encoding"), tt.name)
} else {
assert.NotEqual(t, "gzip", res.Header.Get("Content-Encoding"), tt.name)
}
}
}
// --------------------------------------------------------------------
func BenchmarkGzipHandler_S2k(b *testing.B) { benchmark(b, false, 2048) }