From 7b320119ba532fd409ec7dade7ad02011c309599 Mon Sep 17 00:00:00 2001 From: Niall Sheridan Date: Wed, 18 Oct 2017 13:15:14 +0100 Subject: Update dependencies --- vendor/github.com/gorilla/csrf/Gopkg.lock | 27 +++ vendor/github.com/gorilla/csrf/Gopkg.toml | 34 ++++ vendor/github.com/gorilla/csrf/doc.go | 228 +++++++++++++------------ vendor/github.com/gorilla/handlers/handlers.go | 8 +- vendor/github.com/gorilla/mux/README.md | 71 ++++++-- vendor/github.com/gorilla/mux/doc.go | 12 +- vendor/github.com/gorilla/mux/mux.go | 48 +++++- vendor/github.com/gorilla/mux/regexp.go | 5 +- vendor/github.com/gorilla/mux/route.go | 91 +++++++++- vendor/github.com/gorilla/sessions/README.md | 6 +- vendor/github.com/gorilla/sessions/doc.go | 3 +- 11 files changed, 384 insertions(+), 149 deletions(-) create mode 100644 vendor/github.com/gorilla/csrf/Gopkg.lock create mode 100644 vendor/github.com/gorilla/csrf/Gopkg.toml (limited to 'vendor/github.com/gorilla') diff --git a/vendor/github.com/gorilla/csrf/Gopkg.lock b/vendor/github.com/gorilla/csrf/Gopkg.lock new file mode 100644 index 0000000..5db9540 --- /dev/null +++ b/vendor/github.com/gorilla/csrf/Gopkg.lock @@ -0,0 +1,27 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/gorilla/context" + packages = ["."] + revision = "1ea25387ff6f684839d82767c1733ff4d4d15d0a" + version = "v1.1" + +[[projects]] + name = "github.com/gorilla/securecookie" + packages = ["."] + revision = "667fe4e3466a040b780561fe9b51a83a3753eefc" + version = "v1.1" + +[[projects]] + name = "github.com/pkg/errors" + packages = ["."] + revision = "645ef00459ed84a119197bfb8d8205042c6df63d" + version = "v0.8.0" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "1695686bc8fa0eb76df9fe8c5ca473686071ddcf795a0595a9465a03e8ac9bef" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/vendor/github.com/gorilla/csrf/Gopkg.toml b/vendor/github.com/gorilla/csrf/Gopkg.toml new file mode 100644 index 0000000..02837b1 --- /dev/null +++ b/vendor/github.com/gorilla/csrf/Gopkg.toml @@ -0,0 +1,34 @@ + +# Gopkg.toml example +# +# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" + + +[[constraint]] + name = "github.com/gorilla/context" + version = "1.1.0" + +[[constraint]] + name = "github.com/gorilla/securecookie" + version = "1.1.0" + +[[constraint]] + name = "github.com/pkg/errors" + version = "0.8.0" diff --git a/vendor/github.com/gorilla/csrf/doc.go b/vendor/github.com/gorilla/csrf/doc.go index 301abe0..3046cdc 100644 --- a/vendor/github.com/gorilla/csrf/doc.go +++ b/vendor/github.com/gorilla/csrf/doc.go @@ -4,13 +4,15 @@ prevention middleware for Go web applications & services. It includes: - * The `csrf.Protect` middleware/handler provides CSRF protection on routes - attached to a router or a sub-router. - * A `csrf.Token` function that provides the token to pass into your response, - whether that be a HTML form or a JSON response body. - * ... and a `csrf.TemplateField` helper that you can pass into your `html/template` - templates to replace a `{{ .csrfField }}` template tag with a hidden input - field. +* The `csrf.Protect` middleware/handler provides CSRF protection on routes +attached to a router or a sub-router. + +* A `csrf.Token` function that provides the token to pass into your response, +whether that be a HTML form or a JSON response body. + +* ... and a `csrf.TemplateField` helper that you can pass into your `html/template` +templates to replace a `{{ .csrfField }}` template tag with a hidden input +field. gorilla/csrf is easy to use: add the middleware to individual handlers with the below: @@ -31,66 +33,66 @@ validation. Here's the common use-case: HTML forms you want to provide CSRF protection for, in order to protect malicious POST requests being made: - package main - - import ( - "fmt" - "html/template" - "net/http" - - "github.com/gorilla/csrf" - "github.com/gorilla/mux" - ) - - var form = ` - - - Sign Up! - - -
- - - - {{ .csrfField }} - -
- - - ` - - var t = template.Must(template.New("signup_form.tmpl").Parse(form)) - - func main() { - r := mux.NewRouter() - r.HandleFunc("/signup", ShowSignupForm) - // All POST requests without a valid token will return HTTP 403 Forbidden. - r.HandleFunc("/signup/post", SubmitSignupForm) - - // Add the middleware to your router by wrapping it. - http.ListenAndServe(":8000", - csrf.Protect([]byte("32-byte-long-auth-key"))(r)) - // PS: Don't forget to pass csrf.Secure(false) if you're developing locally - // over plain HTTP (just don't leave it on in production). - } - - func ShowSignupForm(w http.ResponseWriter, r *http.Request) { - // signup_form.tmpl just needs a {{ .csrfField }} template tag for - // csrf.TemplateField to inject the CSRF token into. Easy! - t.ExecuteTemplate(w, "signup_form.tmpl", map[string]interface{}{ - csrf.TemplateTag: csrf.TemplateField(r), - }) - } - - func SubmitSignupForm(w http.ResponseWriter, r *http.Request) { - // We can trust that requests making it this far have satisfied - // our CSRF protection requirements. - fmt.Fprintf(w, "%v\n", r.PostForm) - } + package main + + import ( + "fmt" + "html/template" + "net/http" + + "github.com/gorilla/csrf" + "github.com/gorilla/mux" + ) + + var form = ` + + + Sign Up! + + +
+ + + + {{ .csrfField }} + +
+ + + ` + + var t = template.Must(template.New("signup_form.tmpl").Parse(form)) + + func main() { + r := mux.NewRouter() + r.HandleFunc("/signup", ShowSignupForm) + // All POST requests without a valid token will return HTTP 403 Forbidden. + r.HandleFunc("/signup/post", SubmitSignupForm) + + // Add the middleware to your router by wrapping it. + http.ListenAndServe(":8000", + csrf.Protect([]byte("32-byte-long-auth-key"))(r)) + // PS: Don't forget to pass csrf.Secure(false) if you're developing locally + // over plain HTTP (just don't leave it on in production). + } + + func ShowSignupForm(w http.ResponseWriter, r *http.Request) { + // signup_form.tmpl just needs a {{ .csrfField }} template tag for + // csrf.TemplateField to inject the CSRF token into. Easy! + t.ExecuteTemplate(w, "signup_form.tmpl", map[string]interface{}{ + csrf.TemplateTag: csrf.TemplateField(r), + }) + } + + func SubmitSignupForm(w http.ResponseWriter, r *http.Request) { + // We can trust that requests making it this far have satisfied + // our CSRF protection requirements. + fmt.Fprintf(w, "%v\n", r.PostForm) + } Note that the CSRF middleware will (by necessity) consume the request body if the token is passed via POST form values. If you need to consume this in your @@ -101,39 +103,39 @@ You can also send the CSRF token in the response header. This approach is useful if you're using a front-end JavaScript framework like Ember or Angular, or are providing a JSON API: - package main + package main - import ( - "github.com/gorilla/csrf" - "github.com/gorilla/mux" - ) + import ( + "github.com/gorilla/csrf" + "github.com/gorilla/mux" + ) - func main() { - r := mux.NewRouter() + func main() { + r := mux.NewRouter() - api := r.PathPrefix("/api").Subrouter() - api.HandleFunc("/user/:id", GetUser).Methods("GET") + api := r.PathPrefix("/api").Subrouter() + api.HandleFunc("/user/:id", GetUser).Methods("GET") - http.ListenAndServe(":8000", - csrf.Protect([]byte("32-byte-long-auth-key"))(r)) - } + http.ListenAndServe(":8000", + csrf.Protect([]byte("32-byte-long-auth-key"))(r)) + } - func GetUser(w http.ResponseWriter, r *http.Request) { - // Authenticate the request, get the id from the route params, - // and fetch the user from the DB, etc. + func GetUser(w http.ResponseWriter, r *http.Request) { + // Authenticate the request, get the id from the route params, + // and fetch the user from the DB, etc. - // Get the token and pass it in the CSRF header. Our JSON-speaking client - // or JavaScript framework can now read the header and return the token in - // in its own "X-CSRF-Token" request header on the subsequent POST. - w.Header().Set("X-CSRF-Token", csrf.Token(r)) - b, err := json.Marshal(user) - if err != nil { - http.Error(w, err.Error(), 500) - return - } + // Get the token and pass it in the CSRF header. Our JSON-speaking client + // or JavaScript framework can now read the header and return the token in + // in its own "X-CSRF-Token" request header on the subsequent POST. + w.Header().Set("X-CSRF-Token", csrf.Token(r)) + b, err := json.Marshal(user) + if err != nil { + http.Error(w, err.Error(), 500) + return + } - w.Write(b) - } + w.Write(b) + } If you're writing a client that's supposed to mimic browser behavior, make sure to send back the CSRF cookie (the default name is _gorilla_csrf, but this can be changed @@ -141,23 +143,29 @@ with the CookieName Option) along with either the X-CSRF-Token header or the gor In addition: getting CSRF protection right is important, so here's some background: - * This library generates unique-per-request (masked) tokens as a mitigation - against the [BREACH attack](http://breachattack.com/). - * The 'base' (unmasked) token is stored in the session, which means that - multiple browser tabs won't cause a user problems as their per-request token - is compared with the base token. - * Operates on a "whitelist only" approach where safe (non-mutating) HTTP methods - (GET, HEAD, OPTIONS, TRACE) are the *only* methods where token validation is not - enforced. - * The design is based on the battle-tested - [Django](https://docs.djangoproject.com/en/1.8/ref/csrf/) and [Ruby on - Rails](http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html) - approaches. - * Cookies are authenticated and based on the [securecookie](https://github.com/gorilla/securecookie) - library. They're also Secure (issued over HTTPS only) and are HttpOnly - by default, because sane defaults are important. - * Go's `crypto/rand` library is used to generate the 32 byte (256 bit) tokens - and the one-time-pad used for masking them. +* This library generates unique-per-request (masked) tokens as a mitigation +against the BREACH attack (http://breachattack.com/). + +* The 'base' (unmasked) token is stored in the session, which means that +multiple browser tabs won't cause a user problems as their per-request token +is compared with the base token. + +* Operates on a "whitelist only" approach where safe (non-mutating) HTTP methods +(GET, HEAD, OPTIONS, TRACE) are the *only* methods where token validation is not +enforced. + +* The design is based on the battle-tested Django +(https://docs.djangoproject.com/en/1.8/ref/csrf/) and Ruby on Rails +(http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html) +approaches. + +* Cookies are authenticated and based on the securecookie +(https://github.com/gorilla/securecookie) library. They're also Secure (issued +over HTTPS only) and are HttpOnly by default, because sane defaults are +important. + +* Go's `crypto/rand` library is used to generate the 32 byte (256 bit) tokens +and the one-time-pad used for masking them. This library does not seek to be adventurous. diff --git a/vendor/github.com/gorilla/handlers/handlers.go b/vendor/github.com/gorilla/handlers/handlers.go index 551f8ff..75db7f8 100644 --- a/vendor/github.com/gorilla/handlers/handlers.go +++ b/vendor/github.com/gorilla/handlers/handlers.go @@ -79,9 +79,9 @@ func (h combinedLoggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Reque } func makeLogger(w http.ResponseWriter) loggingResponseWriter { - var logger loggingResponseWriter = &responseLogger{w: w} + var logger loggingResponseWriter = &responseLogger{w: w, status: http.StatusOK} if _, ok := w.(http.Hijacker); ok { - logger = &hijackLogger{responseLogger{w: w}} + logger = &hijackLogger{responseLogger{w: w, status: http.StatusOK}} } h, ok1 := logger.(http.Hijacker) c, ok2 := w.(http.CloseNotifier) @@ -114,10 +114,6 @@ func (l *responseLogger) Header() http.Header { } func (l *responseLogger) Write(b []byte) (int, error) { - if l.status == 0 { - // The status will be StatusOK if WriteHeader has not been called yet - l.status = http.StatusOK - } size, err := l.w.Write(b) l.size += size return size, err diff --git a/vendor/github.com/gorilla/mux/README.md b/vendor/github.com/gorilla/mux/README.md index cdab878..b096bf6 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) --- @@ -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: @@ -168,7 +176,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: @@ -179,6 +186,7 @@ package main import ( "fmt" "net/http" + "strings" "github.com/gorilla/mux" ) @@ -190,15 +198,25 @@ func handler(w http.ResponseWriter, r *http.Request) { func main() { r := mux.NewRouter() r.HandleFunc("/", handler) - r.HandleFunc("/products", handler) - r.HandleFunc("/articles", handler) - r.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 { return err } - fmt.Println(t) + // 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[^/]+)$' + 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 }) http.Handle("/", r) @@ -258,19 +276,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. @@ -308,6 +328,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[^/]+)$'. + 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 00daf4a..cce30b2 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 d66ec38..fb69196 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/regexp.go b/vendor/github.com/gorilla/mux/regexp.go index 0189ad3..80d1f78 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 5544c1f..6863adb 100644 --- a/vendor/github.com/gorilla/mux/route.go +++ b/vendor/github.com/gorilla/mux/route.go @@ -31,6 +31,8 @@ type Route struct { 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. buildOnly bool // The name used to build URLs. @@ -50,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 @@ -66,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) @@ -394,6 +412,9 @@ func (r *Route) Schemes(schemes ...string) *Route { for k, v := range schemes { schemes[k] = strings.ToLower(v) } + if r.buildScheme == "" && len(schemes) > 0 { + r.buildScheme = schemes[0] + } return r.addMatcher(schemeMatcher(schemes)) } @@ -477,22 +498,33 @@ 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 { - // Set a default scheme. - scheme = "http" if host, err = r.regexp.host.url(values); err != nil { return nil, err } + scheme = "http" + if s := r.getBuildScheme(); s != "" { + scheme = s + } } if r.regexp.path != nil { if path, err = r.regexp.path.url(values); err != nil { 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 } @@ -514,10 +546,14 @@ func (r *Route) URLHost(pairs ...string) (*url.URL, error) { if err != nil { return nil, err } - return &url.URL{ + u := &url.URL{ Scheme: "http", 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(). @@ -558,6 +594,36 @@ func (r *Route) GetPathTemplate() (string, error) { 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 // route match. // This is useful for building simple REST API documentation and for instrumentation @@ -599,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 { diff --git a/vendor/github.com/gorilla/sessions/README.md b/vendor/github.com/gorilla/sessions/README.md index ebc60d0..10eb7f0 100644 --- a/vendor/github.com/gorilla/sessions/README.md +++ b/vendor/github.com/gorilla/sessions/README.md @@ -44,14 +44,14 @@ Let's start with an example that shows the sessions API in a nutshell: First we initialize a session store calling `NewCookieStore()` and passing a secret key used to authenticate the session. Inside the handler, we call -`store.Get()` to retrieve an existing session or a new one. Then we set some -session values in session.Values, which is a `map[interface{}]interface{}`. +`store.Get()` to retrieve an existing session or create a new one. Then we set +some session values in session.Values, which is a `map[interface{}]interface{}`. And finally we call `session.Save()` to save the session in the response. Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with [`context.ClearHandler`](http://www.gorillatoolkit.org/pkg/context#ClearHandler) -as or else you will leak memory! An easy way to do this is to wrap the top-level +or else you will leak memory! An easy way to do this is to wrap the top-level mux when calling http.ListenAndServe: ```go diff --git a/vendor/github.com/gorilla/sessions/doc.go b/vendor/github.com/gorilla/sessions/doc.go index 668e05e..591d932 100644 --- a/vendor/github.com/gorilla/sessions/doc.go +++ b/vendor/github.com/gorilla/sessions/doc.go @@ -29,8 +29,7 @@ Let's start with an example that shows the sessions API in a nutshell: var store = sessions.NewCookieStore([]byte("something-very-secret")) func MyHandler(w http.ResponseWriter, r *http.Request) { - // Get a session. We're ignoring the error resulted from decoding an - // existing session: Get() always returns a session, even if empty. + // Get a session. Get() always returns a session, even if empty. session, err := store.Get(r, "session-name") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) -- cgit v1.2.3