This release drops support for Go < 1.7, and removes the gorilla/context
dependency (which was needed for older Go versions).
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
| ... | ... |
@@ -5,8 +5,7 @@ github.com/Microsoft/go-winio v0.4.11 |
| 5 | 5 |
github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a |
| 6 | 6 |
github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git |
| 7 | 7 |
github.com/golang/gddo 9b12a26f3fbd7397dee4e20939ddca719d840d2a |
| 8 |
-github.com/gorilla/context v1.1 |
|
| 9 |
-github.com/gorilla/mux v1.6.2 |
|
| 8 |
+github.com/gorilla/mux v1.7.0 |
|
| 10 | 9 |
github.com/Microsoft/opengcs v0.3.9 |
| 11 | 10 |
github.com/kr/pty 5cf931ef8f |
| 12 | 11 |
github.com/mattn/go-shellwords v1.0.3 |
| 13 | 12 |
deleted file mode 100644 |
| ... | ... |
@@ -1,27 +0,0 @@ |
| 1 |
-Copyright (c) 2012 Rodrigo Moraes. All rights reserved. |
|
| 2 |
- |
|
| 3 |
-Redistribution and use in source and binary forms, with or without |
|
| 4 |
-modification, are permitted provided that the following conditions are |
|
| 5 |
-met: |
|
| 6 |
- |
|
| 7 |
- * Redistributions of source code must retain the above copyright |
|
| 8 |
-notice, this list of conditions and the following disclaimer. |
|
| 9 |
- * Redistributions in binary form must reproduce the above |
|
| 10 |
-copyright notice, this list of conditions and the following disclaimer |
|
| 11 |
-in the documentation and/or other materials provided with the |
|
| 12 |
-distribution. |
|
| 13 |
- * Neither the name of Google Inc. nor the names of its |
|
| 14 |
-contributors may be used to endorse or promote products derived from |
|
| 15 |
-this software without specific prior written permission. |
|
| 16 |
- |
|
| 17 |
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
| 18 |
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
| 19 |
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
| 20 |
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
| 21 |
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
| 22 |
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
| 23 |
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
| 24 |
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
| 25 |
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
| 26 |
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
| 27 |
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 28 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,7 +0,0 @@ |
| 1 |
-context |
|
| 2 |
-======= |
|
| 3 |
-[](https://travis-ci.org/gorilla/context) |
|
| 4 |
- |
|
| 5 |
-gorilla/context is a general purpose registry for global request variables. |
|
| 6 |
- |
|
| 7 |
-Read the full documentation here: http://www.gorillatoolkit.org/pkg/context |
| 8 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,143 +0,0 @@ |
| 1 |
-// Copyright 2012 The Gorilla Authors. All rights reserved. |
|
| 2 |
-// Use of this source code is governed by a BSD-style |
|
| 3 |
-// license that can be found in the LICENSE file. |
|
| 4 |
- |
|
| 5 |
-package context |
|
| 6 |
- |
|
| 7 |
-import ( |
|
| 8 |
- "net/http" |
|
| 9 |
- "sync" |
|
| 10 |
- "time" |
|
| 11 |
-) |
|
| 12 |
- |
|
| 13 |
-var ( |
|
| 14 |
- mutex sync.RWMutex |
|
| 15 |
- data = make(map[*http.Request]map[interface{}]interface{})
|
|
| 16 |
- datat = make(map[*http.Request]int64) |
|
| 17 |
-) |
|
| 18 |
- |
|
| 19 |
-// Set stores a value for a given key in a given request. |
|
| 20 |
-func Set(r *http.Request, key, val interface{}) {
|
|
| 21 |
- mutex.Lock() |
|
| 22 |
- if data[r] == nil {
|
|
| 23 |
- data[r] = make(map[interface{}]interface{})
|
|
| 24 |
- datat[r] = time.Now().Unix() |
|
| 25 |
- } |
|
| 26 |
- data[r][key] = val |
|
| 27 |
- mutex.Unlock() |
|
| 28 |
-} |
|
| 29 |
- |
|
| 30 |
-// Get returns a value stored for a given key in a given request. |
|
| 31 |
-func Get(r *http.Request, key interface{}) interface{} {
|
|
| 32 |
- mutex.RLock() |
|
| 33 |
- if ctx := data[r]; ctx != nil {
|
|
| 34 |
- value := ctx[key] |
|
| 35 |
- mutex.RUnlock() |
|
| 36 |
- return value |
|
| 37 |
- } |
|
| 38 |
- mutex.RUnlock() |
|
| 39 |
- return nil |
|
| 40 |
-} |
|
| 41 |
- |
|
| 42 |
-// GetOk returns stored value and presence state like multi-value return of map access. |
|
| 43 |
-func GetOk(r *http.Request, key interface{}) (interface{}, bool) {
|
|
| 44 |
- mutex.RLock() |
|
| 45 |
- if _, ok := data[r]; ok {
|
|
| 46 |
- value, ok := data[r][key] |
|
| 47 |
- mutex.RUnlock() |
|
| 48 |
- return value, ok |
|
| 49 |
- } |
|
| 50 |
- mutex.RUnlock() |
|
| 51 |
- return nil, false |
|
| 52 |
-} |
|
| 53 |
- |
|
| 54 |
-// GetAll returns all stored values for the request as a map. Nil is returned for invalid requests. |
|
| 55 |
-func GetAll(r *http.Request) map[interface{}]interface{} {
|
|
| 56 |
- mutex.RLock() |
|
| 57 |
- if context, ok := data[r]; ok {
|
|
| 58 |
- result := make(map[interface{}]interface{}, len(context))
|
|
| 59 |
- for k, v := range context {
|
|
| 60 |
- result[k] = v |
|
| 61 |
- } |
|
| 62 |
- mutex.RUnlock() |
|
| 63 |
- return result |
|
| 64 |
- } |
|
| 65 |
- mutex.RUnlock() |
|
| 66 |
- return nil |
|
| 67 |
-} |
|
| 68 |
- |
|
| 69 |
-// GetAllOk returns all stored values for the request as a map and a boolean value that indicates if |
|
| 70 |
-// the request was registered. |
|
| 71 |
-func GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) {
|
|
| 72 |
- mutex.RLock() |
|
| 73 |
- context, ok := data[r] |
|
| 74 |
- result := make(map[interface{}]interface{}, len(context))
|
|
| 75 |
- for k, v := range context {
|
|
| 76 |
- result[k] = v |
|
| 77 |
- } |
|
| 78 |
- mutex.RUnlock() |
|
| 79 |
- return result, ok |
|
| 80 |
-} |
|
| 81 |
- |
|
| 82 |
-// Delete removes a value stored for a given key in a given request. |
|
| 83 |
-func Delete(r *http.Request, key interface{}) {
|
|
| 84 |
- mutex.Lock() |
|
| 85 |
- if data[r] != nil {
|
|
| 86 |
- delete(data[r], key) |
|
| 87 |
- } |
|
| 88 |
- mutex.Unlock() |
|
| 89 |
-} |
|
| 90 |
- |
|
| 91 |
-// Clear removes all values stored for a given request. |
|
| 92 |
-// |
|
| 93 |
-// This is usually called by a handler wrapper to clean up request |
|
| 94 |
-// variables at the end of a request lifetime. See ClearHandler(). |
|
| 95 |
-func Clear(r *http.Request) {
|
|
| 96 |
- mutex.Lock() |
|
| 97 |
- clear(r) |
|
| 98 |
- mutex.Unlock() |
|
| 99 |
-} |
|
| 100 |
- |
|
| 101 |
-// clear is Clear without the lock. |
|
| 102 |
-func clear(r *http.Request) {
|
|
| 103 |
- delete(data, r) |
|
| 104 |
- delete(datat, r) |
|
| 105 |
-} |
|
| 106 |
- |
|
| 107 |
-// Purge removes request data stored for longer than maxAge, in seconds. |
|
| 108 |
-// It returns the amount of requests removed. |
|
| 109 |
-// |
|
| 110 |
-// If maxAge <= 0, all request data is removed. |
|
| 111 |
-// |
|
| 112 |
-// This is only used for sanity check: in case context cleaning was not |
|
| 113 |
-// properly set some request data can be kept forever, consuming an increasing |
|
| 114 |
-// amount of memory. In case this is detected, Purge() must be called |
|
| 115 |
-// periodically until the problem is fixed. |
|
| 116 |
-func Purge(maxAge int) int {
|
|
| 117 |
- mutex.Lock() |
|
| 118 |
- count := 0 |
|
| 119 |
- if maxAge <= 0 {
|
|
| 120 |
- count = len(data) |
|
| 121 |
- data = make(map[*http.Request]map[interface{}]interface{})
|
|
| 122 |
- datat = make(map[*http.Request]int64) |
|
| 123 |
- } else {
|
|
| 124 |
- min := time.Now().Unix() - int64(maxAge) |
|
| 125 |
- for r := range data {
|
|
| 126 |
- if datat[r] < min {
|
|
| 127 |
- clear(r) |
|
| 128 |
- count++ |
|
| 129 |
- } |
|
| 130 |
- } |
|
| 131 |
- } |
|
| 132 |
- mutex.Unlock() |
|
| 133 |
- return count |
|
| 134 |
-} |
|
| 135 |
- |
|
| 136 |
-// ClearHandler wraps an http.Handler and clears request values at the end |
|
| 137 |
-// of a request lifetime. |
|
| 138 |
-func ClearHandler(h http.Handler) http.Handler {
|
|
| 139 |
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
| 140 |
- defer Clear(r) |
|
| 141 |
- h.ServeHTTP(w, r) |
|
| 142 |
- }) |
|
| 143 |
-} |
| 144 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,82 +0,0 @@ |
| 1 |
-// Copyright 2012 The Gorilla Authors. All rights reserved. |
|
| 2 |
-// Use of this source code is governed by a BSD-style |
|
| 3 |
-// license that can be found in the LICENSE file. |
|
| 4 |
- |
|
| 5 |
-/* |
|
| 6 |
-Package context stores values shared during a request lifetime. |
|
| 7 |
- |
|
| 8 |
-For example, a router can set variables extracted from the URL and later |
|
| 9 |
-application handlers can access those values, or it can be used to store |
|
| 10 |
-sessions values to be saved at the end of a request. There are several |
|
| 11 |
-others common uses. |
|
| 12 |
- |
|
| 13 |
-The idea was posted by Brad Fitzpatrick to the go-nuts mailing list: |
|
| 14 |
- |
|
| 15 |
- http://groups.google.com/group/golang-nuts/msg/e2d679d303aa5d53 |
|
| 16 |
- |
|
| 17 |
-Here's the basic usage: first define the keys that you will need. The key |
|
| 18 |
-type is interface{} so a key can be of any type that supports equality.
|
|
| 19 |
-Here we define a key using a custom int type to avoid name collisions: |
|
| 20 |
- |
|
| 21 |
- package foo |
|
| 22 |
- |
|
| 23 |
- import ( |
|
| 24 |
- "github.com/gorilla/context" |
|
| 25 |
- ) |
|
| 26 |
- |
|
| 27 |
- type key int |
|
| 28 |
- |
|
| 29 |
- const MyKey key = 0 |
|
| 30 |
- |
|
| 31 |
-Then set a variable. Variables are bound to an http.Request object, so you |
|
| 32 |
-need a request instance to set a value: |
|
| 33 |
- |
|
| 34 |
- context.Set(r, MyKey, "bar") |
|
| 35 |
- |
|
| 36 |
-The application can later access the variable using the same key you provided: |
|
| 37 |
- |
|
| 38 |
- func MyHandler(w http.ResponseWriter, r *http.Request) {
|
|
| 39 |
- // val is "bar". |
|
| 40 |
- val := context.Get(r, foo.MyKey) |
|
| 41 |
- |
|
| 42 |
- // returns ("bar", true)
|
|
| 43 |
- val, ok := context.GetOk(r, foo.MyKey) |
|
| 44 |
- // ... |
|
| 45 |
- } |
|
| 46 |
- |
|
| 47 |
-And that's all about the basic usage. We discuss some other ideas below. |
|
| 48 |
- |
|
| 49 |
-Any type can be stored in the context. To enforce a given type, make the key |
|
| 50 |
-private and wrap Get() and Set() to accept and return values of a specific |
|
| 51 |
-type: |
|
| 52 |
- |
|
| 53 |
- type key int |
|
| 54 |
- |
|
| 55 |
- const mykey key = 0 |
|
| 56 |
- |
|
| 57 |
- // GetMyKey returns a value for this package from the request values. |
|
| 58 |
- func GetMyKey(r *http.Request) SomeType {
|
|
| 59 |
- if rv := context.Get(r, mykey); rv != nil {
|
|
| 60 |
- return rv.(SomeType) |
|
| 61 |
- } |
|
| 62 |
- return nil |
|
| 63 |
- } |
|
| 64 |
- |
|
| 65 |
- // SetMyKey sets a value for this package in the request values. |
|
| 66 |
- func SetMyKey(r *http.Request, val SomeType) {
|
|
| 67 |
- context.Set(r, mykey, val) |
|
| 68 |
- } |
|
| 69 |
- |
|
| 70 |
-Variables must be cleared at the end of a request, to remove all values |
|
| 71 |
-that were stored. This can be done in an http.Handler, after a request was |
|
| 72 |
-served. Just call Clear() passing the request: |
|
| 73 |
- |
|
| 74 |
- context.Clear(r) |
|
| 75 |
- |
|
| 76 |
-...or use ClearHandler(), which conveniently wraps an http.Handler to clear |
|
| 77 |
-variables at the end of a request lifetime. |
|
| 78 |
- |
|
| 79 |
-The Routers from the packages gorilla/mux and gorilla/pat call Clear() |
|
| 80 |
-so if you are using either of them you don't need to clear the context manually. |
|
| 81 |
-*/ |
|
| 82 |
-package context |
| ... | ... |
@@ -1,4 +1,4 @@ |
| 1 |
-Copyright (c) 2012 Rodrigo Moraes. All rights reserved. |
|
| 1 |
+Copyright (c) 2012-2018 The Gorilla Authors. All rights reserved. |
|
| 2 | 2 |
|
| 3 | 3 |
Redistribution and use in source and binary forms, with or without |
| 4 | 4 |
modification, are permitted provided that the following conditions are |
| ... | ... |
@@ -6,7 +6,7 @@ |
| 6 | 6 |
|
| 7 | 7 |
 |
| 8 | 8 |
|
| 9 |
-http://www.gorillatoolkit.org/pkg/mux |
|
| 9 |
+https://www.gorillatoolkit.org/pkg/mux |
|
| 10 | 10 |
|
| 11 | 11 |
Package `gorilla/mux` implements a request router and dispatcher for matching incoming requests to |
| 12 | 12 |
their respective handler. |
| ... | ... |
@@ -88,7 +88,7 @@ r := mux.NewRouter() |
| 88 | 88 |
// Only matches if domain is "www.example.com". |
| 89 | 89 |
r.Host("www.example.com")
|
| 90 | 90 |
// Matches a dynamic subdomain. |
| 91 |
-r.Host("{subdomain:[a-z]+}.domain.com")
|
|
| 91 |
+r.Host("{subdomain:[a-z]+}.example.com")
|
|
| 92 | 92 |
``` |
| 93 | 93 |
|
| 94 | 94 |
There are several other matchers that can be added. To match path prefixes: |
| ... | ... |
@@ -238,13 +238,13 @@ This also works for host and query value variables: |
| 238 | 238 |
|
| 239 | 239 |
```go |
| 240 | 240 |
r := mux.NewRouter() |
| 241 |
-r.Host("{subdomain}.domain.com").
|
|
| 241 |
+r.Host("{subdomain}.example.com").
|
|
| 242 | 242 |
Path("/articles/{category}/{id:[0-9]+}").
|
| 243 | 243 |
Queries("filter", "{filter}").
|
| 244 | 244 |
HandlerFunc(ArticleHandler). |
| 245 | 245 |
Name("article")
|
| 246 | 246 |
|
| 247 |
-// url.String() will be "http://news.domain.com/articles/technology/42?filter=gorilla" |
|
| 247 |
+// url.String() will be "http://news.example.com/articles/technology/42?filter=gorilla" |
|
| 248 | 248 |
url, err := r.Get("article").URL("subdomain", "news",
|
| 249 | 249 |
"category", "technology", |
| 250 | 250 |
"id", "42", |
| ... | ... |
@@ -264,7 +264,7 @@ r.HeadersRegexp("Content-Type", "application/(text|json)")
|
| 264 | 264 |
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: |
| 265 | 265 |
|
| 266 | 266 |
```go |
| 267 |
-// "http://news.domain.com/" |
|
| 267 |
+// "http://news.example.com/" |
|
| 268 | 268 |
host, err := r.Get("article").URLHost("subdomain", "news")
|
| 269 | 269 |
|
| 270 | 270 |
// "/articles/technology/42" |
| ... | ... |
@@ -275,12 +275,12 @@ And if you use subrouters, host and path defined separately can be built as well |
| 275 | 275 |
|
| 276 | 276 |
```go |
| 277 | 277 |
r := mux.NewRouter() |
| 278 |
-s := r.Host("{subdomain}.domain.com").Subrouter()
|
|
| 278 |
+s := r.Host("{subdomain}.example.com").Subrouter()
|
|
| 279 | 279 |
s.Path("/articles/{category}/{id:[0-9]+}").
|
| 280 | 280 |
HandlerFunc(ArticleHandler). |
| 281 | 281 |
Name("article")
|
| 282 | 282 |
|
| 283 |
-// "http://news.domain.com/articles/technology/42" |
|
| 283 |
+// "http://news.example.com/articles/technology/42" |
|
| 284 | 284 |
url, err := r.Get("article").URL("subdomain", "news",
|
| 285 | 285 |
"category", "technology", |
| 286 | 286 |
"id", "42") |
| ... | ... |
@@ -503,8 +503,8 @@ package main |
| 503 | 503 |
|
| 504 | 504 |
func HealthCheckHandler(w http.ResponseWriter, r *http.Request) {
|
| 505 | 505 |
// A very simple health check. |
| 506 |
- w.WriteHeader(http.StatusOK) |
|
| 507 | 506 |
w.Header().Set("Content-Type", "application/json")
|
| 507 |
+ w.WriteHeader(http.StatusOK) |
|
| 508 | 508 |
|
| 509 | 509 |
// In the future we could report back on the status of our DB, or our cache |
| 510 | 510 |
// (e.g. Redis) by performing a simple PING, and include them in the response. |
| 511 | 511 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,18 @@ |
| 0 |
+package mux |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "context" |
|
| 4 |
+ "net/http" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+func contextGet(r *http.Request, key interface{}) interface{} {
|
|
| 8 |
+ return r.Context().Value(key) |
|
| 9 |
+} |
|
| 10 |
+ |
|
| 11 |
+func contextSet(r *http.Request, key, val interface{}) *http.Request {
|
|
| 12 |
+ if val == nil {
|
|
| 13 |
+ return r |
|
| 14 |
+ } |
|
| 15 |
+ |
|
| 16 |
+ return r.WithContext(context.WithValue(r.Context(), key, val)) |
|
| 17 |
+} |
| 0 | 18 |
deleted file mode 100644 |
| ... | ... |
@@ -1,26 +0,0 @@ |
| 1 |
-// +build !go1.7 |
|
| 2 |
- |
|
| 3 |
-package mux |
|
| 4 |
- |
|
| 5 |
-import ( |
|
| 6 |
- "net/http" |
|
| 7 |
- |
|
| 8 |
- "github.com/gorilla/context" |
|
| 9 |
-) |
|
| 10 |
- |
|
| 11 |
-func contextGet(r *http.Request, key interface{}) interface{} {
|
|
| 12 |
- return context.Get(r, key) |
|
| 13 |
-} |
|
| 14 |
- |
|
| 15 |
-func contextSet(r *http.Request, key, val interface{}) *http.Request {
|
|
| 16 |
- if val == nil {
|
|
| 17 |
- return r |
|
| 18 |
- } |
|
| 19 |
- |
|
| 20 |
- context.Set(r, key, val) |
|
| 21 |
- return r |
|
| 22 |
-} |
|
| 23 |
- |
|
| 24 |
-func contextClear(r *http.Request) {
|
|
| 25 |
- context.Clear(r) |
|
| 26 |
-} |
| 27 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,24 +0,0 @@ |
| 1 |
-// +build go1.7 |
|
| 2 |
- |
|
| 3 |
-package mux |
|
| 4 |
- |
|
| 5 |
-import ( |
|
| 6 |
- "context" |
|
| 7 |
- "net/http" |
|
| 8 |
-) |
|
| 9 |
- |
|
| 10 |
-func contextGet(r *http.Request, key interface{}) interface{} {
|
|
| 11 |
- return r.Context().Value(key) |
|
| 12 |
-} |
|
| 13 |
- |
|
| 14 |
-func contextSet(r *http.Request, key, val interface{}) *http.Request {
|
|
| 15 |
- if val == nil {
|
|
| 16 |
- return r |
|
| 17 |
- } |
|
| 18 |
- |
|
| 19 |
- return r.WithContext(context.WithValue(r.Context(), key, val)) |
|
| 20 |
-} |
|
| 21 |
- |
|
| 22 |
-func contextClear(r *http.Request) {
|
|
| 23 |
- return |
|
| 24 |
-} |
| ... | ... |
@@ -22,7 +22,7 @@ var ( |
| 22 | 22 |
|
| 23 | 23 |
// NewRouter returns a new router instance. |
| 24 | 24 |
func NewRouter() *Router {
|
| 25 |
- return &Router{namedRoutes: make(map[string]*Route), KeepContext: false}
|
|
| 25 |
+ return &Router{namedRoutes: make(map[string]*Route)}
|
|
| 26 | 26 |
} |
| 27 | 27 |
|
| 28 | 28 |
// Router registers routes to be matched and dispatches a handler. |
| ... | ... |
@@ -50,24 +50,78 @@ type Router struct {
|
| 50 | 50 |
// Configurable Handler to be used when the request method does not match the route. |
| 51 | 51 |
MethodNotAllowedHandler http.Handler |
| 52 | 52 |
|
| 53 |
- // Parent route, if this is a subrouter. |
|
| 54 |
- parent parentRoute |
|
| 55 | 53 |
// Routes to be matched, in order. |
| 56 | 54 |
routes []*Route |
| 55 |
+ |
|
| 57 | 56 |
// Routes by name for URL building. |
| 58 | 57 |
namedRoutes map[string]*Route |
| 59 |
- // See Router.StrictSlash(). This defines the flag for new routes. |
|
| 60 |
- strictSlash bool |
|
| 61 |
- // See Router.SkipClean(). This defines the flag for new routes. |
|
| 62 |
- skipClean bool |
|
| 58 |
+ |
|
| 63 | 59 |
// If true, do not clear the request context after handling the request. |
| 64 |
- // This has no effect when go1.7+ is used, since the context is stored |
|
| 60 |
+ // |
|
| 61 |
+ // Deprecated: No effect when go1.7+ is used, since the context is stored |
|
| 65 | 62 |
// on the request itself. |
| 66 | 63 |
KeepContext bool |
| 67 |
- // see Router.UseEncodedPath(). This defines a flag for all routes. |
|
| 68 |
- useEncodedPath bool |
|
| 64 |
+ |
|
| 69 | 65 |
// Slice of middlewares to be called after a match is found |
| 70 | 66 |
middlewares []middleware |
| 67 |
+ |
|
| 68 |
+ // configuration shared with `Route` |
|
| 69 |
+ routeConf |
|
| 70 |
+} |
|
| 71 |
+ |
|
| 72 |
+// common route configuration shared between `Router` and `Route` |
|
| 73 |
+type routeConf struct {
|
|
| 74 |
+ // If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to"
|
|
| 75 |
+ useEncodedPath bool |
|
| 76 |
+ |
|
| 77 |
+ // If true, when the path pattern is "/path/", accessing "/path" will |
|
| 78 |
+ // redirect to the former and vice versa. |
|
| 79 |
+ strictSlash bool |
|
| 80 |
+ |
|
| 81 |
+ // If true, when the path pattern is "/path//to", accessing "/path//to" |
|
| 82 |
+ // will not redirect |
|
| 83 |
+ skipClean bool |
|
| 84 |
+ |
|
| 85 |
+ // Manager for the variables from host and path. |
|
| 86 |
+ regexp routeRegexpGroup |
|
| 87 |
+ |
|
| 88 |
+ // List of matchers. |
|
| 89 |
+ matchers []matcher |
|
| 90 |
+ |
|
| 91 |
+ // The scheme used when building URLs. |
|
| 92 |
+ buildScheme string |
|
| 93 |
+ |
|
| 94 |
+ buildVarsFunc BuildVarsFunc |
|
| 95 |
+} |
|
| 96 |
+ |
|
| 97 |
+// returns an effective deep copy of `routeConf` |
|
| 98 |
+func copyRouteConf(r routeConf) routeConf {
|
|
| 99 |
+ c := r |
|
| 100 |
+ |
|
| 101 |
+ if r.regexp.path != nil {
|
|
| 102 |
+ c.regexp.path = copyRouteRegexp(r.regexp.path) |
|
| 103 |
+ } |
|
| 104 |
+ |
|
| 105 |
+ if r.regexp.host != nil {
|
|
| 106 |
+ c.regexp.host = copyRouteRegexp(r.regexp.host) |
|
| 107 |
+ } |
|
| 108 |
+ |
|
| 109 |
+ c.regexp.queries = make([]*routeRegexp, 0, len(r.regexp.queries)) |
|
| 110 |
+ for _, q := range r.regexp.queries {
|
|
| 111 |
+ c.regexp.queries = append(c.regexp.queries, copyRouteRegexp(q)) |
|
| 112 |
+ } |
|
| 113 |
+ |
|
| 114 |
+ c.matchers = make([]matcher, 0, len(r.matchers)) |
|
| 115 |
+ for _, m := range r.matchers {
|
|
| 116 |
+ c.matchers = append(c.matchers, m) |
|
| 117 |
+ } |
|
| 118 |
+ |
|
| 119 |
+ return c |
|
| 120 |
+} |
|
| 121 |
+ |
|
| 122 |
+func copyRouteRegexp(r *routeRegexp) *routeRegexp {
|
|
| 123 |
+ c := *r |
|
| 124 |
+ return &c |
|
| 71 | 125 |
} |
| 72 | 126 |
|
| 73 | 127 |
// Match attempts to match the given request against the router's registered routes. |
| ... | ... |
@@ -155,22 +209,18 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
| 155 | 155 |
handler = http.NotFoundHandler() |
| 156 | 156 |
} |
| 157 | 157 |
|
| 158 |
- if !r.KeepContext {
|
|
| 159 |
- defer contextClear(req) |
|
| 160 |
- } |
|
| 161 |
- |
|
| 162 | 158 |
handler.ServeHTTP(w, req) |
| 163 | 159 |
} |
| 164 | 160 |
|
| 165 | 161 |
// Get returns a route registered with the given name. |
| 166 | 162 |
func (r *Router) Get(name string) *Route {
|
| 167 |
- return r.getNamedRoutes()[name] |
|
| 163 |
+ return r.namedRoutes[name] |
|
| 168 | 164 |
} |
| 169 | 165 |
|
| 170 | 166 |
// GetRoute returns a route registered with the given name. This method |
| 171 | 167 |
// was renamed to Get() and remains here for backwards compatibility. |
| 172 | 168 |
func (r *Router) GetRoute(name string) *Route {
|
| 173 |
- return r.getNamedRoutes()[name] |
|
| 169 |
+ return r.namedRoutes[name] |
|
| 174 | 170 |
} |
| 175 | 171 |
|
| 176 | 172 |
// StrictSlash defines the trailing slash behavior for new routes. The initial |
| ... | ... |
@@ -222,50 +272,13 @@ func (r *Router) UseEncodedPath() *Router {
|
| 222 | 222 |
} |
| 223 | 223 |
|
| 224 | 224 |
// ---------------------------------------------------------------------------- |
| 225 |
-// parentRoute |
|
| 226 |
-// ---------------------------------------------------------------------------- |
|
| 227 |
- |
|
| 228 |
-func (r *Router) getBuildScheme() string {
|
|
| 229 |
- if r.parent != nil {
|
|
| 230 |
- return r.parent.getBuildScheme() |
|
| 231 |
- } |
|
| 232 |
- return "" |
|
| 233 |
-} |
|
| 234 |
- |
|
| 235 |
-// getNamedRoutes returns the map where named routes are registered. |
|
| 236 |
-func (r *Router) getNamedRoutes() map[string]*Route {
|
|
| 237 |
- if r.namedRoutes == nil {
|
|
| 238 |
- if r.parent != nil {
|
|
| 239 |
- r.namedRoutes = r.parent.getNamedRoutes() |
|
| 240 |
- } else {
|
|
| 241 |
- r.namedRoutes = make(map[string]*Route) |
|
| 242 |
- } |
|
| 243 |
- } |
|
| 244 |
- return r.namedRoutes |
|
| 245 |
-} |
|
| 246 |
- |
|
| 247 |
-// getRegexpGroup returns regexp definitions from the parent route, if any. |
|
| 248 |
-func (r *Router) getRegexpGroup() *routeRegexpGroup {
|
|
| 249 |
- if r.parent != nil {
|
|
| 250 |
- return r.parent.getRegexpGroup() |
|
| 251 |
- } |
|
| 252 |
- return nil |
|
| 253 |
-} |
|
| 254 |
- |
|
| 255 |
-func (r *Router) buildVars(m map[string]string) map[string]string {
|
|
| 256 |
- if r.parent != nil {
|
|
| 257 |
- m = r.parent.buildVars(m) |
|
| 258 |
- } |
|
| 259 |
- return m |
|
| 260 |
-} |
|
| 261 |
- |
|
| 262 |
-// ---------------------------------------------------------------------------- |
|
| 263 | 225 |
// Route factories |
| 264 | 226 |
// ---------------------------------------------------------------------------- |
| 265 | 227 |
|
| 266 | 228 |
// NewRoute registers an empty route. |
| 267 | 229 |
func (r *Router) NewRoute() *Route {
|
| 268 |
- route := &Route{parent: r, strictSlash: r.strictSlash, skipClean: r.skipClean, useEncodedPath: r.useEncodedPath}
|
|
| 230 |
+ // initialize a route with a copy of the parent router's configuration |
|
| 231 |
+ route := &Route{routeConf: copyRouteConf(r.routeConf), namedRoutes: r.namedRoutes}
|
|
| 269 | 232 |
r.routes = append(r.routes, route) |
| 270 | 233 |
return route |
| 271 | 234 |
} |
| ... | ... |
@@ -267,7 +267,7 @@ type routeRegexpGroup struct {
|
| 267 | 267 |
} |
| 268 | 268 |
|
| 269 | 269 |
// setMatch extracts the variables from the URL once a route matches. |
| 270 |
-func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) {
|
|
| 270 |
+func (v routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) {
|
|
| 271 | 271 |
// Store host variables. |
| 272 | 272 |
if v.host != nil {
|
| 273 | 273 |
host := getHost(req) |
| ... | ... |
@@ -296,7 +296,7 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) |
| 296 | 296 |
} else {
|
| 297 | 297 |
u.Path += "/" |
| 298 | 298 |
} |
| 299 |
- m.Handler = http.RedirectHandler(u.String(), 301) |
|
| 299 |
+ m.Handler = http.RedirectHandler(u.String(), http.StatusMovedPermanently) |
|
| 300 | 300 |
} |
| 301 | 301 |
} |
| 302 | 302 |
} |
| ... | ... |
@@ -312,17 +312,13 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) |
| 312 | 312 |
} |
| 313 | 313 |
|
| 314 | 314 |
// getHost tries its best to return the request host. |
| 315 |
+// According to section 14.23 of RFC 2616 the Host header |
|
| 316 |
+// can include the port number if the default value of 80 is not used. |
|
| 315 | 317 |
func getHost(r *http.Request) string {
|
| 316 | 318 |
if r.URL.IsAbs() {
|
| 317 | 319 |
return r.URL.Host |
| 318 | 320 |
} |
| 319 |
- host := r.Host |
|
| 320 |
- // Slice off any port information. |
|
| 321 |
- if i := strings.Index(host, ":"); i != -1 {
|
|
| 322 |
- host = host[:i] |
|
| 323 |
- } |
|
| 324 |
- return host |
|
| 325 |
- |
|
| 321 |
+ return r.Host |
|
| 326 | 322 |
} |
| 327 | 323 |
|
| 328 | 324 |
func extractVars(input string, matches []int, names []string, output map[string]string) {
|
| ... | ... |
@@ -15,24 +15,8 @@ import ( |
| 15 | 15 |
|
| 16 | 16 |
// Route stores information to match a request and build URLs. |
| 17 | 17 |
type Route struct {
|
| 18 |
- // Parent where the route was registered (a Router). |
|
| 19 |
- parent parentRoute |
|
| 20 | 18 |
// Request handler for the route. |
| 21 | 19 |
handler http.Handler |
| 22 |
- // List of matchers. |
|
| 23 |
- matchers []matcher |
|
| 24 |
- // Manager for the variables from host and path. |
|
| 25 |
- regexp *routeRegexpGroup |
|
| 26 |
- // If true, when the path pattern is "/path/", accessing "/path" will |
|
| 27 |
- // redirect to the former and vice versa. |
|
| 28 |
- strictSlash bool |
|
| 29 |
- // If true, when the path pattern is "/path//to", accessing "/path//to" |
|
| 30 |
- // will not redirect |
|
| 31 |
- skipClean bool |
|
| 32 |
- // If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to"
|
|
| 33 |
- useEncodedPath bool |
|
| 34 |
- // The scheme used when building URLs. |
|
| 35 |
- buildScheme string |
|
| 36 | 20 |
// If true, this route never matches: it is only used to build URLs. |
| 37 | 21 |
buildOnly bool |
| 38 | 22 |
// The name used to build URLs. |
| ... | ... |
@@ -40,7 +24,11 @@ type Route struct {
|
| 40 | 40 |
// Error resulted from building a route. |
| 41 | 41 |
err error |
| 42 | 42 |
|
| 43 |
- buildVarsFunc BuildVarsFunc |
|
| 43 |
+ // "global" reference to all named routes |
|
| 44 |
+ namedRoutes map[string]*Route |
|
| 45 |
+ |
|
| 46 |
+ // config possibly passed in from `Router` |
|
| 47 |
+ routeConf |
|
| 44 | 48 |
} |
| 45 | 49 |
|
| 46 | 50 |
// SkipClean reports whether path cleaning is enabled for this route via |
| ... | ... |
@@ -64,6 +52,18 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
|
| 64 | 64 |
matchErr = ErrMethodMismatch |
| 65 | 65 |
continue |
| 66 | 66 |
} |
| 67 |
+ |
|
| 68 |
+ // Ignore ErrNotFound errors. These errors arise from match call |
|
| 69 |
+ // to Subrouters. |
|
| 70 |
+ // |
|
| 71 |
+ // This prevents subsequent matching subrouters from failing to |
|
| 72 |
+ // run middleware. If not ignored, the middleware would see a |
|
| 73 |
+ // non-nil MatchErr and be skipped, even when there was a |
|
| 74 |
+ // matching route. |
|
| 75 |
+ if match.MatchErr == ErrNotFound {
|
|
| 76 |
+ match.MatchErr = nil |
|
| 77 |
+ } |
|
| 78 |
+ |
|
| 67 | 79 |
matchErr = nil |
| 68 | 80 |
return false |
| 69 | 81 |
} |
| ... | ... |
@@ -93,9 +93,7 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
|
| 93 | 93 |
} |
| 94 | 94 |
|
| 95 | 95 |
// Set variables. |
| 96 |
- if r.regexp != nil {
|
|
| 97 |
- r.regexp.setMatch(req, match, r) |
|
| 98 |
- } |
|
| 96 |
+ r.regexp.setMatch(req, match, r) |
|
| 99 | 97 |
return true |
| 100 | 98 |
} |
| 101 | 99 |
|
| ... | ... |
@@ -137,7 +135,7 @@ func (r *Route) GetHandler() http.Handler {
|
| 137 | 137 |
// Name ----------------------------------------------------------------------- |
| 138 | 138 |
|
| 139 | 139 |
// Name sets the name for the route, used to build URLs. |
| 140 |
-// If the name was registered already it will be overwritten. |
|
| 140 |
+// It is an error to call Name more than once on a route. |
|
| 141 | 141 |
func (r *Route) Name(name string) *Route {
|
| 142 | 142 |
if r.name != "" {
|
| 143 | 143 |
r.err = fmt.Errorf("mux: route already has name %q, can't set %q",
|
| ... | ... |
@@ -145,7 +143,7 @@ func (r *Route) Name(name string) *Route {
|
| 145 | 145 |
} |
| 146 | 146 |
if r.err == nil {
|
| 147 | 147 |
r.name = name |
| 148 |
- r.getNamedRoutes()[name] = r |
|
| 148 |
+ r.namedRoutes[name] = r |
|
| 149 | 149 |
} |
| 150 | 150 |
return r |
| 151 | 151 |
} |
| ... | ... |
@@ -177,7 +175,6 @@ func (r *Route) addRegexpMatcher(tpl string, typ regexpType) error {
|
| 177 | 177 |
if r.err != nil {
|
| 178 | 178 |
return r.err |
| 179 | 179 |
} |
| 180 |
- r.regexp = r.getRegexpGroup() |
|
| 181 | 180 |
if typ == regexpTypePath || typ == regexpTypePrefix {
|
| 182 | 181 |
if len(tpl) > 0 && tpl[0] != '/' {
|
| 183 | 182 |
return fmt.Errorf("mux: path must start with a slash, got %q", tpl)
|
| ... | ... |
@@ -424,7 +421,7 @@ func (r *Route) Schemes(schemes ...string) *Route {
|
| 424 | 424 |
for k, v := range schemes {
|
| 425 | 425 |
schemes[k] = strings.ToLower(v) |
| 426 | 426 |
} |
| 427 |
- if r.buildScheme == "" && len(schemes) > 0 {
|
|
| 427 |
+ if len(schemes) > 0 {
|
|
| 428 | 428 |
r.buildScheme = schemes[0] |
| 429 | 429 |
} |
| 430 | 430 |
return r.addMatcher(schemeMatcher(schemes)) |
| ... | ... |
@@ -439,7 +436,15 @@ type BuildVarsFunc func(map[string]string) map[string]string |
| 439 | 439 |
// BuildVarsFunc adds a custom function to be used to modify build variables |
| 440 | 440 |
// before a route's URL is built. |
| 441 | 441 |
func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route {
|
| 442 |
- r.buildVarsFunc = f |
|
| 442 |
+ if r.buildVarsFunc != nil {
|
|
| 443 |
+ // compose the old and new functions |
|
| 444 |
+ old := r.buildVarsFunc |
|
| 445 |
+ r.buildVarsFunc = func(m map[string]string) map[string]string {
|
|
| 446 |
+ return f(old(m)) |
|
| 447 |
+ } |
|
| 448 |
+ } else {
|
|
| 449 |
+ r.buildVarsFunc = f |
|
| 450 |
+ } |
|
| 443 | 451 |
return r |
| 444 | 452 |
} |
| 445 | 453 |
|
| ... | ... |
@@ -458,7 +463,8 @@ func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route {
|
| 458 | 458 |
// Here, the routes registered in the subrouter won't be tested if the host |
| 459 | 459 |
// doesn't match. |
| 460 | 460 |
func (r *Route) Subrouter() *Router {
|
| 461 |
- router := &Router{parent: r, strictSlash: r.strictSlash}
|
|
| 461 |
+ // initialize a subrouter with a copy of the parent route's configuration |
|
| 462 |
+ router := &Router{routeConf: copyRouteConf(r.routeConf), namedRoutes: r.namedRoutes}
|
|
| 462 | 463 |
r.addMatcher(router) |
| 463 | 464 |
return router |
| 464 | 465 |
} |
| ... | ... |
@@ -502,9 +508,6 @@ func (r *Route) URL(pairs ...string) (*url.URL, error) {
|
| 502 | 502 |
if r.err != nil {
|
| 503 | 503 |
return nil, r.err |
| 504 | 504 |
} |
| 505 |
- if r.regexp == nil {
|
|
| 506 |
- return nil, errors.New("mux: route doesn't have a host or path")
|
|
| 507 |
- } |
|
| 508 | 505 |
values, err := r.prepareVars(pairs...) |
| 509 | 506 |
if err != nil {
|
| 510 | 507 |
return nil, err |
| ... | ... |
@@ -516,8 +519,8 @@ func (r *Route) URL(pairs ...string) (*url.URL, error) {
|
| 516 | 516 |
return nil, err |
| 517 | 517 |
} |
| 518 | 518 |
scheme = "http" |
| 519 |
- if s := r.getBuildScheme(); s != "" {
|
|
| 520 |
- scheme = s |
|
| 519 |
+ if r.buildScheme != "" {
|
|
| 520 |
+ scheme = r.buildScheme |
|
| 521 | 521 |
} |
| 522 | 522 |
} |
| 523 | 523 |
if r.regexp.path != nil {
|
| ... | ... |
@@ -547,7 +550,7 @@ func (r *Route) URLHost(pairs ...string) (*url.URL, error) {
|
| 547 | 547 |
if r.err != nil {
|
| 548 | 548 |
return nil, r.err |
| 549 | 549 |
} |
| 550 |
- if r.regexp == nil || r.regexp.host == nil {
|
|
| 550 |
+ if r.regexp.host == nil {
|
|
| 551 | 551 |
return nil, errors.New("mux: route doesn't have a host")
|
| 552 | 552 |
} |
| 553 | 553 |
values, err := r.prepareVars(pairs...) |
| ... | ... |
@@ -562,8 +565,8 @@ func (r *Route) URLHost(pairs ...string) (*url.URL, error) {
|
| 562 | 562 |
Scheme: "http", |
| 563 | 563 |
Host: host, |
| 564 | 564 |
} |
| 565 |
- if s := r.getBuildScheme(); s != "" {
|
|
| 566 |
- u.Scheme = s |
|
| 565 |
+ if r.buildScheme != "" {
|
|
| 566 |
+ u.Scheme = r.buildScheme |
|
| 567 | 567 |
} |
| 568 | 568 |
return u, nil |
| 569 | 569 |
} |
| ... | ... |
@@ -575,7 +578,7 @@ func (r *Route) URLPath(pairs ...string) (*url.URL, error) {
|
| 575 | 575 |
if r.err != nil {
|
| 576 | 576 |
return nil, r.err |
| 577 | 577 |
} |
| 578 |
- if r.regexp == nil || r.regexp.path == nil {
|
|
| 578 |
+ if r.regexp.path == nil {
|
|
| 579 | 579 |
return nil, errors.New("mux: route doesn't have a path")
|
| 580 | 580 |
} |
| 581 | 581 |
values, err := r.prepareVars(pairs...) |
| ... | ... |
@@ -600,7 +603,7 @@ func (r *Route) GetPathTemplate() (string, error) {
|
| 600 | 600 |
if r.err != nil {
|
| 601 | 601 |
return "", r.err |
| 602 | 602 |
} |
| 603 |
- if r.regexp == nil || r.regexp.path == nil {
|
|
| 603 |
+ if r.regexp.path == nil {
|
|
| 604 | 604 |
return "", errors.New("mux: route doesn't have a path")
|
| 605 | 605 |
} |
| 606 | 606 |
return r.regexp.path.template, nil |
| ... | ... |
@@ -614,7 +617,7 @@ func (r *Route) GetPathRegexp() (string, error) {
|
| 614 | 614 |
if r.err != nil {
|
| 615 | 615 |
return "", r.err |
| 616 | 616 |
} |
| 617 |
- if r.regexp == nil || r.regexp.path == nil {
|
|
| 617 |
+ if r.regexp.path == nil {
|
|
| 618 | 618 |
return "", errors.New("mux: route does not have a path")
|
| 619 | 619 |
} |
| 620 | 620 |
return r.regexp.path.regexp.String(), nil |
| ... | ... |
@@ -629,7 +632,7 @@ func (r *Route) GetQueriesRegexp() ([]string, error) {
|
| 629 | 629 |
if r.err != nil {
|
| 630 | 630 |
return nil, r.err |
| 631 | 631 |
} |
| 632 |
- if r.regexp == nil || r.regexp.queries == nil {
|
|
| 632 |
+ if r.regexp.queries == nil {
|
|
| 633 | 633 |
return nil, errors.New("mux: route doesn't have queries")
|
| 634 | 634 |
} |
| 635 | 635 |
var queries []string |
| ... | ... |
@@ -648,7 +651,7 @@ func (r *Route) GetQueriesTemplates() ([]string, error) {
|
| 648 | 648 |
if r.err != nil {
|
| 649 | 649 |
return nil, r.err |
| 650 | 650 |
} |
| 651 |
- if r.regexp == nil || r.regexp.queries == nil {
|
|
| 651 |
+ if r.regexp.queries == nil {
|
|
| 652 | 652 |
return nil, errors.New("mux: route doesn't have queries")
|
| 653 | 653 |
} |
| 654 | 654 |
var queries []string |
| ... | ... |
@@ -683,7 +686,7 @@ func (r *Route) GetHostTemplate() (string, error) {
|
| 683 | 683 |
if r.err != nil {
|
| 684 | 684 |
return "", r.err |
| 685 | 685 |
} |
| 686 |
- if r.regexp == nil || r.regexp.host == nil {
|
|
| 686 |
+ if r.regexp.host == nil {
|
|
| 687 | 687 |
return "", errors.New("mux: route doesn't have a host")
|
| 688 | 688 |
} |
| 689 | 689 |
return r.regexp.host.template, nil |
| ... | ... |
@@ -700,64 +703,8 @@ func (r *Route) prepareVars(pairs ...string) (map[string]string, error) {
|
| 700 | 700 |
} |
| 701 | 701 |
|
| 702 | 702 |
func (r *Route) buildVars(m map[string]string) map[string]string {
|
| 703 |
- if r.parent != nil {
|
|
| 704 |
- m = r.parent.buildVars(m) |
|
| 705 |
- } |
|
| 706 | 703 |
if r.buildVarsFunc != nil {
|
| 707 | 704 |
m = r.buildVarsFunc(m) |
| 708 | 705 |
} |
| 709 | 706 |
return m |
| 710 | 707 |
} |
| 711 |
- |
|
| 712 |
-// ---------------------------------------------------------------------------- |
|
| 713 |
-// parentRoute |
|
| 714 |
-// ---------------------------------------------------------------------------- |
|
| 715 |
- |
|
| 716 |
-// parentRoute allows routes to know about parent host and path definitions. |
|
| 717 |
-type parentRoute interface {
|
|
| 718 |
- getBuildScheme() string |
|
| 719 |
- getNamedRoutes() map[string]*Route |
|
| 720 |
- getRegexpGroup() *routeRegexpGroup |
|
| 721 |
- buildVars(map[string]string) map[string]string |
|
| 722 |
-} |
|
| 723 |
- |
|
| 724 |
-func (r *Route) getBuildScheme() string {
|
|
| 725 |
- if r.buildScheme != "" {
|
|
| 726 |
- return r.buildScheme |
|
| 727 |
- } |
|
| 728 |
- if r.parent != nil {
|
|
| 729 |
- return r.parent.getBuildScheme() |
|
| 730 |
- } |
|
| 731 |
- return "" |
|
| 732 |
-} |
|
| 733 |
- |
|
| 734 |
-// getNamedRoutes returns the map where named routes are registered. |
|
| 735 |
-func (r *Route) getNamedRoutes() map[string]*Route {
|
|
| 736 |
- if r.parent == nil {
|
|
| 737 |
- // During tests router is not always set. |
|
| 738 |
- r.parent = NewRouter() |
|
| 739 |
- } |
|
| 740 |
- return r.parent.getNamedRoutes() |
|
| 741 |
-} |
|
| 742 |
- |
|
| 743 |
-// getRegexpGroup returns regexp definitions from this route. |
|
| 744 |
-func (r *Route) getRegexpGroup() *routeRegexpGroup {
|
|
| 745 |
- if r.regexp == nil {
|
|
| 746 |
- if r.parent == nil {
|
|
| 747 |
- // During tests router is not always set. |
|
| 748 |
- r.parent = NewRouter() |
|
| 749 |
- } |
|
| 750 |
- regexp := r.parent.getRegexpGroup() |
|
| 751 |
- if regexp == nil {
|
|
| 752 |
- r.regexp = new(routeRegexpGroup) |
|
| 753 |
- } else {
|
|
| 754 |
- // Copy. |
|
| 755 |
- r.regexp = &routeRegexpGroup{
|
|
| 756 |
- host: regexp.host, |
|
| 757 |
- path: regexp.path, |
|
| 758 |
- queries: regexp.queries, |
|
| 759 |
- } |
|
| 760 |
- } |
|
| 761 |
- } |
|
| 762 |
- return r.regexp |
|
| 763 |
-} |