Browse Source

Fix "Queries" matcher to support out-of-order query string parameters

pull/56/head
Raphael Simon 12 years ago
parent
commit
69237eaae5
  1. 9
      mux_test.go
  2. 27
      regexp.go
  3. 41
      route.go

9
mux_test.go

@ -462,6 +462,15 @@ func TestQueries(t *testing.T) {
path: "", path: "",
shouldMatch: true, shouldMatch: true,
}, },
{
title: "Queries route, match with a query string out of order",
route: new(Route).Host("www.example.com").Path("/api").Queries("foo", "bar", "baz", "ding"),
request: newRequest("GET", "http://www.example.com/api?baz=ding&foo=bar"),
vars: map[string]string{},
host: "",
path: "",
shouldMatch: true,
},
{ {
title: "Queries route, bad query", title: "Queries route, bad query",
route: new(Route).Queries("foo", "bar", "baz", "ding"), route: new(Route).Queries("foo", "bar", "baz", "ding"),

27
regexp.go

@ -34,7 +34,7 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
// Now let's parse it. // Now let's parse it.
defaultPattern := "[^/]+" defaultPattern := "[^/]+"
if matchQuery { if matchQuery {
defaultPattern = "[^?]+" defaultPattern = "[^?&]+"
matchPrefix, strictSlash = true, false matchPrefix, strictSlash = true, false
} else if matchHost { } else if matchHost {
defaultPattern = "[^.]+" defaultPattern = "[^.]+"
@ -51,9 +51,9 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
} }
varsN := make([]string, len(idxs)/2) varsN := make([]string, len(idxs)/2)
varsR := make([]*regexp.Regexp, len(idxs)/2) varsR := make([]*regexp.Regexp, len(idxs)/2)
pattern := bytes.NewBufferString("^") pattern := bytes.NewBufferString("")
if matchQuery { if !matchQuery {
pattern = bytes.NewBufferString("") pattern.WriteByte('^')
} }
reverse := bytes.NewBufferString("") reverse := bytes.NewBufferString("")
var end int var end int
@ -209,9 +209,9 @@ func braceIndices(s string) ([]int, error) {
// routeRegexpGroup groups the route matchers that carry variables. // routeRegexpGroup groups the route matchers that carry variables.
type routeRegexpGroup struct { type routeRegexpGroup struct {
host *routeRegexp host *routeRegexp
path *routeRegexp path *routeRegexp
query *routeRegexp queries []*routeRegexp
} }
// setMatch extracts the variables from the URL once a route matches. // setMatch extracts the variables from the URL once a route matches.
@ -249,11 +249,14 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
} }
} }
// Store query string variables. // Store query string variables.
if v.query != nil { if v.queries != nil && len(v.queries) > 0 {
queryVars := v.query.regexp.FindStringSubmatch(req.URL.RawQuery) rawQuery := req.URL.RawQuery
if queryVars != nil { for _, q := range v.queries {
for k, v := range v.query.varsN { queryVars := q.regexp.FindStringSubmatch(rawQuery)
m.Vars[v] = queryVars[k+1] if queryVars != nil {
for k, v := range q.varsN {
m.Vars[v] = queryVars[k+1]
}
} }
} }
} }

41
route.go

@ -5,7 +5,6 @@
package mux package mux
import ( import (
"bytes"
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
@ -153,14 +152,16 @@ func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery
if err != nil { if err != nil {
return err return err
} }
if matchHost { if r.regexp.queries != nil {
if r.regexp.path != nil { for _, q := range r.regexp.queries {
if err = uniqueVars(rr.varsN, r.regexp.path.varsN); err != nil { if err = uniqueVars(rr.varsN, q.varsN); err != nil {
return err return err
} }
} }
if r.regexp.query != nil { }
if err = uniqueVars(rr.varsN, r.regexp.query.varsN); err != nil { if matchHost {
if r.regexp.path != nil {
if err = uniqueVars(rr.varsN, r.regexp.path.varsN); err != nil {
return err return err
} }
} }
@ -172,18 +173,13 @@ func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery
} }
} }
if matchQuery { if matchQuery {
if r.regexp.path != nil { if r.regexp.queries == nil {
if err = uniqueVars(rr.varsN, r.regexp.path.varsN); err != nil { r.regexp.queries = make([]*routeRegexp, 1)
return err r.regexp.queries[0] = rr
} } else {
r.regexp.queries = append(r.regexp.queries, rr)
} }
r.regexp.query = rr
} else { } else {
if r.regexp.query != nil {
if err = uniqueVars(rr.varsN, r.regexp.query.varsN); err != nil {
return err
}
}
r.regexp.path = rr r.regexp.path = rr
} }
} }
@ -345,12 +341,11 @@ func (r *Route) Queries(pairs ...string) *Route {
"mux: number of parameters must be multiple of 2, got %v", pairs) "mux: number of parameters must be multiple of 2, got %v", pairs)
return nil return nil
} }
var buf bytes.Buffer
for i := 0; i < length; i += 2 { for i := 0; i < length; i += 2 {
buf.WriteString(fmt.Sprintf("%s=%s&", pairs[i], pairs[i+1])) if r.err = r.addRegexpMatcher(fmt.Sprintf("%s=%s", pairs[i], pairs[i+1]), false, true, true); r.err != nil {
return r
}
} }
tpl := strings.TrimRight(buf.String(), "&")
r.err = r.addRegexpMatcher(tpl, false, true, true)
return r return r
} }
@ -527,9 +522,9 @@ func (r *Route) getRegexpGroup() *routeRegexpGroup {
} else { } else {
// Copy. // Copy.
r.regexp = &routeRegexpGroup{ r.regexp = &routeRegexpGroup{
host: regexp.host, host: regexp.host,
path: regexp.path, path: regexp.path,
query: regexp.query, queries: regexp.queries,
} }
} }
} }

Loading…
Cancel
Save