diff --git a/httpbin/handlers.go b/httpbin/handlers.go index baccdfa3b0a06aee27554564cbb73ca0c9e3d8d6..384abbee04f182275d7ef01e002123c55dc622aa 100644 --- a/httpbin/handlers.go +++ b/httpbin/handlers.go @@ -176,3 +176,23 @@ func (h *HTTPBin) Status(w http.ResponseWriter, r *http.Request) { w.WriteHeader(code) } } + +// ResponseHeaders responds with a map of header values +func (h *HTTPBin) ResponseHeaders(w http.ResponseWriter, r *http.Request) { + args, err := url.ParseQuery(r.URL.RawQuery) + if err != nil { + http.Error(w, fmt.Sprintf("error parsing query params: %s", err), http.StatusBadRequest) + return + } + + for k, vs := range args { + for _, v := range vs { + w.Header().Add(http.CanonicalHeaderKey(k), v) + } + } + body, _ := json.Marshal(args) + if contentType := w.Header().Get("Content-Type"); contentType == "" { + w.Header().Set("Content-Type", "application/json; encoding=utf-8") + } + w.Write(body) +} diff --git a/httpbin/handlers_test.go b/httpbin/handlers_test.go index 11bc1ffed6cffaa284d4c4676cfe5b286e91cc9f..7545812b3c330cabf9d32f00073260cd75f8862c 100644 --- a/httpbin/handlers_test.go +++ b/httpbin/handlers_test.go @@ -109,6 +109,30 @@ func TestGet__Basic(t *testing.T) { } } +func TestGet__WithParams(t *testing.T) { + params := url.Values{} + params.Set("foo", "foo") + params.Add("bar", "bar1") + params.Add("bar", "bar2") + + r, _ := http.NewRequest("GET", fmt.Sprintf("/get?%s", params.Encode()), nil) + w := httptest.NewRecorder() + handler.ServeHTTP(w, r) + + assertStatusCode(t, w, http.StatusOK) + assertContentType(t, w, "application/json; encoding=utf-8") + + var resp *bodyResponse + err := json.Unmarshal(w.Body.Bytes(), &resp) + if err != nil { + t.Fatalf("failed to unmarshal body %s from JSON: %s", w.Body, err) + } + + if resp.Args.Encode() != params.Encode() { + t.Fatalf("args mismatch: %s != %s", resp.Args.Encode(), params.Encode()) + } +} + func TestGet__OnlyAllowsGets(t *testing.T) { r, _ := http.NewRequest("POST", "/get", nil) w := httptest.NewRecorder() @@ -461,3 +485,50 @@ func TestStatus__Simple(t *testing.T) { } } } + +func TestResponseHeaders(t *testing.T) { + headers := map[string][]string{ + "Content-Type": {"test/test"}, + "Foo": {"foo"}, + "Bar": {"bar1, bar2"}, + } + + params := url.Values{} + for k, vs := range headers { + for _, v := range vs { + params.Add(k, v) + } + } + + r, _ := http.NewRequest("GET", fmt.Sprintf("/response-headers?%s", params.Encode()), nil) + w := httptest.NewRecorder() + handler.ServeHTTP(w, r) + + assertStatusCode(t, w, http.StatusOK) + + for k, expectedValues := range headers { + values, ok := w.HeaderMap[k] + if !ok { + t.Fatalf("expected header %s in response headers", k) + } + if !reflect.DeepEqual(values, expectedValues) { + t.Fatalf("expected key values %#v for header %s, got %#v", expectedValues, k, values) + } + } + + resp := &http.Header{} + err := json.Unmarshal(w.Body.Bytes(), resp) + if err != nil { + t.Fatalf("failed to unmarshal body %s from JSON: %s", w.Body, err) + } + + for k, expectedValues := range headers { + values, ok := (*resp)[k] + if !ok { + t.Fatalf("expected header %s in response body", k) + } + if !reflect.DeepEqual(values, expectedValues) { + t.Fatalf("expected key values %#v for header %s, got %#v", expectedValues, k, values) + } + } +} diff --git a/httpbin/httpbin.go b/httpbin/httpbin.go index 83a6d26e62b5de3ae7818c0b27744c8d7cb57874..48e721430d608ebffcda583e2b26ed7c87a0f08b 100644 --- a/httpbin/httpbin.go +++ b/httpbin/httpbin.go @@ -65,6 +65,7 @@ func (h *HTTPBin) Handler() http.Handler { mux.HandleFunc("/user-agent", h.UserAgent) mux.HandleFunc("/headers", h.Headers) mux.HandleFunc("/status/", h.Status) + mux.HandleFunc("/response-headers", h.ResponseHeaders) return logger(cors(mux)) }