internal/httpd/trailingslash_test.go

v1.34.0
gitbay/internal/httpd/trailingslash_test.go history · blame · raw

65 lines · 2289 bytes

 1package httpd
 2
 3import (
 4	"bufio"
 5	"net/http"
 6	"net/http/httptest"
 7	"strings"
 8	"testing"
 9)
10
11// A path that only misses because of a trailing slash redirects to the
12// path without it, query intact; one that misses either way is 404, and
13// a POST is never redirected (#233).
14func TestTrailingSlashRedirects(t *testing.T) {
15	h := plainServer().Handler()
16	for from, to := range map[string]string{
17		"/cmc/":                   "/cmc",
18		"/cmc/ccleberg/":          "/cmc/ccleberg",
19		"/cmc/-/snippets/":        "/cmc/-/snippets",
20		"/krz/gitbay/mrs/12/":     "/krz/gitbay/mrs/12",
21		"/krz/gitbay/issues/?q=x": "/krz/gitbay/issues?q=x",
22	} {
23		w := get(t, h, from, nil)
24		if w.Code != http.StatusMovedPermanently || w.Header().Get("Location") != to {
25			t.Errorf("%s: %d %q, want 301 %q", from, w.Code, w.Header().Get("Location"), to)
26		}
27	}
28	for _, p := range []string{"/", "/krz/gitbay/nothing/"} {
29		if w := get(t, h, p, nil); p != "/" && w.Code != 404 {
30			t.Errorf("%s: status %d, want 404", p, w.Code)
31		}
32	}
33	// A Location must not leave the site: the mux cleans a leading //
34	// before the fallback runs, and a backslash is escaped (#153).
35	for _, p := range []string{"//evil.example/", "/\\evil.example/"} {
36		w := get(t, h, p, nil)
37		if loc := w.Header().Get("Location"); strings.HasPrefix(loc, "//") || strings.Contains(loc, "\\") {
38			t.Errorf("%s: Location %q leaves the site", p, loc)
39		}
40	}
41	// An absolute-form request line, which RFC 7230 requires a server to
42	// accept, fills URL.Scheme and URL.Host. Neither may reach Location.
43	// ReadRequest also takes Host from the URL; it is pinned back to the
44	// site so this stays a test of the forge handler rather than of the
45	// pages router.
46	raw := "GET http://evil.example/cmc/ HTTP/1.1\r\nHost: forge.test\r\n\r\n"
47	abs, err := http.ReadRequest(bufio.NewReader(strings.NewReader(raw)))
48	if err != nil {
49		t.Fatal(err)
50	}
51	abs.Host = "forge.test"
52	aw := httptest.NewRecorder()
53	h.ServeHTTP(aw, abs)
54	if loc := aw.Header().Get("Location"); loc != "/cmc" {
55		t.Errorf("absolute-form request: Location %q, want %q", loc, "/cmc")
56	}
57
58	r := httptest.NewRequest("POST", "/cmc/", nil)
59	r.Host = "forge.test"
60	w := httptest.NewRecorder()
61	h.ServeHTTP(w, r)
62	if w.Code != 404 {
63		t.Errorf("POST /cmc/: status %d, want 404", w.Code)
64	}
65}