mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
vendor: use tags for gorilla projects
Signed-off-by: Alexander Morozov <lk4d4@docker.com>
This commit is contained in:
parent
2684459ed4
commit
98530ac8e2
8 changed files with 620 additions and 86 deletions
|
@ -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/Sirupsen/logrus v0.10.0 # logrus is a common dependency among multiple deps
|
||||||
clone git github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
|
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/go-check/check 03a4d9dcf2f92eae8e90ed42aa2656f63fdd0b14 https://github.com/cpuguy83/check.git
|
||||||
clone git github.com/gorilla/context 14f550f51a
|
clone git github.com/gorilla/context v1.1
|
||||||
clone git github.com/gorilla/mux e444e69cbd
|
clone git github.com/gorilla/mux v1.1
|
||||||
clone git github.com/kr/pty 5cf931ef8f
|
clone git github.com/kr/pty 5cf931ef8f
|
||||||
clone git github.com/mattn/go-shellwords v1.0.0
|
clone git github.com/mattn/go-shellwords v1.0.0
|
||||||
clone git github.com/mattn/go-sqlite3 v1.1.0
|
clone git github.com/mattn/go-sqlite3 v1.1.0
|
||||||
|
|
|
@ -1,7 +1,19 @@
|
||||||
language: go
|
language: go
|
||||||
|
sudo: false
|
||||||
|
|
||||||
go:
|
matrix:
|
||||||
- 1.0
|
include:
|
||||||
- 1.1
|
- go: 1.3
|
||||||
- 1.2
|
- go: 1.4
|
||||||
- tip
|
- 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 ./...
|
||||||
|
|
23
vendor/src/github.com/gorilla/mux/.travis.yml
vendored
23
vendor/src/github.com/gorilla/mux/.travis.yml
vendored
|
@ -1,7 +1,20 @@
|
||||||
language: go
|
language: go
|
||||||
|
sudo: false
|
||||||
|
|
||||||
go:
|
matrix:
|
||||||
- 1.0
|
include:
|
||||||
- 1.1
|
- go: 1.2
|
||||||
- 1.2
|
- go: 1.3
|
||||||
- tip
|
- 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 ./...
|
||||||
|
|
241
vendor/src/github.com/gorilla/mux/README.md
vendored
241
vendor/src/github.com/gorilla/mux/README.md
vendored
|
@ -1,7 +1,242 @@
|
||||||
mux
|
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.
|
||||||
|
|
31
vendor/src/github.com/gorilla/mux/doc.go
vendored
31
vendor/src/github.com/gorilla/mux/doc.go
vendored
|
@ -3,7 +3,7 @@
|
||||||
// license that can be found in the LICENSE file.
|
// 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
|
The name mux stands for "HTTP request multiplexer". Like the standard
|
||||||
http.ServeMux, mux.Router matches incoming requests against a list of
|
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:
|
pattern to be matched. They can also have variables:
|
||||||
|
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
// Only matches if domain is "www.domain.com".
|
// Only matches if domain is "www.example.com".
|
||||||
r.Host("www.domain.com")
|
r.Host("www.example.com")
|
||||||
// Matches a dynamic subdomain.
|
// Matches a dynamic subdomain.
|
||||||
r.Host("{subdomain:[a-z]+}.domain.com")
|
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 {
|
r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
|
||||||
return r.ProtoMajor == 0
|
return r.ProtoMajor == 0
|
||||||
})
|
})
|
||||||
|
|
||||||
...and finally, it is possible to combine several matchers in a single route:
|
...and finally, it is possible to combine several matchers in a single route:
|
||||||
|
|
||||||
r.HandleFunc("/products", ProductsHandler).
|
r.HandleFunc("/products", ProductsHandler).
|
||||||
Host("www.domain.com").
|
Host("www.example.com").
|
||||||
Methods("GET").
|
Methods("GET").
|
||||||
Schemes("http")
|
Schemes("http")
|
||||||
|
|
||||||
|
@ -103,11 +103,11 @@ a way to group several routes that share the same requirements.
|
||||||
We call it "subrouting".
|
We call it "subrouting".
|
||||||
|
|
||||||
For example, let's say we have several URLs that should only match when the
|
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:
|
from it:
|
||||||
|
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
s := r.Host("www.domain.com").Subrouter()
|
s := r.Host("www.example.com").Subrouter()
|
||||||
|
|
||||||
Then register routes in the 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)
|
s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
|
||||||
|
|
||||||
The three URL paths we registered above will only be tested if the domain is
|
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
|
only convenient, but also optimizes request matching. You can create
|
||||||
subrouters combining any attribute matchers accepted by a route.
|
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.String() will be "http://news.domain.com/articles/technology/42"
|
||||||
url, err := r.Get("article").URL("subdomain", "news",
|
url, err := r.Get("article").URL("subdomain", "news",
|
||||||
"category", "technology",
|
"category", "technology",
|
||||||
"id", "42")
|
"id", "42")
|
||||||
|
|
||||||
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
|
||||||
generated URL will always match a registered route -- the only exception is
|
generated URL will always match a registered route -- the only exception is
|
||||||
for explicitly defined "build-only" routes which never match.
|
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:
|
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,
|
use the methods URLHost() or URLPath() instead. For the previous route,
|
||||||
we would do:
|
we would do:
|
||||||
|
@ -193,7 +200,7 @@ as well:
|
||||||
|
|
||||||
// "http://news.domain.com/articles/technology/42"
|
// "http://news.domain.com/articles/technology/42"
|
||||||
url, err := r.Get("article").URL("subdomain", "news",
|
url, err := r.Get("article").URL("subdomain", "news",
|
||||||
"category", "technology",
|
"category", "technology",
|
||||||
"id", "42")
|
"id", "42")
|
||||||
*/
|
*/
|
||||||
package mux
|
package mux
|
||||||
|
|
154
vendor/src/github.com/gorilla/mux/mux.go
vendored
154
vendor/src/github.com/gorilla/mux/mux.go
vendored
|
@ -5,9 +5,11 @@
|
||||||
package mux
|
package mux
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
"github.com/gorilla/context"
|
"github.com/gorilla/context"
|
||||||
)
|
)
|
||||||
|
@ -57,6 +59,12 @@ func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Closest match for a router (includes sub-routers)
|
||||||
|
if r.NotFoundHandler != nil {
|
||||||
|
match.Handler = r.NotFoundHandler
|
||||||
|
return true
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +76,7 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
// 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(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:
|
// 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
|
// http://code.google.com/p/go/issues/detail?id=5252
|
||||||
url := *req.URL
|
url := *req.URL
|
||||||
|
@ -87,10 +95,7 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
setCurrentRoute(req, match.Route)
|
setCurrentRoute(req, match.Route)
|
||||||
}
|
}
|
||||||
if handler == nil {
|
if handler == nil {
|
||||||
handler = r.NotFoundHandler
|
handler = http.NotFoundHandler()
|
||||||
if handler == nil {
|
|
||||||
handler = http.NotFoundHandler()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if !r.KeepContext {
|
if !r.KeepContext {
|
||||||
defer context.Clear(req)
|
defer context.Clear(req)
|
||||||
|
@ -152,6 +157,13 @@ func (r *Router) getRegexpGroup() *routeRegexpGroup {
|
||||||
return nil
|
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
|
// Route factories
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -224,6 +236,58 @@ func (r *Router) Schemes(schemes ...string) *Route {
|
||||||
return r.NewRoute().Schemes(schemes...)
|
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
|
// Context
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -251,6 +315,10 @@ func Vars(r *http.Request) map[string]string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CurrentRoute returns the matched route for the current request, if any.
|
// 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 {
|
func CurrentRoute(r *http.Request) *Route {
|
||||||
if rv := context.Get(r, routeKey); rv != nil {
|
if rv := context.Get(r, routeKey); rv != nil {
|
||||||
return rv.(*Route)
|
return rv.(*Route)
|
||||||
|
@ -259,11 +327,15 @@ func CurrentRoute(r *http.Request) *Route {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setVars(r *http.Request, val interface{}) {
|
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{}) {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// mapFromPairs converts variadic string parameters to a string map.
|
// checkPairs returns the count of strings passed in, and an error if
|
||||||
func mapFromPairs(pairs ...string) (map[string]string, error) {
|
// the count is not an even number.
|
||||||
|
func checkPairs(pairs ...string) (int, error) {
|
||||||
length := len(pairs)
|
length := len(pairs)
|
||||||
if length%2 != 0 {
|
if length%2 != 0 {
|
||||||
return nil, fmt.Errorf(
|
return length, fmt.Errorf(
|
||||||
"mux: number of parameters must be multiple of 2, got %v", pairs)
|
"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)
|
m := make(map[string]string, length/2)
|
||||||
for i := 0; i < length; i += 2 {
|
for i := 0; i < length; i += 2 {
|
||||||
m[pairs[i]] = pairs[i+1]
|
m[pairs[i]] = pairs[i+1]
|
||||||
|
@ -314,6 +397,24 @@ func mapFromPairs(pairs ...string) (map[string]string, error) {
|
||||||
return m, nil
|
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.
|
// matchInArray returns true if the given string value is in the array.
|
||||||
func matchInArray(arr []string, value string) bool {
|
func matchInArray(arr []string, value string) bool {
|
||||||
for _, v := range arr {
|
for _, v := range arr {
|
||||||
|
@ -324,9 +425,8 @@ func matchInArray(arr []string, value string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// matchMap returns true if the given key/value pairs exist in a given map.
|
// matchMapWithString returns true if the given key/value pairs exist in a given map.
|
||||||
func matchMap(toCheck map[string]string, toMatch map[string][]string,
|
func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool {
|
||||||
canonicalKey bool) bool {
|
|
||||||
for k, v := range toCheck {
|
for k, v := range toCheck {
|
||||||
// Check if key exists.
|
// Check if key exists.
|
||||||
if canonicalKey {
|
if canonicalKey {
|
||||||
|
@ -351,3 +451,31 @@ func matchMap(toCheck map[string]string, toMatch map[string][]string,
|
||||||
}
|
}
|
||||||
return true
|
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
|
||||||
|
}
|
||||||
|
|
98
vendor/src/github.com/gorilla/mux/regexp.go
vendored
98
vendor/src/github.com/gorilla/mux/regexp.go
vendored
|
@ -10,6 +10,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -34,8 +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 = "[^?&]*"
|
||||||
matchPrefix = true
|
|
||||||
} else if matchHost {
|
} else if matchHost {
|
||||||
defaultPattern = "[^.]+"
|
defaultPattern = "[^.]+"
|
||||||
matchPrefix = false
|
matchPrefix = false
|
||||||
|
@ -53,9 +53,7 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
|
||||||
varsN := make([]string, len(idxs)/2)
|
varsN := make([]string, len(idxs)/2)
|
||||||
varsR := make([]*regexp.Regexp, len(idxs)/2)
|
varsR := make([]*regexp.Regexp, len(idxs)/2)
|
||||||
pattern := bytes.NewBufferString("")
|
pattern := bytes.NewBufferString("")
|
||||||
if !matchQuery {
|
pattern.WriteByte('^')
|
||||||
pattern.WriteByte('^')
|
|
||||||
}
|
|
||||||
reverse := bytes.NewBufferString("")
|
reverse := bytes.NewBufferString("")
|
||||||
var end int
|
var end int
|
||||||
var err error
|
var err error
|
||||||
|
@ -75,9 +73,11 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
|
||||||
tpl[idxs[i]:end])
|
tpl[idxs[i]:end])
|
||||||
}
|
}
|
||||||
// Build the regexp pattern.
|
// 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.
|
// Build the reverse template.
|
||||||
fmt.Fprintf(reverse, "%s%%s", raw)
|
fmt.Fprintf(reverse, "%s%%s", raw)
|
||||||
|
|
||||||
// Append variable name and compiled pattern.
|
// Append variable name and compiled pattern.
|
||||||
varsN[i/2] = name
|
varsN[i/2] = name
|
||||||
varsR[i/2], err = regexp.Compile(fmt.Sprintf("^%s$", patt))
|
varsR[i/2], err = regexp.Compile(fmt.Sprintf("^%s$", patt))
|
||||||
|
@ -91,6 +91,12 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
|
||||||
if strictSlash {
|
if strictSlash {
|
||||||
pattern.WriteString("[/]?")
|
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 {
|
if !matchPrefix {
|
||||||
pattern.WriteByte('$')
|
pattern.WriteByte('$')
|
||||||
}
|
}
|
||||||
|
@ -141,20 +147,17 @@ type routeRegexp struct {
|
||||||
func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {
|
func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {
|
||||||
if !r.matchHost {
|
if !r.matchHost {
|
||||||
if r.matchQuery {
|
if r.matchQuery {
|
||||||
return r.regexp.MatchString(req.URL.RawQuery)
|
return r.matchQueryString(req)
|
||||||
} else {
|
|
||||||
return r.regexp.MatchString(req.URL.Path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return r.regexp.MatchString(req.URL.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.regexp.MatchString(getHost(req))
|
return r.regexp.MatchString(getHost(req))
|
||||||
}
|
}
|
||||||
|
|
||||||
// url builds a URL part using the given values.
|
// url builds a URL part using the given values.
|
||||||
func (r *routeRegexp) url(pairs ...string) (string, error) {
|
func (r *routeRegexp) url(values map[string]string) (string, error) {
|
||||||
values, err := mapFromPairs(pairs...)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
urlValues := make([]interface{}, len(r.varsN))
|
urlValues := make([]interface{}, len(r.varsN))
|
||||||
for k, v := range r.varsN {
|
for k, v := range r.varsN {
|
||||||
value, ok := values[v]
|
value, ok := values[v]
|
||||||
|
@ -179,11 +182,31 @@ func (r *routeRegexp) url(pairs ...string) (string, error) {
|
||||||
return rv, nil
|
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.
|
// braceIndices returns the first level curly brace indices from a string.
|
||||||
// It returns an error in case of unbalanced braces.
|
// It returns an error in case of unbalanced braces.
|
||||||
func braceIndices(s string) ([]int, error) {
|
func braceIndices(s string) ([]int, error) {
|
||||||
var level, idx int
|
var level, idx int
|
||||||
idxs := make([]int, 0)
|
var idxs []int
|
||||||
for i := 0; i < len(s); i++ {
|
for i := 0; i < len(s); i++ {
|
||||||
switch s[i] {
|
switch s[i] {
|
||||||
case '{':
|
case '{':
|
||||||
|
@ -204,6 +227,11 @@ func braceIndices(s string) ([]int, error) {
|
||||||
return idxs, nil
|
return idxs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// varGroupName builds a capturing group name for the indexed variable.
|
||||||
|
func varGroupName(idx int) string {
|
||||||
|
return "v" + strconv.Itoa(idx)
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// routeRegexpGroup
|
// routeRegexpGroup
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -219,20 +247,17 @@ type routeRegexpGroup struct {
|
||||||
func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) {
|
func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) {
|
||||||
// Store host variables.
|
// Store host variables.
|
||||||
if v.host != nil {
|
if v.host != nil {
|
||||||
hostVars := v.host.regexp.FindStringSubmatch(getHost(req))
|
host := getHost(req)
|
||||||
if hostVars != nil {
|
matches := v.host.regexp.FindStringSubmatchIndex(host)
|
||||||
for k, v := range v.host.varsN {
|
if len(matches) > 0 {
|
||||||
m.Vars[v] = hostVars[k+1]
|
extractVars(host, matches, v.host.varsN, m.Vars)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Store path variables.
|
// Store path variables.
|
||||||
if v.path != nil {
|
if v.path != nil {
|
||||||
pathVars := v.path.regexp.FindStringSubmatch(req.URL.Path)
|
matches := v.path.regexp.FindStringSubmatchIndex(req.URL.Path)
|
||||||
if pathVars != nil {
|
if len(matches) > 0 {
|
||||||
for k, v := range v.path.varsN {
|
extractVars(req.URL.Path, matches, v.path.varsN, m.Vars)
|
||||||
m.Vars[v] = pathVars[k+1]
|
|
||||||
}
|
|
||||||
// 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(req.URL.Path, "/")
|
||||||
|
@ -250,13 +275,11 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Store query string variables.
|
// Store query string variables.
|
||||||
rawQuery := req.URL.RawQuery
|
|
||||||
for _, q := range v.queries {
|
for _, q := range v.queries {
|
||||||
queryVars := q.regexp.FindStringSubmatch(rawQuery)
|
queryURL := q.getURLQuery(req)
|
||||||
if queryVars != nil {
|
matches := q.regexp.FindStringSubmatchIndex(queryURL)
|
||||||
for k, v := range q.varsN {
|
if len(matches) > 0 {
|
||||||
m.Vars[v] = queryVars[k+1]
|
extractVars(queryURL, matches, q.varsN, m.Vars)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -274,3 +297,16 @@ func getHost(r *http.Request) string {
|
||||||
return host
|
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++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
133
vendor/src/github.com/gorilla/mux/route.go
vendored
133
vendor/src/github.com/gorilla/mux/route.go
vendored
|
@ -9,6 +9,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,6 +32,8 @@ type Route struct {
|
||||||
name string
|
name string
|
||||||
// Error resulted from building a route.
|
// Error resulted from building a route.
|
||||||
err error
|
err error
|
||||||
|
|
||||||
|
buildVarsFunc BuildVarsFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match matches the route against the request.
|
// 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
|
type headerMatcher map[string]string
|
||||||
|
|
||||||
func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool {
|
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.
|
// 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")
|
// "X-Requested-With", "XMLHttpRequest")
|
||||||
//
|
//
|
||||||
// The above route will only match if both request header values match.
|
// The above route will only match if both request header values match.
|
||||||
//
|
// If the value is an empty string, it will match any value if the key is set.
|
||||||
// It the value is an empty string, it will match any value if the key is set.
|
|
||||||
func (r *Route) Headers(pairs ...string) *Route {
|
func (r *Route) Headers(pairs ...string) *Route {
|
||||||
if r.err == nil {
|
if r.err == nil {
|
||||||
var headers map[string]string
|
var headers map[string]string
|
||||||
headers, r.err = mapFromPairs(pairs...)
|
headers, r.err = mapFromPairsToString(pairs...)
|
||||||
return r.addMatcher(headerMatcher(headers))
|
return r.addMatcher(headerMatcher(headers))
|
||||||
}
|
}
|
||||||
return r
|
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 -----------------------------------------------------------------------
|
||||||
|
|
||||||
// Host adds a matcher for the URL host.
|
// Host adds a matcher for the URL host.
|
||||||
// It accepts a template with zero or more URL variables enclosed by {}.
|
// 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.
|
// - {name} matches anything until the next dot.
|
||||||
//
|
//
|
||||||
|
@ -221,7 +248,7 @@ func (r *Route) Headers(pairs ...string) *Route {
|
||||||
// For example:
|
// For example:
|
||||||
//
|
//
|
||||||
// r := mux.NewRouter()
|
// r := mux.NewRouter()
|
||||||
// r.Host("www.domain.com")
|
// r.Host("www.example.com")
|
||||||
// r.Host("{subdomain}.domain.com")
|
// r.Host("{subdomain}.domain.com")
|
||||||
// r.Host("{subdomain:[a-z]+}.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.
|
// MatcherFunc is the function signature used by custom matchers.
|
||||||
type MatcherFunc func(*http.Request, *RouteMatch) bool
|
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 {
|
func (m MatcherFunc) Match(r *http.Request, match *RouteMatch) bool {
|
||||||
return m(r, match)
|
return m(r, match)
|
||||||
}
|
}
|
||||||
|
@ -270,7 +298,7 @@ func (r *Route) Methods(methods ...string) *Route {
|
||||||
// Path adds a matcher for the URL path.
|
// Path adds a matcher for the URL path.
|
||||||
// It accepts a template with zero or more URL variables enclosed by {}. The
|
// It accepts a template with zero or more URL variables enclosed by {}. The
|
||||||
// template must start with a "/".
|
// 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.
|
// - {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.
|
// 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.
|
// - {name} matches anything until the next slash.
|
||||||
//
|
//
|
||||||
|
@ -334,7 +362,7 @@ func (r *Route) Queries(pairs ...string) *Route {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
for i := 0; i < length; i += 2 {
|
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
|
return r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,6 +388,19 @@ func (r *Route) Schemes(schemes ...string) *Route {
|
||||||
return r.addMatcher(schemeMatcher(schemes))
|
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 ------------------------------------------------------------------
|
||||||
|
|
||||||
// Subrouter creates a subrouter for the route.
|
// 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:
|
// It will test the inner routes only if the parent route matched. For example:
|
||||||
//
|
//
|
||||||
// r := mux.NewRouter()
|
// r := mux.NewRouter()
|
||||||
// s := r.Host("www.domain.com").Subrouter()
|
// s := r.Host("www.example.com").Subrouter()
|
||||||
// s.HandleFunc("/products/", ProductsHandler)
|
// s.HandleFunc("/products/", ProductsHandler)
|
||||||
// s.HandleFunc("/products/{key}", ProductHandler)
|
// s.HandleFunc("/products/{key}", ProductHandler)
|
||||||
// s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
|
// 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 {
|
if r.regexp == nil {
|
||||||
return nil, errors.New("mux: route doesn't have a host or path")
|
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 scheme, host, path string
|
||||||
var err error
|
|
||||||
if r.regexp.host != nil {
|
if r.regexp.host != nil {
|
||||||
// Set a default scheme.
|
// Set a default scheme.
|
||||||
scheme = "http"
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if r.regexp.path != nil {
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -453,7 +497,11 @@ func (r *Route) URLHost(pairs ...string) (*url.URL, error) {
|
||||||
if r.regexp == nil || r.regexp.host == nil {
|
if r.regexp == nil || r.regexp.host == nil {
|
||||||
return nil, errors.New("mux: route doesn't have a host")
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -473,7 +521,11 @@ func (r *Route) URLPath(pairs ...string) (*url.URL, error) {
|
||||||
if r.regexp == nil || r.regexp.path == nil {
|
if r.regexp == nil || r.regexp.path == nil {
|
||||||
return nil, errors.New("mux: route doesn't have a path")
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -482,6 +534,56 @@ func (r *Route) URLPath(pairs ...string) (*url.URL, error) {
|
||||||
}, nil
|
}, 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
|
// parentRoute
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -490,6 +592,7 @@ func (r *Route) URLPath(pairs ...string) (*url.URL, error) {
|
||||||
type parentRoute interface {
|
type parentRoute interface {
|
||||||
getNamedRoutes() map[string]*Route
|
getNamedRoutes() map[string]*Route
|
||||||
getRegexpGroup() *routeRegexpGroup
|
getRegexpGroup() *routeRegexpGroup
|
||||||
|
buildVars(map[string]string) map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// getNamedRoutes returns the map where named routes are registered.
|
// getNamedRoutes returns the map where named routes are registered.
|
||||||
|
|
Loading…
Add table
Reference in a new issue