Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions fox.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"net"
"net/http"
"path"
"regexp"
"slices"
"strings"
"sync"
Expand Down Expand Up @@ -975,15 +976,24 @@ func Sub(router *Router) HandlerFunc {

*subCtx.subPatterns = append(*subCtx.subPatterns, *c.subPatterns...)

lastTkType := route.pattern.tokens[len(route.pattern.tokens)-1].typ
lastTk := route.pattern.tokens[len(route.pattern.tokens)-1]
var p string
switch lastTkType {
switch lastTk.typ {
case nodeWildcard:
key := (*c.paramsKeys)[len(*c.paramsKeys)-1]
p = strings.TrimSuffix(c.pattern[:len(c.pattern)-(len(key)+wildcardExtraChar)], "/")
extra := len(key) + wildcardExtraChar
if lastTk.regexp != nil {
// +1 for the ':' separator between name and regex source.
extra += 1 + len(rawExpr(lastTk.regexp))
}
p = strings.TrimSuffix(c.pattern[:len(c.pattern)-extra], "/")
case nodeParam:
key := (*c.paramsKeys)[len(*c.paramsKeys)-1]
p = strings.TrimSuffix(c.pattern[:len(c.pattern)-(len(key)+paramExtraChar)], "/")
extra := len(key) + paramExtraChar
if lastTk.regexp != nil {
extra += 1 + len(rawExpr(lastTk.regexp))
}
p = strings.TrimSuffix(c.pattern[:len(c.pattern)-extra], "/")
default:
// Reaching this case means the parent route does not end with a catch-all parameter (e.g., /api/
// instead of /api/+{rest}). This is technically a misuse of the sub-router API, but we handle it
Expand Down Expand Up @@ -1124,3 +1134,8 @@ func firstHeader(headers http.Header, k string) (string, bool) {
}
return v[0], true
}

func rawExpr(re *regexp.Regexp) string {
expr := re.String()
return expr[4 : len(expr)-2]
}
28 changes: 28 additions & 0 deletions fox_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1478,6 +1478,34 @@ func TestRouter_ServeHTTP_HandleSubRouter(t *testing.T) {
assert.Equal(t, http.StatusNotFound, w.Code)
})

t.Run("sub-router registered with regex wildcard", func(t *testing.T) {
sub := MustRouter()
sub.MustAdd(MethodGet, "/users", patternHandler)

fx := MustRouter(AllowRegexpParam(true))
require.NoError(t, onlyError(fx.Add(MethodGet, "/api/+{rest:[a-z]+}", Sub(sub))))

req := httptest.NewRequest(http.MethodGet, "/api/users", nil)
w := httptest.NewRecorder()
fx.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "/api/users", w.Body.String())
})

t.Run("sub-router registered with regex param", func(t *testing.T) {
sub := MustRouter()
sub.MustAdd(MethodGet, "/users", patternHandler)

fx := MustRouter(AllowRegexpParam(true))
require.NoError(t, onlyError(fx.Add(MethodGet, "/api/{name:[a-z]+}", Sub(sub))))

req := httptest.NewRequest(http.MethodGet, "/api/users", nil)
w := httptest.NewRecorder()
fx.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "/api/users", w.Body.String())
})

t.Run("sub-router no route handler sees clean context", func(t *testing.T) {
var pat, tenant string
var route *Route
Expand Down
6 changes: 2 additions & 4 deletions matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,7 @@ func (m QueryRegexpMatcher) Key() string {

// Value returns the regular expression matching the query parameter.
func (m QueryRegexpMatcher) Value() string {
expr := m.regex.String()
return expr[4 : len(expr)-2]
return rawExpr(m.regex)
}

// String returns a textual representation of the matcher in the form "qx:key=expr".
Expand Down Expand Up @@ -224,8 +223,7 @@ func (m HeaderRegexpMatcher) Key() string {

// Value returns the regular expression matching the header.
func (m HeaderRegexpMatcher) Value() string {
expr := m.regex.String()
return expr[4 : len(expr)-2]
return rawExpr(m.regex)
}

// Match reports whether the request contains the configured header with any value matching the configured regular
Expand Down
4 changes: 1 addition & 3 deletions tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -953,9 +953,7 @@ func concat(a, b string) string {
// placeholder ("?" for params, "*" for catch-alls).
func canonicalKey(tk token) string {
if tk.regexp != nil {
// Strip the surrounding ^(?: and )$ added by compileParamRegexp.
expr := tk.regexp.String()
return expr[4 : len(expr)-2]
return rawExpr(tk.regexp)
}
switch tk.typ {
case nodeParam:
Expand Down
Loading