diff --git a/context_test.go b/context_test.go index 364a92ae..70295620 100644 --- a/context_test.go +++ b/context_test.go @@ -3868,3 +3868,38 @@ func BenchmarkGetMapFromFormData(b *testing.B) { }) } } + +func TestWildcardParamUnicodeConcurrency(t *testing.T) { + router := New() + + router.GET("/user/:name", func(c *Context) { + name := c.Param("name") + assert.NotEmpty(t, name) + }) + + router.GET("/files/*filepath", func(c *Context) { + filepath := c.Param("filepath") + assert.NotEmpty(t, filepath) + }) + + 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) + assert.Equal(t, http.StatusOK, w.Code) + } + }() + } + wg.Wait() +} diff --git a/tree.go b/tree.go index 580abbaf..f12d3b5c 100644 --- a/tree.go +++ b/tree.go @@ -509,6 +509,11 @@ walk: // Outer loop for walking the tree // Expand slice within preallocated capacity i := len(*value.params) *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] if unescape { if v, err := url.QueryUnescape(val); err == nil {