Browse Source

fix use of capturing subexpressions in pattern matches.

The router now associates a regexp named group with each mux variable.
It only fills variables when capturing group name match instead of
relying on indices, which doesn't work if a variable regexp has interior
capturing groups.

Fixes #62
pull/117/head
Kamil Kisiel 11 years ago
parent
commit
e73f183699
  1. 27
      mux_test.go
  2. 29
      regexp.go

27
mux_test.go

@ -108,6 +108,15 @@ func TestHost(t *testing.T) {
path: "", path: "",
shouldMatch: true, shouldMatch: true,
}, },
{
title: "Host route with pattern, additional capturing group, match",
route: new(Route).Host("aaa.{v1:[a-z]{2}(b|c)}.ccc"),
request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
vars: map[string]string{"v1": "bbb"},
host: "aaa.bbb.ccc",
path: "",
shouldMatch: true,
},
{ {
title: "Host route with pattern, wrong host in request URL", title: "Host route with pattern, wrong host in request URL",
route: new(Route).Host("aaa.{v1:[a-z]{3}}.ccc"), route: new(Route).Host("aaa.{v1:[a-z]{3}}.ccc"),
@ -260,6 +269,15 @@ func TestPath(t *testing.T) {
path: "/111/222/333", path: "/111/222/333",
shouldMatch: false, shouldMatch: false,
}, },
{
title: "Path route with multiple patterns with pipe, match",
route: new(Route).Path("/{category:a|(b/c)}/{product}/{id:[0-9]+}"),
request: newRequest("GET", "http://localhost/a/product_name/1"),
vars: map[string]string{"category": "a", "product": "product_name", "id": "1"},
host: "",
path: "/a/product_name/1",
shouldMatch: true,
},
} }
for _, test := range tests { for _, test := range tests {
@ -597,6 +615,15 @@ func TestQueries(t *testing.T) {
path: "", path: "",
shouldMatch: false, shouldMatch: false,
}, },
{
title: "Queries route with regexp pattern with quantifier, additional capturing group",
route: new(Route).Queries("foo", "{v1:[0-9]{1}(a|b)}"),
request: newRequest("GET", "http://localhost?foo=1a"),
vars: map[string]string{"v1": "1a"},
host: "",
path: "",
shouldMatch: true,
},
{ {
title: "Queries route with regexp pattern with quantifier, additional variable in query string, regexp does not match", title: "Queries route with regexp pattern with quantifier, additional variable in query string, regexp does not match",
route: new(Route).Queries("foo", "{v1:[0-9]{1}}"), route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),

29
regexp.go

@ -72,7 +72,7 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
tpl[idxs[i]:end]) tpl[idxs[i]:end])
} }
// Build the regexp pattern. // Build the regexp pattern.
fmt.Fprintf(pattern, "%s(%s)", regexp.QuoteMeta(raw), patt) fmt.Fprintf(pattern, "%s(?P<%s>%s)", regexp.QuoteMeta(raw), name, patt)
// Build the reverse template. // Build the reverse template.
fmt.Fprintf(reverse, "%s%%s", raw) fmt.Fprintf(reverse, "%s%%s", raw)
@ -241,8 +241,13 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
if v.host != nil { if v.host != nil {
hostVars := v.host.regexp.FindStringSubmatch(getHost(req)) hostVars := v.host.regexp.FindStringSubmatch(getHost(req))
if hostVars != nil { if hostVars != nil {
for k, v := range v.host.varsN { subexpNames := v.host.regexp.SubexpNames()
m.Vars[v] = hostVars[k+1] varName := 0
for i, name := range subexpNames[1:] {
if name != "" && v.host.varsN[varName] == name {
m.Vars[name] = hostVars[i+1]
varName++
}
} }
} }
} }
@ -250,8 +255,13 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
if v.path != nil { if v.path != nil {
pathVars := v.path.regexp.FindStringSubmatch(req.URL.Path) pathVars := v.path.regexp.FindStringSubmatch(req.URL.Path)
if pathVars != nil { if pathVars != nil {
for k, v := range v.path.varsN { subexpNames := v.path.regexp.SubexpNames()
m.Vars[v] = pathVars[k+1] varName := 0
for i, name := range subexpNames[1:] {
if name != "" && v.path.varsN[varName] == name {
m.Vars[name] = pathVars[i+1]
varName++
}
} }
// Check if we should redirect. // Check if we should redirect.
if v.path.strictSlash { if v.path.strictSlash {
@ -273,8 +283,13 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
for _, q := range v.queries { for _, q := range v.queries {
queryVars := q.regexp.FindStringSubmatch(q.getUrlQuery(req)) queryVars := q.regexp.FindStringSubmatch(q.getUrlQuery(req))
if queryVars != nil { if queryVars != nil {
for k, v := range q.varsN { subexpNames := q.regexp.SubexpNames()
m.Vars[v] = queryVars[k+1] varName := 0
for i, name := range subexpNames[1:] {
if name != "" && q.varsN[varName] == name {
m.Vars[name] = queryVars[i+1]
varName++
}
} }
} }
} }

Loading…
Cancel
Save