internal/httpd/pagesredirect_test.go

v1.32.0
gitbay/internal/httpd/pagesredirect_test.go history · blame · raw

57 lines · 2025 bytes

 1package httpd
 2
 3import (
 4	"net/http/httptest"
 5	"strings"
 6	"testing"
 7)
 8
 9// A redirect target built from the request path must not be able to leave
10// the site. `r.URL.Path` keeps a leading `//` — Go's URL parser does not
11// normalise it — and `Location: //evil.example/` is protocol-relative, so
12// a browser follows it to another origin (gosecurity:S5146, #153).
13//
14// The directory-redirect targets are derived from the cleaned path, so
15// this asserts the property rather than the spelling: whatever the code
16// emits, it must be a same-origin path.
17func TestPageRedirectCannotLeaveTheSite(t *testing.T) {
18	cases := []string{
19		"//evil.example",
20		"//evil.example/deep",
21		"///evil.example",
22		"/\\evil.example",
23		"//evil.example/../..",
24	}
25	for _, p := range cases {
26		got := pageRedirectTarget(p)
27		if got == "" {
28			continue // no redirect for this shape is a fine answer
29		}
30		if strings.HasPrefix(got, "//") || strings.HasPrefix(got, "/\\") {
31			t.Errorf("request %q redirects to %q, which a browser reads as another origin", p, got)
32		}
33		if !strings.HasPrefix(got, "/") {
34			t.Errorf("request %q redirects to %q, which is not an absolute path", p, got)
35		}
36	}
37}
38
39// The ordinary case still behaves: a directory URL without a trailing
40// slash gains one, so relative links inside the page resolve.
41func TestPageRedirectAddsTrailingSlash(t *testing.T) {
42	if got, want := pageRedirectTarget("/guide"), "/guide/"; got != want {
43		t.Errorf("pageRedirectTarget(/guide) = %q, want %q", got, want)
44	}
45	if got, want := pageRedirectTarget("/a/b/c"), "/a/b/c/"; got != want {
46		t.Errorf("pageRedirectTarget(/a/b/c) = %q, want %q", got, want)
47	}
48}
49
50// Guard against a regression in the shape the fix relies on: httptest
51// builds the request the same way the server sees it.
52func TestRawPathKeepsDoubleSlash(t *testing.T) {
53	r := httptest.NewRequest("GET", "http://host//evil.example", nil)
54	if r.URL.Path != "//evil.example" {
55		t.Skipf("net/url normalised the path to %q; the hazard this guards is gone", r.URL.Path)
56	}
57}