From aabe5a1f7db073b37ab74c60088ffea8ba5d2dad Mon Sep 17 00:00:00 2001
From: Will McCutchen <will@mccutch.org>
Date: Fri, 2 Dec 2016 08:43:46 -0800
Subject: [PATCH] Add /deflate handler

---
 httpbin/handlers.go      | 22 +++++++++++++++++++++
 httpbin/handlers_test.go | 41 ++++++++++++++++++++++++++++++++++++++++
 httpbin/httpbin.go       |  7 +++++++
 3 files changed, 70 insertions(+)

diff --git a/httpbin/handlers.go b/httpbin/handlers.go
index bf2e889..f2b6629 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 b48f492..f3cbef8 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 d08b57e..41ff3da 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
-- 
GitLab