فهرست منبع

Merge pull request #25502 from LK4D4/update_gorilla

vendor: use tags for gorilla projects
Justin Cormack 9 سال پیش
والد
کامیت
b2b41b2194

+ 2 - 2
hack/vendor.sh

@@ -48,8 +48,8 @@ clone git github.com/Microsoft/go-winio v0.3.4
 clone git github.com/Sirupsen/logrus v0.10.0 # logrus is a common dependency among multiple deps
 clone git github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
 clone git github.com/go-check/check 03a4d9dcf2f92eae8e90ed42aa2656f63fdd0b14 https://github.com/cpuguy83/check.git
-clone git github.com/gorilla/context 14f550f51a
-clone git github.com/gorilla/mux e444e69cbd
+clone git github.com/gorilla/context v1.1
+clone git github.com/gorilla/mux v1.1
 clone git github.com/kr/pty 5cf931ef8f
 clone git github.com/mattn/go-shellwords v1.0.0
 clone git github.com/mattn/go-sqlite3 v1.1.0

+ 17 - 5
vendor/src/github.com/gorilla/context/.travis.yml

@@ -1,7 +1,19 @@
 language: go
+sudo: false
 
-go:
-  - 1.0
-  - 1.1
-  - 1.2
-  - tip
+matrix:
+  include:
+    - go: 1.3
+    - go: 1.4
+    - go: 1.5
+    - go: 1.6
+    - go: tip
+
+install:
+  - go get golang.org/x/tools/cmd/vet
+
+script:
+  - go get -t -v ./...
+  - diff -u <(echo -n) <(gofmt -d .)
+  - go tool vet .
+  - go test -v -race ./...

+ 18 - 5
vendor/src/github.com/gorilla/mux/.travis.yml

@@ -1,7 +1,20 @@
 language: go
+sudo: false
 
-go:
-  - 1.0
-  - 1.1
-  - 1.2
-  - tip
+matrix:
+  include:
+    - go: 1.2
+    - go: 1.3
+    - go: 1.4
+    - go: 1.5
+    - go: 1.6
+    - go: tip
+
+install:
+  - go get golang.org/x/tools/cmd/vet
+
+script:
+  - go get -t -v ./...
+  - diff -u <(echo -n) <(gofmt -d .)
+  - go tool vet .
+  - go test -v -race ./...

+ 238 - 3
vendor/src/github.com/gorilla/mux/README.md

@@ -1,7 +1,242 @@
 mux
 ===
-[![Build Status](https://travis-ci.org/gorilla/mux.png?branch=master)](https://travis-ci.org/gorilla/mux)
+[![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux)
+[![Build Status](https://travis-ci.org/gorilla/mux.svg?branch=master)](https://travis-ci.org/gorilla/mux)
 
-gorilla/mux is a powerful URL router and dispatcher.
+http://www.gorillatoolkit.org/pkg/mux
 
-Read the full documentation here: http://www.gorillatoolkit.org/pkg/mux
+Package `gorilla/mux` implements a request router and dispatcher.
+
+The name mux stands for "HTTP request multiplexer". Like the standard `http.ServeMux`, `mux.Router` matches incoming requests against a list of registered routes and calls a handler for the route that matches the URL 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.
+* 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.
+* It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`.
+
+Let's start registering a couple of URL paths and handlers:
+
+```go
+func main() {
+	r := mux.NewRouter()
+	r.HandleFunc("/", HomeHandler)
+	r.HandleFunc("/products", ProductsHandler)
+	r.HandleFunc("/articles", ArticlesHandler)
+	http.Handle("/", r)
+}
+```
+
+Here we register three routes mapping URL paths to handlers. This is equivalent to how `http.HandleFunc()` works: if an incoming request URL matches one of the paths, the corresponding handler is called passing (`http.ResponseWriter`, `*http.Request`) as parameters.
+
+Paths can have variables. They are defined using the format `{name}` or `{name:pattern}`. If a regular expression pattern is not defined, the matched variable will be anything until the next slash. For example:
+
+```go
+r := mux.NewRouter()
+r.HandleFunc("/products/{key}", ProductHandler)
+r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
+r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
+```
+
+The names are used to create a map of route variables which can be retrieved calling `mux.Vars()`:
+
+```go
+vars := mux.Vars(request)
+category := vars["category"]
+```
+
+And this is all you need to know about the basic usage. More advanced options are explained below.
+
+Routes can also be restricted to a domain or subdomain. Just define a host pattern to be matched. They can also have variables:
+
+```go
+r := mux.NewRouter()
+// Only matches if domain is "www.example.com".
+r.Host("www.example.com")
+// Matches a dynamic subdomain.
+r.Host("{subdomain:[a-z]+}.domain.com")
+```
+
+There are several other matchers that can be added. To match path prefixes:
+
+```go
+r.PathPrefix("/products/")
+```
+
+...or HTTP methods:
+
+```go
+r.Methods("GET", "POST")
+```
+
+...or URL schemes:
+
+```go
+r.Schemes("https")
+```
+
+...or header values:
+
+```go
+r.Headers("X-Requested-With", "XMLHttpRequest")
+```
+
+...or query values:
+
+```go
+r.Queries("key", "value")
+```
+
+...or to use a custom matcher function:
+
+```go
+r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
+	return r.ProtoMajor == 0
+})
+```
+
+...and finally, it is possible to combine several matchers in a single route:
+
+```go
+r.HandleFunc("/products", ProductsHandler).
+  Host("www.example.com").
+  Methods("GET").
+  Schemes("http")
+```
+
+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:
+
+```go
+r := mux.NewRouter()
+s := r.Host("www.example.com").Subrouter()
+```
+
+Then register routes in the subrouter:
+
+```go
+s.HandleFunc("/products/", ProductsHandler)
+s.HandleFunc("/products/{key}", ProductHandler)
+s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
+```
+
+The three URL paths we registered above will only be tested if the domain is `www.example.com`, because the subrouter is tested first. This is not only convenient, but also optimizes request matching. You can create subrouters combining any attribute matchers accepted by a route.
+
+Subrouters can be used to create domain or path "namespaces": you define subrouters in a central place and then parts of the app can register its paths relatively to a given subrouter.
+
+There's one more thing about subroutes. When a subrouter has a path prefix, the inner routes use it as base for their paths:
+
+```go
+r := mux.NewRouter()
+s := r.PathPrefix("/products").Subrouter()
+// "/products/"
+s.HandleFunc("/", ProductsHandler)
+// "/products/{key}/"
+s.HandleFunc("/{key}/", ProductHandler)
+// "/products/{key}/details"
+s.HandleFunc("/{key}/details", ProductDetailsHandler)
+```
+
+Now let's see how to build registered URLs.
+
+Routes can be named. All routes that define a name can have their URLs built, or "reversed". We define a name calling `Name()` on a route. For example:
+
+```go
+r := mux.NewRouter()
+r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
+  Name("article")
+```
+
+To build a URL, get the route and call the `URL()` method, passing a sequence of key/value pairs for the route variables. For the previous route, we would do:
+
+```go
+url, err := r.Get("article").URL("category", "technology", "id", "42")
+```
+
+...and the result will be a `url.URL` with the following path:
+
+```
+"/articles/technology/42"
+```
+
+This also works for host variables:
+
+```go
+r := mux.NewRouter()
+r.Host("{subdomain}.domain.com").
+  Path("/articles/{category}/{id:[0-9]+}").
+  HandlerFunc(ArticleHandler).
+  Name("article")
+
+// url.String() will be "http://news.domain.com/articles/technology/42"
+url, err := r.Get("article").URL("subdomain", "news",
+                                 "category", "technology",
+                                 "id", "42")
+```
+
+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.
+
+Regex support also exists for matching Headers within a route. For example, we could do:
+
+```go
+r.HeadersRegexp("Content-Type", "application/(text|json)")
+```
+
+...and the route will match both requests with a Content-Type of `application/json` as well as `application/text`
+
+There's also a way to build only the URL host or path for a route: use the methods `URLHost()` or `URLPath()` instead. For the previous route, we would do:
+
+```go
+// "http://news.domain.com/"
+host, err := r.Get("article").URLHost("subdomain", "news")
+
+// "/articles/technology/42"
+path, err := r.Get("article").URLPath("category", "technology", "id", "42")
+```
+
+And if you use subrouters, host and path defined separately can be built as well:
+
+```go
+r := mux.NewRouter()
+s := r.Host("{subdomain}.domain.com").Subrouter()
+s.Path("/articles/{category}/{id:[0-9]+}").
+  HandlerFunc(ArticleHandler).
+  Name("article")
+
+// "http://news.domain.com/articles/technology/42"
+url, err := r.Get("article").URL("subdomain", "news",
+                                 "category", "technology",
+                                 "id", "42")
+```
+
+## Full Example
+
+Here's a complete, runnable example of a small `mux` based server:
+
+```go
+package main
+
+import (
+	"net/http"
+
+	"github.com/gorilla/mux"
+)
+
+func YourHandler(w http.ResponseWriter, r *http.Request) {
+	w.Write([]byte("Gorilla!\n"))
+}
+
+func main() {
+	r := mux.NewRouter()
+	// Routes consist of a path and a handler function.
+	r.HandleFunc("/", YourHandler)
+
+	// Bind to a port and pass our router in
+	http.ListenAndServe(":8000", r)
+}
+```
+
+## License
+
+BSD licensed. See the LICENSE file for details.

+ 19 - 12
vendor/src/github.com/gorilla/mux/doc.go

@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 /*
-Package gorilla/mux implements a request router and dispatcher.
+Package mux implements a request router and dispatcher.
 
 The name mux stands for "HTTP request multiplexer". Like the standard
 http.ServeMux, mux.Router matches incoming requests against a list of
@@ -60,8 +60,8 @@ Routes can also be restricted to a domain or subdomain. Just define a host
 pattern to be matched. They can also have variables:
 
 	r := mux.NewRouter()
-	// Only matches if domain is "www.domain.com".
-	r.Host("www.domain.com")
+	// Only matches if domain is "www.example.com".
+	r.Host("www.example.com")
 	// Matches a dynamic subdomain.
 	r.Host("{subdomain:[a-z]+}.domain.com")
 
@@ -89,12 +89,12 @@ There are several other matchers that can be added. To match path prefixes:
 
 	r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
 		return r.ProtoMajor == 0
-    })
+	})
 
 ...and finally, it is possible to combine several matchers in a single route:
 
 	r.HandleFunc("/products", ProductsHandler).
-	  Host("www.domain.com").
+	  Host("www.example.com").
 	  Methods("GET").
 	  Schemes("http")
 
@@ -103,11 +103,11 @@ 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.domain.com". Create a route for that host and get a "subrouter"
+host is "www.example.com". Create a route for that host and get a "subrouter"
 from it:
 
 	r := mux.NewRouter()
-	s := r.Host("www.domain.com").Subrouter()
+	s := r.Host("www.example.com").Subrouter()
 
 Then register routes in the subrouter:
 
@@ -116,7 +116,7 @@ Then register routes in the subrouter:
 	s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
 
 The three URL paths we registered above will only be tested if the domain is
-"www.domain.com", because the subrouter is tested first. This is not
+"www.example.com", because the subrouter is tested first. This is not
 only convenient, but also optimizes request matching. You can create
 subrouters combining any attribute matchers accepted by a route.
 
@@ -164,14 +164,21 @@ This also works for host variables:
 
 	// url.String() will be "http://news.domain.com/articles/technology/42"
 	url, err := r.Get("article").URL("subdomain", "news",
-									 "category", "technology",
-									 "id", "42")
+	                                 "category", "technology",
+	                                 "id", "42")
 
 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.
 
+Regex support also exists for matching Headers within a route. For example, we could do:
+
+	r.HeadersRegexp("Content-Type", "application/(text|json)")
+
+...and the route will match both requests with a Content-Type of `application/json` as well as
+`application/text`
+
 There's also a way to build only the URL host or path for a route:
 use the methods URLHost() or URLPath() instead. For the previous route,
 we would do:
@@ -193,7 +200,7 @@ as well:
 
 	// "http://news.domain.com/articles/technology/42"
 	url, err := r.Get("article").URL("subdomain", "news",
-									 "category", "technology",
-									 "id", "42")
+	                                 "category", "technology",
+	                                 "id", "42")
 */
 package mux

+ 141 - 13
vendor/src/github.com/gorilla/mux/mux.go

@@ -5,9 +5,11 @@
 package mux
 
 import (
+	"errors"
 	"fmt"
 	"net/http"
 	"path"
+	"regexp"
 
 	"github.com/gorilla/context"
 )
@@ -57,6 +59,12 @@ func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
 			return true
 		}
 	}
+
+	// Closest match for a router (includes sub-routers)
+	if r.NotFoundHandler != nil {
+		match.Handler = r.NotFoundHandler
+		return true
+	}
 	return false
 }
 
@@ -68,7 +76,7 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 	// Clean path to canonical form and redirect.
 	if p := cleanPath(req.URL.Path); p != req.URL.Path {
 
-		// Added 3 lines (Philip Schlump) - It was droping 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:
 		// http://code.google.com/p/go/issues/detail?id=5252
 		url := *req.URL
@@ -87,10 +95,7 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 		setCurrentRoute(req, match.Route)
 	}
 	if handler == nil {
-		handler = r.NotFoundHandler
-		if handler == nil {
-			handler = http.NotFoundHandler()
-		}
+		handler = http.NotFoundHandler()
 	}
 	if !r.KeepContext {
 		defer context.Clear(req)
@@ -152,6 +157,13 @@ func (r *Router) getRegexpGroup() *routeRegexpGroup {
 	return nil
 }
 
+func (r *Router) buildVars(m map[string]string) map[string]string {
+	if r.parent != nil {
+		m = r.parent.buildVars(m)
+	}
+	return m
+}
+
 // ----------------------------------------------------------------------------
 // Route factories
 // ----------------------------------------------------------------------------
@@ -224,6 +236,58 @@ func (r *Router) Schemes(schemes ...string) *Route {
 	return r.NewRoute().Schemes(schemes...)
 }
 
+// BuildVarsFunc registers a new route with a custom function for modifying
+// route variables before building a URL.
+func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route {
+	return r.NewRoute().BuildVarsFunc(f)
+}
+
+// Walk walks the router and all its sub-routers, calling walkFn for each route
+// in the tree. The routes are walked in the order they were added. Sub-routers
+// are explored depth-first.
+func (r *Router) Walk(walkFn WalkFunc) error {
+	return r.walk(walkFn, []*Route{})
+}
+
+// SkipRouter is used as a return value from WalkFuncs to indicate that the
+// router that walk is about to descend down to should be skipped.
+var SkipRouter = errors.New("skip this router")
+
+// WalkFunc is the type of the function called for each route visited by Walk.
+// At every invocation, it is given the current route, and the current router,
+// and a list of ancestor routes that lead to the current route.
+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
+		}
+		for _, sr := range t.matchers {
+			if h, ok := sr.(*Router); ok {
+				err := h.walk(walkFn, ancestors)
+				if err != nil {
+					return err
+				}
+			}
+		}
+		if h, ok := t.handler.(*Router); ok {
+			ancestors = append(ancestors, t)
+			err := h.walk(walkFn, ancestors)
+			if err != nil {
+				return err
+			}
+			ancestors = ancestors[:len(ancestors)-1]
+		}
+	}
+	return nil
+}
+
 // ----------------------------------------------------------------------------
 // Context
 // ----------------------------------------------------------------------------
@@ -251,6 +315,10 @@ func Vars(r *http.Request) map[string]string {
 }
 
 // CurrentRoute returns the matched route for the current request, if any.
+// This only works when called inside the handler of the matched route
+// because the matched route is stored in the request context which is cleared
+// after the handler returns, unless the KeepContext option is set on the
+// Router.
 func CurrentRoute(r *http.Request) *Route {
 	if rv := context.Get(r, routeKey); rv != nil {
 		return rv.(*Route)
@@ -259,11 +327,15 @@ func CurrentRoute(r *http.Request) *Route {
 }
 
 func setVars(r *http.Request, val interface{}) {
-	context.Set(r, varsKey, val)
+	if val != nil {
+		context.Set(r, varsKey, val)
+	}
 }
 
 func setCurrentRoute(r *http.Request, val interface{}) {
-	context.Set(r, routeKey, val)
+	if val != nil {
+		context.Set(r, routeKey, val)
+	}
 }
 
 // ----------------------------------------------------------------------------
@@ -300,13 +372,24 @@ func uniqueVars(s1, s2 []string) error {
 	return nil
 }
 
-// mapFromPairs converts variadic string parameters to a string map.
-func mapFromPairs(pairs ...string) (map[string]string, error) {
+// checkPairs returns the count of strings passed in, and an error if
+// the count is not an even number.
+func checkPairs(pairs ...string) (int, error) {
 	length := len(pairs)
 	if length%2 != 0 {
-		return nil, fmt.Errorf(
+		return length, fmt.Errorf(
 			"mux: number of parameters must be multiple of 2, got %v", pairs)
 	}
+	return length, nil
+}
+
+// mapFromPairsToString converts variadic string parameters to a
+// string to string map.
+func mapFromPairsToString(pairs ...string) (map[string]string, error) {
+	length, err := checkPairs(pairs...)
+	if err != nil {
+		return nil, err
+	}
 	m := make(map[string]string, length/2)
 	for i := 0; i < length; i += 2 {
 		m[pairs[i]] = pairs[i+1]
@@ -314,6 +397,24 @@ func mapFromPairs(pairs ...string) (map[string]string, error) {
 	return m, nil
 }
 
+// mapFromPairsToRegex converts variadic string paramers to a
+// string to regex map.
+func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
+	length, err := checkPairs(pairs...)
+	if err != nil {
+		return nil, err
+	}
+	m := make(map[string]*regexp.Regexp, length/2)
+	for i := 0; i < length; i += 2 {
+		regex, err := regexp.Compile(pairs[i+1])
+		if err != nil {
+			return nil, err
+		}
+		m[pairs[i]] = regex
+	}
+	return m, nil
+}
+
 // matchInArray returns true if the given string value is in the array.
 func matchInArray(arr []string, value string) bool {
 	for _, v := range arr {
@@ -324,9 +425,8 @@ func matchInArray(arr []string, value string) bool {
 	return false
 }
 
-// matchMap returns true if the given key/value pairs exist in a given map.
-func matchMap(toCheck map[string]string, toMatch map[string][]string,
-	canonicalKey bool) bool {
+// matchMapWithString returns true if the given key/value pairs exist in a given map.
+func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool {
 	for k, v := range toCheck {
 		// Check if key exists.
 		if canonicalKey {
@@ -351,3 +451,31 @@ func matchMap(toCheck map[string]string, toMatch map[string][]string,
 	}
 	return true
 }
+
+// matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against
+// the given regex
+func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool {
+	for k, v := range toCheck {
+		// Check if key exists.
+		if canonicalKey {
+			k = http.CanonicalHeaderKey(k)
+		}
+		if values := toMatch[k]; values == nil {
+			return false
+		} else if v != nil {
+			// If value was defined as an empty string we only check that the
+			// key exists. Otherwise we also check for equality.
+			valueExists := false
+			for _, value := range values {
+				if v.MatchString(value) {
+					valueExists = true
+					break
+				}
+			}
+			if !valueExists {
+				return false
+			}
+		}
+	}
+	return true
+}

+ 67 - 31
vendor/src/github.com/gorilla/mux/regexp.go

@@ -10,6 +10,7 @@ import (
 	"net/http"
 	"net/url"
 	"regexp"
+	"strconv"
 	"strings"
 )
 
@@ -34,8 +35,7 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
 	// Now let's parse it.
 	defaultPattern := "[^/]+"
 	if matchQuery {
-		defaultPattern = "[^?&]+"
-		matchPrefix = true
+		defaultPattern = "[^?&]*"
 	} else if matchHost {
 		defaultPattern = "[^.]+"
 		matchPrefix = false
@@ -53,9 +53,7 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
 	varsN := make([]string, len(idxs)/2)
 	varsR := make([]*regexp.Regexp, len(idxs)/2)
 	pattern := bytes.NewBufferString("")
-	if !matchQuery {
-		pattern.WriteByte('^')
-	}
+	pattern.WriteByte('^')
 	reverse := bytes.NewBufferString("")
 	var end int
 	var err error
@@ -75,9 +73,11 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
 				tpl[idxs[i]:end])
 		}
 		// Build the regexp pattern.
-		fmt.Fprintf(pattern, "%s(%s)", regexp.QuoteMeta(raw), patt)
+		fmt.Fprintf(pattern, "%s(?P<%s>%s)", regexp.QuoteMeta(raw), varGroupName(i/2), patt)
+
 		// Build the reverse template.
 		fmt.Fprintf(reverse, "%s%%s", raw)
+
 		// Append variable name and compiled pattern.
 		varsN[i/2] = name
 		varsR[i/2], err = regexp.Compile(fmt.Sprintf("^%s$", patt))
@@ -91,6 +91,12 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
 	if strictSlash {
 		pattern.WriteString("[/]?")
 	}
+	if matchQuery {
+		// Add the default pattern if the query value is empty
+		if queryVal := strings.SplitN(template, "=", 2)[1]; queryVal == "" {
+			pattern.WriteString(defaultPattern)
+		}
+	}
 	if !matchPrefix {
 		pattern.WriteByte('$')
 	}
@@ -141,20 +147,17 @@ type routeRegexp struct {
 func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {
 	if !r.matchHost {
 		if r.matchQuery {
-			return r.regexp.MatchString(req.URL.RawQuery)
-		} else {
-			return r.regexp.MatchString(req.URL.Path)
+			return r.matchQueryString(req)
 		}
+
+		return r.regexp.MatchString(req.URL.Path)
 	}
+
 	return r.regexp.MatchString(getHost(req))
 }
 
 // url builds a URL part using the given values.
-func (r *routeRegexp) url(pairs ...string) (string, error) {
-	values, err := mapFromPairs(pairs...)
-	if err != nil {
-		return "", err
-	}
+func (r *routeRegexp) url(values map[string]string) (string, error) {
 	urlValues := make([]interface{}, len(r.varsN))
 	for k, v := range r.varsN {
 		value, ok := values[v]
@@ -179,11 +182,31 @@ func (r *routeRegexp) url(pairs ...string) (string, error) {
 	return rv, nil
 }
 
+// getURLQuery returns a single query parameter from a request URL.
+// For a URL with foo=bar&baz=ding, we return only the relevant key
+// value pair for the routeRegexp.
+func (r *routeRegexp) getURLQuery(req *http.Request) string {
+	if !r.matchQuery {
+		return ""
+	}
+	templateKey := strings.SplitN(r.template, "=", 2)[0]
+	for key, vals := range req.URL.Query() {
+		if key == templateKey && len(vals) > 0 {
+			return key + "=" + vals[0]
+		}
+	}
+	return ""
+}
+
+func (r *routeRegexp) matchQueryString(req *http.Request) bool {
+	return r.regexp.MatchString(r.getURLQuery(req))
+}
+
 // braceIndices returns the first level curly brace indices from a string.
 // It returns an error in case of unbalanced braces.
 func braceIndices(s string) ([]int, error) {
 	var level, idx int
-	idxs := make([]int, 0)
+	var idxs []int
 	for i := 0; i < len(s); i++ {
 		switch s[i] {
 		case '{':
@@ -204,6 +227,11 @@ func braceIndices(s string) ([]int, error) {
 	return idxs, nil
 }
 
+// varGroupName builds a capturing group name for the indexed variable.
+func varGroupName(idx int) string {
+	return "v" + strconv.Itoa(idx)
+}
+
 // ----------------------------------------------------------------------------
 // routeRegexpGroup
 // ----------------------------------------------------------------------------
@@ -219,20 +247,17 @@ type routeRegexpGroup struct {
 func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) {
 	// Store host variables.
 	if v.host != nil {
-		hostVars := v.host.regexp.FindStringSubmatch(getHost(req))
-		if hostVars != nil {
-			for k, v := range v.host.varsN {
-				m.Vars[v] = hostVars[k+1]
-			}
+		host := getHost(req)
+		matches := v.host.regexp.FindStringSubmatchIndex(host)
+		if len(matches) > 0 {
+			extractVars(host, matches, v.host.varsN, m.Vars)
 		}
 	}
 	// Store path variables.
 	if v.path != nil {
-		pathVars := v.path.regexp.FindStringSubmatch(req.URL.Path)
-		if pathVars != nil {
-			for k, v := range v.path.varsN {
-				m.Vars[v] = pathVars[k+1]
-			}
+		matches := v.path.regexp.FindStringSubmatchIndex(req.URL.Path)
+		if len(matches) > 0 {
+			extractVars(req.URL.Path, matches, v.path.varsN, m.Vars)
 			// Check if we should redirect.
 			if v.path.strictSlash {
 				p1 := strings.HasSuffix(req.URL.Path, "/")
@@ -250,13 +275,11 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
 		}
 	}
 	// Store query string variables.
-	rawQuery := req.URL.RawQuery
 	for _, q := range v.queries {
-		queryVars := q.regexp.FindStringSubmatch(rawQuery)
-		if queryVars != nil {
-			for k, v := range q.varsN {
-				m.Vars[v] = queryVars[k+1]
-			}
+		queryURL := q.getURLQuery(req)
+		matches := q.regexp.FindStringSubmatchIndex(queryURL)
+		if len(matches) > 0 {
+			extractVars(queryURL, matches, q.varsN, m.Vars)
 		}
 	}
 }
@@ -274,3 +297,16 @@ func getHost(r *http.Request) string {
 	return host
 
 }
+
+func extractVars(input string, matches []int, names []string, output map[string]string) {
+	matchesCount := 0
+	prevEnd := -1
+	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++
+		}
+	}
+}

+ 118 - 15
vendor/src/github.com/gorilla/mux/route.go

@@ -9,6 +9,7 @@ import (
 	"fmt"
 	"net/http"
 	"net/url"
+	"regexp"
 	"strings"
 )
 
@@ -31,6 +32,8 @@ type Route struct {
 	name string
 	// Error resulted from building a route.
 	err error
+
+	buildVarsFunc BuildVarsFunc
 }
 
 // Match matches the route against the request.
@@ -186,7 +189,7 @@ func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery
 type headerMatcher map[string]string
 
 func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool {
-	return matchMap(m, r.Header, true)
+	return matchMapWithString(m, r.Header, true)
 }
 
 // Headers adds a matcher for request header values.
@@ -197,22 +200,46 @@ func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool {
 //               "X-Requested-With", "XMLHttpRequest")
 //
 // The above route will only match if both request header values match.
-//
-// It the value is an empty string, it will match any value if the key is set.
+// If the value is an empty string, it will match any value if the key is set.
 func (r *Route) Headers(pairs ...string) *Route {
 	if r.err == nil {
 		var headers map[string]string
-		headers, r.err = mapFromPairs(pairs...)
+		headers, r.err = mapFromPairsToString(pairs...)
 		return r.addMatcher(headerMatcher(headers))
 	}
 	return r
 }
 
+// headerRegexMatcher matches the request against the route given a regex for the header
+type headerRegexMatcher map[string]*regexp.Regexp
+
+func (m headerRegexMatcher) Match(r *http.Request, match *RouteMatch) bool {
+	return matchMapWithRegex(m, r.Header, true)
+}
+
+// HeadersRegexp accepts a sequence of key/value pairs, where the value has regex
+// support. For example:
+//
+//     r := mux.NewRouter()
+//     r.HeadersRegexp("Content-Type", "application/(text|json)",
+//               "X-Requested-With", "XMLHttpRequest")
+//
+// The above route will only match if both the request header matches both regular expressions.
+// It the value is an empty string, it will match any value if the key is set.
+func (r *Route) HeadersRegexp(pairs ...string) *Route {
+	if r.err == nil {
+		var headers map[string]*regexp.Regexp
+		headers, r.err = mapFromPairsToRegex(pairs...)
+		return r.addMatcher(headerRegexMatcher(headers))
+	}
+	return r
+}
+
 // Host -----------------------------------------------------------------------
 
 // Host adds a matcher for the URL host.
 // It accepts a template with zero or more URL variables enclosed by {}.
-// Variables can define an optional regexp pattern to me matched:
+// Variables can define an optional regexp pattern to be matched:
 //
 // - {name} matches anything until the next dot.
 //
@@ -221,7 +248,7 @@ func (r *Route) Headers(pairs ...string) *Route {
 // For example:
 //
 //     r := mux.NewRouter()
-//     r.Host("www.domain.com")
+//     r.Host("www.example.com")
 //     r.Host("{subdomain}.domain.com")
 //     r.Host("{subdomain:[a-z]+}.domain.com")
 //
@@ -237,6 +264,7 @@ func (r *Route) Host(tpl string) *Route {
 // MatcherFunc is the function signature used by custom matchers.
 type MatcherFunc func(*http.Request, *RouteMatch) bool
 
+// Match returns the match for a given request.
 func (m MatcherFunc) Match(r *http.Request, match *RouteMatch) bool {
 	return m(r, match)
 }
@@ -270,7 +298,7 @@ func (r *Route) Methods(methods ...string) *Route {
 // Path adds a matcher for the URL path.
 // It accepts a template with zero or more URL variables enclosed by {}. The
 // template must start with a "/".
-// Variables can define an optional regexp pattern to me matched:
+// Variables can define an optional regexp pattern to be matched:
 //
 // - {name} matches anything until the next slash.
 //
@@ -321,7 +349,7 @@ func (r *Route) PathPrefix(tpl string) *Route {
 //
 // It the value is an empty string, it will match any value if the key is set.
 //
-// Variables can define an optional regexp pattern to me matched:
+// Variables can define an optional regexp pattern to be matched:
 //
 // - {name} matches anything until the next slash.
 //
@@ -334,7 +362,7 @@ func (r *Route) Queries(pairs ...string) *Route {
 		return nil
 	}
 	for i := 0; i < length; i += 2 {
-		if r.err = r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], false, true, true); r.err != nil {
+		if r.err = r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], false, false, true); r.err != nil {
 			return r
 		}
 	}
@@ -360,6 +388,19 @@ func (r *Route) Schemes(schemes ...string) *Route {
 	return r.addMatcher(schemeMatcher(schemes))
 }
 
+// BuildVarsFunc --------------------------------------------------------------
+
+// BuildVarsFunc is the function signature used by custom build variable
+// functions (which can modify route variables before a route's URL is built).
+type BuildVarsFunc func(map[string]string) map[string]string
+
+// BuildVarsFunc adds a custom function to be used to modify build variables
+// before a route's URL is built.
+func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route {
+	r.buildVarsFunc = f
+	return r
+}
+
 // Subrouter ------------------------------------------------------------------
 
 // Subrouter creates a subrouter for the route.
@@ -367,7 +408,7 @@ func (r *Route) Schemes(schemes ...string) *Route {
 // It will test the inner routes only if the parent route matched. For example:
 //
 //     r := mux.NewRouter()
-//     s := r.Host("www.domain.com").Subrouter()
+//     s := r.Host("www.example.com").Subrouter()
 //     s.HandleFunc("/products/", ProductsHandler)
 //     s.HandleFunc("/products/{key}", ProductHandler)
 //     s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
@@ -422,17 +463,20 @@ func (r *Route) URL(pairs ...string) (*url.URL, error) {
 	if r.regexp == nil {
 		return nil, errors.New("mux: route doesn't have a host or path")
 	}
+	values, err := r.prepareVars(pairs...)
+	if err != nil {
+		return nil, err
+	}
 	var scheme, host, path string
-	var err error
 	if r.regexp.host != nil {
 		// Set a default scheme.
 		scheme = "http"
-		if host, err = r.regexp.host.url(pairs...); err != nil {
+		if host, err = r.regexp.host.url(values); err != nil {
 			return nil, err
 		}
 	}
 	if r.regexp.path != nil {
-		if path, err = r.regexp.path.url(pairs...); err != nil {
+		if path, err = r.regexp.path.url(values); err != nil {
 			return nil, err
 		}
 	}
@@ -453,7 +497,11 @@ func (r *Route) URLHost(pairs ...string) (*url.URL, error) {
 	if r.regexp == nil || r.regexp.host == nil {
 		return nil, errors.New("mux: route doesn't have a host")
 	}
-	host, err := r.regexp.host.url(pairs...)
+	values, err := r.prepareVars(pairs...)
+	if err != nil {
+		return nil, err
+	}
+	host, err := r.regexp.host.url(values)
 	if err != nil {
 		return nil, err
 	}
@@ -473,7 +521,11 @@ func (r *Route) URLPath(pairs ...string) (*url.URL, error) {
 	if r.regexp == nil || r.regexp.path == nil {
 		return nil, errors.New("mux: route doesn't have a path")
 	}
-	path, err := r.regexp.path.url(pairs...)
+	values, err := r.prepareVars(pairs...)
+	if err != nil {
+		return nil, err
+	}
+	path, err := r.regexp.path.url(values)
 	if err != nil {
 		return nil, err
 	}
@@ -482,6 +534,56 @@ func (r *Route) URLPath(pairs ...string) (*url.URL, error) {
 	}, nil
 }
 
+// GetPathTemplate returns the template used to build the
+// route match.
+// 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) GetPathTemplate() (string, error) {
+	if r.err != nil {
+		return "", r.err
+	}
+	if r.regexp == nil || r.regexp.path == nil {
+		return "", errors.New("mux: route doesn't have a path")
+	}
+	return r.regexp.path.template, nil
+}
+
+// GetHostTemplate returns the template used to build the
+// route match.
+// 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 host.
+func (r *Route) GetHostTemplate() (string, error) {
+	if r.err != nil {
+		return "", r.err
+	}
+	if r.regexp == nil || r.regexp.host == nil {
+		return "", errors.New("mux: route doesn't have a host")
+	}
+	return r.regexp.host.template, nil
+}
+
+// prepareVars converts the route variable pairs into a map. If the route has a
+// BuildVarsFunc, it is invoked.
+func (r *Route) prepareVars(pairs ...string) (map[string]string, error) {
+	m, err := mapFromPairsToString(pairs...)
+	if err != nil {
+		return nil, err
+	}
+	return r.buildVars(m), nil
+}
+
+func (r *Route) buildVars(m map[string]string) map[string]string {
+	if r.parent != nil {
+		m = r.parent.buildVars(m)
+	}
+	if r.buildVarsFunc != nil {
+		m = r.buildVarsFunc(m)
+	}
+	return m
+}
+
 // ----------------------------------------------------------------------------
 // parentRoute
 // ----------------------------------------------------------------------------
@@ -490,6 +592,7 @@ func (r *Route) URLPath(pairs ...string) (*url.URL, error) {
 type parentRoute interface {
 	getNamedRoutes() map[string]*Route
 	getRegexpGroup() *routeRegexpGroup
+	buildVars(map[string]string) map[string]string
 }
 
 // getNamedRoutes returns the map where named routes are registered.