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/README.md50
-rw-r--r--vendor/github.com/gorilla/mux/doc.go12
-rw-r--r--vendor/github.com/gorilla/mux/mux.go48
-rw-r--r--vendor/github.com/gorilla/mux/mux_test.go145
-rw-r--r--vendor/github.com/gorilla/mux/old_test.go8
-rw-r--r--vendor/github.com/gorilla/mux/regexp.go5
-rw-r--r--vendor/github.com/gorilla/mux/route.go50
7 files changed, 282 insertions, 36 deletions
diff --git a/vendor/github.com/gorilla/mux/README.md b/vendor/github.com/gorilla/mux/README.md
index 56c67134f..8dcd71887 100644
--- a/vendor/github.com/gorilla/mux/README.md
+++ b/vendor/github.com/gorilla/mux/README.md
@@ -15,7 +15,7 @@ The name mux stands for "HTTP request multiplexer". Like the standard `http.Serv
* It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`.
* Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers.
-* URL hosts and paths can have variables with an optional regular expression.
+* URL hosts, paths and query values can have variables with an optional regular expression.
* Registered URLs can be built, or "reversed", which helps maintaining references to resources.
* Routes can be used as subrouters: nested routes are only tested if the parent route matches. This is useful to define groups of routes that share common conditions like a host, a path prefix or other repeated attributes. As a bonus, this optimizes request matching.
@@ -24,9 +24,9 @@ The name mux stands for "HTTP request multiplexer". Like the standard `http.Serv
* [Install](#install)
* [Examples](#examples)
* [Matching Routes](#matching-routes)
-* [Listing Routes](#listing-routes)
* [Static Files](#static-files)
* [Registered URLs](#registered-urls)
+* [Walking Routes](#walking-routes)
* [Full Example](#full-example)
---
@@ -168,7 +168,6 @@ s.HandleFunc("/{key}/", ProductHandler)
// "/products/{key}/details"
s.HandleFunc("/{key}/details", ProductDetailsHandler)
```
-
### Listing Routes
Routes on a mux can be listed using the Router.Walk method—useful for generating documentation:
@@ -191,9 +190,9 @@ func handler(w http.ResponseWriter, r *http.Request) {
func main() {
r := mux.NewRouter()
r.HandleFunc("/", handler)
- r.Methods("POST").HandleFunc("/products", handler)
- r.Methods("GET").HandleFunc("/articles", handler)
- r.Methods("GET", "PUT").HandleFunc("/articles/{id}", handler)
+ r.HandleFunc("/products", handler).Methods("POST")
+ r.HandleFunc("/articles", handler).Methods("GET")
+ r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
t, err := route.GetPathTemplate()
if err != nil {
@@ -269,19 +268,21 @@ url, err := r.Get("article").URL("category", "technology", "id", "42")
"/articles/technology/42"
```
-This also works for host variables:
+This also works for host and query value variables:
```go
r := mux.NewRouter()
r.Host("{subdomain}.domain.com").
Path("/articles/{category}/{id:[0-9]+}").
+ Queries("filter", "{filter}").
HandlerFunc(ArticleHandler).
Name("article")
-// url.String() will be "http://news.domain.com/articles/technology/42"
+// url.String() will be "http://news.domain.com/articles/technology/42?filter=gorilla"
url, err := r.Get("article").URL("subdomain", "news",
"category", "technology",
- "id", "42")
+ "id", "42",
+ "filter", "gorilla")
```
All variables defined in the route are required, and their values must conform to the corresponding patterns. These requirements guarantee that a generated URL will always match a registered route -- the only exception is for explicitly defined "build-only" routes which never match.
@@ -319,6 +320,37 @@ url, err := r.Get("article").URL("subdomain", "news",
"id", "42")
```
+### Walking Routes
+
+The `Walk` function on `mux.Router` can be used to visit all of the routes that are registered on a router. For example,
+the following prints all of the registered routes:
+
+```go
+r := mux.NewRouter()
+r.HandleFunc("/", handler)
+r.HandleFunc("/products", handler).Methods("POST")
+r.HandleFunc("/articles", handler).Methods("GET")
+r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
+r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
+ t, err := route.GetPathTemplate()
+ 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
+ }
+ m, err := route.GetMethods()
+ if err != nil {
+ return err
+ }
+ fmt.Println(strings.Join(m, ","), t, p)
+ return nil
+})
+```
+
## Full Example
Here's a complete, runnable example of a small `mux` based server:
diff --git a/vendor/github.com/gorilla/mux/doc.go b/vendor/github.com/gorilla/mux/doc.go
index 00daf4a72..cce30b2f0 100644
--- a/vendor/github.com/gorilla/mux/doc.go
+++ b/vendor/github.com/gorilla/mux/doc.go
@@ -12,8 +12,8 @@ or other conditions. The main features are:
* Requests can be matched based on URL host, path, path prefix, schemes,
header and query values, HTTP methods or using custom matchers.
- * URL hosts and paths can have variables with an optional regular
- expression.
+ * URL hosts, paths and query values can have variables with an optional
+ regular expression.
* Registered URLs can be built, or "reversed", which helps maintaining
references to resources.
* Routes can be used as subrouters: nested routes are only tested if the
@@ -188,18 +188,20 @@ key/value pairs for the route variables. For the previous route, we would do:
"/articles/technology/42"
-This also works for host variables:
+This also works for host and query value variables:
r := mux.NewRouter()
r.Host("{subdomain}.domain.com").
Path("/articles/{category}/{id:[0-9]+}").
+ Queries("filter", "{filter}").
HandlerFunc(ArticleHandler).
Name("article")
- // url.String() will be "http://news.domain.com/articles/technology/42"
+ // url.String() will be "http://news.domain.com/articles/technology/42?filter=gorilla"
url, err := r.Get("article").URL("subdomain", "news",
"category", "technology",
- "id", "42")
+ "id", "42",
+ "filter", "gorilla")
All variables defined in the route are required, and their values must
conform to the corresponding patterns. These requirements guarantee that a
diff --git a/vendor/github.com/gorilla/mux/mux.go b/vendor/github.com/gorilla/mux/mux.go
index d66ec3841..fb69196db 100644
--- a/vendor/github.com/gorilla/mux/mux.go
+++ b/vendor/github.com/gorilla/mux/mux.go
@@ -13,6 +13,10 @@ import (
"strings"
)
+var (
+ ErrMethodMismatch = errors.New("method is not allowed")
+)
+
// NewRouter returns a new router instance.
func NewRouter() *Router {
return &Router{namedRoutes: make(map[string]*Route), KeepContext: false}
@@ -39,6 +43,10 @@ func NewRouter() *Router {
type Router struct {
// Configurable Handler to be used when no route matches.
NotFoundHandler http.Handler
+
+ // Configurable Handler to be used when the request method does not match the route.
+ MethodNotAllowedHandler http.Handler
+
// Parent route, if this is a subrouter.
parent parentRoute
// Routes to be matched, in order.
@@ -65,6 +73,11 @@ func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
}
}
+ if match.MatchErr == ErrMethodMismatch && r.MethodNotAllowedHandler != nil {
+ match.Handler = r.MethodNotAllowedHandler
+ return true
+ }
+
// Closest match for a router (includes sub-routers)
if r.NotFoundHandler != nil {
match.Handler = r.NotFoundHandler
@@ -105,9 +118,15 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
req = setVars(req, match.Vars)
req = setCurrentRoute(req, match.Route)
}
+
+ if handler == nil && match.MatchErr == ErrMethodMismatch {
+ handler = methodNotAllowedHandler()
+ }
+
if handler == nil {
handler = http.NotFoundHandler()
}
+
if !r.KeepContext {
defer contextClear(req)
}
@@ -176,6 +195,13 @@ func (r *Router) UseEncodedPath() *Router {
// parentRoute
// ----------------------------------------------------------------------------
+func (r *Router) getBuildScheme() string {
+ if r.parent != nil {
+ return r.parent.getBuildScheme()
+ }
+ return ""
+}
+
// getNamedRoutes returns the map where named routes are registered.
func (r *Router) getNamedRoutes() map[string]*Route {
if r.namedRoutes == nil {
@@ -299,10 +325,6 @@ type WalkFunc func(route *Route, router *Router, ancestors []*Route) error
func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
for _, t := range r.routes {
- if t.regexp == nil || t.regexp.path == nil || t.regexp.path.template == "" {
- continue
- }
-
err := walkFn(t, r, ancestors)
if err == SkipRouter {
continue
@@ -312,10 +334,12 @@ func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
}
for _, sr := range t.matchers {
if h, ok := sr.(*Router); ok {
+ ancestors = append(ancestors, t)
err := h.walk(walkFn, ancestors)
if err != nil {
return err
}
+ ancestors = ancestors[:len(ancestors)-1]
}
}
if h, ok := t.handler.(*Router); ok {
@@ -339,6 +363,11 @@ type RouteMatch struct {
Route *Route
Handler http.Handler
Vars map[string]string
+
+ // MatchErr is set to appropriate matching error
+ // It is set to ErrMethodMismatch if there is a mismatch in
+ // the request method and route method
+ MatchErr error
}
type contextKey int
@@ -458,7 +487,7 @@ func mapFromPairsToString(pairs ...string) (map[string]string, error) {
return m, nil
}
-// mapFromPairsToRegex converts variadic string paramers to a
+// mapFromPairsToRegex converts variadic string parameters to a
// string to regex map.
func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
length, err := checkPairs(pairs...)
@@ -540,3 +569,12 @@ func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]s
}
return true
}
+
+// methodNotAllowed replies to the request with an HTTP status code 405.
+func methodNotAllowed(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusMethodNotAllowed)
+}
+
+// methodNotAllowedHandler returns a simple request handler
+// that replies to each request with a status code 405.
+func methodNotAllowedHandler() http.Handler { return http.HandlerFunc(methodNotAllowed) }
diff --git a/vendor/github.com/gorilla/mux/mux_test.go b/vendor/github.com/gorilla/mux/mux_test.go
index 19ef5a8cc..484fab431 100644
--- a/vendor/github.com/gorilla/mux/mux_test.go
+++ b/vendor/github.com/gorilla/mux/mux_test.go
@@ -11,6 +11,7 @@ import (
"fmt"
"net/http"
"net/url"
+ "reflect"
"strings"
"testing"
)
@@ -35,6 +36,7 @@ type routeTest struct {
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
@@ -743,6 +745,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{},
host: "",
path: "",
+ query: "foo=bar&baz=ding",
shouldMatch: true,
},
{
@@ -752,6 +755,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{},
host: "",
path: "",
+ query: "foo=bar&baz=ding",
pathTemplate: `/api`,
hostTemplate: `www.example.com`,
shouldMatch: true,
@@ -763,6 +767,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{},
host: "",
path: "",
+ query: "foo=bar&baz=ding",
pathTemplate: `/api`,
hostTemplate: `www.example.com`,
shouldMatch: true,
@@ -783,6 +788,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"v1": "bar"},
host: "",
path: "",
+ query: "foo=bar",
shouldMatch: true,
},
{
@@ -792,6 +798,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"v1": "bar", "v2": "ding"},
host: "",
path: "",
+ query: "foo=bar&baz=ding",
shouldMatch: true,
},
{
@@ -801,6 +808,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"v1": "10"},
host: "",
path: "",
+ query: "foo=10",
shouldMatch: true,
},
{
@@ -819,6 +827,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"v1": "1"},
host: "",
path: "",
+ query: "foo=1",
shouldMatch: true,
},
{
@@ -828,6 +837,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"v1": "1"},
host: "",
path: "",
+ query: "foo=1",
shouldMatch: true,
},
{
@@ -846,6 +856,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"v1": "1a"},
host: "",
path: "",
+ query: "foo=1a",
shouldMatch: true,
},
{
@@ -864,6 +875,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"v-1": "bar"},
host: "",
path: "",
+ query: "foo=bar",
shouldMatch: true,
},
{
@@ -873,6 +885,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"v-1": "bar", "v-2": "ding"},
host: "",
path: "",
+ query: "foo=bar&baz=ding",
shouldMatch: true,
},
{
@@ -882,6 +895,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"v-1": "10"},
host: "",
path: "",
+ query: "foo=10",
shouldMatch: true,
},
{
@@ -891,6 +905,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"v-1": "1a"},
host: "",
path: "",
+ query: "foo=1a",
shouldMatch: true,
},
{
@@ -900,6 +915,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{},
host: "",
path: "",
+ query: "foo=",
shouldMatch: true,
},
{
@@ -918,6 +934,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{},
host: "",
path: "",
+ query: "foo=",
shouldMatch: true,
},
{
@@ -945,6 +962,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"foo": ""},
host: "",
path: "",
+ query: "foo=",
shouldMatch: true,
},
{
@@ -956,6 +974,16 @@ func TestQueries(t *testing.T) {
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,
+ },
}
for _, test := range tests {
@@ -1187,6 +1215,28 @@ func TestSubRouter(t *testing.T) {
pathTemplate: `/{category}`,
shouldMatch: true,
},
+ {
+ title: "Build with scheme on parent router",
+ route: new(Route).Schemes("ftp").Host("google.com").Subrouter().Path("/"),
+ request: newRequest("GET", "ftp://google.com/"),
+ scheme: "ftp",
+ host: "google.com",
+ path: "/",
+ pathTemplate: `/`,
+ hostTemplate: `google.com`,
+ shouldMatch: true,
+ },
+ {
+ title: "Prefer scheme on child route when building URLs",
+ route: new(Route).Schemes("https", "ftp").Host("google.com").Subrouter().Schemes("ftp").Path("/"),
+ request: newRequest("GET", "ftp://google.com/"),
+ scheme: "ftp",
+ host: "google.com",
+ path: "/",
+ pathTemplate: `/`,
+ hostTemplate: `google.com`,
+ shouldMatch: true,
+ },
}
for _, test := range tests {
@@ -1382,14 +1432,58 @@ func TestWalkNested(t *testing.T) {
l2 := l1.PathPrefix("/l").Subrouter()
l2.Path("/a")
- paths := []string{"/g", "/g/o", "/g/o/r", "/g/o/r/i", "/g/o/r/i/l", "/g/o/r/i/l/l", "/g/o/r/i/l/l/a"}
+ testCases := []struct {
+ path string
+ ancestors []*Route
+ }{
+ {"/g", []*Route{}},
+ {"/g/o", []*Route{g.parent.(*Route)}},
+ {"/g/o/r", []*Route{g.parent.(*Route), o.parent.(*Route)}},
+ {"/g/o/r/i", []*Route{g.parent.(*Route), o.parent.(*Route), r.parent.(*Route)}},
+ {"/g/o/r/i/l", []*Route{g.parent.(*Route), o.parent.(*Route), r.parent.(*Route), i.parent.(*Route)}},
+ {"/g/o/r/i/l/l", []*Route{g.parent.(*Route), o.parent.(*Route), r.parent.(*Route), i.parent.(*Route), l1.parent.(*Route)}},
+ {"/g/o/r/i/l/l/a", []*Route{g.parent.(*Route), o.parent.(*Route), r.parent.(*Route), i.parent.(*Route), l1.parent.(*Route), l2.parent.(*Route)}},
+ }
+
idx := 0
err := router.Walk(func(route *Route, router *Router, ancestors []*Route) error {
- path := paths[idx]
+ path := testCases[idx].path
tpl := route.regexp.path.template
if tpl != path {
t.Errorf(`Expected %s got %s`, path, tpl)
}
+ currWantAncestors := testCases[idx].ancestors
+ if !reflect.DeepEqual(currWantAncestors, ancestors) {
+ t.Errorf(`Expected %+v got %+v`, currWantAncestors, ancestors)
+ }
+ idx++
+ return nil
+ })
+ if err != nil {
+ panic(err)
+ }
+ if idx != len(testCases) {
+ t.Errorf("Expected %d routes, found %d", len(testCases), idx)
+ }
+}
+
+func TestWalkSubrouters(t *testing.T) {
+ router := NewRouter()
+
+ g := router.Path("/g").Subrouter()
+ o := g.PathPrefix("/o").Subrouter()
+ o.Methods("GET")
+ o.Methods("PUT")
+
+ // all 4 routes should be matched, but final 2 routes do not have path templates
+ paths := []string{"/g", "/g/o", "", ""}
+ idx := 0
+ err := router.Walk(func(route *Route, router *Router, ancestors []*Route) error {
+ path := paths[idx]
+ tpl, _ := route.GetPathTemplate()
+ if tpl != path {
+ t.Errorf(`Expected %s got %s`, path, tpl)
+ }
idx++
return nil
})
@@ -1492,6 +1586,7 @@ func testRoute(t *testing.T, test routeTest) {
route := test.route
vars := test.vars
shouldMatch := test.shouldMatch
+ query := test.query
shouldRedirect := test.shouldRedirect
uri := url.URL{
Scheme: test.scheme,
@@ -1561,6 +1656,13 @@ func testRoute(t *testing.T, test routeTest) {
return
}
}
+ if query != "" {
+ u, _ := route.URL(mapToPairs(match.Vars)...)
+ if query != u.RawQuery {
+ t.Errorf("(%v) URL query not equal: expected %v, got %v", test.title, query, u.RawQuery)
+ return
+ }
+ }
if shouldRedirect && match.Handler == nil {
t.Errorf("(%v) Did not redirect", test.title)
return
@@ -1769,3 +1871,42 @@ 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/old_test.go b/vendor/github.com/gorilla/mux/old_test.go
index 9bdc5e5d1..3751e4727 100644
--- a/vendor/github.com/gorilla/mux/old_test.go
+++ b/vendor/github.com/gorilla/mux/old_test.go
@@ -121,12 +121,7 @@ func TestRouteMatchers(t *testing.T) {
var routeMatch RouteMatch
matched := router.Match(request, &routeMatch)
if matched != shouldMatch {
- // Need better messages. :)
- if matched {
- t.Errorf("Should match.")
- } else {
- t.Errorf("Should not match.")
- }
+ t.Errorf("Expected: %v\nGot: %v\nRequest: %v %v", shouldMatch, matched, request.Method, url)
}
if matched {
@@ -188,7 +183,6 @@ func TestRouteMatchers(t *testing.T) {
match(true)
// 2nd route --------------------------------------------------------------
-
// Everything match.
reset2()
match(true)
diff --git a/vendor/github.com/gorilla/mux/regexp.go b/vendor/github.com/gorilla/mux/regexp.go
index 0189ad346..80d1f7858 100644
--- a/vendor/github.com/gorilla/mux/regexp.go
+++ b/vendor/github.com/gorilla/mux/regexp.go
@@ -35,7 +35,7 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash,
// Now let's parse it.
defaultPattern := "[^/]+"
if matchQuery {
- defaultPattern = "[^?&]*"
+ defaultPattern = ".*"
} else if matchHost {
defaultPattern = "[^.]+"
matchPrefix = false
@@ -178,6 +178,9 @@ func (r *routeRegexp) url(values map[string]string) (string, error) {
if !ok {
return "", fmt.Errorf("mux: missing route variable %q", v)
}
+ if r.matchQuery {
+ value = url.QueryEscape(value)
+ }
urlValues[k] = value
}
rv := fmt.Sprintf(r.reverse, urlValues...)
diff --git a/vendor/github.com/gorilla/mux/route.go b/vendor/github.com/gorilla/mux/route.go
index 56dcbbdc5..6863adba5 100644
--- a/vendor/github.com/gorilla/mux/route.go
+++ b/vendor/github.com/gorilla/mux/route.go
@@ -52,12 +52,27 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
if r.buildOnly || r.err != nil {
return false
}
+
+ var matchErr error
+
// Match everything.
for _, m := range r.matchers {
if matched := m.Match(req, match); !matched {
+ if _, ok := m.(methodMatcher); ok {
+ matchErr = ErrMethodMismatch
+ continue
+ }
+ matchErr = nil
return false
}
}
+
+ if matchErr != nil {
+ match.MatchErr = matchErr
+ return false
+ }
+
+ match.MatchErr = nil
// Yay, we have a match. Let's collect some info about it.
if match.Route == nil {
match.Route = r
@@ -68,6 +83,7 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
if match.Vars == nil {
match.Vars = make(map[string]string)
}
+
// Set variables.
if r.regexp != nil {
r.regexp.setMatch(req, match, r)
@@ -482,13 +498,14 @@ func (r *Route) URL(pairs ...string) (*url.URL, error) {
return nil, err
}
var scheme, host, path string
+ queries := make([]string, 0, len(r.regexp.queries))
if r.regexp.host != nil {
if host, err = r.regexp.host.url(values); err != nil {
return nil, err
}
scheme = "http"
- if r.buildScheme != "" {
- scheme = r.buildScheme
+ if s := r.getBuildScheme(); s != "" {
+ scheme = s
}
}
if r.regexp.path != nil {
@@ -496,10 +513,18 @@ func (r *Route) URL(pairs ...string) (*url.URL, error) {
return nil, err
}
}
+ for _, q := range r.regexp.queries {
+ var query string
+ if query, err = q.url(values); err != nil {
+ return nil, err
+ }
+ queries = append(queries, query)
+ }
return &url.URL{
- Scheme: scheme,
- Host: host,
- Path: path,
+ Scheme: scheme,
+ Host: host,
+ Path: path,
+ RawQuery: strings.Join(queries, "&"),
}, nil
}
@@ -525,8 +550,8 @@ func (r *Route) URLHost(pairs ...string) (*url.URL, error) {
Scheme: "http",
Host: host,
}
- if r.buildScheme != "" {
- u.Scheme = r.buildScheme
+ if s := r.getBuildScheme(); s != "" {
+ u.Scheme = s
}
return u, nil
}
@@ -640,11 +665,22 @@ func (r *Route) buildVars(m map[string]string) map[string]string {
// parentRoute allows routes to know about parent host and path definitions.
type parentRoute interface {
+ getBuildScheme() string
getNamedRoutes() map[string]*Route
getRegexpGroup() *routeRegexpGroup
buildVars(map[string]string) map[string]string
}
+func (r *Route) getBuildScheme() string {
+ if r.buildScheme != "" {
+ return r.buildScheme
+ }
+ if r.parent != nil {
+ return r.parent.getBuildScheme()
+ }
+ return ""
+}
+
// getNamedRoutes returns the map where named routes are registered.
func (r *Route) getNamedRoutes() map[string]*Route {
if r.parent == nil {