diff --git a/httpbin/handlers.go b/httpbin/handlers.go index bf2e8895ed629251a76bd57fee9beaf7ed9eee54..f2b6629ab2562f35cf05515dcb41b83aec573b5a 100644 --- a/httpbin/handlers.go +++ b/httpbin/handlers.go @@ -2,6 +2,7 @@ package httpbin import ( "bytes" + "compress/flate" "compress/gzip" "encoding/json" "fmt" @@ -90,6 +91,27 @@ func (h *HTTPBin) Gzip(w http.ResponseWriter, r *http.Request) { writeJSON(w, gzBody, http.StatusOK) } +// Deflate returns a gzipped response +func (h *HTTPBin) Deflate(w http.ResponseWriter, r *http.Request) { + resp := &deflateResponse{ + Headers: r.Header, + Origin: getOrigin(r), + Deflated: true, + } + body, _ := json.Marshal(resp) + + buf := &bytes.Buffer{} + w2, _ := flate.NewWriter(buf, flate.DefaultCompression) + w2.Write(body) + w2.Close() + + compressedBody := buf.Bytes() + + w.Header().Set("Content-Encoding", "deflate") + w.Header().Set("Content-Length", fmt.Sprintf("%d", len(compressedBody))) + writeJSON(w, compressedBody, http.StatusOK) +} + // IP echoes the IP address of the incoming request func (h *HTTPBin) IP(w http.ResponseWriter, r *http.Request) { body, _ := json.Marshal(&ipResponse{ diff --git a/httpbin/handlers_test.go b/httpbin/handlers_test.go index b48f4923d84e2307529f511a0ae14b4ae5b296fd..f3cbef82b074ddf8e3b3a0bc5ead71c360266993 100644 --- a/httpbin/handlers_test.go +++ b/httpbin/handlers_test.go @@ -2,6 +2,7 @@ package httpbin import ( "bytes" + "compress/flate" "compress/gzip" "encoding/json" "fmt" @@ -1122,3 +1123,43 @@ func TestGzip(t *testing.T) { t.Fatalf("expected compressed body") } } + +func TestDeflate(t *testing.T) { + r, _ := http.NewRequest("GET", "/deflate", nil) + w := httptest.NewRecorder() + handler.ServeHTTP(w, r) + + assertContentType(t, w, "application/json; encoding=utf-8") + assertHeader(t, w, "Content-Encoding", "deflate") + assertStatusCode(t, w, http.StatusOK) + + contentLengthHeader := w.HeaderMap.Get("Content-Length") + if contentLengthHeader == "" { + t.Fatalf("missing Content-Length header in response") + } + + contentLength, err := strconv.Atoi(contentLengthHeader) + if err != nil { + t.Fatal(err) + } + + reader := flate.NewReader(w.Body) + body, err := ioutil.ReadAll(reader) + if err != nil { + t.Fatal(err) + } + + var resp *deflateResponse + err = json.Unmarshal(body, &resp) + if err != nil { + t.Fatalf("error unmarshalling response: %s", err) + } + + if resp.Deflated != true { + t.Fatalf("expected resp.Deflated == true") + } + + if len(body) >= contentLength { + t.Fatalf("expected compressed body") + } +} diff --git a/httpbin/httpbin.go b/httpbin/httpbin.go index d08b57ef2a5fa8490cc913a2a141a7b9da427e45..41ff3dac51d4d83bac560f5b9b767a9d751df746 100644 --- a/httpbin/httpbin.go +++ b/httpbin/httpbin.go @@ -52,6 +52,12 @@ type gzipResponse struct { Gzipped bool `json:"gzipped"` } +type deflateResponse struct { + Headers http.Header `json:"headers"` + Origin string `json:"origin"` + Deflated bool `json:"deflated"` +} + // Options are used to configure HTTPBin type Options struct { MaxMemory int64 @@ -94,6 +100,7 @@ func (h *HTTPBin) Handler() http.Handler { mux.HandleFunc("/hidden-basic-auth/", h.HiddenBasicAuth) mux.HandleFunc("/digest-auth/", h.DigestAuth) + mux.HandleFunc("/deflate", h.Deflate) mux.HandleFunc("/gzip", h.Gzip) // Make sure our ServeMux doesn't "helpfully" redirect these invalid