From 1462a07cf4d0ffa034c9d438484faa2f553ed995 Mon Sep 17 00:00:00 2001 From: Will McCutchen <will@mccutch.org> Date: Tue, 30 May 2017 17:29:50 -0700 Subject: [PATCH] Add /redirect-to --- httpbin/handlers.go | 26 +++++++++++++++++++++++ httpbin/handlers_test.go | 45 ++++++++++++++++++++++++++++++++++++++++ httpbin/httpbin.go | 2 ++ 3 files changed, 73 insertions(+) diff --git a/httpbin/handlers.go b/httpbin/handlers.go index fb27c4b..29ed07d 100644 --- a/httpbin/handlers.go +++ b/httpbin/handlers.go @@ -293,6 +293,32 @@ func (h *HTTPBin) AbsoluteRedirect(w http.ResponseWriter, r *http.Request) { doRedirect(w, r, false) } +// RedirectTo responds with a redirect to a specific URL with an optional +// status code, which defaults to 302 +func (h *HTTPBin) RedirectTo(w http.ResponseWriter, r *http.Request) { + q := r.URL.Query() + + url := q.Get("url") + if url == "" { + http.Error(w, "Missing URL", http.StatusBadRequest) + return + } + + var err error + statusCode := http.StatusFound + rawStatusCode := q.Get("status_code") + if rawStatusCode != "" { + statusCode, err = strconv.Atoi(q.Get("status_code")) + if err != nil || statusCode < 300 || statusCode > 399 { + http.Error(w, "Invalid status code", http.StatusBadRequest) + return + } + } + + w.Header().Set("Location", url) + w.WriteHeader(statusCode) +} + // Cookies responds with the cookies in the incoming request func (h *HTTPBin) Cookies(w http.ResponseWriter, r *http.Request) { resp := cookiesResponse{} diff --git a/httpbin/handlers_test.go b/httpbin/handlers_test.go index d08e382..5dd8424 100644 --- a/httpbin/handlers_test.go +++ b/httpbin/handlers_test.go @@ -823,6 +823,51 @@ func TestRedirects(t *testing.T) { } } +func TestRedirectTo(t *testing.T) { + var okTests = []struct { + url string + expectedLocation string + expectedStatus int + }{ + {"/redirect-to?url=http://www.example.com/", "http://www.example.com/", http.StatusFound}, + {"/redirect-to?url=http://www.example.com/&status_code=307", "http://www.example.com/", http.StatusTemporaryRedirect}, + + {"/redirect-to?url=/get", "/get", http.StatusFound}, + {"/redirect-to?url=/get&status_code=307", "/get", http.StatusTemporaryRedirect}, + + {"/redirect-to?url=foo", "foo", http.StatusFound}, + } + + for _, test := range okTests { + t.Run("ok"+test.url, func(t *testing.T) { + r, _ := http.NewRequest("GET", test.url, nil) + w := httptest.NewRecorder() + handler.ServeHTTP(w, r) + + assertStatusCode(t, w, test.expectedStatus) + assertHeader(t, w, "Location", test.expectedLocation) + }) + } + + var badTests = []struct { + url string + expectedStatus int + }{ + {"/redirect-to", http.StatusBadRequest}, + {"/redirect-to?status_code=302", http.StatusBadRequest}, + {"/redirect-to?url=foo&status_code=418", http.StatusBadRequest}, + } + for _, test := range badTests { + t.Run("bad"+test.url, func(t *testing.T) { + r, _ := http.NewRequest("GET", test.url, nil) + w := httptest.NewRecorder() + handler.ServeHTTP(w, r) + + assertStatusCode(t, w, test.expectedStatus) + }) + } +} + func TestCookies(t *testing.T) { testCookies := func(t *testing.T, cookies cookiesResponse) { r, _ := http.NewRequest("GET", "/cookies", nil) diff --git a/httpbin/httpbin.go b/httpbin/httpbin.go index 8e835cb..69d38cd 100644 --- a/httpbin/httpbin.go +++ b/httpbin/httpbin.go @@ -102,9 +102,11 @@ func (h *HTTPBin) Handler() http.Handler { mux.HandleFunc("/response-headers", h.ResponseHeaders) mux.HandleFunc("/status/", h.Status) + mux.HandleFunc("/redirect/", h.Redirect) mux.HandleFunc("/relative-redirect/", h.RelativeRedirect) mux.HandleFunc("/absolute-redirect/", h.AbsoluteRedirect) + mux.HandleFunc("/redirect-to", h.RedirectTo) mux.HandleFunc("/cookies", h.Cookies) mux.HandleFunc("/cookies/set", h.SetCookies) -- GitLab