diff --git a/middleware/middleware.go b/middleware/middleware.go index 4562d03b5..288eeedc5 100644 --- a/middleware/middleware.go +++ b/middleware/middleware.go @@ -24,11 +24,11 @@ func captureTokens(pattern *regexp.Regexp, input string) *strings.Replacer { return nil } values := groups[0][1:] - replace := make([]string, 2*len(values)) - for i, v := range values { - j := 2 * i - replace[j] = "$" + strconv.Itoa(i+1) - replace[j+1] = v + // strings.Replacer tries old strings in argument order, so list the highest + // index first. Otherwise "$1" matches the start of "$10". + replace := make([]string, 0, 2*len(values)) + for i := len(values); i > 0; i-- { + replace = append(replace, "$"+strconv.Itoa(i), values[i-1]) } return strings.NewReplacer(replace...) } diff --git a/middleware/rewrite_test.go b/middleware/rewrite_test.go index adcc8e9f5..ae9e37b6d 100644 --- a/middleware/rewrite_test.go +++ b/middleware/rewrite_test.go @@ -315,3 +315,33 @@ func TestEchoRewriteReplacementEscaping(t *testing.T) { }) } } + +func TestEchoRewriteTwoDigitCaptures(t *testing.T) { + e := echo.New() + + e.Pre(RewriteWithConfig(RewriteConfig{ + Rules: map[string]string{ + "^/t/*/*/*/*/*/*/*/*/*/*/*": "/r/$11/$10/$1", + }, + RegexRules: map[*regexp.Regexp]string{ + regexp.MustCompile("^/x/(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)$"): "/v/$11/$10/$1", + }, + })) + + testCases := []struct { + requestPath string + expectPath string + }{ + {"/t/a/b/c/d/e/f/g/h/i/j/k", "/r/k/j/a"}, + {"/x/abcdefghijk", "/v/k/j/a"}, + } + + for _, tc := range testCases { + t.Run(tc.requestPath, func(t *testing.T) { + req := httptest.NewRequest(http.MethodGet, tc.requestPath, nil) + rec := httptest.NewRecorder() + e.ServeHTTP(rec, req) + assert.Equal(t, tc.expectPath, req.URL.EscapedPath()) + }) + } +}