Skip to content

Commit e17e530

Browse files
committed
net/http: refine trailing-slash redirect logic
Do not add a trailing slash and redirect if the path already ends in a slash. Also, and unrelatedly, add a test for cleanPath. Fixes #65624. Change-Id: Ifcf9edc929d2eb6db88132c09d2bade85c5dda3d Reviewed-on: https://go-review.googlesource.com/c/go/+/562557 Reviewed-by: Damien Neil <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 2a59041 commit e17e530

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

src/net/http/serve_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,22 @@ func TestServeWithSlashRedirectForHostPatterns(t *testing.T) {
597597
}
598598
}
599599

600+
// Test that we don't attempt trailing-slash redirect on a path that already has
601+
// a trailing slash.
602+
// See issue #65624.
603+
func TestMuxNoSlashRedirectWithTrailingSlash(t *testing.T) {
604+
mux := NewServeMux()
605+
mux.HandleFunc("/{x}/", func(w ResponseWriter, r *Request) {
606+
fmt.Fprintln(w, "ok")
607+
})
608+
w := httptest.NewRecorder()
609+
req, _ := NewRequest("GET", "/", nil)
610+
mux.ServeHTTP(w, req)
611+
if g, w := w.Code, 404; g != w {
612+
t.Errorf("got %d, want %d", g, w)
613+
}
614+
}
615+
600616
func TestShouldRedirectConcurrency(t *testing.T) { run(t, testShouldRedirectConcurrency) }
601617
func testShouldRedirectConcurrency(t *testing.T, mode testMode) {
602618
mux := NewServeMux()

src/net/http/server.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2577,8 +2577,8 @@ func (mux *ServeMux) matchOrRedirect(host, method, path string, u *url.URL) (_ *
25772577

25782578
n, matches := mux.tree.match(host, method, path)
25792579
// If we have an exact match, or we were asked not to try trailing-slash redirection,
2580-
// then we're done.
2581-
if !exactMatch(n, path) && u != nil {
2580+
// or the URL already has a trailing slash, then we're done.
2581+
if !exactMatch(n, path) && u != nil && !strings.HasSuffix(path, "/") {
25822582
// If there is an exact match with a trailing slash, then redirect.
25832583
path += "/"
25842584
n2, _ := mux.tree.match(host, method, path)

src/net/http/server_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,24 @@ func TestEscapedPathsAndPatterns(t *testing.T) {
250250
t.Run("1.21", func(t *testing.T) { run(t, true) })
251251
}
252252

253+
func TestCleanPath(t *testing.T) {
254+
for _, test := range []struct {
255+
in, want string
256+
}{
257+
{"//", "/"},
258+
{"/x", "/x"},
259+
{"//x", "/x"},
260+
{"x//", "/x/"},
261+
{"a//b/////c", "/a/b/c"},
262+
{"/foo/../bar/./..//baz", "/baz"},
263+
} {
264+
got := cleanPath(test.in)
265+
if got != test.want {
266+
t.Errorf("%s: got %q, want %q", test.in, got, test.want)
267+
}
268+
}
269+
}
270+
253271
func BenchmarkServerMatch(b *testing.B) {
254272
fn := func(w ResponseWriter, r *Request) {
255273
fmt.Fprintf(w, "OK")

0 commit comments

Comments
 (0)