diff --git a/httpbin/handlers.go b/httpbin/handlers.go index d2ac4067..6409930c 100644 --- a/httpbin/handlers.go +++ b/httpbin/handlers.go @@ -8,6 +8,7 @@ import ( "fmt" "net/http" "net/url" + "sort" "strconv" "strings" "time" @@ -390,7 +391,17 @@ func (h *HTTPBin) RedirectTo(w http.ResponseWriter, r *http.Request) { if u.IsAbs() && len(h.AllowedRedirectDomains) > 0 { if _, ok := h.AllowedRedirectDomains[u.Hostname()]; !ok { - http.Error(w, "Forbidden redirect URL. Be careful with this link.", http.StatusForbidden) + domainListItems := make([]string, 0, len(h.AllowedRedirectDomains)) + for domain := range h.AllowedRedirectDomains { + domainListItems = append(domainListItems, fmt.Sprintf("- %s", domain)) + } + sort.Strings(domainListItems) + formattedDomains := strings.Join(domainListItems, "\n") + msg := fmt.Sprintf(`Forbidden redirect URL. Please be careful with this link. + +Allowed redirect destinations: +%s`, formattedDomains) + http.Error(w, msg, http.StatusForbidden) return } } diff --git a/httpbin/handlers_test.go b/httpbin/handlers_test.go index 5545db16..f3178707 100644 --- a/httpbin/handlers_test.go +++ b/httpbin/handlers_test.go @@ -74,7 +74,7 @@ func assertBodyEquals(t *testing.T, w *httptest.ResponseRecorder, want string) { t.Helper() have := w.Body.String() if want != have { - t.Fatalf("expected body = %v, got %v", want, have) + t.Fatalf("expected body = %q, got %q", want, have) } } @@ -1239,6 +1239,13 @@ func TestRedirectTo(t *testing.T) { WithObserver(StdLogObserver(log.New(io.Discard, "", 0))), ).Handler() + allowedDomainsError := `Forbidden redirect URL. Please be careful with this link. + +Allowed redirect destinations: +- example.org +- httpbingo.org +` + allowListTests := []struct { url string expectedStatus int @@ -1257,6 +1264,9 @@ func TestRedirectTo(t *testing.T) { w := httptest.NewRecorder() allowListHandler.ServeHTTP(w, r) assertStatusCode(t, w, test.expectedStatus) + if test.expectedStatus >= 400 { + assertBodyEquals(t, w, allowedDomainsError) + } }) } }