Bump gorilla/mux version.
This commit is contained in:
parent
3f650bbd11
commit
32b2736efd
7 changed files with 273 additions and 62 deletions
2
glide.lock
generated
2
glide.lock
generated
|
@ -87,7 +87,7 @@ imports:
|
||||||
- name: github.com/containous/flaeg
|
- name: github.com/containous/flaeg
|
||||||
version: b5d2dc5878df07c2d74413348186982e7b865871
|
version: b5d2dc5878df07c2d74413348186982e7b865871
|
||||||
- name: github.com/containous/mux
|
- name: github.com/containous/mux
|
||||||
version: a819b77bba13f0c0cbe36e437bc2e948411b3996
|
version: af6ea922f7683d9706834157e6b0610e22ccb2db
|
||||||
- name: github.com/containous/staert
|
- name: github.com/containous/staert
|
||||||
version: 1e26a71803e428fd933f5f9c8e50a26878f53147
|
version: 1e26a71803e428fd933f5f9c8e50a26878f53147
|
||||||
- name: github.com/coreos/etcd
|
- name: github.com/coreos/etcd
|
||||||
|
|
26
vendor/github.com/containous/mux/context_gorilla.go
generated
vendored
Normal file
26
vendor/github.com/containous/mux/context_gorilla.go
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// +build !go1.7
|
||||||
|
|
||||||
|
package mux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func contextGet(r *http.Request, key interface{}) interface{} {
|
||||||
|
return context.Get(r, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func contextSet(r *http.Request, key, val interface{}) *http.Request {
|
||||||
|
if val == nil {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Set(r, key, val)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func contextClear(r *http.Request) {
|
||||||
|
context.Clear(r)
|
||||||
|
}
|
24
vendor/github.com/containous/mux/context_native.go
generated
vendored
Normal file
24
vendor/github.com/containous/mux/context_native.go
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
package mux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func contextGet(r *http.Request, key interface{}) interface{} {
|
||||||
|
return r.Context().Value(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func contextSet(r *http.Request, key, val interface{}) *http.Request {
|
||||||
|
if val == nil {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.WithContext(context.WithValue(r.Context(), key, val))
|
||||||
|
}
|
||||||
|
|
||||||
|
func contextClear(r *http.Request) {
|
||||||
|
return
|
||||||
|
}
|
46
vendor/github.com/containous/mux/doc.go
generated
vendored
46
vendor/github.com/containous/mux/doc.go
generated
vendored
|
@ -12,8 +12,8 @@ or other conditions. The main features are:
|
||||||
|
|
||||||
* Requests can be matched based on URL host, path, path prefix, schemes,
|
* Requests can be matched based on URL host, path, path prefix, schemes,
|
||||||
header and query values, HTTP methods or using custom matchers.
|
header and query values, HTTP methods or using custom matchers.
|
||||||
* URL hosts and paths can have variables with an optional regular
|
* URL hosts, paths and query values can have variables with an optional
|
||||||
expression.
|
regular expression.
|
||||||
* Registered URLs can be built, or "reversed", which helps maintaining
|
* Registered URLs can be built, or "reversed", which helps maintaining
|
||||||
references to resources.
|
references to resources.
|
||||||
* Routes can be used as subrouters: nested routes are only tested if the
|
* Routes can be used as subrouters: nested routes are only tested if the
|
||||||
|
@ -47,12 +47,21 @@ variable will be anything until the next slash. For example:
|
||||||
r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
|
r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
|
||||||
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
|
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
|
||||||
|
|
||||||
|
Groups can be used inside patterns, as long as they are non-capturing (?:re). For example:
|
||||||
|
|
||||||
|
r.HandleFunc("/articles/{category}/{sort:(?:asc|desc|new)}", ArticlesCategoryHandler)
|
||||||
|
|
||||||
The names are used to create a map of route variables which can be retrieved
|
The names are used to create a map of route variables which can be retrieved
|
||||||
calling mux.Vars():
|
calling mux.Vars():
|
||||||
|
|
||||||
vars := mux.Vars(request)
|
vars := mux.Vars(request)
|
||||||
category := vars["category"]
|
category := vars["category"]
|
||||||
|
|
||||||
|
Note that if any capturing groups are present, mux will panic() during parsing. To prevent
|
||||||
|
this, convert any capturing groups to non-capturing, e.g. change "/{sort:(asc|desc)}" to
|
||||||
|
"/{sort:(?:asc|desc)}". This is a change from prior versions which behaved unpredictably
|
||||||
|
when capturing groups were present.
|
||||||
|
|
||||||
And this is all you need to know about the basic usage. More advanced options
|
And this is all you need to know about the basic usage. More advanced options
|
||||||
are explained below.
|
are explained below.
|
||||||
|
|
||||||
|
@ -136,6 +145,31 @@ the inner routes use it as base for their paths:
|
||||||
// "/products/{key}/details"
|
// "/products/{key}/details"
|
||||||
s.HandleFunc("/{key}/details", ProductDetailsHandler)
|
s.HandleFunc("/{key}/details", ProductDetailsHandler)
|
||||||
|
|
||||||
|
Note that the path provided to PathPrefix() represents a "wildcard": calling
|
||||||
|
PathPrefix("/static/").Handler(...) means that the handler will be passed any
|
||||||
|
request that matches "/static/*". This makes it easy to serve static files with mux:
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var dir string
|
||||||
|
|
||||||
|
flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
|
||||||
|
flag.Parse()
|
||||||
|
r := mux.NewRouter()
|
||||||
|
|
||||||
|
// This will serve files under http://localhost:8000/static/<filename>
|
||||||
|
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
|
||||||
|
|
||||||
|
srv := &http.Server{
|
||||||
|
Handler: r,
|
||||||
|
Addr: "127.0.0.1:8000",
|
||||||
|
// Good practice: enforce timeouts for servers you create!
|
||||||
|
WriteTimeout: 15 * time.Second,
|
||||||
|
ReadTimeout: 15 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Fatal(srv.ListenAndServe())
|
||||||
|
}
|
||||||
|
|
||||||
Now let's see how to build registered URLs.
|
Now let's see how to build registered URLs.
|
||||||
|
|
||||||
Routes can be named. All routes that define a name can have their URLs built,
|
Routes can be named. All routes that define a name can have their URLs built,
|
||||||
|
@ -154,18 +188,20 @@ key/value pairs for the route variables. For the previous route, we would do:
|
||||||
|
|
||||||
"/articles/technology/42"
|
"/articles/technology/42"
|
||||||
|
|
||||||
This also works for host variables:
|
This also works for host and query value variables:
|
||||||
|
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.Host("{subdomain}.domain.com").
|
r.Host("{subdomain}.domain.com").
|
||||||
Path("/articles/{category}/{id:[0-9]+}").
|
Path("/articles/{category}/{id:[0-9]+}").
|
||||||
|
Queries("filter", "{filter}").
|
||||||
HandlerFunc(ArticleHandler).
|
HandlerFunc(ArticleHandler).
|
||||||
Name("article")
|
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",
|
url, err := r.Get("article").URL("subdomain", "news",
|
||||||
"category", "technology",
|
"category", "technology",
|
||||||
"id", "42")
|
"id", "42",
|
||||||
|
"filter", "gorilla")
|
||||||
|
|
||||||
All variables defined in the route are required, and their values must
|
All variables defined in the route are required, and their values must
|
||||||
conform to the corresponding patterns. These requirements guarantee that a
|
conform to the corresponding patterns. These requirements guarantee that a
|
||||||
|
|
94
vendor/github.com/containous/mux/mux.go
generated
vendored
94
vendor/github.com/containous/mux/mux.go
generated
vendored
|
@ -11,8 +11,7 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
"github.com/gorilla/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewRouter returns a new router instance.
|
// NewRouter returns a new router instance.
|
||||||
|
@ -51,8 +50,12 @@ type Router struct {
|
||||||
strictSlash bool
|
strictSlash bool
|
||||||
// See Router.SkipClean(). This defines the flag for new routes.
|
// See Router.SkipClean(). This defines the flag for new routes.
|
||||||
skipClean bool
|
skipClean bool
|
||||||
// If true, do not clear the request context after handling the request
|
// If true, do not clear the request context after handling the request.
|
||||||
|
// This has no effect when go1.7+ is used, since the context is stored
|
||||||
|
// on the request itself.
|
||||||
KeepContext bool
|
KeepContext bool
|
||||||
|
// see Router.UseEncodedPath(). This defines a flag for all routes.
|
||||||
|
useEncodedPath bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match matches registered routes against the request.
|
// Match matches registered routes against the request.
|
||||||
|
@ -77,8 +80,12 @@ func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
|
||||||
// mux.Vars(request).
|
// mux.Vars(request).
|
||||||
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
if !r.skipClean {
|
if !r.skipClean {
|
||||||
|
path := req.URL.Path
|
||||||
|
if r.useEncodedPath {
|
||||||
|
path = getPath(req)
|
||||||
|
}
|
||||||
// Clean path to canonical form and redirect.
|
// Clean path to canonical form and redirect.
|
||||||
if p := cleanPath(req.URL.Path); p != req.URL.Path {
|
if p := cleanPath(path); p != path {
|
||||||
|
|
||||||
// Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query.
|
// Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query.
|
||||||
// This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue:
|
// This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue:
|
||||||
|
@ -96,14 +103,14 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
var handler http.Handler
|
var handler http.Handler
|
||||||
if r.Match(req, &match) {
|
if r.Match(req, &match) {
|
||||||
handler = match.Handler
|
handler = match.Handler
|
||||||
setVars(req, match.Vars)
|
req = setVars(req, match.Vars)
|
||||||
setCurrentRoute(req, match.Route)
|
req = setCurrentRoute(req, match.Route)
|
||||||
}
|
}
|
||||||
if handler == nil {
|
if handler == nil {
|
||||||
handler = http.NotFoundHandler()
|
handler = http.NotFoundHandler()
|
||||||
}
|
}
|
||||||
if !r.KeepContext {
|
if !r.KeepContext {
|
||||||
defer context.Clear(req)
|
defer contextClear(req)
|
||||||
}
|
}
|
||||||
handler.ServeHTTP(w, req)
|
handler.ServeHTTP(w, req)
|
||||||
}
|
}
|
||||||
|
@ -151,10 +158,32 @@ func (r *Router) SkipClean(value bool) *Router {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UseEncodedPath tells the router to match the encoded original path
|
||||||
|
// to the routes.
|
||||||
|
// For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to".
|
||||||
|
// This behavior has the drawback of needing to match routes against
|
||||||
|
// r.RequestURI instead of r.URL.Path. Any modifications (such as http.StripPrefix)
|
||||||
|
// to r.URL.Path will not affect routing when this flag is on and thus may
|
||||||
|
// induce unintended behavior.
|
||||||
|
//
|
||||||
|
// If not called, the router will match the unencoded path to the routes.
|
||||||
|
// For eg. "/path/foo%2Fbar/to" will match the path "/path/foo/bar/to"
|
||||||
|
func (r *Router) UseEncodedPath() *Router {
|
||||||
|
r.useEncodedPath = true
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// parentRoute
|
// parentRoute
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func (r *Router) getBuildScheme() string {
|
||||||
|
if r.parent != nil {
|
||||||
|
return r.parent.getBuildScheme()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// getNamedRoutes returns the map where named routes are registered.
|
// getNamedRoutes returns the map where named routes are registered.
|
||||||
func (r *Router) getNamedRoutes() map[string]*Route {
|
func (r *Router) getNamedRoutes() map[string]*Route {
|
||||||
if r.namedRoutes == nil {
|
if r.namedRoutes == nil {
|
||||||
|
@ -188,7 +217,7 @@ func (r *Router) buildVars(m map[string]string) map[string]string {
|
||||||
|
|
||||||
// NewRoute registers an empty route.
|
// NewRoute registers an empty route.
|
||||||
func (r *Router) NewRoute() *Route {
|
func (r *Router) NewRoute() *Route {
|
||||||
route := &Route{parent: r, strictSlash: r.strictSlash, skipClean: r.skipClean}
|
route := &Route{parent: r, strictSlash: r.strictSlash, skipClean: r.skipClean, useEncodedPath: r.useEncodedPath}
|
||||||
r.routes = append(r.routes, route)
|
r.routes = append(r.routes, route)
|
||||||
return route
|
return route
|
||||||
}
|
}
|
||||||
|
@ -278,20 +307,21 @@ type WalkFunc func(route *Route, router *Router, ancestors []*Route) error
|
||||||
|
|
||||||
func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
|
func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
|
||||||
for _, t := range r.routes {
|
for _, t := range r.routes {
|
||||||
if t.regexp == nil || t.regexp.path == nil || t.regexp.path.template == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
err := walkFn(t, r, ancestors)
|
err := walkFn(t, r, ancestors)
|
||||||
if err == SkipRouter {
|
if err == SkipRouter {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
for _, sr := range t.matchers {
|
for _, sr := range t.matchers {
|
||||||
if h, ok := sr.(*Router); ok {
|
if h, ok := sr.(*Router); ok {
|
||||||
|
ancestors = append(ancestors, t)
|
||||||
err := h.walk(walkFn, ancestors)
|
err := h.walk(walkFn, ancestors)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
ancestors = ancestors[:len(ancestors)-1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if h, ok := t.handler.(*Router); ok {
|
if h, ok := t.handler.(*Router); ok {
|
||||||
|
@ -337,7 +367,7 @@ const (
|
||||||
|
|
||||||
// Vars returns the route variables for the current request, if any.
|
// Vars returns the route variables for the current request, if any.
|
||||||
func Vars(r *http.Request) map[string]string {
|
func Vars(r *http.Request) map[string]string {
|
||||||
if rv := context.Get(r, varsKey); rv != nil {
|
if rv := contextGet(r, varsKey); rv != nil {
|
||||||
return rv.(map[string]string)
|
return rv.(map[string]string)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -349,28 +379,46 @@ func Vars(r *http.Request) map[string]string {
|
||||||
// after the handler returns, unless the KeepContext option is set on the
|
// after the handler returns, unless the KeepContext option is set on the
|
||||||
// Router.
|
// Router.
|
||||||
func CurrentRoute(r *http.Request) *Route {
|
func CurrentRoute(r *http.Request) *Route {
|
||||||
if rv := context.Get(r, routeKey); rv != nil {
|
if rv := contextGet(r, routeKey); rv != nil {
|
||||||
return rv.(*Route)
|
return rv.(*Route)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setVars(r *http.Request, val interface{}) {
|
func setVars(r *http.Request, val interface{}) *http.Request {
|
||||||
if val != nil {
|
return contextSet(r, varsKey, val)
|
||||||
context.Set(r, varsKey, val)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func setCurrentRoute(r *http.Request, val interface{}) {
|
func setCurrentRoute(r *http.Request, val interface{}) *http.Request {
|
||||||
if val != nil {
|
return contextSet(r, routeKey, val)
|
||||||
context.Set(r, routeKey, val)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Helpers
|
// 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.
|
// cleanPath returns the canonical path for p, eliminating . and .. elements.
|
||||||
// Borrowed from the net/http package.
|
// Borrowed from the net/http package.
|
||||||
func cleanPath(p string) string {
|
func cleanPath(p string) string {
|
||||||
|
@ -427,7 +475,7 @@ func mapFromPairsToString(pairs ...string) (map[string]string, error) {
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// mapFromPairsToRegex converts variadic string paramers to a
|
// mapFromPairsToRegex converts variadic string parameters to a
|
||||||
// string to regex map.
|
// string to regex map.
|
||||||
func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
|
func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
|
||||||
length, err := checkPairs(pairs...)
|
length, err := checkPairs(pairs...)
|
||||||
|
|
62
vendor/github.com/containous/mux/regexp.go
generated
vendored
62
vendor/github.com/containous/mux/regexp.go
generated
vendored
|
@ -24,7 +24,7 @@ import (
|
||||||
// Previously we accepted only Python-like identifiers for variable
|
// Previously we accepted only Python-like identifiers for variable
|
||||||
// names ([a-zA-Z_][a-zA-Z0-9_]*), but currently the only restriction is that
|
// names ([a-zA-Z_][a-zA-Z0-9_]*), but currently the only restriction is that
|
||||||
// name and pattern can't be empty, and names can't contain a colon.
|
// name and pattern can't be empty, and names can't contain a colon.
|
||||||
func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash bool) (*routeRegexp, error) {
|
func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash, useEncodedPath bool) (*routeRegexp, error) {
|
||||||
// Check if it is well-formed.
|
// Check if it is well-formed.
|
||||||
idxs, errBraces := braceIndices(tpl)
|
idxs, errBraces := braceIndices(tpl)
|
||||||
if errBraces != nil {
|
if errBraces != nil {
|
||||||
|
@ -35,7 +35,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 = ".*"
|
||||||
} else if matchHost {
|
} else if matchHost {
|
||||||
defaultPattern = "[^.]+"
|
defaultPattern = "[^.]+"
|
||||||
matchPrefix = false
|
matchPrefix = false
|
||||||
|
@ -109,16 +109,24 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
|
||||||
if errCompile != nil {
|
if errCompile != nil {
|
||||||
return nil, errCompile
|
return nil, errCompile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for capturing groups which used to work in older versions
|
||||||
|
if reg.NumSubexp() != len(idxs)/2 {
|
||||||
|
panic(fmt.Sprintf("route %s contains capture groups in its regexp. ", template) +
|
||||||
|
"Only non-capturing groups are accepted: e.g. (?:pattern) instead of (pattern)")
|
||||||
|
}
|
||||||
|
|
||||||
// Done!
|
// Done!
|
||||||
return &routeRegexp{
|
return &routeRegexp{
|
||||||
template: template,
|
template: template,
|
||||||
matchHost: matchHost,
|
matchHost: matchHost,
|
||||||
matchQuery: matchQuery,
|
matchQuery: matchQuery,
|
||||||
strictSlash: strictSlash,
|
strictSlash: strictSlash,
|
||||||
regexp: reg,
|
useEncodedPath: useEncodedPath,
|
||||||
reverse: reverse.String(),
|
regexp: reg,
|
||||||
varsN: varsN,
|
reverse: reverse.String(),
|
||||||
varsR: varsR,
|
varsN: varsN,
|
||||||
|
varsR: varsR,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +141,9 @@ type routeRegexp struct {
|
||||||
matchQuery bool
|
matchQuery bool
|
||||||
// The strictSlash value defined on the route, but disabled if PathPrefix was used.
|
// The strictSlash value defined on the route, but disabled if PathPrefix was used.
|
||||||
strictSlash bool
|
strictSlash bool
|
||||||
|
// Determines whether to use encoded path from getPath function or unencoded
|
||||||
|
// req.URL.Path for path matching
|
||||||
|
useEncodedPath bool
|
||||||
// Expanded regexp.
|
// Expanded regexp.
|
||||||
regexp *regexp.Regexp
|
regexp *regexp.Regexp
|
||||||
// Reverse template.
|
// Reverse template.
|
||||||
|
@ -149,8 +160,11 @@ func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {
|
||||||
if r.matchQuery {
|
if r.matchQuery {
|
||||||
return r.matchQueryString(req)
|
return r.matchQueryString(req)
|
||||||
}
|
}
|
||||||
|
path := req.URL.Path
|
||||||
return r.regexp.MatchString(req.URL.Path)
|
if r.useEncodedPath {
|
||||||
|
path = getPath(req)
|
||||||
|
}
|
||||||
|
return r.regexp.MatchString(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.regexp.MatchString(getHost(req))
|
return r.regexp.MatchString(getHost(req))
|
||||||
|
@ -164,6 +178,9 @@ func (r *routeRegexp) url(values map[string]string) (string, error) {
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", fmt.Errorf("mux: missing route variable %q", v)
|
return "", fmt.Errorf("mux: missing route variable %q", v)
|
||||||
}
|
}
|
||||||
|
if r.matchQuery {
|
||||||
|
value = url.QueryEscape(value)
|
||||||
|
}
|
||||||
urlValues[k] = value
|
urlValues[k] = value
|
||||||
}
|
}
|
||||||
rv := fmt.Sprintf(r.reverse, urlValues...)
|
rv := fmt.Sprintf(r.reverse, urlValues...)
|
||||||
|
@ -253,14 +270,18 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
|
||||||
extractVars(host, matches, v.host.varsN, m.Vars)
|
extractVars(host, matches, v.host.varsN, m.Vars)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
path := req.URL.Path
|
||||||
|
if r.useEncodedPath {
|
||||||
|
path = getPath(req)
|
||||||
|
}
|
||||||
// Store path variables.
|
// Store path variables.
|
||||||
if v.path != nil {
|
if v.path != nil {
|
||||||
matches := v.path.regexp.FindStringSubmatchIndex(req.URL.Path)
|
matches := v.path.regexp.FindStringSubmatchIndex(path)
|
||||||
if len(matches) > 0 {
|
if len(matches) > 0 {
|
||||||
extractVars(req.URL.Path, matches, v.path.varsN, m.Vars)
|
extractVars(path, matches, v.path.varsN, m.Vars)
|
||||||
// Check if we should redirect.
|
// Check if we should redirect.
|
||||||
if v.path.strictSlash {
|
if v.path.strictSlash {
|
||||||
p1 := strings.HasSuffix(req.URL.Path, "/")
|
p1 := strings.HasSuffix(path, "/")
|
||||||
p2 := strings.HasSuffix(v.path.template, "/")
|
p2 := strings.HasSuffix(v.path.template, "/")
|
||||||
if p1 != p2 {
|
if p1 != p2 {
|
||||||
u, _ := url.Parse(req.URL.String())
|
u, _ := url.Parse(req.URL.String())
|
||||||
|
@ -299,14 +320,7 @@ func getHost(r *http.Request) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractVars(input string, matches []int, names []string, output map[string]string) {
|
func extractVars(input string, matches []int, names []string, output map[string]string) {
|
||||||
matchesCount := 0
|
for i, name := range names {
|
||||||
prevEnd := -1
|
output[name] = input[matches[2*i+2]:matches[2*i+3]]
|
||||||
for i := 2; i < len(matches) && matchesCount < len(names); i += 2 {
|
|
||||||
if prevEnd < matches[i+1] {
|
|
||||||
value := input[matches[i]:matches[i+1]]
|
|
||||||
output[names[matchesCount]] = value
|
|
||||||
prevEnd = matches[i+1]
|
|
||||||
matchesCount++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
81
vendor/github.com/containous/mux/route.go
generated
vendored
81
vendor/github.com/containous/mux/route.go
generated
vendored
|
@ -29,6 +29,10 @@ type Route struct {
|
||||||
// If true, when the path pattern is "/path//to", accessing "/path//to"
|
// If true, when the path pattern is "/path//to", accessing "/path//to"
|
||||||
// will not redirect
|
// will not redirect
|
||||||
skipClean bool
|
skipClean bool
|
||||||
|
// If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to"
|
||||||
|
useEncodedPath bool
|
||||||
|
// The scheme used when building URLs.
|
||||||
|
buildScheme string
|
||||||
// If true, this route never matches: it is only used to build URLs.
|
// If true, this route never matches: it is only used to build URLs.
|
||||||
buildOnly bool
|
buildOnly bool
|
||||||
// The name used to build URLs.
|
// The name used to build URLs.
|
||||||
|
@ -166,14 +170,14 @@ func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery
|
||||||
}
|
}
|
||||||
r.regexp = r.getRegexpGroup()
|
r.regexp = r.getRegexpGroup()
|
||||||
if !matchHost && !matchQuery {
|
if !matchHost && !matchQuery {
|
||||||
if len(tpl) == 0 || tpl[0] != '/' {
|
if len(tpl) > 0 && tpl[0] != '/' {
|
||||||
return fmt.Errorf("mux: path must start with a slash, got %q", tpl)
|
return fmt.Errorf("mux: path must start with a slash, got %q", tpl)
|
||||||
}
|
}
|
||||||
if r.regexp.path != nil {
|
if r.regexp.path != nil {
|
||||||
tpl = strings.TrimRight(r.regexp.path.template, "/") + tpl
|
tpl = strings.TrimRight(r.regexp.path.template, "/") + tpl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rr, err := newRouteRegexp(tpl, matchHost, matchPrefix, matchQuery, r.strictSlash)
|
rr, err := newRouteRegexp(tpl, matchHost, matchPrefix, matchQuery, r.strictSlash, r.useEncodedPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -407,6 +411,9 @@ func (r *Route) Schemes(schemes ...string) *Route {
|
||||||
for k, v := range schemes {
|
for k, v := range schemes {
|
||||||
schemes[k] = strings.ToLower(v)
|
schemes[k] = strings.ToLower(v)
|
||||||
}
|
}
|
||||||
|
if r.buildScheme == "" && len(schemes) > 0 {
|
||||||
|
r.buildScheme = schemes[0]
|
||||||
|
}
|
||||||
return r.addMatcher(schemeMatcher(schemes))
|
return r.addMatcher(schemeMatcher(schemes))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,22 +497,33 @@ func (r *Route) URL(pairs ...string) (*url.URL, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var scheme, host, path string
|
var scheme, host, path string
|
||||||
|
queries := make([]string, 0, len(r.regexp.queries))
|
||||||
if r.regexp.host != nil {
|
if r.regexp.host != nil {
|
||||||
// Set a default scheme.
|
|
||||||
scheme = "http"
|
|
||||||
if host, err = r.regexp.host.url(values); err != nil {
|
if host, err = r.regexp.host.url(values); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
scheme = "http"
|
||||||
|
if s := r.getBuildScheme(); s != "" {
|
||||||
|
scheme = s
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if r.regexp.path != nil {
|
if r.regexp.path != nil {
|
||||||
if path, err = r.regexp.path.url(values); err != nil {
|
if path, err = r.regexp.path.url(values); err != nil {
|
||||||
return nil, err
|
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{
|
return &url.URL{
|
||||||
Scheme: scheme,
|
Scheme: scheme,
|
||||||
Host: host,
|
Host: host,
|
||||||
Path: path,
|
Path: path,
|
||||||
|
RawQuery: strings.Join(queries, "&"),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -527,10 +545,14 @@ func (r *Route) URLHost(pairs ...string) (*url.URL, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &url.URL{
|
u := &url.URL{
|
||||||
Scheme: "http",
|
Scheme: "http",
|
||||||
Host: host,
|
Host: host,
|
||||||
}, nil
|
}
|
||||||
|
if s := r.getBuildScheme(); s != "" {
|
||||||
|
u.Scheme = s
|
||||||
|
}
|
||||||
|
return u, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// URLPath builds the path part of the URL for a route. See Route.URL().
|
// URLPath builds the path part of the URL for a route. See Route.URL().
|
||||||
|
@ -571,6 +593,36 @@ func (r *Route) GetPathTemplate() (string, error) {
|
||||||
return r.regexp.path.template, nil
|
return r.regexp.path.template, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPathRegexp returns the expanded regular expression used to match route path.
|
||||||
|
// This is useful for building simple REST API documentation and for instrumentation
|
||||||
|
// against third-party services.
|
||||||
|
// An error will be returned if the route does not define a path.
|
||||||
|
func (r *Route) GetPathRegexp() (string, error) {
|
||||||
|
if r.err != nil {
|
||||||
|
return "", r.err
|
||||||
|
}
|
||||||
|
if r.regexp == nil || r.regexp.path == nil {
|
||||||
|
return "", errors.New("mux: route does not have a path")
|
||||||
|
}
|
||||||
|
return r.regexp.path.regexp.String(), 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.
|
||||||
|
// An empty list will be returned if route does not have methods.
|
||||||
|
func (r *Route) GetMethods() ([]string, error) {
|
||||||
|
if r.err != nil {
|
||||||
|
return nil, r.err
|
||||||
|
}
|
||||||
|
for _, m := range r.matchers {
|
||||||
|
if methods, ok := m.(methodMatcher); ok {
|
||||||
|
return []string(methods), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetHostTemplate returns the template used to build the
|
// GetHostTemplate returns the template used to build the
|
||||||
// route match.
|
// route match.
|
||||||
// This is useful for building simple REST API documentation and for instrumentation
|
// This is useful for building simple REST API documentation and for instrumentation
|
||||||
|
@ -612,11 +664,22 @@ func (r *Route) buildVars(m map[string]string) map[string]string {
|
||||||
|
|
||||||
// parentRoute allows routes to know about parent host and path definitions.
|
// parentRoute allows routes to know about parent host and path definitions.
|
||||||
type parentRoute interface {
|
type parentRoute interface {
|
||||||
|
getBuildScheme() string
|
||||||
getNamedRoutes() map[string]*Route
|
getNamedRoutes() map[string]*Route
|
||||||
getRegexpGroup() *routeRegexpGroup
|
getRegexpGroup() *routeRegexpGroup
|
||||||
buildVars(map[string]string) map[string]string
|
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.
|
// getNamedRoutes returns the map where named routes are registered.
|
||||||
func (r *Route) getNamedRoutes() map[string]*Route {
|
func (r *Route) getNamedRoutes() map[string]*Route {
|
||||||
if r.parent == nil {
|
if r.parent == nil {
|
||||||
|
|
Loading…
Reference in a new issue