From bb9f787732b01e0e1681b19fd67e9bc46ae2389d Mon Sep 17 00:00:00 2001
From: Will McCutchen <will@mccutch.org>
Date: Wed, 12 Oct 2016 09:01:48 -0700
Subject: [PATCH] Add /relative-redirect/:n handler

---
 httpbin/handlers.go      | 21 +++++++++++++++++++++
 httpbin/handlers_test.go | 39 +++++++++++++++++++++++++++++++++++++++
 httpbin/httpbin.go       |  2 ++
 3 files changed, 62 insertions(+)

diff --git a/httpbin/handlers.go b/httpbin/handlers.go
index 384abbe..c0115f2 100644
--- a/httpbin/handlers.go
+++ b/httpbin/handlers.go
@@ -196,3 +196,24 @@ func (h *HTTPBin) ResponseHeaders(w http.ResponseWriter, r *http.Request) {
 	}
 	w.Write(body)
 }
+
+// RelativeRedirect responds with an HTTP 302 redirect a given number of times
+func (h *HTTPBin) RelativeRedirect(w http.ResponseWriter, r *http.Request) {
+	parts := strings.Split(r.URL.Path, "/")
+	if len(parts) != 3 {
+		http.Error(w, "Not found", http.StatusNotFound)
+		return
+	}
+	n, err := strconv.Atoi(parts[2])
+	if err != nil || n < 1 {
+		http.Error(w, "Invalid redirect", http.StatusBadRequest)
+	}
+
+	location := fmt.Sprintf("/relative-redirect/%d", n-1)
+	if n == 1 {
+		location = "/get"
+	}
+
+	w.Header().Set("Location", location)
+	w.WriteHeader(http.StatusFound)
+}
diff --git a/httpbin/handlers_test.go b/httpbin/handlers_test.go
index 7545812..970ba8d 100644
--- a/httpbin/handlers_test.go
+++ b/httpbin/handlers_test.go
@@ -532,3 +532,42 @@ func TestResponseHeaders(t *testing.T) {
 		}
 	}
 }
+
+func TestRelativeRedirect__OK(t *testing.T) {
+	var tests = []struct {
+		n        int
+		location string
+	}{
+		{1, "/get"},
+		{2, "/relative-redirect/1"},
+		{100, "/relative-redirect/99"},
+	}
+
+	for _, test := range tests {
+		r, _ := http.NewRequest("GET", fmt.Sprintf("/relative-redirect/%d", test.n), nil)
+		w := httptest.NewRecorder()
+		handler.ServeHTTP(w, r)
+
+		assertStatusCode(t, w, http.StatusFound)
+		assertHeader(t, w, "Location", test.location)
+	}
+}
+
+func TestRelativeRedirect__Errors(t *testing.T) {
+	var tests = []struct {
+		given  interface{}
+		status int
+	}{
+		{3.14, http.StatusBadRequest},
+		{-1, http.StatusBadRequest},
+		{"foo", http.StatusBadRequest},
+	}
+
+	for _, test := range tests {
+		r, _ := http.NewRequest("GET", fmt.Sprintf("/relative-redirect/%v", test.given), nil)
+		w := httptest.NewRecorder()
+		handler.ServeHTTP(w, r)
+
+		assertStatusCode(t, w, test.status)
+	}
+}
diff --git a/httpbin/httpbin.go b/httpbin/httpbin.go
index 48e7214..531e616 100644
--- a/httpbin/httpbin.go
+++ b/httpbin/httpbin.go
@@ -67,6 +67,8 @@ func (h *HTTPBin) Handler() http.Handler {
 	mux.HandleFunc("/status/", h.Status)
 	mux.HandleFunc("/response-headers", h.ResponseHeaders)
 
+	mux.HandleFunc("/relative-redirect/", h.RelativeRedirect)
+
 	return logger(cors(mux))
 }
 
-- 
GitLab