From e73f183699f8ab7d54609771e1fa0ab7ffddc21b Mon Sep 17 00:00:00 2001 From: Kamil Kisiel Date: Thu, 6 Aug 2015 20:31:19 -0700 Subject: [PATCH] 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 --- mux_test.go | 27 +++++++++++++++++++++++++++ regexp.go | 29 ++++++++++++++++++++++------- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/mux_test.go b/mux_test.go index ba47727..455d68e 100644 --- a/mux_test.go +++ b/mux_test.go @@ -108,6 +108,15 @@ func TestHost(t *testing.T) { path: "", 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", route: new(Route).Host("aaa.{v1:[a-z]{3}}.ccc"), @@ -260,6 +269,15 @@ func TestPath(t *testing.T) { path: "/111/222/333", 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 { @@ -597,6 +615,15 @@ func TestQueries(t *testing.T) { path: "", 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", route: new(Route).Queries("foo", "{v1:[0-9]{1}}"), diff --git a/regexp.go b/regexp.go index 7c636d0..6b34fec 100644 --- a/regexp.go +++ b/regexp.go @@ -72,7 +72,7 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash tpl[idxs[i]:end]) } // 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. 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 { hostVars := v.host.regexp.FindStringSubmatch(getHost(req)) if hostVars != nil { - for k, v := range v.host.varsN { - m.Vars[v] = hostVars[k+1] + subexpNames := v.host.regexp.SubexpNames() + 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 { pathVars := v.path.regexp.FindStringSubmatch(req.URL.Path) if pathVars != nil { - for k, v := range v.path.varsN { - m.Vars[v] = pathVars[k+1] + subexpNames := v.path.regexp.SubexpNames() + 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. if v.path.strictSlash { @@ -273,8 +283,13 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) for _, q := range v.queries { queryVars := q.regexp.FindStringSubmatch(q.getUrlQuery(req)) if queryVars != nil { - for k, v := range q.varsN { - m.Vars[v] = queryVars[k+1] + subexpNames := q.regexp.SubexpNames() + varName := 0 + for i, name := range subexpNames[1:] { + if name != "" && q.varsN[varName] == name { + m.Vars[name] = queryVars[i+1] + varName++ + } } } }