summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/gorilla/mux
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/gorilla/mux')
-rw-r--r--vendor/github.com/gorilla/mux/.travis.yml6
-rw-r--r--vendor/github.com/gorilla/mux/README.md36
-rw-r--r--vendor/github.com/gorilla/mux/mux.go51
-rw-r--r--vendor/github.com/gorilla/mux/mux_test.go723
-rw-r--r--vendor/github.com/gorilla/mux/regexp.go6
-rw-r--r--vendor/github.com/gorilla/mux/route.go44
6 files changed, 529 insertions, 337 deletions
diff --git a/vendor/github.com/gorilla/mux/.travis.yml b/vendor/github.com/gorilla/mux/.travis.yml
index ca377e61c..3302233f3 100644
--- a/vendor/github.com/gorilla/mux/.travis.yml
+++ b/vendor/github.com/gorilla/mux/.travis.yml
@@ -3,13 +3,13 @@ sudo: false
matrix:
include:
- - go: 1.2
- - go: 1.3
- - go: 1.4
- go: 1.5
- go: 1.6
- go: 1.7
- go: 1.8
+ - go: 1.9
+ - go: tip
+ allow_failures:
- go: tip
install:
diff --git a/vendor/github.com/gorilla/mux/README.md b/vendor/github.com/gorilla/mux/README.md
index 8dcd71887..67a79e00a 100644
--- a/vendor/github.com/gorilla/mux/README.md
+++ b/vendor/github.com/gorilla/mux/README.md
@@ -135,6 +135,14 @@ r.HandleFunc("/products", ProductsHandler).
Schemes("http")
```
+Routes are tested in the order they were added to the router. If two routes match, the first one wins:
+
+```go
+r := mux.NewRouter()
+r.HandleFunc("/specific", specificHandler)
+r.PathPrefix("/").Handler(catchAllHandler)
+```
+
Setting the same matching conditions again and again can be boring, so we have a way to group several routes that share the same requirements. We call it "subrouting".
For example, let's say we have several URLs that should only match when the host is `www.example.com`. Create a route for that host and get a "subrouter" from it:
@@ -193,22 +201,34 @@ func main() {
r.HandleFunc("/products", handler).Methods("POST")
r.HandleFunc("/articles", handler).Methods("GET")
r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
+ r.HandleFunc("/authors", handler).Queries("surname", "{surname}")
r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
t, err := route.GetPathTemplate()
if err != nil {
return err
}
+ qt, err := route.GetQueriesTemplates()
+ if err != nil {
+ return err
+ }
// p will contain regular expression is compatible with regular expression in Perl, Python, and other languages.
// for instance the regular expression for path '/articles/{id}' will be '^/articles/(?P<v0>[^/]+)$'
p, err := route.GetPathRegexp()
if err != nil {
return err
}
+ // qr will contain a list of regular expressions with the same semantics as GetPathRegexp,
+ // just applied to the Queries pairs instead, e.g., 'Queries("surname", "{surname}") will return
+ // {"^surname=(?P<v0>.*)$}. Where each combined query pair will have an entry in the list.
+ qr, err := route.GetQueriesRegexp()
+ if err != nil {
+ return err
+ }
m, err := route.GetMethods()
if err != nil {
return err
}
- fmt.Println(strings.Join(m, ","), t, p)
+ fmt.Println(strings.Join(m, ","), strings.Join(qt, ","), strings.Join(qr, ","), t, p)
return nil
})
http.Handle("/", r)
@@ -331,22 +351,34 @@ r.HandleFunc("/", handler)
r.HandleFunc("/products", handler).Methods("POST")
r.HandleFunc("/articles", handler).Methods("GET")
r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
+r.HandleFunc("/authors", handler).Queries("surname", "{surname}")
r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
t, err := route.GetPathTemplate()
if err != nil {
return err
}
+ qt, err := route.GetQueriesTemplates()
+ if err != nil {
+ return err
+ }
// p will contain a regular expression that is compatible with regular expressions in Perl, Python, and other languages.
// For example, the regular expression for path '/articles/{id}' will be '^/articles/(?P<v0>[^/]+)$'.
p, err := route.GetPathRegexp()
if err != nil {
return err
}
+ // qr will contain a list of regular expressions with the same semantics as GetPathRegexp,
+ // just applied to the Queries pairs instead, e.g., 'Queries("surname", "{surname}") will return
+ // {"^surname=(?P<v0>.*)$}. Where each combined query pair will have an entry in the list.
+ qr, err := route.GetQueriesRegexp()
+ if err != nil {
+ return err
+ }
m, err := route.GetMethods()
if err != nil {
return err
}
- fmt.Println(strings.Join(m, ","), t, p)
+ fmt.Println(strings.Join(m, ","), strings.Join(qt, ","), strings.Join(qr, ","), t, p)
return nil
})
```
diff --git a/vendor/github.com/gorilla/mux/mux.go b/vendor/github.com/gorilla/mux/mux.go
index fb69196db..49de78923 100644
--- a/vendor/github.com/gorilla/mux/mux.go
+++ b/vendor/github.com/gorilla/mux/mux.go
@@ -10,11 +10,11 @@ import (
"net/http"
"path"
"regexp"
- "strings"
)
var (
ErrMethodMismatch = errors.New("method is not allowed")
+ ErrNotFound = errors.New("no matching route was found")
)
// NewRouter returns a new router instance.
@@ -65,7 +65,17 @@ type Router struct {
useEncodedPath bool
}
-// Match matches registered routes against the request.
+// Match attempts to match the given request against the router's registered routes.
+//
+// If the request matches a route of this router or one of its subrouters the Route,
+// Handler, and Vars fields of the the match argument are filled and this function
+// returns true.
+//
+// If the request does not match any of this router's or its subrouters' routes
+// then this function returns false. If available, a reason for the match failure
+// will be filled in the match argument's MatchErr field. If the match failure type
+// (eg: not found) has a registered handler, the handler is assigned to the Handler
+// field of the match argument.
func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
for _, route := range r.routes {
if route.Match(req, match) {
@@ -73,16 +83,23 @@ func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
}
}
- if match.MatchErr == ErrMethodMismatch && r.MethodNotAllowedHandler != nil {
- match.Handler = r.MethodNotAllowedHandler
- return true
+ if match.MatchErr == ErrMethodMismatch {
+ if r.MethodNotAllowedHandler != nil {
+ match.Handler = r.MethodNotAllowedHandler
+ return true
+ } else {
+ return false
+ }
}
// Closest match for a router (includes sub-routers)
if r.NotFoundHandler != nil {
match.Handler = r.NotFoundHandler
+ match.MatchErr = ErrNotFound
return true
}
+
+ match.MatchErr = ErrNotFound
return false
}
@@ -94,7 +111,7 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if !r.skipClean {
path := req.URL.Path
if r.useEncodedPath {
- path = getPath(req)
+ path = req.URL.EscapedPath()
}
// Clean path to canonical form and redirect.
if p := cleanPath(path); p != path {
@@ -409,28 +426,6 @@ func setCurrentRoute(r *http.Request, val interface{}) *http.Request {
// Helpers
// ----------------------------------------------------------------------------
-// getPath returns the escaped path if possible; doing what URL.EscapedPath()
-// which was added in go1.5 does
-func getPath(req *http.Request) string {
- if req.RequestURI != "" {
- // Extract the path from RequestURI (which is escaped unlike URL.Path)
- // as detailed here as detailed in https://golang.org/pkg/net/url/#URL
- // for < 1.5 server side workaround
- // http://localhost/path/here?v=1 -> /path/here
- path := req.RequestURI
- path = strings.TrimPrefix(path, req.URL.Scheme+`://`)
- path = strings.TrimPrefix(path, req.URL.Host)
- if i := strings.LastIndex(path, "?"); i > -1 {
- path = path[:i]
- }
- if i := strings.LastIndex(path, "#"); i > -1 {
- path = path[:i]
- }
- return path
- }
- return req.URL.Path
-}
-
// cleanPath returns the canonical path for p, eliminating . and .. elements.
// Borrowed from the net/http package.
func cleanPath(p string) string {
diff --git a/vendor/github.com/gorilla/mux/mux_test.go b/vendor/github.com/gorilla/mux/mux_test.go
index 484fab431..6c7e30d19 100644
--- a/vendor/github.com/gorilla/mux/mux_test.go
+++ b/vendor/github.com/gorilla/mux/mux_test.go
@@ -29,20 +29,22 @@ func (r *routeRegexp) GoString() string {
}
type routeTest struct {
- title string // title of the test
- route *Route // the route being tested
- request *http.Request // a request to test the route
- vars map[string]string // the expected vars of the match
- scheme string // the expected scheme of the built URL
- host string // the expected host of the built URL
- path string // the expected path of the built URL
- query string // the expected query string of the built URL
- pathTemplate string // the expected path template of the route
- hostTemplate string // the expected host template of the route
- methods []string // the expected route methods
- pathRegexp string // the expected path regexp
- shouldMatch bool // whether the request is expected to match the route at all
- shouldRedirect bool // whether the request should result in a redirect
+ title string // title of the test
+ route *Route // the route being tested
+ request *http.Request // a request to test the route
+ vars map[string]string // the expected vars of the match
+ scheme string // the expected scheme of the built URL
+ host string // the expected host of the built URL
+ path string // the expected path of the built URL
+ query string // the expected query string of the built URL
+ pathTemplate string // the expected path template of the route
+ hostTemplate string // the expected host template of the route
+ queriesTemplate string // the expected query template of the route
+ methods []string // the expected route methods
+ pathRegexp string // the expected path regexp
+ queriesRegexp string // the expected query regexp
+ shouldMatch bool // whether the request is expected to match the route at all
+ shouldRedirect bool // whether the request should result in a redirect
}
func TestHost(t *testing.T) {
@@ -739,257 +741,309 @@ func TestMethods(t *testing.T) {
func TestQueries(t *testing.T) {
tests := []routeTest{
{
- title: "Queries route, match",
- route: new(Route).Queries("foo", "bar", "baz", "ding"),
- request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
- vars: map[string]string{},
- host: "",
- path: "",
- query: "foo=bar&baz=ding",
- shouldMatch: true,
- },
- {
- title: "Queries route, match with a query string",
- route: new(Route).Host("www.example.com").Path("/api").Queries("foo", "bar", "baz", "ding"),
- request: newRequest("GET", "http://www.example.com/api?foo=bar&baz=ding"),
- vars: map[string]string{},
- host: "",
- path: "",
- query: "foo=bar&baz=ding",
- pathTemplate: `/api`,
- hostTemplate: `www.example.com`,
- 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: "",
- query: "foo=bar&baz=ding",
- pathTemplate: `/api`,
- hostTemplate: `www.example.com`,
- shouldMatch: true,
- },
- {
- title: "Queries route, bad query",
- route: new(Route).Queries("foo", "bar", "baz", "ding"),
- request: newRequest("GET", "http://localhost?foo=bar&baz=dong"),
- vars: map[string]string{},
- host: "",
- path: "",
- shouldMatch: false,
- },
- {
- title: "Queries route with pattern, match",
- route: new(Route).Queries("foo", "{v1}"),
- request: newRequest("GET", "http://localhost?foo=bar"),
- vars: map[string]string{"v1": "bar"},
- host: "",
- path: "",
- query: "foo=bar",
- shouldMatch: true,
- },
- {
- title: "Queries route with multiple patterns, match",
- route: new(Route).Queries("foo", "{v1}", "baz", "{v2}"),
- request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
- vars: map[string]string{"v1": "bar", "v2": "ding"},
- host: "",
- path: "",
- query: "foo=bar&baz=ding",
- shouldMatch: true,
- },
- {
- title: "Queries route with regexp pattern, match",
- route: new(Route).Queries("foo", "{v1:[0-9]+}"),
- request: newRequest("GET", "http://localhost?foo=10"),
- vars: map[string]string{"v1": "10"},
- host: "",
- path: "",
- query: "foo=10",
- shouldMatch: true,
- },
- {
- title: "Queries route with regexp pattern, regexp does not match",
- route: new(Route).Queries("foo", "{v1:[0-9]+}"),
- request: newRequest("GET", "http://localhost?foo=a"),
- vars: map[string]string{},
- host: "",
- path: "",
- shouldMatch: false,
- },
- {
- title: "Queries route with regexp pattern with quantifier, match",
- route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
- request: newRequest("GET", "http://localhost?foo=1"),
- vars: map[string]string{"v1": "1"},
- host: "",
- path: "",
- query: "foo=1",
- shouldMatch: true,
- },
- {
- title: "Queries route with regexp pattern with quantifier, additional variable in query string, match",
- route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
- request: newRequest("GET", "http://localhost?bar=2&foo=1"),
- vars: map[string]string{"v1": "1"},
- host: "",
- path: "",
- query: "foo=1",
- shouldMatch: true,
- },
- {
- title: "Queries route with regexp pattern with quantifier, regexp does not match",
- route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
- request: newRequest("GET", "http://localhost?foo=12"),
- vars: map[string]string{},
- host: "",
- 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: "",
- query: "foo=1a",
- 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}}"),
- request: newRequest("GET", "http://localhost?foo=12"),
- vars: map[string]string{},
- host: "",
- path: "",
- shouldMatch: false,
- },
- {
- title: "Queries route with hyphenated name, match",
- route: new(Route).Queries("foo", "{v-1}"),
- request: newRequest("GET", "http://localhost?foo=bar"),
- vars: map[string]string{"v-1": "bar"},
- host: "",
- path: "",
- query: "foo=bar",
- shouldMatch: true,
- },
- {
- title: "Queries route with multiple hyphenated names, match",
- route: new(Route).Queries("foo", "{v-1}", "baz", "{v-2}"),
- request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
- vars: map[string]string{"v-1": "bar", "v-2": "ding"},
- host: "",
- path: "",
- query: "foo=bar&baz=ding",
- shouldMatch: true,
- },
- {
- title: "Queries route with hyphenate name and pattern, match",
- route: new(Route).Queries("foo", "{v-1:[0-9]+}"),
- request: newRequest("GET", "http://localhost?foo=10"),
- vars: map[string]string{"v-1": "10"},
- host: "",
- path: "",
- query: "foo=10",
- shouldMatch: true,
- },
- {
- title: "Queries route with hyphenated name and pattern with quantifier, additional capturing group",
- route: new(Route).Queries("foo", "{v-1:[0-9]{1}(?:a|b)}"),
- request: newRequest("GET", "http://localhost?foo=1a"),
- vars: map[string]string{"v-1": "1a"},
- host: "",
- path: "",
- query: "foo=1a",
- shouldMatch: true,
- },
- {
- title: "Queries route with empty value, should match",
- route: new(Route).Queries("foo", ""),
- request: newRequest("GET", "http://localhost?foo=bar"),
- vars: map[string]string{},
- host: "",
- path: "",
- query: "foo=",
- shouldMatch: true,
- },
- {
- title: "Queries route with empty value and no parameter in request, should not match",
- route: new(Route).Queries("foo", ""),
- request: newRequest("GET", "http://localhost"),
- vars: map[string]string{},
- host: "",
- path: "",
- shouldMatch: false,
- },
- {
- title: "Queries route with empty value and empty parameter in request, should match",
- route: new(Route).Queries("foo", ""),
- request: newRequest("GET", "http://localhost?foo="),
- vars: map[string]string{},
- host: "",
- path: "",
- query: "foo=",
- shouldMatch: true,
- },
- {
- title: "Queries route with overlapping value, should not match",
- route: new(Route).Queries("foo", "bar"),
- request: newRequest("GET", "http://localhost?foo=barfoo"),
- vars: map[string]string{},
- host: "",
- path: "",
- shouldMatch: false,
- },
- {
- title: "Queries route with no parameter in request, should not match",
- route: new(Route).Queries("foo", "{bar}"),
- request: newRequest("GET", "http://localhost"),
- vars: map[string]string{},
- host: "",
- path: "",
- shouldMatch: false,
- },
- {
- title: "Queries route with empty parameter in request, should match",
- route: new(Route).Queries("foo", "{bar}"),
- request: newRequest("GET", "http://localhost?foo="),
- vars: map[string]string{"foo": ""},
- host: "",
- path: "",
- query: "foo=",
- shouldMatch: true,
- },
- {
- title: "Queries route, bad submatch",
- route: new(Route).Queries("foo", "bar", "baz", "ding"),
- request: newRequest("GET", "http://localhost?fffoo=bar&baz=dingggg"),
- vars: map[string]string{},
- host: "",
- path: "",
- shouldMatch: false,
- },
- {
- title: "Queries route with pattern, match, escaped value",
- route: new(Route).Queries("foo", "{v1}"),
- request: newRequest("GET", "http://localhost?foo=%25bar%26%20%2F%3D%3F"),
- vars: map[string]string{"v1": "%bar& /=?"},
- host: "",
- path: "",
- query: "foo=%25bar%26+%2F%3D%3F",
- shouldMatch: true,
+ title: "Queries route, match",
+ route: new(Route).Queries("foo", "bar", "baz", "ding"),
+ request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ query: "foo=bar&baz=ding",
+ queriesTemplate: "foo=bar,baz=ding",
+ queriesRegexp: "^foo=bar$,^baz=ding$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route, match with a query string",
+ route: new(Route).Host("www.example.com").Path("/api").Queries("foo", "bar", "baz", "ding"),
+ request: newRequest("GET", "http://www.example.com/api?foo=bar&baz=ding"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ query: "foo=bar&baz=ding",
+ pathTemplate: `/api`,
+ hostTemplate: `www.example.com`,
+ queriesTemplate: "foo=bar,baz=ding",
+ queriesRegexp: "^foo=bar$,^baz=ding$",
+ 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: "",
+ query: "foo=bar&baz=ding",
+ pathTemplate: `/api`,
+ hostTemplate: `www.example.com`,
+ queriesTemplate: "foo=bar,baz=ding",
+ queriesRegexp: "^foo=bar$,^baz=ding$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route, bad query",
+ route: new(Route).Queries("foo", "bar", "baz", "ding"),
+ request: newRequest("GET", "http://localhost?foo=bar&baz=dong"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ queriesTemplate: "foo=bar,baz=ding",
+ queriesRegexp: "^foo=bar$,^baz=ding$",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with pattern, match",
+ route: new(Route).Queries("foo", "{v1}"),
+ request: newRequest("GET", "http://localhost?foo=bar"),
+ vars: map[string]string{"v1": "bar"},
+ host: "",
+ path: "",
+ query: "foo=bar",
+ queriesTemplate: "foo={v1}",
+ queriesRegexp: "^foo=(?P<v0>.*)$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with multiple patterns, match",
+ route: new(Route).Queries("foo", "{v1}", "baz", "{v2}"),
+ request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
+ vars: map[string]string{"v1": "bar", "v2": "ding"},
+ host: "",
+ path: "",
+ query: "foo=bar&baz=ding",
+ queriesTemplate: "foo={v1},baz={v2}",
+ queriesRegexp: "^foo=(?P<v0>.*)$,^baz=(?P<v0>.*)$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with regexp pattern, match",
+ route: new(Route).Queries("foo", "{v1:[0-9]+}"),
+ request: newRequest("GET", "http://localhost?foo=10"),
+ vars: map[string]string{"v1": "10"},
+ host: "",
+ path: "",
+ query: "foo=10",
+ queriesTemplate: "foo={v1:[0-9]+}",
+ queriesRegexp: "^foo=(?P<v0>[0-9]+)$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with regexp pattern, regexp does not match",
+ route: new(Route).Queries("foo", "{v1:[0-9]+}"),
+ request: newRequest("GET", "http://localhost?foo=a"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ queriesTemplate: "foo={v1:[0-9]+}",
+ queriesRegexp: "^foo=(?P<v0>[0-9]+)$",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with regexp pattern with quantifier, match",
+ route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
+ request: newRequest("GET", "http://localhost?foo=1"),
+ vars: map[string]string{"v1": "1"},
+ host: "",
+ path: "",
+ query: "foo=1",
+ queriesTemplate: "foo={v1:[0-9]{1}}",
+ queriesRegexp: "^foo=(?P<v0>[0-9]{1})$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with regexp pattern with quantifier, additional variable in query string, match",
+ route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
+ request: newRequest("GET", "http://localhost?bar=2&foo=1"),
+ vars: map[string]string{"v1": "1"},
+ host: "",
+ path: "",
+ query: "foo=1",
+ queriesTemplate: "foo={v1:[0-9]{1}}",
+ queriesRegexp: "^foo=(?P<v0>[0-9]{1})$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with regexp pattern with quantifier, regexp does not match",
+ route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
+ request: newRequest("GET", "http://localhost?foo=12"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ queriesTemplate: "foo={v1:[0-9]{1}}",
+ queriesRegexp: "^foo=(?P<v0>[0-9]{1})$",
+ 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: "",
+ query: "foo=1a",
+ queriesTemplate: "foo={v1:[0-9]{1}(?:a|b)}",
+ queriesRegexp: "^foo=(?P<v0>[0-9]{1}(?:a|b))$",
+ 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}}"),
+ request: newRequest("GET", "http://localhost?foo=12"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ queriesTemplate: "foo={v1:[0-9]{1}}",
+ queriesRegexp: "^foo=(?P<v0>[0-9]{1})$",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with hyphenated name, match",
+ route: new(Route).Queries("foo", "{v-1}"),
+ request: newRequest("GET", "http://localhost?foo=bar"),
+ vars: map[string]string{"v-1": "bar"},
+ host: "",
+ path: "",
+ query: "foo=bar",
+ queriesTemplate: "foo={v-1}",
+ queriesRegexp: "^foo=(?P<v0>.*)$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with multiple hyphenated names, match",
+ route: new(Route).Queries("foo", "{v-1}", "baz", "{v-2}"),
+ request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
+ vars: map[string]string{"v-1": "bar", "v-2": "ding"},
+ host: "",
+ path: "",
+ query: "foo=bar&baz=ding",
+ queriesTemplate: "foo={v-1},baz={v-2}",
+ queriesRegexp: "^foo=(?P<v0>.*)$,^baz=(?P<v0>.*)$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with hyphenate name and pattern, match",
+ route: new(Route).Queries("foo", "{v-1:[0-9]+}"),
+ request: newRequest("GET", "http://localhost?foo=10"),
+ vars: map[string]string{"v-1": "10"},
+ host: "",
+ path: "",
+ query: "foo=10",
+ queriesTemplate: "foo={v-1:[0-9]+}",
+ queriesRegexp: "^foo=(?P<v0>[0-9]+)$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with hyphenated name and pattern with quantifier, additional capturing group",
+ route: new(Route).Queries("foo", "{v-1:[0-9]{1}(?:a|b)}"),
+ request: newRequest("GET", "http://localhost?foo=1a"),
+ vars: map[string]string{"v-1": "1a"},
+ host: "",
+ path: "",
+ query: "foo=1a",
+ queriesTemplate: "foo={v-1:[0-9]{1}(?:a|b)}",
+ queriesRegexp: "^foo=(?P<v0>[0-9]{1}(?:a|b))$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with empty value, should match",
+ route: new(Route).Queries("foo", ""),
+ request: newRequest("GET", "http://localhost?foo=bar"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ query: "foo=",
+ queriesTemplate: "foo=",
+ queriesRegexp: "^foo=.*$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with empty value and no parameter in request, should not match",
+ route: new(Route).Queries("foo", ""),
+ request: newRequest("GET", "http://localhost"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ queriesTemplate: "foo=",
+ queriesRegexp: "^foo=.*$",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with empty value and empty parameter in request, should match",
+ route: new(Route).Queries("foo", ""),
+ request: newRequest("GET", "http://localhost?foo="),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ query: "foo=",
+ queriesTemplate: "foo=",
+ queriesRegexp: "^foo=.*$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with overlapping value, should not match",
+ route: new(Route).Queries("foo", "bar"),
+ request: newRequest("GET", "http://localhost?foo=barfoo"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ queriesTemplate: "foo=bar",
+ queriesRegexp: "^foo=bar$",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with no parameter in request, should not match",
+ route: new(Route).Queries("foo", "{bar}"),
+ request: newRequest("GET", "http://localhost"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ queriesTemplate: "foo={bar}",
+ queriesRegexp: "^foo=(?P<v0>.*)$",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with empty parameter in request, should match",
+ route: new(Route).Queries("foo", "{bar}"),
+ request: newRequest("GET", "http://localhost?foo="),
+ vars: map[string]string{"foo": ""},
+ host: "",
+ path: "",
+ query: "foo=",
+ queriesTemplate: "foo={bar}",
+ queriesRegexp: "^foo=(?P<v0>.*)$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route, bad submatch",
+ route: new(Route).Queries("foo", "bar", "baz", "ding"),
+ request: newRequest("GET", "http://localhost?fffoo=bar&baz=dingggg"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ queriesTemplate: "foo=bar,baz=ding",
+ queriesRegexp: "^foo=bar$,^baz=ding$",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with pattern, match, escaped value",
+ route: new(Route).Queries("foo", "{v1}"),
+ request: newRequest("GET", "http://localhost?foo=%25bar%26%20%2F%3D%3F"),
+ vars: map[string]string{"v1": "%bar& /=?"},
+ host: "",
+ path: "",
+ query: "foo=%25bar%26+%2F%3D%3F",
+ queriesTemplate: "foo={v1}",
+ queriesRegexp: "^foo=(?P<v0>.*)$",
+ shouldMatch: true,
},
}
for _, test := range tests {
testRoute(t, test)
testTemplate(t, test)
+ testQueriesTemplates(t, test)
testUseEscapedRoute(t, test)
+ testQueriesRegexp(t, test)
}
}
@@ -1717,20 +1771,38 @@ func testRegexp(t *testing.T, test routeTest) {
}
}
+func testQueriesRegexp(t *testing.T, test routeTest) {
+ route := test.route
+ queries, queriesErr := route.GetQueriesRegexp()
+ gotQueries := strings.Join(queries, ",")
+ if test.queriesRegexp != "" && queriesErr == nil && gotQueries != test.queriesRegexp {
+ t.Errorf("(%v) GetQueriesRegexp not equal: expected %v, got %v", test.title, test.queriesRegexp, gotQueries)
+ }
+}
+
+func testQueriesTemplates(t *testing.T, test routeTest) {
+ route := test.route
+ queries, queriesErr := route.GetQueriesTemplates()
+ gotQueries := strings.Join(queries, ",")
+ if test.queriesTemplate != "" && queriesErr == nil && gotQueries != test.queriesTemplate {
+ t.Errorf("(%v) GetQueriesTemplates not equal: expected %v, got %v", test.title, test.queriesTemplate, gotQueries)
+ }
+}
+
type TestA301ResponseWriter struct {
hh http.Header
status int
}
-func (ho TestA301ResponseWriter) Header() http.Header {
+func (ho *TestA301ResponseWriter) Header() http.Header {
return http.Header(ho.hh)
}
-func (ho TestA301ResponseWriter) Write(b []byte) (int, error) {
+func (ho *TestA301ResponseWriter) Write(b []byte) (int, error) {
return 0, nil
}
-func (ho TestA301ResponseWriter) WriteHeader(code int) {
+func (ho *TestA301ResponseWriter) WriteHeader(code int) {
ho.status = code
}
@@ -1805,6 +1877,96 @@ func TestSubrouterHeader(t *testing.T) {
}
}
+func TestNoMatchMethodErrorHandler(t *testing.T) {
+ func1 := func(w http.ResponseWriter, r *http.Request) {}
+
+ r := NewRouter()
+ r.HandleFunc("/", func1).Methods("GET", "POST")
+
+ req, _ := http.NewRequest("PUT", "http://localhost/", nil)
+ match := new(RouteMatch)
+ matched := r.Match(req, match)
+
+ if matched {
+ t.Error("Should not have matched route for methods")
+ }
+
+ if match.MatchErr != ErrMethodMismatch {
+ t.Error("Should get ErrMethodMismatch error")
+ }
+
+ resp := NewRecorder()
+ r.ServeHTTP(resp, req)
+ if resp.Code != 405 {
+ t.Errorf("Expecting code %v", 405)
+ }
+
+ // Add matching route
+ r.HandleFunc("/", func1).Methods("PUT")
+
+ match = new(RouteMatch)
+ matched = r.Match(req, match)
+
+ if !matched {
+ t.Error("Should have matched route for methods")
+ }
+
+ if match.MatchErr != nil {
+ t.Error("Should not have any matching error. Found:", match.MatchErr)
+ }
+}
+
+func TestErrMatchNotFound(t *testing.T) {
+ emptyHandler := func(w http.ResponseWriter, r *http.Request) {}
+
+ r := NewRouter()
+ r.HandleFunc("/", emptyHandler)
+ s := r.PathPrefix("/sub/").Subrouter()
+ s.HandleFunc("/", emptyHandler)
+
+ // Regular 404 not found
+ req, _ := http.NewRequest("GET", "/sub/whatever", nil)
+ match := new(RouteMatch)
+ matched := r.Match(req, match)
+
+ if matched {
+ t.Errorf("Subrouter should not have matched that, got %v", match.Route)
+ }
+ // Even without a custom handler, MatchErr is set to ErrNotFound
+ if match.MatchErr != ErrNotFound {
+ t.Errorf("Expected ErrNotFound MatchErr, but was %v", match.MatchErr)
+ }
+
+ // Now lets add a 404 handler to subrouter
+ s.NotFoundHandler = http.NotFoundHandler()
+ req, _ = http.NewRequest("GET", "/sub/whatever", nil)
+
+ // Test the subrouter first
+ match = new(RouteMatch)
+ matched = s.Match(req, match)
+ // Now we should get a match
+ if !matched {
+ t.Errorf("Subrouter should have matched %s", req.RequestURI)
+ }
+ // But MatchErr should be set to ErrNotFound anyway
+ if match.MatchErr != ErrNotFound {
+ t.Errorf("Expected ErrNotFound MatchErr, but was %v", match.MatchErr)
+ }
+
+ // Now test the parent (MatchErr should propagate)
+ match = new(RouteMatch)
+ matched = r.Match(req, match)
+
+ // Now we should get a match
+ if !matched {
+ t.Errorf("Router should have matched %s via subrouter", req.RequestURI)
+ }
+ // But MatchErr should be set to ErrNotFound anyway
+ if match.MatchErr != ErrNotFound {
+ t.Errorf("Expected ErrNotFound MatchErr, but was %v", match.MatchErr)
+ }
+}
+
// mapToPairs converts a string map to a slice of string pairs
func mapToPairs(m map[string]string) []string {
var i int
@@ -1871,42 +2033,3 @@ func newRequest(method, url string) *http.Request {
}
return req
}
-
-func TestNoMatchMethodErrorHandler(t *testing.T) {
- func1 := func(w http.ResponseWriter, r *http.Request) {}
-
- r := NewRouter()
- r.HandleFunc("/", func1).Methods("GET", "POST")
-
- req, _ := http.NewRequest("PUT", "http://localhost/", nil)
- match := new(RouteMatch)
- matched := r.Match(req, match)
-
- if matched {
- t.Error("Should not have matched route for methods")
- }
-
- if match.MatchErr != ErrMethodMismatch {
- t.Error("Should get ErrMethodMismatch error")
- }
-
- resp := NewRecorder()
- r.ServeHTTP(resp, req)
- if resp.Code != 405 {
- t.Errorf("Expecting code %v", 405)
- }
-
- // Add matching route
- r.HandleFunc("/", func1).Methods("PUT")
-
- match = new(RouteMatch)
- matched = r.Match(req, match)
-
- if !matched {
- t.Error("Should have matched route for methods")
- }
-
- if match.MatchErr != nil {
- t.Error("Should not have any matching error. Found:", match.MatchErr)
- }
-}
diff --git a/vendor/github.com/gorilla/mux/regexp.go b/vendor/github.com/gorilla/mux/regexp.go
index 80d1f7858..e83213b7d 100644
--- a/vendor/github.com/gorilla/mux/regexp.go
+++ b/vendor/github.com/gorilla/mux/regexp.go
@@ -141,7 +141,7 @@ type routeRegexp struct {
matchQuery bool
// The strictSlash value defined on the route, but disabled if PathPrefix was used.
strictSlash bool
- // Determines whether to use encoded path from getPath function or unencoded
+ // Determines whether to use encoded req.URL.EnscapedPath() or unencoded
// req.URL.Path for path matching
useEncodedPath bool
// Expanded regexp.
@@ -162,7 +162,7 @@ func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {
}
path := req.URL.Path
if r.useEncodedPath {
- path = getPath(req)
+ path = req.URL.EscapedPath()
}
return r.regexp.MatchString(path)
}
@@ -272,7 +272,7 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
}
path := req.URL.Path
if r.useEncodedPath {
- path = getPath(req)
+ path = req.URL.EscapedPath()
}
// Store path variables.
if v.path != nil {
diff --git a/vendor/github.com/gorilla/mux/route.go b/vendor/github.com/gorilla/mux/route.go
index 6863adba5..69aeae791 100644
--- a/vendor/github.com/gorilla/mux/route.go
+++ b/vendor/github.com/gorilla/mux/route.go
@@ -72,7 +72,11 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
return false
}
- match.MatchErr = nil
+ if match.MatchErr == ErrMethodMismatch {
+ // We found a route which matches request method, clear MatchErr
+ match.MatchErr = nil
+ }
+
// Yay, we have a match. Let's collect some info about it.
if match.Route == nil {
match.Route = r
@@ -608,6 +612,44 @@ func (r *Route) GetPathRegexp() (string, error) {
return r.regexp.path.regexp.String(), nil
}
+// GetQueriesRegexp returns the expanded regular expressions used to match the
+// route queries.
+// This is useful for building simple REST API documentation and for instrumentation
+// against third-party services.
+// An empty list will be returned if the route does not have queries.
+func (r *Route) GetQueriesRegexp() ([]string, error) {
+ if r.err != nil {
+ return nil, r.err
+ }
+ if r.regexp == nil || r.regexp.queries == nil {
+ return nil, errors.New("mux: route doesn't have queries")
+ }
+ var queries []string
+ for _, query := range r.regexp.queries {
+ queries = append(queries, query.regexp.String())
+ }
+ return queries, nil
+}
+
+// GetQueriesTemplates returns the templates used to build the
+// query matching.
+// This is useful for building simple REST API documentation and for instrumentation
+// against third-party services.
+// An empty list will be returned if the route does not define queries.
+func (r *Route) GetQueriesTemplates() ([]string, error) {
+ if r.err != nil {
+ return nil, r.err
+ }
+ if r.regexp == nil || r.regexp.queries == nil {
+ return nil, errors.New("mux: route doesn't have queries")
+ }
+ var queries []string
+ for _, query := range r.regexp.queries {
+ queries = append(queries, query.template)
+ }
+ return queries, nil
+}
+
// GetMethods returns the methods the route matches against
// This is useful for building simple REST API documentation and for instrumentation
// against third-party services.