Merge 517d1edbe002135c41e99e9afd4cea90f7bc4767 into d75fcd4c9ab260e5225de590f1f0f8c0e0e12d11

This commit is contained in:
Harshal Patel 2026-06-05 18:03:30 +00:00 committed by GitHub
commit afcba4467e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 78 additions and 3 deletions

View File

@ -3868,3 +3868,56 @@ func BenchmarkGetMapFromFormData(b *testing.B) {
}) })
} }
} }
func TestWildcardParamUnicodeConcurrency(t *testing.T) {
router := New()
var mu sync.Mutex
var errs []string
router.GET("/user/:name", func(c *Context) {
name := c.Param("name")
if name == "" {
mu.Lock()
errs = append(errs, "name param is empty")
mu.Unlock()
}
})
router.GET("/files/*filepath", func(c *Context) {
filepath := c.Param("filepath")
if filepath == "" {
mu.Lock()
errs = append(errs, "filepath param is empty")
mu.Unlock()
}
})
var wg sync.WaitGroup
paths := []string{
"/user/जयेश",
"/files/🎉/photo.png",
"/user/こんにちは",
}
for i := 0; i < 20; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for _, p := range paths {
req, _ := http.NewRequest(http.MethodGet, p, nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
if w.Code != http.StatusOK {
mu.Lock()
errs = append(errs, "status code is not 200")
mu.Unlock()
}
}
}()
}
wg.Wait()
assert.Empty(t, errs)
}

2
go.mod
View File

@ -12,7 +12,7 @@ require (
github.com/mattn/go-isatty v0.0.20 github.com/mattn/go-isatty v0.0.20
github.com/modern-go/reflect2 v1.0.2 github.com/modern-go/reflect2 v1.0.2
github.com/pelletier/go-toml/v2 v2.2.4 github.com/pelletier/go-toml/v2 v2.2.4
github.com/quic-go/quic-go v0.59.0 github.com/quic-go/quic-go v0.59.1
github.com/stretchr/testify v1.11.1 github.com/stretchr/testify v1.11.1
github.com/ugorji/go/codec v1.3.1 github.com/ugorji/go/codec v1.3.1
go.mongodb.org/mongo-driver/v2 v2.5.0 go.mongodb.org/mongo-driver/v2 v2.5.0

4
go.sum
View File

@ -52,8 +52,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw= github.com/quic-go/quic-go v0.59.1 h1:0Gmua0HW1Tv7ANR7hUYwRyD0MG5OJfgvYSZasGZzBic=
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU= github.com/quic-go/quic-go v0.59.1/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=

View File

@ -509,6 +509,11 @@ walk: // Outer loop for walking the tree
// Expand slice within preallocated capacity // Expand slice within preallocated capacity
i := len(*value.params) i := len(*value.params)
*value.params = (*value.params)[:i+1] *value.params = (*value.params)[:i+1]
// Ensure 'end' index lands exactly on a valid UTF-8 rune boundary
for end > 0 && end < len(path) && !utf8.RuneStart(path[end]) {
end--
}
val := path[:end] val := path[:end]
if unescape { if unescape {
if v, err := url.QueryUnescape(val); err == nil { if v, err := url.QueryUnescape(val); err == nil {

View File

@ -1111,3 +1111,20 @@ func TestTreeFindCaseInsensitivePathWildcardParamAndStaticChild(t *testing.T) {
t.Errorf("Wrong result for '/prefix/something': %s", string(out)) t.Errorf("Wrong result for '/prefix/something': %s", string(out))
} }
} }
func TestTreeWildcardParamImproperBoundaryCoverage(t *testing.T) {
tree := &node{}
// Register a path with a wild named parameter segment
tree.addRoute("/submit/:info", HandlersChain{func(c *Context) {}})
// Pass a path containing a multi-byte sequence where a standard byte segment lookup
// drifts directly into the middle of a continuation block.
// This exercises our inner boundary alignment decrement loop.
path := "/submit/जय"
value := tree.getValue(path, &Params{}, nil, false)
if value.handlers == nil {
t.Errorf("Routing fallback failed on multi-byte parameter verification evaluation.")
}
}