net/http: avoid appending an existing trailing slash to path again

This CL is similar to CL 562557, and it takes over CL 594175.

While here, unrelatedly remove mapKeys function, use slices.Sorted(maps.Keys(ms))
to simplify code.

Fixes #67657

Change-Id: Id8b99216f87a6dcfd6d5fa61407b515324c79112
Reviewed-on: https://go-review.googlesource.com/c/go/+/594737
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
Reviewed-by: Joedian Reid <joedian@google.com>
This commit is contained in:
Jes Cok 2024-06-26 01:35:13 +08:00 committed by Jonathan Amsterdam
parent 7f90b960a9
commit 773767def0
3 changed files with 22 additions and 15 deletions

View file

@ -7,6 +7,7 @@ package http
import (
"fmt"
"io"
"maps"
"strings"
"testing"
@ -261,9 +262,7 @@ func TestMatchingMethods(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
ms := map[string]bool{}
test.tree.matchingMethods(test.host, test.path, ms)
keys := mapKeys(ms)
slices.Sort(keys)
got := strings.Join(keys, ",")
got := strings.Join(slices.Sorted(maps.Keys(ms)), ",")
if got != test.want {
t.Errorf("got %s, want %s", got, test.want)
}

View file

@ -613,6 +613,22 @@ func TestMuxNoSlashRedirectWithTrailingSlash(t *testing.T) {
}
}
// Test that we don't attempt trailing-slash response 405 on a path that already has
// a trailing slash.
// See issue #67657.
func TestMuxNoSlash405WithTrailingSlash(t *testing.T) {
mux := NewServeMux()
mux.HandleFunc("GET /{x}/", func(w ResponseWriter, r *Request) {
fmt.Fprintln(w, "ok")
})
w := httptest.NewRecorder()
req, _ := NewRequest("GET", "/", nil)
mux.ServeHTTP(w, req)
if g, w := w.Code, 404; g != w {
t.Errorf("got %d, want %d", g, w)
}
}
func TestShouldRedirectConcurrency(t *testing.T) { run(t, testShouldRedirectConcurrency) }
func testShouldRedirectConcurrency(t *testing.T, mode testMode) {
mux := NewServeMux()

View file

@ -16,6 +16,7 @@ import (
"internal/godebug"
"io"
"log"
"maps"
"math/rand"
"net"
"net/textproto"
@ -2721,19 +2722,10 @@ func (mux *ServeMux) matchingMethods(host, path string) []string {
ms := map[string]bool{}
mux.tree.matchingMethods(host, path, ms)
// matchOrRedirect will try appending a trailing slash if there is no match.
mux.tree.matchingMethods(host, path+"/", ms)
methods := mapKeys(ms)
slices.Sort(methods)
return methods
}
// TODO(jba): replace with maps.Keys when it is defined.
func mapKeys[K comparable, V any](m map[K]V) []K {
var ks []K
for k := range m {
ks = append(ks, k)
if !strings.HasSuffix(path, "/") {
mux.tree.matchingMethods(host, path+"/", ms)
}
return ks
return slices.Sorted(maps.Keys(ms))
}
// ServeHTTP dispatches the request to the handler whose