mirror of
				https://github.com/linuxkit/linuxkit.git
				synced 2025-10-30 06:25:10 +00:00 
			
		
		
		
	infrakit: Move the hyperkit instance plugin into the source directory
- The tools directory ideally should not contain source code - Removes double vendoring of packagages - Makes it easer to hook the build into the top-level Makefile Eventually, the plugin should be moved to the infrakit repo. Signed-off-by: Rolf Neugebauer <rolf.neugebauer@docker.com>
This commit is contained in:
		
							
								
								
									
										27
									
								
								vendor/github.com/gorilla/context/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/gorilla/context/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| Copyright (c) 2012 Rodrigo Moraes. All rights reserved. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are | ||||
| met: | ||||
|  | ||||
| 	 * Redistributions of source code must retain the above copyright | ||||
| notice, this list of conditions and the following disclaimer. | ||||
| 	 * Redistributions in binary form must reproduce the above | ||||
| copyright notice, this list of conditions and the following disclaimer | ||||
| in the documentation and/or other materials provided with the | ||||
| distribution. | ||||
| 	 * Neither the name of Google Inc. nor the names of its | ||||
| contributors may be used to endorse or promote products derived from | ||||
| this software without specific prior written permission. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
							
								
								
									
										10
									
								
								vendor/github.com/gorilla/context/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/gorilla/context/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| context | ||||
| ======= | ||||
| [](https://travis-ci.org/gorilla/context) | ||||
|  | ||||
| gorilla/context is a general purpose registry for global request variables. | ||||
|  | ||||
| > Note: gorilla/context, having been born well before `context.Context` existed, does not play well | ||||
| > with the shallow copying of the request that [`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext) (added to net/http Go 1.7 onwards) performs. You should either use *just* gorilla/context, or moving forward, the new `http.Request.Context()`. | ||||
|  | ||||
| Read the full documentation here: http://www.gorillatoolkit.org/pkg/context | ||||
							
								
								
									
										143
									
								
								vendor/github.com/gorilla/context/context.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								vendor/github.com/gorilla/context/context.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,143 @@ | ||||
| // Copyright 2012 The Gorilla Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package context | ||||
|  | ||||
| import ( | ||||
| 	"net/http" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	mutex sync.RWMutex | ||||
| 	data  = make(map[*http.Request]map[interface{}]interface{}) | ||||
| 	datat = make(map[*http.Request]int64) | ||||
| ) | ||||
|  | ||||
| // Set stores a value for a given key in a given request. | ||||
| func Set(r *http.Request, key, val interface{}) { | ||||
| 	mutex.Lock() | ||||
| 	if data[r] == nil { | ||||
| 		data[r] = make(map[interface{}]interface{}) | ||||
| 		datat[r] = time.Now().Unix() | ||||
| 	} | ||||
| 	data[r][key] = val | ||||
| 	mutex.Unlock() | ||||
| } | ||||
|  | ||||
| // Get returns a value stored for a given key in a given request. | ||||
| func Get(r *http.Request, key interface{}) interface{} { | ||||
| 	mutex.RLock() | ||||
| 	if ctx := data[r]; ctx != nil { | ||||
| 		value := ctx[key] | ||||
| 		mutex.RUnlock() | ||||
| 		return value | ||||
| 	} | ||||
| 	mutex.RUnlock() | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // GetOk returns stored value and presence state like multi-value return of map access. | ||||
| func GetOk(r *http.Request, key interface{}) (interface{}, bool) { | ||||
| 	mutex.RLock() | ||||
| 	if _, ok := data[r]; ok { | ||||
| 		value, ok := data[r][key] | ||||
| 		mutex.RUnlock() | ||||
| 		return value, ok | ||||
| 	} | ||||
| 	mutex.RUnlock() | ||||
| 	return nil, false | ||||
| } | ||||
|  | ||||
| // GetAll returns all stored values for the request as a map. Nil is returned for invalid requests. | ||||
| func GetAll(r *http.Request) map[interface{}]interface{} { | ||||
| 	mutex.RLock() | ||||
| 	if context, ok := data[r]; ok { | ||||
| 		result := make(map[interface{}]interface{}, len(context)) | ||||
| 		for k, v := range context { | ||||
| 			result[k] = v | ||||
| 		} | ||||
| 		mutex.RUnlock() | ||||
| 		return result | ||||
| 	} | ||||
| 	mutex.RUnlock() | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // GetAllOk returns all stored values for the request as a map and a boolean value that indicates if | ||||
| // the request was registered. | ||||
| func GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) { | ||||
| 	mutex.RLock() | ||||
| 	context, ok := data[r] | ||||
| 	result := make(map[interface{}]interface{}, len(context)) | ||||
| 	for k, v := range context { | ||||
| 		result[k] = v | ||||
| 	} | ||||
| 	mutex.RUnlock() | ||||
| 	return result, ok | ||||
| } | ||||
|  | ||||
| // Delete removes a value stored for a given key in a given request. | ||||
| func Delete(r *http.Request, key interface{}) { | ||||
| 	mutex.Lock() | ||||
| 	if data[r] != nil { | ||||
| 		delete(data[r], key) | ||||
| 	} | ||||
| 	mutex.Unlock() | ||||
| } | ||||
|  | ||||
| // Clear removes all values stored for a given request. | ||||
| // | ||||
| // This is usually called by a handler wrapper to clean up request | ||||
| // variables at the end of a request lifetime. See ClearHandler(). | ||||
| func Clear(r *http.Request) { | ||||
| 	mutex.Lock() | ||||
| 	clear(r) | ||||
| 	mutex.Unlock() | ||||
| } | ||||
|  | ||||
| // clear is Clear without the lock. | ||||
| func clear(r *http.Request) { | ||||
| 	delete(data, r) | ||||
| 	delete(datat, r) | ||||
| } | ||||
|  | ||||
| // Purge removes request data stored for longer than maxAge, in seconds. | ||||
| // It returns the amount of requests removed. | ||||
| // | ||||
| // If maxAge <= 0, all request data is removed. | ||||
| // | ||||
| // This is only used for sanity check: in case context cleaning was not | ||||
| // properly set some request data can be kept forever, consuming an increasing | ||||
| // amount of memory. In case this is detected, Purge() must be called | ||||
| // periodically until the problem is fixed. | ||||
| func Purge(maxAge int) int { | ||||
| 	mutex.Lock() | ||||
| 	count := 0 | ||||
| 	if maxAge <= 0 { | ||||
| 		count = len(data) | ||||
| 		data = make(map[*http.Request]map[interface{}]interface{}) | ||||
| 		datat = make(map[*http.Request]int64) | ||||
| 	} else { | ||||
| 		min := time.Now().Unix() - int64(maxAge) | ||||
| 		for r := range data { | ||||
| 			if datat[r] < min { | ||||
| 				clear(r) | ||||
| 				count++ | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	mutex.Unlock() | ||||
| 	return count | ||||
| } | ||||
|  | ||||
| // ClearHandler wraps an http.Handler and clears request values at the end | ||||
| // of a request lifetime. | ||||
| func ClearHandler(h http.Handler) http.Handler { | ||||
| 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 		defer Clear(r) | ||||
| 		h.ServeHTTP(w, r) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										88
									
								
								vendor/github.com/gorilla/context/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								vendor/github.com/gorilla/context/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | ||||
| // Copyright 2012 The Gorilla Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| /* | ||||
| Package context stores values shared during a request lifetime. | ||||
|  | ||||
| Note: gorilla/context, having been born well before `context.Context` existed, | ||||
| does not play well > with the shallow copying of the request that | ||||
| [`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext) | ||||
| (added to net/http Go 1.7 onwards) performs. You should either use *just* | ||||
| gorilla/context, or moving forward, the new `http.Request.Context()`. | ||||
|  | ||||
| For example, a router can set variables extracted from the URL and later | ||||
| application handlers can access those values, or it can be used to store | ||||
| sessions values to be saved at the end of a request. There are several | ||||
| others common uses. | ||||
|  | ||||
| The idea was posted by Brad Fitzpatrick to the go-nuts mailing list: | ||||
|  | ||||
| 	http://groups.google.com/group/golang-nuts/msg/e2d679d303aa5d53 | ||||
|  | ||||
| Here's the basic usage: first define the keys that you will need. The key | ||||
| type is interface{} so a key can be of any type that supports equality. | ||||
| Here we define a key using a custom int type to avoid name collisions: | ||||
|  | ||||
| 	package foo | ||||
|  | ||||
| 	import ( | ||||
| 		"github.com/gorilla/context" | ||||
| 	) | ||||
|  | ||||
| 	type key int | ||||
|  | ||||
| 	const MyKey key = 0 | ||||
|  | ||||
| Then set a variable. Variables are bound to an http.Request object, so you | ||||
| need a request instance to set a value: | ||||
|  | ||||
| 	context.Set(r, MyKey, "bar") | ||||
|  | ||||
| The application can later access the variable using the same key you provided: | ||||
|  | ||||
| 	func MyHandler(w http.ResponseWriter, r *http.Request) { | ||||
| 		// val is "bar". | ||||
| 		val := context.Get(r, foo.MyKey) | ||||
|  | ||||
| 		// returns ("bar", true) | ||||
| 		val, ok := context.GetOk(r, foo.MyKey) | ||||
| 		// ... | ||||
| 	} | ||||
|  | ||||
| And that's all about the basic usage. We discuss some other ideas below. | ||||
|  | ||||
| Any type can be stored in the context. To enforce a given type, make the key | ||||
| private and wrap Get() and Set() to accept and return values of a specific | ||||
| type: | ||||
|  | ||||
| 	type key int | ||||
|  | ||||
| 	const mykey key = 0 | ||||
|  | ||||
| 	// GetMyKey returns a value for this package from the request values. | ||||
| 	func GetMyKey(r *http.Request) SomeType { | ||||
| 		if rv := context.Get(r, mykey); rv != nil { | ||||
| 			return rv.(SomeType) | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	// SetMyKey sets a value for this package in the request values. | ||||
| 	func SetMyKey(r *http.Request, val SomeType) { | ||||
| 		context.Set(r, mykey, val) | ||||
| 	} | ||||
|  | ||||
| Variables must be cleared at the end of a request, to remove all values | ||||
| that were stored. This can be done in an http.Handler, after a request was | ||||
| served. Just call Clear() passing the request: | ||||
|  | ||||
| 	context.Clear(r) | ||||
|  | ||||
| ...or use ClearHandler(), which conveniently wraps an http.Handler to clear | ||||
| variables at the end of a request lifetime. | ||||
|  | ||||
| The Routers from the packages gorilla/mux and gorilla/pat call Clear() | ||||
| so if you are using either of them you don't need to clear the context manually. | ||||
| */ | ||||
| package context | ||||
							
								
								
									
										27
									
								
								vendor/github.com/gorilla/mux/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/gorilla/mux/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| Copyright (c) 2012 Rodrigo Moraes. All rights reserved. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are | ||||
| met: | ||||
|  | ||||
| 	 * Redistributions of source code must retain the above copyright | ||||
| notice, this list of conditions and the following disclaimer. | ||||
| 	 * Redistributions in binary form must reproduce the above | ||||
| copyright notice, this list of conditions and the following disclaimer | ||||
| in the documentation and/or other materials provided with the | ||||
| distribution. | ||||
| 	 * Neither the name of Google Inc. nor the names of its | ||||
| contributors may be used to endorse or promote products derived from | ||||
| this software without specific prior written permission. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
							
								
								
									
										340
									
								
								vendor/github.com/gorilla/mux/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										340
									
								
								vendor/github.com/gorilla/mux/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,340 @@ | ||||
| gorilla/mux | ||||
| === | ||||
| [](https://godoc.org/github.com/gorilla/mux) | ||||
| [](https://travis-ci.org/gorilla/mux) | ||||
| [](https://sourcegraph.com/github.com/gorilla/mux?badge) | ||||
|  | ||||
|  | ||||
|  | ||||
| http://www.gorillatoolkit.org/pkg/mux | ||||
|  | ||||
| Package `gorilla/mux` implements a request router and dispatcher for matching incoming requests to | ||||
| their respective handler. | ||||
|  | ||||
| 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: | ||||
|  | ||||
| * It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`. | ||||
| * Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers. | ||||
| * URL hosts and paths can have variables with an optional regular expression. | ||||
| * 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. | ||||
|  | ||||
| --- | ||||
|  | ||||
| * [Install](#install) | ||||
| * [Examples](#examples) | ||||
| * [Matching Routes](#matching-routes) | ||||
| * [Listing Routes](#listing-routes) | ||||
| * [Static Files](#static-files) | ||||
| * [Registered URLs](#registered-urls) | ||||
| * [Full Example](#full-example) | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## Install | ||||
|  | ||||
| With a [correctly configured](https://golang.org/doc/install#testing) Go toolchain: | ||||
|  | ||||
| ```sh | ||||
| go get -u github.com/gorilla/mux | ||||
| ``` | ||||
|  | ||||
| ## Examples | ||||
|  | ||||
| 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 | ||||
| func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) { | ||||
| 	vars := mux.Vars(r) | ||||
| 	w.WriteHeader(http.StatusOK) | ||||
| 	fmt.Fprintf(w, "Category: %v\n", vars["category"]) | ||||
| } | ||||
| ``` | ||||
|  | ||||
| And this is all you need to know about the basic usage. More advanced options are explained below. | ||||
|  | ||||
| ### Matching Routes | ||||
|  | ||||
| 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) | ||||
| ``` | ||||
|  | ||||
| ### Listing Routes | ||||
|  | ||||
| Routes on a mux can be listed using the Router.Walk method—useful for generating documentation: | ||||
|  | ||||
| ```go | ||||
| package main | ||||
|  | ||||
| import ( | ||||
|     "fmt" | ||||
|     "net/http" | ||||
|  | ||||
|     "github.com/gorilla/mux" | ||||
| ) | ||||
|  | ||||
| func handler(w http.ResponseWriter, r *http.Request) { | ||||
|     return | ||||
| } | ||||
|  | ||||
| func main() { | ||||
|     r := mux.NewRouter() | ||||
|     r.HandleFunc("/", handler) | ||||
|     r.HandleFunc("/products", handler) | ||||
|     r.HandleFunc("/articles", handler) | ||||
|     r.HandleFunc("/articles/{id}", handler) | ||||
|     r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error { | ||||
|         t, err := route.GetPathTemplate() | ||||
|         if err != nil { | ||||
|             return err | ||||
|         } | ||||
|         fmt.Println(t) | ||||
|         return nil | ||||
|     }) | ||||
|     http.Handle("/", r) | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ### Static Files | ||||
|  | ||||
| Note that the path provided to `PathPrefix()` represents a "wildcard": calling | ||||
| `PathPrefix("/static/").Handler(...)` means that the handler will be passed any | ||||
| request that matches "/static/*". This makes it easy to serve static files with mux: | ||||
|  | ||||
| ```go | ||||
| func main() { | ||||
| 	var dir string | ||||
|  | ||||
| 	flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir") | ||||
| 	flag.Parse() | ||||
| 	r := mux.NewRouter() | ||||
|  | ||||
| 	// This will serve files under http://localhost:8000/static/<filename> | ||||
| 	r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir)))) | ||||
|  | ||||
| 	srv := &http.Server{ | ||||
| 		Handler:      r, | ||||
| 		Addr:         "127.0.0.1:8000", | ||||
| 		// Good practice: enforce timeouts for servers you create! | ||||
| 		WriteTimeout: 15 * time.Second, | ||||
| 		ReadTimeout:  15 * time.Second, | ||||
| 	} | ||||
|  | ||||
| 	log.Fatal(srv.ListenAndServe()) | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ### Registered URLs | ||||
|  | ||||
| Now let's see how to build registered URLs. | ||||
|  | ||||
| Routes can be named. All routes that define a name can have their URLs built, 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" | ||||
| 	"log" | ||||
| 	"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 | ||||
| 	log.Fatal(http.ListenAndServe(":8000", r)) | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ## License | ||||
|  | ||||
| BSD licensed. See the LICENSE file for details. | ||||
							
								
								
									
										26
									
								
								vendor/github.com/gorilla/mux/context_gorilla.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/gorilla/mux/context_gorilla.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| // +build !go1.7 | ||||
|  | ||||
| package mux | ||||
|  | ||||
| import ( | ||||
| 	"net/http" | ||||
|  | ||||
| 	"github.com/gorilla/context" | ||||
| ) | ||||
|  | ||||
| func contextGet(r *http.Request, key interface{}) interface{} { | ||||
| 	return context.Get(r, key) | ||||
| } | ||||
|  | ||||
| func contextSet(r *http.Request, key, val interface{}) *http.Request { | ||||
| 	if val == nil { | ||||
| 		return r | ||||
| 	} | ||||
|  | ||||
| 	context.Set(r, key, val) | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| func contextClear(r *http.Request) { | ||||
| 	context.Clear(r) | ||||
| } | ||||
							
								
								
									
										24
									
								
								vendor/github.com/gorilla/mux/context_native.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/gorilla/mux/context_native.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| // +build go1.7 | ||||
|  | ||||
| package mux | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"net/http" | ||||
| ) | ||||
|  | ||||
| func contextGet(r *http.Request, key interface{}) interface{} { | ||||
| 	return r.Context().Value(key) | ||||
| } | ||||
|  | ||||
| func contextSet(r *http.Request, key, val interface{}) *http.Request { | ||||
| 	if val == nil { | ||||
| 		return r | ||||
| 	} | ||||
|  | ||||
| 	return r.WithContext(context.WithValue(r.Context(), key, val)) | ||||
| } | ||||
|  | ||||
| func contextClear(r *http.Request) { | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										240
									
								
								vendor/github.com/gorilla/mux/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										240
									
								
								vendor/github.com/gorilla/mux/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,240 @@ | ||||
| // Copyright 2012 The Gorilla Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| /* | ||||
| Package mux implements a request router and dispatcher. | ||||
|  | ||||
| The name mux stands for "HTTP request multiplexer". Like the standard | ||||
| http.ServeMux, mux.Router matches incoming requests against a list of | ||||
| 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: | ||||
|  | ||||
| 	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: | ||||
|  | ||||
| 	r := mux.NewRouter() | ||||
| 	r.HandleFunc("/products/{key}", ProductHandler) | ||||
| 	r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler) | ||||
| 	r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler) | ||||
|  | ||||
| Groups can be used inside patterns, as long as they are non-capturing (?:re). For example: | ||||
|  | ||||
| 	r.HandleFunc("/articles/{category}/{sort:(?:asc|desc|new)}", ArticlesCategoryHandler) | ||||
|  | ||||
| The names are used to create a map of route variables which can be retrieved | ||||
| calling mux.Vars(): | ||||
|  | ||||
| 	vars := mux.Vars(request) | ||||
| 	category := vars["category"] | ||||
|  | ||||
| Note that if any capturing groups are present, mux will panic() during parsing. To prevent | ||||
| this, convert any capturing groups to non-capturing, e.g. change "/{sort:(asc|desc)}" to | ||||
| "/{sort:(?:asc|desc)}". This is a change from prior versions which behaved unpredictably | ||||
| when capturing groups were present. | ||||
|  | ||||
| And this is all you need to know about the basic usage. More advanced options | ||||
| 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: | ||||
|  | ||||
| 	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: | ||||
|  | ||||
| 	r.PathPrefix("/products/") | ||||
|  | ||||
| ...or HTTP methods: | ||||
|  | ||||
| 	r.Methods("GET", "POST") | ||||
|  | ||||
| ...or URL schemes: | ||||
|  | ||||
| 	r.Schemes("https") | ||||
|  | ||||
| ...or header values: | ||||
|  | ||||
| 	r.Headers("X-Requested-With", "XMLHttpRequest") | ||||
|  | ||||
| ...or query values: | ||||
|  | ||||
| 	r.Queries("key", "value") | ||||
|  | ||||
| ...or to use a custom matcher function: | ||||
|  | ||||
| 	r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool { | ||||
| 		return r.ProtoMajor == 0 | ||||
| 	}) | ||||
|  | ||||
| ...and finally, it is possible to combine several matchers in a single route: | ||||
|  | ||||
| 	r.HandleFunc("/products", ProductsHandler). | ||||
| 	  Host("www.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: | ||||
|  | ||||
| 	r := mux.NewRouter() | ||||
| 	s := r.Host("www.example.com").Subrouter() | ||||
|  | ||||
| Then register routes in the subrouter: | ||||
|  | ||||
| 	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: | ||||
|  | ||||
| 	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) | ||||
|  | ||||
| Note that the path provided to PathPrefix() represents a "wildcard": calling | ||||
| PathPrefix("/static/").Handler(...) means that the handler will be passed any | ||||
| request that matches "/static/*". This makes it easy to serve static files with mux: | ||||
|  | ||||
| 	func main() { | ||||
| 		var dir string | ||||
|  | ||||
| 		flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir") | ||||
| 		flag.Parse() | ||||
| 		r := mux.NewRouter() | ||||
|  | ||||
| 		// This will serve files under http://localhost:8000/static/<filename> | ||||
| 		r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir)))) | ||||
|  | ||||
| 		srv := &http.Server{ | ||||
| 			Handler:      r, | ||||
| 			Addr:         "127.0.0.1:8000", | ||||
| 			// Good practice: enforce timeouts for servers you create! | ||||
| 			WriteTimeout: 15 * time.Second, | ||||
| 			ReadTimeout:  15 * time.Second, | ||||
| 		} | ||||
|  | ||||
| 		log.Fatal(srv.ListenAndServe()) | ||||
| 	} | ||||
|  | ||||
| Now let's see how to build registered URLs. | ||||
|  | ||||
| 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: | ||||
|  | ||||
| 	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: | ||||
|  | ||||
| 	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: | ||||
|  | ||||
| 	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: | ||||
|  | ||||
| 	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: | ||||
|  | ||||
| 	// "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: | ||||
|  | ||||
| 	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") | ||||
| */ | ||||
| package mux | ||||
							
								
								
									
										542
									
								
								vendor/github.com/gorilla/mux/mux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										542
									
								
								vendor/github.com/gorilla/mux/mux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,542 @@ | ||||
| // Copyright 2012 The Gorilla Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package mux | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"path" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // NewRouter returns a new router instance. | ||||
| func NewRouter() *Router { | ||||
| 	return &Router{namedRoutes: make(map[string]*Route), KeepContext: false} | ||||
| } | ||||
|  | ||||
| // Router registers routes to be matched and dispatches a handler. | ||||
| // | ||||
| // It implements the http.Handler interface, so it can be registered to serve | ||||
| // requests: | ||||
| // | ||||
| //     var router = mux.NewRouter() | ||||
| // | ||||
| //     func main() { | ||||
| //         http.Handle("/", router) | ||||
| //     } | ||||
| // | ||||
| // Or, for Google App Engine, register it in a init() function: | ||||
| // | ||||
| //     func init() { | ||||
| //         http.Handle("/", router) | ||||
| //     } | ||||
| // | ||||
| // This will send all incoming requests to the router. | ||||
| type Router struct { | ||||
| 	// Configurable Handler to be used when no route matches. | ||||
| 	NotFoundHandler http.Handler | ||||
| 	// Parent route, if this is a subrouter. | ||||
| 	parent parentRoute | ||||
| 	// Routes to be matched, in order. | ||||
| 	routes []*Route | ||||
| 	// Routes by name for URL building. | ||||
| 	namedRoutes map[string]*Route | ||||
| 	// See Router.StrictSlash(). This defines the flag for new routes. | ||||
| 	strictSlash bool | ||||
| 	// See Router.SkipClean(). This defines the flag for new routes. | ||||
| 	skipClean bool | ||||
| 	// If true, do not clear the request context after handling the request. | ||||
| 	// This has no effect when go1.7+ is used, since the context is stored | ||||
| 	// on the request itself. | ||||
| 	KeepContext bool | ||||
| 	// see Router.UseEncodedPath(). This defines a flag for all routes. | ||||
| 	useEncodedPath bool | ||||
| } | ||||
|  | ||||
| // Match matches registered routes against the request. | ||||
| func (r *Router) Match(req *http.Request, match *RouteMatch) bool { | ||||
| 	for _, route := range r.routes { | ||||
| 		if route.Match(req, match) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Closest match for a router (includes sub-routers) | ||||
| 	if r.NotFoundHandler != nil { | ||||
| 		match.Handler = r.NotFoundHandler | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // ServeHTTP dispatches the handler registered in the matched route. | ||||
| // | ||||
| // When there is a match, the route variables can be retrieved calling | ||||
| // mux.Vars(request). | ||||
| func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { | ||||
| 	if !r.skipClean { | ||||
| 		path := req.URL.Path | ||||
| 		if r.useEncodedPath { | ||||
| 			path = getPath(req) | ||||
| 		} | ||||
| 		// Clean path to canonical form and redirect. | ||||
| 		if p := cleanPath(path); p != path { | ||||
|  | ||||
| 			// Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query. | ||||
| 			// This matches with fix in go 1.2 r.c. 4 for same problem.  Go Issue: | ||||
| 			// http://code.google.com/p/go/issues/detail?id=5252 | ||||
| 			url := *req.URL | ||||
| 			url.Path = p | ||||
| 			p = url.String() | ||||
|  | ||||
| 			w.Header().Set("Location", p) | ||||
| 			w.WriteHeader(http.StatusMovedPermanently) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	var match RouteMatch | ||||
| 	var handler http.Handler | ||||
| 	if r.Match(req, &match) { | ||||
| 		handler = match.Handler | ||||
| 		req = setVars(req, match.Vars) | ||||
| 		req = setCurrentRoute(req, match.Route) | ||||
| 	} | ||||
| 	if handler == nil { | ||||
| 		handler = http.NotFoundHandler() | ||||
| 	} | ||||
| 	if !r.KeepContext { | ||||
| 		defer contextClear(req) | ||||
| 	} | ||||
| 	handler.ServeHTTP(w, req) | ||||
| } | ||||
|  | ||||
| // Get returns a route registered with the given name. | ||||
| func (r *Router) Get(name string) *Route { | ||||
| 	return r.getNamedRoutes()[name] | ||||
| } | ||||
|  | ||||
| // GetRoute returns a route registered with the given name. This method | ||||
| // was renamed to Get() and remains here for backwards compatibility. | ||||
| func (r *Router) GetRoute(name string) *Route { | ||||
| 	return r.getNamedRoutes()[name] | ||||
| } | ||||
|  | ||||
| // StrictSlash defines the trailing slash behavior for new routes. The initial | ||||
| // value is false. | ||||
| // | ||||
| // When true, if the route path is "/path/", accessing "/path" will redirect | ||||
| // to the former and vice versa. In other words, your application will always | ||||
| // see the path as specified in the route. | ||||
| // | ||||
| // When false, if the route path is "/path", accessing "/path/" will not match | ||||
| // this route and vice versa. | ||||
| // | ||||
| // Special case: when a route sets a path prefix using the PathPrefix() method, | ||||
| // strict slash is ignored for that route because the redirect behavior can't | ||||
| // be determined from a prefix alone. However, any subrouters created from that | ||||
| // route inherit the original StrictSlash setting. | ||||
| func (r *Router) StrictSlash(value bool) *Router { | ||||
| 	r.strictSlash = value | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // SkipClean defines the path cleaning behaviour for new routes. The initial | ||||
| // value is false. Users should be careful about which routes are not cleaned | ||||
| // | ||||
| // When true, if the route path is "/path//to", it will remain with the double | ||||
| // slash. This is helpful if you have a route like: /fetch/http://xkcd.com/534/ | ||||
| // | ||||
| // When false, the path will be cleaned, so /fetch/http://xkcd.com/534/ will | ||||
| // become /fetch/http/xkcd.com/534 | ||||
| func (r *Router) SkipClean(value bool) *Router { | ||||
| 	r.skipClean = value | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // UseEncodedPath tells the router to match the encoded original path | ||||
| // to the routes. | ||||
| // For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to". | ||||
| // This behavior has the drawback of needing to match routes against | ||||
| // r.RequestURI instead of r.URL.Path. Any modifications (such as http.StripPrefix) | ||||
| // to r.URL.Path will not affect routing when this flag is on and thus may | ||||
| // induce unintended behavior. | ||||
| // | ||||
| // If not called, the router will match the unencoded path to the routes. | ||||
| // For eg. "/path/foo%2Fbar/to" will match the path "/path/foo/bar/to" | ||||
| func (r *Router) UseEncodedPath() *Router { | ||||
| 	r.useEncodedPath = true | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // parentRoute | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| // getNamedRoutes returns the map where named routes are registered. | ||||
| func (r *Router) getNamedRoutes() map[string]*Route { | ||||
| 	if r.namedRoutes == nil { | ||||
| 		if r.parent != nil { | ||||
| 			r.namedRoutes = r.parent.getNamedRoutes() | ||||
| 		} else { | ||||
| 			r.namedRoutes = make(map[string]*Route) | ||||
| 		} | ||||
| 	} | ||||
| 	return r.namedRoutes | ||||
| } | ||||
|  | ||||
| // getRegexpGroup returns regexp definitions from the parent route, if any. | ||||
| func (r *Router) getRegexpGroup() *routeRegexpGroup { | ||||
| 	if r.parent != nil { | ||||
| 		return r.parent.getRegexpGroup() | ||||
| 	} | ||||
| 	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 | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| // NewRoute registers an empty route. | ||||
| func (r *Router) NewRoute() *Route { | ||||
| 	route := &Route{parent: r, strictSlash: r.strictSlash, skipClean: r.skipClean, useEncodedPath: r.useEncodedPath} | ||||
| 	r.routes = append(r.routes, route) | ||||
| 	return route | ||||
| } | ||||
|  | ||||
| // Handle registers a new route with a matcher for the URL path. | ||||
| // See Route.Path() and Route.Handler(). | ||||
| func (r *Router) Handle(path string, handler http.Handler) *Route { | ||||
| 	return r.NewRoute().Path(path).Handler(handler) | ||||
| } | ||||
|  | ||||
| // HandleFunc registers a new route with a matcher for the URL path. | ||||
| // See Route.Path() and Route.HandlerFunc(). | ||||
| func (r *Router) HandleFunc(path string, f func(http.ResponseWriter, | ||||
| 	*http.Request)) *Route { | ||||
| 	return r.NewRoute().Path(path).HandlerFunc(f) | ||||
| } | ||||
|  | ||||
| // Headers registers a new route with a matcher for request header values. | ||||
| // See Route.Headers(). | ||||
| func (r *Router) Headers(pairs ...string) *Route { | ||||
| 	return r.NewRoute().Headers(pairs...) | ||||
| } | ||||
|  | ||||
| // Host registers a new route with a matcher for the URL host. | ||||
| // See Route.Host(). | ||||
| func (r *Router) Host(tpl string) *Route { | ||||
| 	return r.NewRoute().Host(tpl) | ||||
| } | ||||
|  | ||||
| // MatcherFunc registers a new route with a custom matcher function. | ||||
| // See Route.MatcherFunc(). | ||||
| func (r *Router) MatcherFunc(f MatcherFunc) *Route { | ||||
| 	return r.NewRoute().MatcherFunc(f) | ||||
| } | ||||
|  | ||||
| // Methods registers a new route with a matcher for HTTP methods. | ||||
| // See Route.Methods(). | ||||
| func (r *Router) Methods(methods ...string) *Route { | ||||
| 	return r.NewRoute().Methods(methods...) | ||||
| } | ||||
|  | ||||
| // Path registers a new route with a matcher for the URL path. | ||||
| // See Route.Path(). | ||||
| func (r *Router) Path(tpl string) *Route { | ||||
| 	return r.NewRoute().Path(tpl) | ||||
| } | ||||
|  | ||||
| // PathPrefix registers a new route with a matcher for the URL path prefix. | ||||
| // See Route.PathPrefix(). | ||||
| func (r *Router) PathPrefix(tpl string) *Route { | ||||
| 	return r.NewRoute().PathPrefix(tpl) | ||||
| } | ||||
|  | ||||
| // Queries registers a new route with a matcher for URL query values. | ||||
| // See Route.Queries(). | ||||
| func (r *Router) Queries(pairs ...string) *Route { | ||||
| 	return r.NewRoute().Queries(pairs...) | ||||
| } | ||||
|  | ||||
| // Schemes registers a new route with a matcher for URL schemes. | ||||
| // See Route.Schemes(). | ||||
| func (r *Router) Schemes(schemes ...string) *Route { | ||||
| 	return r.NewRoute().Schemes(schemes...) | ||||
| } | ||||
|  | ||||
| // BuildVarsFunc registers a new route with a custom function for modifying | ||||
| // route variables before building a URL. | ||||
| func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route { | ||||
| 	return r.NewRoute().BuildVarsFunc(f) | ||||
| } | ||||
|  | ||||
| // Walk walks the router and all its sub-routers, calling walkFn for each route | ||||
| // in the tree. The routes are walked in the order they were added. Sub-routers | ||||
| // are explored depth-first. | ||||
| func (r *Router) Walk(walkFn WalkFunc) error { | ||||
| 	return r.walk(walkFn, []*Route{}) | ||||
| } | ||||
|  | ||||
| // SkipRouter is used as a return value from WalkFuncs to indicate that the | ||||
| // router that walk is about to descend down to should be skipped. | ||||
| var SkipRouter = errors.New("skip this router") | ||||
|  | ||||
| // WalkFunc is the type of the function called for each route visited by Walk. | ||||
| // At every invocation, it is given the current route, and the current router, | ||||
| // and a list of ancestor routes that lead to the current route. | ||||
| type WalkFunc func(route *Route, router *Router, ancestors []*Route) error | ||||
|  | ||||
| func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error { | ||||
| 	for _, t := range r.routes { | ||||
| 		if t.regexp == nil || t.regexp.path == nil || t.regexp.path.template == "" { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		err := walkFn(t, r, ancestors) | ||||
| 		if err == SkipRouter { | ||||
| 			continue | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		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 | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| // RouteMatch stores information about a matched route. | ||||
| type RouteMatch struct { | ||||
| 	Route   *Route | ||||
| 	Handler http.Handler | ||||
| 	Vars    map[string]string | ||||
| } | ||||
|  | ||||
| type contextKey int | ||||
|  | ||||
| const ( | ||||
| 	varsKey contextKey = iota | ||||
| 	routeKey | ||||
| ) | ||||
|  | ||||
| // Vars returns the route variables for the current request, if any. | ||||
| func Vars(r *http.Request) map[string]string { | ||||
| 	if rv := contextGet(r, varsKey); rv != nil { | ||||
| 		return rv.(map[string]string) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // CurrentRoute returns the matched route for the current request, if any. | ||||
| // This only works when called inside the handler of the matched route | ||||
| // because the matched route is stored in the request context which is cleared | ||||
| // after the handler returns, unless the KeepContext option is set on the | ||||
| // Router. | ||||
| func CurrentRoute(r *http.Request) *Route { | ||||
| 	if rv := contextGet(r, routeKey); rv != nil { | ||||
| 		return rv.(*Route) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func setVars(r *http.Request, val interface{}) *http.Request { | ||||
| 	return contextSet(r, varsKey, val) | ||||
| } | ||||
|  | ||||
| func setCurrentRoute(r *http.Request, val interface{}) *http.Request { | ||||
| 	return contextSet(r, routeKey, val) | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Helpers | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| // getPath returns the escaped path if possible; doing what URL.EscapedPath() | ||||
| // which was added in go1.5 does | ||||
| func getPath(req *http.Request) string { | ||||
| 	if req.RequestURI != "" { | ||||
| 		// Extract the path from RequestURI (which is escaped unlike URL.Path) | ||||
| 		// as detailed here as detailed in https://golang.org/pkg/net/url/#URL | ||||
| 		// for < 1.5 server side workaround | ||||
| 		// http://localhost/path/here?v=1 -> /path/here | ||||
| 		path := req.RequestURI | ||||
| 		path = strings.TrimPrefix(path, req.URL.Scheme+`://`) | ||||
| 		path = strings.TrimPrefix(path, req.URL.Host) | ||||
| 		if i := strings.LastIndex(path, "?"); i > -1 { | ||||
| 			path = path[:i] | ||||
| 		} | ||||
| 		if i := strings.LastIndex(path, "#"); i > -1 { | ||||
| 			path = path[:i] | ||||
| 		} | ||||
| 		return path | ||||
| 	} | ||||
| 	return req.URL.Path | ||||
| } | ||||
|  | ||||
| // cleanPath returns the canonical path for p, eliminating . and .. elements. | ||||
| // Borrowed from the net/http package. | ||||
| func cleanPath(p string) string { | ||||
| 	if p == "" { | ||||
| 		return "/" | ||||
| 	} | ||||
| 	if p[0] != '/' { | ||||
| 		p = "/" + p | ||||
| 	} | ||||
| 	np := path.Clean(p) | ||||
| 	// path.Clean removes trailing slash except for root; | ||||
| 	// put the trailing slash back if necessary. | ||||
| 	if p[len(p)-1] == '/' && np != "/" { | ||||
| 		np += "/" | ||||
| 	} | ||||
|  | ||||
| 	return np | ||||
| } | ||||
|  | ||||
| // uniqueVars returns an error if two slices contain duplicated strings. | ||||
| func uniqueVars(s1, s2 []string) error { | ||||
| 	for _, v1 := range s1 { | ||||
| 		for _, v2 := range s2 { | ||||
| 			if v1 == v2 { | ||||
| 				return fmt.Errorf("mux: duplicated route variable %q", v2) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // checkPairs returns the count of strings passed in, and an error if | ||||
| // the count is not an even number. | ||||
| func checkPairs(pairs ...string) (int, error) { | ||||
| 	length := len(pairs) | ||||
| 	if length%2 != 0 { | ||||
| 		return length, fmt.Errorf( | ||||
| 			"mux: number of parameters must be multiple of 2, got %v", pairs) | ||||
| 	} | ||||
| 	return length, nil | ||||
| } | ||||
|  | ||||
| // mapFromPairsToString converts variadic string parameters to a | ||||
| // string to string map. | ||||
| func mapFromPairsToString(pairs ...string) (map[string]string, error) { | ||||
| 	length, err := checkPairs(pairs...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	m := make(map[string]string, length/2) | ||||
| 	for i := 0; i < length; i += 2 { | ||||
| 		m[pairs[i]] = pairs[i+1] | ||||
| 	} | ||||
| 	return m, nil | ||||
| } | ||||
|  | ||||
| // mapFromPairsToRegex converts variadic string paramers to a | ||||
| // string to regex map. | ||||
| func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) { | ||||
| 	length, err := checkPairs(pairs...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	m := make(map[string]*regexp.Regexp, length/2) | ||||
| 	for i := 0; i < length; i += 2 { | ||||
| 		regex, err := regexp.Compile(pairs[i+1]) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		m[pairs[i]] = regex | ||||
| 	} | ||||
| 	return m, nil | ||||
| } | ||||
|  | ||||
| // matchInArray returns true if the given string value is in the array. | ||||
| func matchInArray(arr []string, value string) bool { | ||||
| 	for _, v := range arr { | ||||
| 		if v == value { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // matchMapWithString returns true if the given key/value pairs exist in a given map. | ||||
| func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool { | ||||
| 	for k, v := range toCheck { | ||||
| 		// Check if key exists. | ||||
| 		if canonicalKey { | ||||
| 			k = http.CanonicalHeaderKey(k) | ||||
| 		} | ||||
| 		if values := toMatch[k]; values == nil { | ||||
| 			return false | ||||
| 		} else if v != "" { | ||||
| 			// 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 == value { | ||||
| 					valueExists = true | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 			if !valueExists { | ||||
| 				return false | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	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 | ||||
| } | ||||
							
								
								
									
										323
									
								
								vendor/github.com/gorilla/mux/regexp.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										323
									
								
								vendor/github.com/gorilla/mux/regexp.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,323 @@ | ||||
| // Copyright 2012 The Gorilla Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package mux | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // newRouteRegexp parses a route template and returns a routeRegexp, | ||||
| // used to match a host, a path or a query string. | ||||
| // | ||||
| // It will extract named variables, assemble a regexp to be matched, create | ||||
| // a "reverse" template to build URLs and compile regexps to validate variable | ||||
| // values used in URL building. | ||||
| // | ||||
| // Previously we accepted only Python-like identifiers for variable | ||||
| // names ([a-zA-Z_][a-zA-Z0-9_]*), but currently the only restriction is that | ||||
| // name and pattern can't be empty, and names can't contain a colon. | ||||
| func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash, useEncodedPath bool) (*routeRegexp, error) { | ||||
| 	// Check if it is well-formed. | ||||
| 	idxs, errBraces := braceIndices(tpl) | ||||
| 	if errBraces != nil { | ||||
| 		return nil, errBraces | ||||
| 	} | ||||
| 	// Backup the original. | ||||
| 	template := tpl | ||||
| 	// Now let's parse it. | ||||
| 	defaultPattern := "[^/]+" | ||||
| 	if matchQuery { | ||||
| 		defaultPattern = "[^?&]*" | ||||
| 	} else if matchHost { | ||||
| 		defaultPattern = "[^.]+" | ||||
| 		matchPrefix = false | ||||
| 	} | ||||
| 	// Only match strict slash if not matching | ||||
| 	if matchPrefix || matchHost || matchQuery { | ||||
| 		strictSlash = false | ||||
| 	} | ||||
| 	// Set a flag for strictSlash. | ||||
| 	endSlash := false | ||||
| 	if strictSlash && strings.HasSuffix(tpl, "/") { | ||||
| 		tpl = tpl[:len(tpl)-1] | ||||
| 		endSlash = true | ||||
| 	} | ||||
| 	varsN := make([]string, len(idxs)/2) | ||||
| 	varsR := make([]*regexp.Regexp, len(idxs)/2) | ||||
| 	pattern := bytes.NewBufferString("") | ||||
| 	pattern.WriteByte('^') | ||||
| 	reverse := bytes.NewBufferString("") | ||||
| 	var end int | ||||
| 	var err error | ||||
| 	for i := 0; i < len(idxs); i += 2 { | ||||
| 		// Set all values we are interested in. | ||||
| 		raw := tpl[end:idxs[i]] | ||||
| 		end = idxs[i+1] | ||||
| 		parts := strings.SplitN(tpl[idxs[i]+1:end-1], ":", 2) | ||||
| 		name := parts[0] | ||||
| 		patt := defaultPattern | ||||
| 		if len(parts) == 2 { | ||||
| 			patt = parts[1] | ||||
| 		} | ||||
| 		// Name or pattern can't be empty. | ||||
| 		if name == "" || patt == "" { | ||||
| 			return nil, fmt.Errorf("mux: missing name or pattern in %q", | ||||
| 				tpl[idxs[i]:end]) | ||||
| 		} | ||||
| 		// Build the regexp pattern. | ||||
| 		fmt.Fprintf(pattern, "%s(?P<%s>%s)", regexp.QuoteMeta(raw), varGroupName(i/2), patt) | ||||
|  | ||||
| 		// Build the reverse template. | ||||
| 		fmt.Fprintf(reverse, "%s%%s", raw) | ||||
|  | ||||
| 		// Append variable name and compiled pattern. | ||||
| 		varsN[i/2] = name | ||||
| 		varsR[i/2], err = regexp.Compile(fmt.Sprintf("^%s$", patt)) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	// Add the remaining. | ||||
| 	raw := tpl[end:] | ||||
| 	pattern.WriteString(regexp.QuoteMeta(raw)) | ||||
| 	if strictSlash { | ||||
| 		pattern.WriteString("[/]?") | ||||
| 	} | ||||
| 	if matchQuery { | ||||
| 		// Add the default pattern if the query value is empty | ||||
| 		if queryVal := strings.SplitN(template, "=", 2)[1]; queryVal == "" { | ||||
| 			pattern.WriteString(defaultPattern) | ||||
| 		} | ||||
| 	} | ||||
| 	if !matchPrefix { | ||||
| 		pattern.WriteByte('$') | ||||
| 	} | ||||
| 	reverse.WriteString(raw) | ||||
| 	if endSlash { | ||||
| 		reverse.WriteByte('/') | ||||
| 	} | ||||
| 	// Compile full regexp. | ||||
| 	reg, errCompile := regexp.Compile(pattern.String()) | ||||
| 	if errCompile != nil { | ||||
| 		return nil, errCompile | ||||
| 	} | ||||
|  | ||||
| 	// Check for capturing groups which used to work in older versions | ||||
| 	if reg.NumSubexp() != len(idxs)/2 { | ||||
| 		panic(fmt.Sprintf("route %s contains capture groups in its regexp. ", template) + | ||||
| 			"Only non-capturing groups are accepted: e.g. (?:pattern) instead of (pattern)") | ||||
| 	} | ||||
|  | ||||
| 	// Done! | ||||
| 	return &routeRegexp{ | ||||
| 		template:       template, | ||||
| 		matchHost:      matchHost, | ||||
| 		matchQuery:     matchQuery, | ||||
| 		strictSlash:    strictSlash, | ||||
| 		useEncodedPath: useEncodedPath, | ||||
| 		regexp:         reg, | ||||
| 		reverse:        reverse.String(), | ||||
| 		varsN:          varsN, | ||||
| 		varsR:          varsR, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // routeRegexp stores a regexp to match a host or path and information to | ||||
| // collect and validate route variables. | ||||
| type routeRegexp struct { | ||||
| 	// The unmodified template. | ||||
| 	template string | ||||
| 	// True for host match, false for path or query string match. | ||||
| 	matchHost bool | ||||
| 	// True for query string match, false for path and host match. | ||||
| 	matchQuery bool | ||||
| 	// The strictSlash value defined on the route, but disabled if PathPrefix was used. | ||||
| 	strictSlash bool | ||||
| 	// Determines whether to use encoded path from getPath function or unencoded | ||||
| 	// req.URL.Path for path matching | ||||
| 	useEncodedPath bool | ||||
| 	// Expanded regexp. | ||||
| 	regexp *regexp.Regexp | ||||
| 	// Reverse template. | ||||
| 	reverse string | ||||
| 	// Variable names. | ||||
| 	varsN []string | ||||
| 	// Variable regexps (validators). | ||||
| 	varsR []*regexp.Regexp | ||||
| } | ||||
|  | ||||
| // Match matches the regexp against the URL host or path. | ||||
| func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool { | ||||
| 	if !r.matchHost { | ||||
| 		if r.matchQuery { | ||||
| 			return r.matchQueryString(req) | ||||
| 		} | ||||
| 		path := req.URL.Path | ||||
| 		if r.useEncodedPath { | ||||
| 			path = getPath(req) | ||||
| 		} | ||||
| 		return r.regexp.MatchString(path) | ||||
| 	} | ||||
|  | ||||
| 	return r.regexp.MatchString(getHost(req)) | ||||
| } | ||||
|  | ||||
| // url builds a URL part using the given values. | ||||
| func (r *routeRegexp) url(values map[string]string) (string, error) { | ||||
| 	urlValues := make([]interface{}, len(r.varsN)) | ||||
| 	for k, v := range r.varsN { | ||||
| 		value, ok := values[v] | ||||
| 		if !ok { | ||||
| 			return "", fmt.Errorf("mux: missing route variable %q", v) | ||||
| 		} | ||||
| 		urlValues[k] = value | ||||
| 	} | ||||
| 	rv := fmt.Sprintf(r.reverse, urlValues...) | ||||
| 	if !r.regexp.MatchString(rv) { | ||||
| 		// The URL is checked against the full regexp, instead of checking | ||||
| 		// individual variables. This is faster but to provide a good error | ||||
| 		// message, we check individual regexps if the URL doesn't match. | ||||
| 		for k, v := range r.varsN { | ||||
| 			if !r.varsR[k].MatchString(values[v]) { | ||||
| 				return "", fmt.Errorf( | ||||
| 					"mux: variable %q doesn't match, expected %q", values[v], | ||||
| 					r.varsR[k].String()) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return rv, nil | ||||
| } | ||||
|  | ||||
| // getURLQuery returns a single query parameter from a request URL. | ||||
| // For a URL with foo=bar&baz=ding, we return only the relevant key | ||||
| // value pair for the routeRegexp. | ||||
| func (r *routeRegexp) getURLQuery(req *http.Request) string { | ||||
| 	if !r.matchQuery { | ||||
| 		return "" | ||||
| 	} | ||||
| 	templateKey := strings.SplitN(r.template, "=", 2)[0] | ||||
| 	for key, vals := range req.URL.Query() { | ||||
| 		if key == templateKey && len(vals) > 0 { | ||||
| 			return key + "=" + vals[0] | ||||
| 		} | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (r *routeRegexp) matchQueryString(req *http.Request) bool { | ||||
| 	return r.regexp.MatchString(r.getURLQuery(req)) | ||||
| } | ||||
|  | ||||
| // braceIndices returns the first level curly brace indices from a string. | ||||
| // It returns an error in case of unbalanced braces. | ||||
| func braceIndices(s string) ([]int, error) { | ||||
| 	var level, idx int | ||||
| 	var idxs []int | ||||
| 	for i := 0; i < len(s); i++ { | ||||
| 		switch s[i] { | ||||
| 		case '{': | ||||
| 			if level++; level == 1 { | ||||
| 				idx = i | ||||
| 			} | ||||
| 		case '}': | ||||
| 			if level--; level == 0 { | ||||
| 				idxs = append(idxs, idx, i+1) | ||||
| 			} else if level < 0 { | ||||
| 				return nil, fmt.Errorf("mux: unbalanced braces in %q", s) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if level != 0 { | ||||
| 		return nil, fmt.Errorf("mux: unbalanced braces in %q", s) | ||||
| 	} | ||||
| 	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 groups the route matchers that carry variables. | ||||
| type routeRegexpGroup struct { | ||||
| 	host    *routeRegexp | ||||
| 	path    *routeRegexp | ||||
| 	queries []*routeRegexp | ||||
| } | ||||
|  | ||||
| // setMatch extracts the variables from the URL once a route matches. | ||||
| func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) { | ||||
| 	// Store host variables. | ||||
| 	if v.host != nil { | ||||
| 		host := getHost(req) | ||||
| 		matches := v.host.regexp.FindStringSubmatchIndex(host) | ||||
| 		if len(matches) > 0 { | ||||
| 			extractVars(host, matches, v.host.varsN, m.Vars) | ||||
| 		} | ||||
| 	} | ||||
| 	path := req.URL.Path | ||||
| 	if r.useEncodedPath { | ||||
| 		path = getPath(req) | ||||
| 	} | ||||
| 	// Store path variables. | ||||
| 	if v.path != nil { | ||||
| 		matches := v.path.regexp.FindStringSubmatchIndex(path) | ||||
| 		if len(matches) > 0 { | ||||
| 			extractVars(path, matches, v.path.varsN, m.Vars) | ||||
| 			// Check if we should redirect. | ||||
| 			if v.path.strictSlash { | ||||
| 				p1 := strings.HasSuffix(path, "/") | ||||
| 				p2 := strings.HasSuffix(v.path.template, "/") | ||||
| 				if p1 != p2 { | ||||
| 					u, _ := url.Parse(req.URL.String()) | ||||
| 					if p1 { | ||||
| 						u.Path = u.Path[:len(u.Path)-1] | ||||
| 					} else { | ||||
| 						u.Path += "/" | ||||
| 					} | ||||
| 					m.Handler = http.RedirectHandler(u.String(), 301) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	// Store query string variables. | ||||
| 	for _, q := range v.queries { | ||||
| 		queryURL := q.getURLQuery(req) | ||||
| 		matches := q.regexp.FindStringSubmatchIndex(queryURL) | ||||
| 		if len(matches) > 0 { | ||||
| 			extractVars(queryURL, matches, q.varsN, m.Vars) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // getHost tries its best to return the request host. | ||||
| func getHost(r *http.Request) string { | ||||
| 	if r.URL.IsAbs() { | ||||
| 		return r.URL.Host | ||||
| 	} | ||||
| 	host := r.Host | ||||
| 	// Slice off any port information. | ||||
| 	if i := strings.Index(host, ":"); i != -1 { | ||||
| 		host = host[:i] | ||||
| 	} | ||||
| 	return host | ||||
|  | ||||
| } | ||||
|  | ||||
| func extractVars(input string, matches []int, names []string, output map[string]string) { | ||||
| 	for i, name := range names { | ||||
| 		output[name] = input[matches[2*i+2]:matches[2*i+3]] | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										636
									
								
								vendor/github.com/gorilla/mux/route.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										636
									
								
								vendor/github.com/gorilla/mux/route.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,636 @@ | ||||
| // Copyright 2012 The Gorilla Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package mux | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // Route stores information to match a request and build URLs. | ||||
| type Route struct { | ||||
| 	// Parent where the route was registered (a Router). | ||||
| 	parent parentRoute | ||||
| 	// Request handler for the route. | ||||
| 	handler http.Handler | ||||
| 	// List of matchers. | ||||
| 	matchers []matcher | ||||
| 	// Manager for the variables from host and path. | ||||
| 	regexp *routeRegexpGroup | ||||
| 	// If true, when the path pattern is "/path/", accessing "/path" will | ||||
| 	// redirect to the former and vice versa. | ||||
| 	strictSlash bool | ||||
| 	// If true, when the path pattern is "/path//to", accessing "/path//to" | ||||
| 	// will not redirect | ||||
| 	skipClean bool | ||||
| 	// If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to" | ||||
| 	useEncodedPath bool | ||||
| 	// If true, this route never matches: it is only used to build URLs. | ||||
| 	buildOnly bool | ||||
| 	// The name used to build URLs. | ||||
| 	name string | ||||
| 	// Error resulted from building a route. | ||||
| 	err error | ||||
|  | ||||
| 	buildVarsFunc BuildVarsFunc | ||||
| } | ||||
|  | ||||
| func (r *Route) SkipClean() bool { | ||||
| 	return r.skipClean | ||||
| } | ||||
|  | ||||
| // Match matches the route against the request. | ||||
| func (r *Route) Match(req *http.Request, match *RouteMatch) bool { | ||||
| 	if r.buildOnly || r.err != nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	// Match everything. | ||||
| 	for _, m := range r.matchers { | ||||
| 		if matched := m.Match(req, match); !matched { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	// Yay, we have a match. Let's collect some info about it. | ||||
| 	if match.Route == nil { | ||||
| 		match.Route = r | ||||
| 	} | ||||
| 	if match.Handler == nil { | ||||
| 		match.Handler = r.handler | ||||
| 	} | ||||
| 	if match.Vars == nil { | ||||
| 		match.Vars = make(map[string]string) | ||||
| 	} | ||||
| 	// Set variables. | ||||
| 	if r.regexp != nil { | ||||
| 		r.regexp.setMatch(req, match, r) | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Route attributes | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| // GetError returns an error resulted from building the route, if any. | ||||
| func (r *Route) GetError() error { | ||||
| 	return r.err | ||||
| } | ||||
|  | ||||
| // BuildOnly sets the route to never match: it is only used to build URLs. | ||||
| func (r *Route) BuildOnly() *Route { | ||||
| 	r.buildOnly = true | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // Handler -------------------------------------------------------------------- | ||||
|  | ||||
| // Handler sets a handler for the route. | ||||
| func (r *Route) Handler(handler http.Handler) *Route { | ||||
| 	if r.err == nil { | ||||
| 		r.handler = handler | ||||
| 	} | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // HandlerFunc sets a handler function for the route. | ||||
| func (r *Route) HandlerFunc(f func(http.ResponseWriter, *http.Request)) *Route { | ||||
| 	return r.Handler(http.HandlerFunc(f)) | ||||
| } | ||||
|  | ||||
| // GetHandler returns the handler for the route, if any. | ||||
| func (r *Route) GetHandler() http.Handler { | ||||
| 	return r.handler | ||||
| } | ||||
|  | ||||
| // Name ----------------------------------------------------------------------- | ||||
|  | ||||
| // Name sets the name for the route, used to build URLs. | ||||
| // If the name was registered already it will be overwritten. | ||||
| func (r *Route) Name(name string) *Route { | ||||
| 	if r.name != "" { | ||||
| 		r.err = fmt.Errorf("mux: route already has name %q, can't set %q", | ||||
| 			r.name, name) | ||||
| 	} | ||||
| 	if r.err == nil { | ||||
| 		r.name = name | ||||
| 		r.getNamedRoutes()[name] = r | ||||
| 	} | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // GetName returns the name for the route, if any. | ||||
| func (r *Route) GetName() string { | ||||
| 	return r.name | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Matchers | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| // matcher types try to match a request. | ||||
| type matcher interface { | ||||
| 	Match(*http.Request, *RouteMatch) bool | ||||
| } | ||||
|  | ||||
| // addMatcher adds a matcher to the route. | ||||
| func (r *Route) addMatcher(m matcher) *Route { | ||||
| 	if r.err == nil { | ||||
| 		r.matchers = append(r.matchers, m) | ||||
| 	} | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // addRegexpMatcher adds a host or path matcher and builder to a route. | ||||
| func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery bool) error { | ||||
| 	if r.err != nil { | ||||
| 		return r.err | ||||
| 	} | ||||
| 	r.regexp = r.getRegexpGroup() | ||||
| 	if !matchHost && !matchQuery { | ||||
| 		if len(tpl) > 0 && tpl[0] != '/' { | ||||
| 			return fmt.Errorf("mux: path must start with a slash, got %q", tpl) | ||||
| 		} | ||||
| 		if r.regexp.path != nil { | ||||
| 			tpl = strings.TrimRight(r.regexp.path.template, "/") + tpl | ||||
| 		} | ||||
| 	} | ||||
| 	rr, err := newRouteRegexp(tpl, matchHost, matchPrefix, matchQuery, r.strictSlash, r.useEncodedPath) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, q := range r.regexp.queries { | ||||
| 		if err = uniqueVars(rr.varsN, q.varsN); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	if matchHost { | ||||
| 		if r.regexp.path != nil { | ||||
| 			if err = uniqueVars(rr.varsN, r.regexp.path.varsN); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		r.regexp.host = rr | ||||
| 	} else { | ||||
| 		if r.regexp.host != nil { | ||||
| 			if err = uniqueVars(rr.varsN, r.regexp.host.varsN); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		if matchQuery { | ||||
| 			r.regexp.queries = append(r.regexp.queries, rr) | ||||
| 		} else { | ||||
| 			r.regexp.path = rr | ||||
| 		} | ||||
| 	} | ||||
| 	r.addMatcher(rr) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Headers -------------------------------------------------------------------- | ||||
|  | ||||
| // headerMatcher matches the request against header values. | ||||
| type headerMatcher map[string]string | ||||
|  | ||||
| func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool { | ||||
| 	return matchMapWithString(m, r.Header, true) | ||||
| } | ||||
|  | ||||
| // Headers adds a matcher for request header values. | ||||
| // It accepts a sequence of key/value pairs to be matched. For example: | ||||
| // | ||||
| //     r := mux.NewRouter() | ||||
| //     r.Headers("Content-Type", "application/json", | ||||
| //               "X-Requested-With", "XMLHttpRequest") | ||||
| // | ||||
| // 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. | ||||
| func (r *Route) Headers(pairs ...string) *Route { | ||||
| 	if r.err == nil { | ||||
| 		var headers map[string]string | ||||
| 		headers, r.err = mapFromPairsToString(pairs...) | ||||
| 		return r.addMatcher(headerMatcher(headers)) | ||||
| 	} | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // headerRegexMatcher matches the request against the route given a regex for the header | ||||
| type headerRegexMatcher map[string]*regexp.Regexp | ||||
|  | ||||
| func (m headerRegexMatcher) Match(r *http.Request, match *RouteMatch) bool { | ||||
| 	return matchMapWithRegex(m, r.Header, true) | ||||
| } | ||||
|  | ||||
| // HeadersRegexp accepts a sequence of key/value pairs, where the value has regex | ||||
| // support. For example: | ||||
| // | ||||
| //     r := mux.NewRouter() | ||||
| //     r.HeadersRegexp("Content-Type", "application/(text|json)", | ||||
| //               "X-Requested-With", "XMLHttpRequest") | ||||
| // | ||||
| // The above route will only match if both the request header matches both regular expressions. | ||||
| // It the value is an empty string, it will match any value if the key is set. | ||||
| func (r *Route) HeadersRegexp(pairs ...string) *Route { | ||||
| 	if r.err == nil { | ||||
| 		var headers map[string]*regexp.Regexp | ||||
| 		headers, r.err = mapFromPairsToRegex(pairs...) | ||||
| 		return r.addMatcher(headerRegexMatcher(headers)) | ||||
| 	} | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // Host ----------------------------------------------------------------------- | ||||
|  | ||||
| // Host adds a matcher for the URL host. | ||||
| // It accepts a template with zero or more URL variables enclosed by {}. | ||||
| // Variables can define an optional regexp pattern to be matched: | ||||
| // | ||||
| // - {name} matches anything until the next dot. | ||||
| // | ||||
| // - {name:pattern} matches the given regexp pattern. | ||||
| // | ||||
| // For example: | ||||
| // | ||||
| //     r := mux.NewRouter() | ||||
| //     r.Host("www.example.com") | ||||
| //     r.Host("{subdomain}.domain.com") | ||||
| //     r.Host("{subdomain:[a-z]+}.domain.com") | ||||
| // | ||||
| // Variable names must be unique in a given route. They can be retrieved | ||||
| // calling mux.Vars(request). | ||||
| func (r *Route) Host(tpl string) *Route { | ||||
| 	r.err = r.addRegexpMatcher(tpl, true, false, false) | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // MatcherFunc ---------------------------------------------------------------- | ||||
|  | ||||
| // MatcherFunc is the function signature used by custom matchers. | ||||
| type MatcherFunc func(*http.Request, *RouteMatch) bool | ||||
|  | ||||
| // Match returns the match for a given request. | ||||
| func (m MatcherFunc) Match(r *http.Request, match *RouteMatch) bool { | ||||
| 	return m(r, match) | ||||
| } | ||||
|  | ||||
| // MatcherFunc adds a custom function to be used as request matcher. | ||||
| func (r *Route) MatcherFunc(f MatcherFunc) *Route { | ||||
| 	return r.addMatcher(f) | ||||
| } | ||||
|  | ||||
| // Methods -------------------------------------------------------------------- | ||||
|  | ||||
| // methodMatcher matches the request against HTTP methods. | ||||
| type methodMatcher []string | ||||
|  | ||||
| func (m methodMatcher) Match(r *http.Request, match *RouteMatch) bool { | ||||
| 	return matchInArray(m, r.Method) | ||||
| } | ||||
|  | ||||
| // Methods adds a matcher for HTTP methods. | ||||
| // It accepts a sequence of one or more methods to be matched, e.g.: | ||||
| // "GET", "POST", "PUT". | ||||
| func (r *Route) Methods(methods ...string) *Route { | ||||
| 	for k, v := range methods { | ||||
| 		methods[k] = strings.ToUpper(v) | ||||
| 	} | ||||
| 	return r.addMatcher(methodMatcher(methods)) | ||||
| } | ||||
|  | ||||
| // Path ----------------------------------------------------------------------- | ||||
|  | ||||
| // Path adds a matcher for the URL path. | ||||
| // It accepts a template with zero or more URL variables enclosed by {}. The | ||||
| // template must start with a "/". | ||||
| // Variables can define an optional regexp pattern to be matched: | ||||
| // | ||||
| // - {name} matches anything until the next slash. | ||||
| // | ||||
| // - {name:pattern} matches the given regexp pattern. | ||||
| // | ||||
| // For example: | ||||
| // | ||||
| //     r := mux.NewRouter() | ||||
| //     r.Path("/products/").Handler(ProductsHandler) | ||||
| //     r.Path("/products/{key}").Handler(ProductsHandler) | ||||
| //     r.Path("/articles/{category}/{id:[0-9]+}"). | ||||
| //       Handler(ArticleHandler) | ||||
| // | ||||
| // Variable names must be unique in a given route. They can be retrieved | ||||
| // calling mux.Vars(request). | ||||
| func (r *Route) Path(tpl string) *Route { | ||||
| 	r.err = r.addRegexpMatcher(tpl, false, false, false) | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // PathPrefix ----------------------------------------------------------------- | ||||
|  | ||||
| // PathPrefix adds a matcher for the URL path prefix. This matches if the given | ||||
| // template is a prefix of the full URL path. See Route.Path() for details on | ||||
| // the tpl argument. | ||||
| // | ||||
| // Note that it does not treat slashes specially ("/foobar/" will be matched by | ||||
| // the prefix "/foo") so you may want to use a trailing slash here. | ||||
| // | ||||
| // Also note that the setting of Router.StrictSlash() has no effect on routes | ||||
| // with a PathPrefix matcher. | ||||
| func (r *Route) PathPrefix(tpl string) *Route { | ||||
| 	r.err = r.addRegexpMatcher(tpl, false, true, false) | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // Query ---------------------------------------------------------------------- | ||||
|  | ||||
| // Queries adds a matcher for URL query values. | ||||
| // It accepts a sequence of key/value pairs. Values may define variables. | ||||
| // For example: | ||||
| // | ||||
| //     r := mux.NewRouter() | ||||
| //     r.Queries("foo", "bar", "id", "{id:[0-9]+}") | ||||
| // | ||||
| // The above route will only match if the URL contains the defined queries | ||||
| // values, e.g.: ?foo=bar&id=42. | ||||
| // | ||||
| // 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 be matched: | ||||
| // | ||||
| // - {name} matches anything until the next slash. | ||||
| // | ||||
| // - {name:pattern} matches the given regexp pattern. | ||||
| func (r *Route) Queries(pairs ...string) *Route { | ||||
| 	length := len(pairs) | ||||
| 	if length%2 != 0 { | ||||
| 		r.err = fmt.Errorf( | ||||
| 			"mux: number of parameters must be multiple of 2, got %v", pairs) | ||||
| 		return nil | ||||
| 	} | ||||
| 	for i := 0; i < length; i += 2 { | ||||
| 		if r.err = r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], false, false, true); r.err != nil { | ||||
| 			return r | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // Schemes -------------------------------------------------------------------- | ||||
|  | ||||
| // schemeMatcher matches the request against URL schemes. | ||||
| type schemeMatcher []string | ||||
|  | ||||
| func (m schemeMatcher) Match(r *http.Request, match *RouteMatch) bool { | ||||
| 	return matchInArray(m, r.URL.Scheme) | ||||
| } | ||||
|  | ||||
| // Schemes adds a matcher for URL schemes. | ||||
| // It accepts a sequence of schemes to be matched, e.g.: "http", "https". | ||||
| func (r *Route) Schemes(schemes ...string) *Route { | ||||
| 	for k, v := range schemes { | ||||
| 		schemes[k] = strings.ToLower(v) | ||||
| 	} | ||||
| 	return r.addMatcher(schemeMatcher(schemes)) | ||||
| } | ||||
|  | ||||
| // BuildVarsFunc -------------------------------------------------------------- | ||||
|  | ||||
| // BuildVarsFunc is the function signature used by custom build variable | ||||
| // functions (which can modify route variables before a route's URL is built). | ||||
| type BuildVarsFunc func(map[string]string) map[string]string | ||||
|  | ||||
| // BuildVarsFunc adds a custom function to be used to modify build variables | ||||
| // before a route's URL is built. | ||||
| func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route { | ||||
| 	r.buildVarsFunc = f | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // Subrouter ------------------------------------------------------------------ | ||||
|  | ||||
| // Subrouter creates a subrouter for the route. | ||||
| // | ||||
| // It will test the inner routes only if the parent route matched. For example: | ||||
| // | ||||
| //     r := mux.NewRouter() | ||||
| //     s := r.Host("www.example.com").Subrouter() | ||||
| //     s.HandleFunc("/products/", ProductsHandler) | ||||
| //     s.HandleFunc("/products/{key}", ProductHandler) | ||||
| //     s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler) | ||||
| // | ||||
| // Here, the routes registered in the subrouter won't be tested if the host | ||||
| // doesn't match. | ||||
| func (r *Route) Subrouter() *Router { | ||||
| 	router := &Router{parent: r, strictSlash: r.strictSlash} | ||||
| 	r.addMatcher(router) | ||||
| 	return router | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // URL building | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| // URL builds a URL for the route. | ||||
| // | ||||
| // It accepts a sequence of key/value pairs for the route variables. For | ||||
| // example, given this route: | ||||
| // | ||||
| //     r := mux.NewRouter() | ||||
| //     r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). | ||||
| //       Name("article") | ||||
| // | ||||
| // ...a URL for it can be built using: | ||||
| // | ||||
| //     url, err := r.Get("article").URL("category", "technology", "id", "42") | ||||
| // | ||||
| // ...which will return an url.URL with the following path: | ||||
| // | ||||
| //     "/articles/technology/42" | ||||
| // | ||||
| // This also works for host variables: | ||||
| // | ||||
| //     r := mux.NewRouter() | ||||
| //     r.Host("{subdomain}.domain.com"). | ||||
| //       HandleFunc("/articles/{category}/{id:[0-9]+}", 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. | ||||
| func (r *Route) URL(pairs ...string) (*url.URL, error) { | ||||
| 	if r.err != nil { | ||||
| 		return nil, r.err | ||||
| 	} | ||||
| 	if r.regexp == nil { | ||||
| 		return nil, errors.New("mux: route doesn't have a host or path") | ||||
| 	} | ||||
| 	values, err := r.prepareVars(pairs...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	var scheme, host, path string | ||||
| 	if r.regexp.host != nil { | ||||
| 		// Set a default scheme. | ||||
| 		scheme = "http" | ||||
| 		if host, err = r.regexp.host.url(values); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	if r.regexp.path != nil { | ||||
| 		if path, err = r.regexp.path.url(values); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	return &url.URL{ | ||||
| 		Scheme: scheme, | ||||
| 		Host:   host, | ||||
| 		Path:   path, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // URLHost builds the host part of the URL for a route. See Route.URL(). | ||||
| // | ||||
| // The route must have a host defined. | ||||
| func (r *Route) URLHost(pairs ...string) (*url.URL, error) { | ||||
| 	if r.err != nil { | ||||
| 		return nil, r.err | ||||
| 	} | ||||
| 	if r.regexp == nil || r.regexp.host == nil { | ||||
| 		return nil, errors.New("mux: route doesn't have a host") | ||||
| 	} | ||||
| 	values, err := r.prepareVars(pairs...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	host, err := r.regexp.host.url(values) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &url.URL{ | ||||
| 		Scheme: "http", | ||||
| 		Host:   host, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // URLPath builds the path part of the URL for a route. See Route.URL(). | ||||
| // | ||||
| // The route must have a path defined. | ||||
| func (r *Route) URLPath(pairs ...string) (*url.URL, error) { | ||||
| 	if r.err != nil { | ||||
| 		return nil, r.err | ||||
| 	} | ||||
| 	if r.regexp == nil || r.regexp.path == nil { | ||||
| 		return nil, errors.New("mux: route doesn't have a path") | ||||
| 	} | ||||
| 	values, err := r.prepareVars(pairs...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	path, err := r.regexp.path.url(values) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &url.URL{ | ||||
| 		Path: path, | ||||
| 	}, 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 allows routes to know about parent host and path definitions. | ||||
| type parentRoute interface { | ||||
| 	getNamedRoutes() map[string]*Route | ||||
| 	getRegexpGroup() *routeRegexpGroup | ||||
| 	buildVars(map[string]string) map[string]string | ||||
| } | ||||
|  | ||||
| // getNamedRoutes returns the map where named routes are registered. | ||||
| func (r *Route) getNamedRoutes() map[string]*Route { | ||||
| 	if r.parent == nil { | ||||
| 		// During tests router is not always set. | ||||
| 		r.parent = NewRouter() | ||||
| 	} | ||||
| 	return r.parent.getNamedRoutes() | ||||
| } | ||||
|  | ||||
| // getRegexpGroup returns regexp definitions from this route. | ||||
| func (r *Route) getRegexpGroup() *routeRegexpGroup { | ||||
| 	if r.regexp == nil { | ||||
| 		if r.parent == nil { | ||||
| 			// During tests router is not always set. | ||||
| 			r.parent = NewRouter() | ||||
| 		} | ||||
| 		regexp := r.parent.getRegexpGroup() | ||||
| 		if regexp == nil { | ||||
| 			r.regexp = new(routeRegexpGroup) | ||||
| 		} else { | ||||
| 			// Copy. | ||||
| 			r.regexp = &routeRegexpGroup{ | ||||
| 				host:    regexp.host, | ||||
| 				path:    regexp.path, | ||||
| 				queries: regexp.queries, | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return r.regexp | ||||
| } | ||||
							
								
								
									
										27
									
								
								vendor/github.com/gorilla/rpc/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/gorilla/rpc/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| Copyright (c) 2012 Rodrigo Moraes. All rights reserved. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are | ||||
| met: | ||||
|  | ||||
| 	 * Redistributions of source code must retain the above copyright | ||||
| notice, this list of conditions and the following disclaimer. | ||||
| 	 * Redistributions in binary form must reproduce the above | ||||
| copyright notice, this list of conditions and the following disclaimer | ||||
| in the documentation and/or other materials provided with the | ||||
| distribution. | ||||
| 	 * Neither the name of Google Inc. nor the names of its | ||||
| contributors may be used to endorse or promote products derived from | ||||
| this software without specific prior written permission. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
							
								
								
									
										7
									
								
								vendor/github.com/gorilla/rpc/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/gorilla/rpc/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| rpc | ||||
| === | ||||
| [](https://travis-ci.org/gorilla/rpc) | ||||
|  | ||||
| gorilla/rpc is a foundation for RPC over HTTP services, providing access to the exported methods of an object through HTTP requests. | ||||
|  | ||||
| Read the full documentation here: http://www.gorillatoolkit.org/pkg/rpc | ||||
							
								
								
									
										27
									
								
								vendor/github.com/gorilla/rpc/v2/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/gorilla/rpc/v2/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| Copyright (c) 2012 Rodrigo Moraes. All rights reserved. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are | ||||
| met: | ||||
|  | ||||
| 	 * Redistributions of source code must retain the above copyright | ||||
| notice, this list of conditions and the following disclaimer. | ||||
| 	 * Redistributions in binary form must reproduce the above | ||||
| copyright notice, this list of conditions and the following disclaimer | ||||
| in the documentation and/or other materials provided with the | ||||
| distribution. | ||||
| 	 * Neither the name of Google Inc. nor the names of its | ||||
| contributors may be used to endorse or promote products derived from | ||||
| this software without specific prior written permission. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
							
								
								
									
										6
									
								
								vendor/github.com/gorilla/rpc/v2/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/gorilla/rpc/v2/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| rpc | ||||
| === | ||||
|  | ||||
| gorilla/rpc is a foundation for RPC over HTTP services, providing access to the exported methods of an object through HTTP requests. | ||||
|  | ||||
| Read the full documentation here: http://www.gorillatoolkit.org/pkg/rpc | ||||
							
								
								
									
										90
									
								
								vendor/github.com/gorilla/rpc/v2/compression_selector.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								vendor/github.com/gorilla/rpc/v2/compression_selector.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,90 @@ | ||||
| // Copyright 2009 The Go Authors. All rights reserved. | ||||
| // Copyright 2012 The Gorilla Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package rpc | ||||
|  | ||||
| import ( | ||||
| 	"compress/flate" | ||||
| 	"compress/gzip" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 	"unicode" | ||||
| ) | ||||
|  | ||||
| // gzipWriter writes and closes the gzip writer. | ||||
| type gzipWriter struct { | ||||
| 	w *gzip.Writer | ||||
| } | ||||
|  | ||||
| func (gw *gzipWriter) Write(p []byte) (n int, err error) { | ||||
| 	defer gw.w.Close() | ||||
| 	return gw.w.Write(p) | ||||
| } | ||||
|  | ||||
| // gzipEncoder implements the gzip compressed http encoder. | ||||
| type gzipEncoder struct { | ||||
| } | ||||
|  | ||||
| func (enc *gzipEncoder) Encode(w http.ResponseWriter) io.Writer { | ||||
| 	w.Header().Set("Content-Encoding", "gzip") | ||||
| 	return &gzipWriter{gzip.NewWriter(w)} | ||||
| } | ||||
|  | ||||
| // flateWriter writes and closes the flate writer. | ||||
| type flateWriter struct { | ||||
| 	w *flate.Writer | ||||
| } | ||||
|  | ||||
| func (fw *flateWriter) Write(p []byte) (n int, err error) { | ||||
| 	defer fw.w.Close() | ||||
| 	return fw.w.Write(p) | ||||
| } | ||||
|  | ||||
| // flateEncoder implements the flate compressed http encoder. | ||||
| type flateEncoder struct { | ||||
| } | ||||
|  | ||||
| func (enc *flateEncoder) Encode(w http.ResponseWriter) io.Writer { | ||||
| 	fw, err := flate.NewWriter(w, flate.DefaultCompression) | ||||
| 	if err != nil { | ||||
| 		return w | ||||
| 	} | ||||
| 	w.Header().Set("Content-Encoding", "deflate") | ||||
| 	return &flateWriter{fw} | ||||
| } | ||||
|  | ||||
| // CompressionSelector generates the compressed http encoder. | ||||
| type CompressionSelector struct { | ||||
| } | ||||
|  | ||||
| // acceptedEnc returns the first compression type in "Accept-Encoding" header | ||||
| // field of the request. | ||||
| func acceptedEnc(req *http.Request) string { | ||||
| 	encHeader := req.Header.Get("Accept-Encoding") | ||||
| 	if encHeader == "" { | ||||
| 		return "" | ||||
| 	} | ||||
| 	encTypes := strings.FieldsFunc(encHeader, func(r rune) bool { | ||||
| 		return unicode.IsSpace(r) || r == ',' | ||||
| 	}) | ||||
| 	for _, enc := range encTypes { | ||||
| 		if enc == "gzip" || enc == "deflate" { | ||||
| 			return enc | ||||
| 		} | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| // Select method selects the correct compression encoder based on http HEADER. | ||||
| func (_ *CompressionSelector) Select(r *http.Request) Encoder { | ||||
| 	switch acceptedEnc(r) { | ||||
| 	case "gzip": | ||||
| 		return &gzipEncoder{} | ||||
| 	case "flate": | ||||
| 		return &flateEncoder{} | ||||
| 	} | ||||
| 	return DefaultEncoder | ||||
| } | ||||
							
								
								
									
										81
									
								
								vendor/github.com/gorilla/rpc/v2/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								vendor/github.com/gorilla/rpc/v2/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | ||||
| // Copyright 2009 The Go Authors. All rights reserved. | ||||
| // Copyright 2012 The Gorilla Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| /* | ||||
| Package gorilla/rpc is a foundation for RPC over HTTP services, providing | ||||
| access to the exported methods of an object through HTTP requests. | ||||
|  | ||||
| This package derives from the standard net/rpc package but uses a single HTTP | ||||
| request per call instead of persistent connections. Other differences | ||||
| compared to net/rpc: | ||||
|  | ||||
| 	- Multiple codecs can be registered in the same server. | ||||
| 	- A codec is chosen based on the "Content-Type" header from the request. | ||||
| 	- Service methods also receive http.Request as parameter. | ||||
| 	- This package can be used on Google App Engine. | ||||
|  | ||||
| Let's setup a server and register a codec and service: | ||||
|  | ||||
| 	import ( | ||||
| 		"http" | ||||
| 		"github.com/gorilla/rpc/v2" | ||||
| 		"github.com/gorilla/rpc/v2/json" | ||||
| 	) | ||||
|  | ||||
| 	func init() { | ||||
| 		s := rpc.NewServer() | ||||
| 		s.RegisterCodec(json.NewCodec(), "application/json") | ||||
| 		s.RegisterService(new(HelloService), "") | ||||
| 		http.Handle("/rpc", s) | ||||
| 	} | ||||
|  | ||||
| This server handles requests to the "/rpc" path using a JSON codec. | ||||
| A codec is tied to a content type. In the example above, the JSON codec is | ||||
| registered to serve requests with "application/json" as the value for the | ||||
| "Content-Type" header. If the header includes a charset definition, it is | ||||
| ignored; only the media-type part is taken into account. | ||||
|  | ||||
| A service can be registered using a name. If the name is empty, like in the | ||||
| example above, it will be inferred from the service type. | ||||
|  | ||||
| That's all about the server setup. Now let's define a simple service: | ||||
|  | ||||
| 	type HelloArgs struct { | ||||
| 		Who string | ||||
| 	} | ||||
|  | ||||
| 	type HelloReply struct { | ||||
| 		Message string | ||||
| 	} | ||||
|  | ||||
| 	type HelloService struct {} | ||||
|  | ||||
| 	func (h *HelloService) Say(r *http.Request, args *HelloArgs, reply *HelloReply) error { | ||||
| 		reply.Message = "Hello, " + args.Who + "!" | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| The example above defines a service with a method "HelloService.Say" and | ||||
| the arguments and reply related to that method. | ||||
|  | ||||
| The service must be exported (begin with an upper case letter) or local | ||||
| (defined in the package registering the service). | ||||
|  | ||||
| When a service is registered, the server inspects the service methods | ||||
| and make available the ones that follow these rules: | ||||
|  | ||||
| 	- The method name is exported. | ||||
| 	- The method has three arguments: *http.Request, *args, *reply. | ||||
| 	- All three arguments are pointers. | ||||
| 	- The second and third arguments are exported or local. | ||||
| 	- The method has return type error. | ||||
|  | ||||
| All other methods are ignored. | ||||
|  | ||||
| Gorilla has packages with common RPC codecs. Check out their documentation: | ||||
|  | ||||
| 	JSON: http://gorilla-web.appspot.com/pkg/rpc/json | ||||
| */ | ||||
| package rpc | ||||
							
								
								
									
										43
									
								
								vendor/github.com/gorilla/rpc/v2/encoder_selector.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								vendor/github.com/gorilla/rpc/v2/encoder_selector.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| // Copyright 2009 The Go Authors. All rights reserved. | ||||
| // Copyright 2012 The Gorilla Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package rpc | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| ) | ||||
|  | ||||
| // Encoder interface contains the encoder for http response. | ||||
| // Eg. gzip, flate compressions. | ||||
| type Encoder interface { | ||||
| 	Encode(w http.ResponseWriter) io.Writer | ||||
| } | ||||
|  | ||||
| type encoder struct { | ||||
| } | ||||
|  | ||||
| func (_ *encoder) Encode(w http.ResponseWriter) io.Writer { | ||||
| 	return w | ||||
| } | ||||
|  | ||||
| var DefaultEncoder = &encoder{} | ||||
|  | ||||
| // EncoderSelector interface provides a way to select encoder using the http | ||||
| // request. Typically people can use this to check HEADER of the request and | ||||
| // figure out client capabilities. | ||||
| // Eg. "Accept-Encoding" tells about supported compressions. | ||||
| type EncoderSelector interface { | ||||
| 	Select(r *http.Request) Encoder | ||||
| } | ||||
|  | ||||
| type encoderSelector struct { | ||||
| } | ||||
|  | ||||
| func (_ *encoderSelector) Select(_ *http.Request) Encoder { | ||||
| 	return DefaultEncoder | ||||
| } | ||||
|  | ||||
| var DefaultEncoderSelector = &encoderSelector{} | ||||
							
								
								
									
										75
									
								
								vendor/github.com/gorilla/rpc/v2/json2/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								vendor/github.com/gorilla/rpc/v2/json2/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| // Copyright 2009 The Go Authors. All rights reserved. | ||||
| // Copyright 2012 The Gorilla Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package json2 | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"io" | ||||
| 	"math/rand" | ||||
| ) | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Request and Response | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| // clientRequest represents a JSON-RPC request sent by a client. | ||||
| type clientRequest struct { | ||||
| 	// JSON-RPC protocol. | ||||
| 	Version string `json:"jsonrpc"` | ||||
|  | ||||
| 	// A String containing the name of the method to be invoked. | ||||
| 	Method string `json:"method"` | ||||
|  | ||||
| 	// Object to pass as request parameter to the method. | ||||
| 	Params interface{} `json:"params"` | ||||
|  | ||||
| 	// The request id. This can be of any type. It is used to match the | ||||
| 	// response with the request that it is replying to. | ||||
| 	Id uint64 `json:"id"` | ||||
| } | ||||
|  | ||||
| // clientResponse represents a JSON-RPC response returned to a client. | ||||
| type clientResponse struct { | ||||
| 	Version string           `json:"jsonrpc"` | ||||
| 	Result  *json.RawMessage `json:"result"` | ||||
| 	Error   *json.RawMessage `json:"error"` | ||||
| } | ||||
|  | ||||
| // EncodeClientRequest encodes parameters for a JSON-RPC client request. | ||||
| func EncodeClientRequest(method string, args interface{}) ([]byte, error) { | ||||
| 	c := &clientRequest{ | ||||
| 		Version: "2.0", | ||||
| 		Method:  method, | ||||
| 		Params:  args, | ||||
| 		Id:      uint64(rand.Int63()), | ||||
| 	} | ||||
| 	return json.Marshal(c) | ||||
| } | ||||
|  | ||||
| // DecodeClientResponse decodes the response body of a client request into | ||||
| // the interface reply. | ||||
| func DecodeClientResponse(r io.Reader, reply interface{}) error { | ||||
| 	var c clientResponse | ||||
| 	if err := json.NewDecoder(r).Decode(&c); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if c.Error != nil { | ||||
| 		jsonErr := &Error{} | ||||
| 		if err := json.Unmarshal(*c.Error, jsonErr); err != nil { | ||||
| 			return &Error{ | ||||
| 				Code:    E_SERVER, | ||||
| 				Message: string(*c.Error), | ||||
| 			} | ||||
| 		} | ||||
| 		return jsonErr | ||||
| 	} | ||||
|  | ||||
| 	if c.Result == nil { | ||||
| 		return ErrNullResult | ||||
| 	} | ||||
|  | ||||
| 	return json.Unmarshal(*c.Result, reply) | ||||
| } | ||||
							
								
								
									
										39
									
								
								vendor/github.com/gorilla/rpc/v2/json2/error.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/gorilla/rpc/v2/json2/error.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| // Copyright 2009 The Go Authors. All rights reserved. | ||||
| // Copyright 2012 The Gorilla Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package json2 | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| ) | ||||
|  | ||||
| type ErrorCode int | ||||
|  | ||||
| const ( | ||||
| 	E_PARSE       ErrorCode = -32700 | ||||
| 	E_INVALID_REQ ErrorCode = -32600 | ||||
| 	E_NO_METHOD   ErrorCode = -32601 | ||||
| 	E_BAD_PARAMS  ErrorCode = -32602 | ||||
| 	E_INTERNAL    ErrorCode = -32603 | ||||
| 	E_SERVER      ErrorCode = -32000 | ||||
| ) | ||||
|  | ||||
| var ErrNullResult = errors.New("result is null") | ||||
|  | ||||
| type Error struct { | ||||
| 	// A Number that indicates the error type that occurred. | ||||
| 	Code ErrorCode `json:"code"` /* required */ | ||||
|  | ||||
| 	// A String providing a short description of the error. | ||||
| 	// The message SHOULD be limited to a concise single sentence. | ||||
| 	Message string `json:"message"` /* required */ | ||||
|  | ||||
| 	// A Primitive or Structured value that contains additional information about the error. | ||||
| 	Data interface{} `json:"data"` /* optional */ | ||||
| } | ||||
|  | ||||
| func (e *Error) Error() string { | ||||
| 	return e.Message | ||||
| } | ||||
							
								
								
									
										202
									
								
								vendor/github.com/gorilla/rpc/v2/json2/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								vendor/github.com/gorilla/rpc/v2/json2/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,202 @@ | ||||
| // Copyright 2009 The Go Authors. All rights reserved. | ||||
| // Copyright 2012 The Gorilla Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package json2 | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"net/http" | ||||
|  | ||||
| 	"github.com/gorilla/rpc/v2" | ||||
| ) | ||||
|  | ||||
| var null = json.RawMessage([]byte("null")) | ||||
| var Version = "2.0" | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Request and Response | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| // serverRequest represents a JSON-RPC request received by the server. | ||||
| type serverRequest struct { | ||||
| 	// JSON-RPC protocol. | ||||
| 	Version string `json:"jsonrpc"` | ||||
|  | ||||
| 	// A String containing the name of the method to be invoked. | ||||
| 	Method string `json:"method"` | ||||
|  | ||||
| 	// A Structured value to pass as arguments to the method. | ||||
| 	Params *json.RawMessage `json:"params"` | ||||
|  | ||||
| 	// The request id. MUST be a string, number or null. | ||||
| 	// Our implementation will not do type checking for id. | ||||
| 	// It will be copied as it is. | ||||
| 	Id *json.RawMessage `json:"id"` | ||||
| } | ||||
|  | ||||
| // serverResponse represents a JSON-RPC response returned by the server. | ||||
| type serverResponse struct { | ||||
| 	// JSON-RPC protocol. | ||||
| 	Version string `json:"jsonrpc"` | ||||
|  | ||||
| 	// The Object that was returned by the invoked method. This must be null | ||||
| 	// in case there was an error invoking the method. | ||||
| 	// As per spec the member will be omitted if there was an error. | ||||
| 	Result interface{} `json:"result,omitempty"` | ||||
|  | ||||
| 	// An Error object if there was an error invoking the method. It must be | ||||
| 	// null if there was no error. | ||||
| 	// As per spec the member will be omitted if there was no error. | ||||
| 	Error *Error `json:"error,omitempty"` | ||||
|  | ||||
| 	// This must be the same id as the request it is responding to. | ||||
| 	Id *json.RawMessage `json:"id"` | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Codec | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| // NewcustomCodec returns a new JSON Codec based on passed encoder selector. | ||||
| func NewCustomCodec(encSel rpc.EncoderSelector) *Codec { | ||||
| 	return &Codec{encSel: encSel} | ||||
| } | ||||
|  | ||||
| // NewCodec returns a new JSON Codec. | ||||
| func NewCodec() *Codec { | ||||
| 	return NewCustomCodec(rpc.DefaultEncoderSelector) | ||||
| } | ||||
|  | ||||
| // Codec creates a CodecRequest to process each request. | ||||
| type Codec struct { | ||||
| 	encSel rpc.EncoderSelector | ||||
| } | ||||
|  | ||||
| // NewRequest returns a CodecRequest. | ||||
| func (c *Codec) NewRequest(r *http.Request) rpc.CodecRequest { | ||||
| 	return newCodecRequest(r, c.encSel.Select(r)) | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // CodecRequest | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| // newCodecRequest returns a new CodecRequest. | ||||
| func newCodecRequest(r *http.Request, encoder rpc.Encoder) rpc.CodecRequest { | ||||
| 	// Decode the request body and check if RPC method is valid. | ||||
| 	req := new(serverRequest) | ||||
| 	err := json.NewDecoder(r.Body).Decode(req) | ||||
| 	if err != nil { | ||||
| 		err = &Error{ | ||||
| 			Code:    E_PARSE, | ||||
| 			Message: err.Error(), | ||||
| 			Data:    req, | ||||
| 		} | ||||
| 	} | ||||
| 	if req.Version != Version { | ||||
| 		err = &Error{ | ||||
| 			Code:    E_INVALID_REQ, | ||||
| 			Message: "jsonrpc must be " + Version, | ||||
| 			Data:    req, | ||||
| 		} | ||||
| 	} | ||||
| 	r.Body.Close() | ||||
| 	return &CodecRequest{request: req, err: err, encoder: encoder} | ||||
| } | ||||
|  | ||||
| // CodecRequest decodes and encodes a single request. | ||||
| type CodecRequest struct { | ||||
| 	request *serverRequest | ||||
| 	err     error | ||||
| 	encoder rpc.Encoder | ||||
| } | ||||
|  | ||||
| // Method returns the RPC method for the current request. | ||||
| // | ||||
| // The method uses a dotted notation as in "Service.Method". | ||||
| func (c *CodecRequest) Method() (string, error) { | ||||
| 	if c.err == nil { | ||||
| 		return c.request.Method, nil | ||||
| 	} | ||||
| 	return "", c.err | ||||
| } | ||||
|  | ||||
| // ReadRequest fills the request object for the RPC method. | ||||
| // | ||||
| // ReadRequest parses request parameters in two supported forms in | ||||
| // accordance with http://www.jsonrpc.org/specification#parameter_structures | ||||
| // | ||||
| // by-position: params MUST be an Array, containing the | ||||
| // values in the Server expected order. | ||||
| // | ||||
| // by-name: params MUST be an Object, with member names | ||||
| // that match the Server expected parameter names. The | ||||
| // absence of expected names MAY result in an error being | ||||
| // generated. The names MUST match exactly, including | ||||
| // case, to the method's expected parameters. | ||||
| func (c *CodecRequest) ReadRequest(args interface{}) error { | ||||
| 	if c.err == nil && c.request.Params != nil { | ||||
| 		// Note: if c.request.Params is nil it's not an error, it's an optional member. | ||||
| 		// JSON params structured object. Unmarshal to the args object. | ||||
| 		if err := json.Unmarshal(*c.request.Params, args); err != nil { | ||||
| 			// Clearly JSON params is not a structured object, | ||||
| 			// fallback and attempt an unmarshal with JSON params as | ||||
| 			// array value and RPC params is struct. Unmarshal into | ||||
| 			// array containing the request struct. | ||||
| 			params := [1]interface{}{args} | ||||
| 			if err = json.Unmarshal(*c.request.Params, ¶ms); err != nil { | ||||
| 				c.err = &Error{ | ||||
| 					Code:    E_INVALID_REQ, | ||||
| 					Message: err.Error(), | ||||
| 					Data:    c.request.Params, | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return c.err | ||||
| } | ||||
|  | ||||
| // WriteResponse encodes the response and writes it to the ResponseWriter. | ||||
| func (c *CodecRequest) WriteResponse(w http.ResponseWriter, reply interface{}) { | ||||
| 	res := &serverResponse{ | ||||
| 		Version: Version, | ||||
| 		Result:  reply, | ||||
| 		Id:      c.request.Id, | ||||
| 	} | ||||
| 	c.writeServerResponse(w, res) | ||||
| } | ||||
|  | ||||
| func (c *CodecRequest) WriteError(w http.ResponseWriter, status int, err error) { | ||||
| 	jsonErr, ok := err.(*Error) | ||||
| 	if !ok { | ||||
| 		jsonErr = &Error{ | ||||
| 			Code:    E_SERVER, | ||||
| 			Message: err.Error(), | ||||
| 		} | ||||
| 	} | ||||
| 	res := &serverResponse{ | ||||
| 		Version: Version, | ||||
| 		Error:   jsonErr, | ||||
| 		Id:      c.request.Id, | ||||
| 	} | ||||
| 	c.writeServerResponse(w, res) | ||||
| } | ||||
|  | ||||
| func (c *CodecRequest) writeServerResponse(w http.ResponseWriter, res *serverResponse) { | ||||
| 	// Id is null for notifications and they don't have a response. | ||||
| 	if c.request.Id != nil { | ||||
| 		w.Header().Set("Content-Type", "application/json; charset=utf-8") | ||||
| 		encoder := json.NewEncoder(c.encoder.Encode(w)) | ||||
| 		err := encoder.Encode(res) | ||||
|  | ||||
| 		// Not sure in which case will this happen. But seems harmless. | ||||
| 		if err != nil { | ||||
| 			rpc.WriteError(w, 400, err.Error()) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type EmptyResponse struct { | ||||
| } | ||||
							
								
								
									
										164
									
								
								vendor/github.com/gorilla/rpc/v2/map.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								vendor/github.com/gorilla/rpc/v2/map.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,164 @@ | ||||
| // Copyright 2009 The Go Authors. All rights reserved. | ||||
| // Copyright 2012 The Gorilla Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package rpc | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"unicode" | ||||
| 	"unicode/utf8" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// Precompute the reflect.Type of error and http.Request | ||||
| 	typeOfError   = reflect.TypeOf((*error)(nil)).Elem() | ||||
| 	typeOfRequest = reflect.TypeOf((*http.Request)(nil)).Elem() | ||||
| ) | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // service | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| type service struct { | ||||
| 	name     string                    // name of service | ||||
| 	rcvr     reflect.Value             // receiver of methods for the service | ||||
| 	rcvrType reflect.Type              // type of the receiver | ||||
| 	methods  map[string]*serviceMethod // registered methods | ||||
| } | ||||
|  | ||||
| type serviceMethod struct { | ||||
| 	method    reflect.Method // receiver method | ||||
| 	argsType  reflect.Type   // type of the request argument | ||||
| 	replyType reflect.Type   // type of the response argument | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // serviceMap | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| // serviceMap is a registry for services. | ||||
| type serviceMap struct { | ||||
| 	mutex    sync.Mutex | ||||
| 	services map[string]*service | ||||
| } | ||||
|  | ||||
| // register adds a new service using reflection to extract its methods. | ||||
| func (m *serviceMap) register(rcvr interface{}, name string) error { | ||||
| 	// Setup service. | ||||
| 	s := &service{ | ||||
| 		name:     name, | ||||
| 		rcvr:     reflect.ValueOf(rcvr), | ||||
| 		rcvrType: reflect.TypeOf(rcvr), | ||||
| 		methods:  make(map[string]*serviceMethod), | ||||
| 	} | ||||
| 	if name == "" { | ||||
| 		s.name = reflect.Indirect(s.rcvr).Type().Name() | ||||
| 		if !isExported(s.name) { | ||||
| 			return fmt.Errorf("rpc: type %q is not exported", s.name) | ||||
| 		} | ||||
| 	} | ||||
| 	if s.name == "" { | ||||
| 		return fmt.Errorf("rpc: no service name for type %q", | ||||
| 			s.rcvrType.String()) | ||||
| 	} | ||||
| 	// Setup methods. | ||||
| 	for i := 0; i < s.rcvrType.NumMethod(); i++ { | ||||
| 		method := s.rcvrType.Method(i) | ||||
| 		mtype := method.Type | ||||
| 		// Method must be exported. | ||||
| 		if method.PkgPath != "" { | ||||
| 			continue | ||||
| 		} | ||||
| 		// Method needs four ins: receiver, *http.Request, *args, *reply. | ||||
| 		if mtype.NumIn() != 4 { | ||||
| 			continue | ||||
| 		} | ||||
| 		// First argument must be a pointer and must be http.Request. | ||||
| 		reqType := mtype.In(1) | ||||
| 		if reqType.Kind() != reflect.Ptr || reqType.Elem() != typeOfRequest { | ||||
| 			continue | ||||
| 		} | ||||
| 		// Second argument must be a pointer and must be exported. | ||||
| 		args := mtype.In(2) | ||||
| 		if args.Kind() != reflect.Ptr || !isExportedOrBuiltin(args) { | ||||
| 			continue | ||||
| 		} | ||||
| 		// Third argument must be a pointer and must be exported. | ||||
| 		reply := mtype.In(3) | ||||
| 		if reply.Kind() != reflect.Ptr || !isExportedOrBuiltin(reply) { | ||||
| 			continue | ||||
| 		} | ||||
| 		// Method needs one out: error. | ||||
| 		if mtype.NumOut() != 1 { | ||||
| 			continue | ||||
| 		} | ||||
| 		if returnType := mtype.Out(0); returnType != typeOfError { | ||||
| 			continue | ||||
| 		} | ||||
| 		s.methods[method.Name] = &serviceMethod{ | ||||
| 			method:    method, | ||||
| 			argsType:  args.Elem(), | ||||
| 			replyType: reply.Elem(), | ||||
| 		} | ||||
| 	} | ||||
| 	if len(s.methods) == 0 { | ||||
| 		return fmt.Errorf("rpc: %q has no exported methods of suitable type", | ||||
| 			s.name) | ||||
| 	} | ||||
| 	// Add to the map. | ||||
| 	m.mutex.Lock() | ||||
| 	defer m.mutex.Unlock() | ||||
| 	if m.services == nil { | ||||
| 		m.services = make(map[string]*service) | ||||
| 	} else if _, ok := m.services[s.name]; ok { | ||||
| 		return fmt.Errorf("rpc: service already defined: %q", s.name) | ||||
| 	} | ||||
| 	m.services[s.name] = s | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // get returns a registered service given a method name. | ||||
| // | ||||
| // The method name uses a dotted notation as in "Service.Method". | ||||
| func (m *serviceMap) get(method string) (*service, *serviceMethod, error) { | ||||
| 	parts := strings.Split(method, ".") | ||||
| 	if len(parts) != 2 { | ||||
| 		err := fmt.Errorf("rpc: service/method request ill-formed: %q", method) | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	m.mutex.Lock() | ||||
| 	service := m.services[parts[0]] | ||||
| 	m.mutex.Unlock() | ||||
| 	if service == nil { | ||||
| 		err := fmt.Errorf("rpc: can't find service %q", method) | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	serviceMethod := service.methods[parts[1]] | ||||
| 	if serviceMethod == nil { | ||||
| 		err := fmt.Errorf("rpc: can't find method %q", method) | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	return service, serviceMethod, nil | ||||
| } | ||||
|  | ||||
| // isExported returns true of a string is an exported (upper case) name. | ||||
| func isExported(name string) bool { | ||||
| 	rune, _ := utf8.DecodeRuneInString(name) | ||||
| 	return unicode.IsUpper(rune) | ||||
| } | ||||
|  | ||||
| // isExportedOrBuiltin returns true if a type is exported or a builtin. | ||||
| func isExportedOrBuiltin(t reflect.Type) bool { | ||||
| 	for t.Kind() == reflect.Ptr { | ||||
| 		t = t.Elem() | ||||
| 	} | ||||
| 	// PkgPath will be non-empty even for an exported type, | ||||
| 	// so we need to check the type name as well. | ||||
| 	return isExported(t.Name()) || t.PkgPath() == "" | ||||
| } | ||||
							
								
								
									
										164
									
								
								vendor/github.com/gorilla/rpc/v2/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								vendor/github.com/gorilla/rpc/v2/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,164 @@ | ||||
| // Copyright 2009 The Go Authors. All rights reserved. | ||||
| // Copyright 2012 The Gorilla Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package rpc | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Codec | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| // Codec creates a CodecRequest to process each request. | ||||
| type Codec interface { | ||||
| 	NewRequest(*http.Request) CodecRequest | ||||
| } | ||||
|  | ||||
| // CodecRequest decodes a request and encodes a response using a specific | ||||
| // serialization scheme. | ||||
| type CodecRequest interface { | ||||
| 	// Reads the request and returns the RPC method name. | ||||
| 	Method() (string, error) | ||||
| 	// Reads the request filling the RPC method args. | ||||
| 	ReadRequest(interface{}) error | ||||
| 	// Writes the response using the RPC method reply. | ||||
| 	WriteResponse(http.ResponseWriter, interface{}) | ||||
| 	// Writes an error produced by the server. | ||||
| 	WriteError(w http.ResponseWriter, status int, err error) | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Server | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| // NewServer returns a new RPC server. | ||||
| func NewServer() *Server { | ||||
| 	return &Server{ | ||||
| 		codecs:   make(map[string]Codec), | ||||
| 		services: new(serviceMap), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Server serves registered RPC services using registered codecs. | ||||
| type Server struct { | ||||
| 	codecs   map[string]Codec | ||||
| 	services *serviceMap | ||||
| } | ||||
|  | ||||
| // RegisterCodec adds a new codec to the server. | ||||
| // | ||||
| // Codecs are defined to process a given serialization scheme, e.g., JSON or | ||||
| // XML. A codec is chosen based on the "Content-Type" header from the request, | ||||
| // excluding the charset definition. | ||||
| func (s *Server) RegisterCodec(codec Codec, contentType string) { | ||||
| 	s.codecs[strings.ToLower(contentType)] = codec | ||||
| } | ||||
|  | ||||
| // RegisterService adds a new service to the server. | ||||
| // | ||||
| // The name parameter is optional: if empty it will be inferred from | ||||
| // the receiver type name. | ||||
| // | ||||
| // Methods from the receiver will be extracted if these rules are satisfied: | ||||
| // | ||||
| //    - The receiver is exported (begins with an upper case letter) or local | ||||
| //      (defined in the package registering the service). | ||||
| //    - The method name is exported. | ||||
| //    - The method has three arguments: *http.Request, *args, *reply. | ||||
| //    - All three arguments are pointers. | ||||
| //    - The second and third arguments are exported or local. | ||||
| //    - The method has return type error. | ||||
| // | ||||
| // All other methods are ignored. | ||||
| func (s *Server) RegisterService(receiver interface{}, name string) error { | ||||
| 	return s.services.register(receiver, name) | ||||
| } | ||||
|  | ||||
| // HasMethod returns true if the given method is registered. | ||||
| // | ||||
| // The method uses a dotted notation as in "Service.Method". | ||||
| func (s *Server) HasMethod(method string) bool { | ||||
| 	if _, _, err := s.services.get(method); err == nil { | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // ServeHTTP | ||||
| func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||||
| 	if r.Method != "POST" { | ||||
| 		WriteError(w, 405, "rpc: POST method required, received "+r.Method) | ||||
| 		return | ||||
| 	} | ||||
| 	contentType := r.Header.Get("Content-Type") | ||||
| 	idx := strings.Index(contentType, ";") | ||||
| 	if idx != -1 { | ||||
| 		contentType = contentType[:idx] | ||||
| 	} | ||||
| 	var codec Codec | ||||
| 	if contentType == "" && len(s.codecs) == 1 { | ||||
| 		// If Content-Type is not set and only one codec has been registered, | ||||
| 		// then default to that codec. | ||||
| 		for _, c := range s.codecs { | ||||
| 			codec = c | ||||
| 		} | ||||
| 	} else if codec = s.codecs[strings.ToLower(contentType)]; codec == nil { | ||||
| 		WriteError(w, 415, "rpc: unrecognized Content-Type: "+contentType) | ||||
| 		return | ||||
| 	} | ||||
| 	// Create a new codec request. | ||||
| 	codecReq := codec.NewRequest(r) | ||||
| 	// Get service method to be called. | ||||
| 	method, errMethod := codecReq.Method() | ||||
| 	if errMethod != nil { | ||||
| 		codecReq.WriteError(w, 400, errMethod) | ||||
| 		return | ||||
| 	} | ||||
| 	serviceSpec, methodSpec, errGet := s.services.get(method) | ||||
| 	if errGet != nil { | ||||
| 		codecReq.WriteError(w, 400, errGet) | ||||
| 		return | ||||
| 	} | ||||
| 	// Decode the args. | ||||
| 	args := reflect.New(methodSpec.argsType) | ||||
| 	if errRead := codecReq.ReadRequest(args.Interface()); errRead != nil { | ||||
| 		codecReq.WriteError(w, 400, errRead) | ||||
| 		return | ||||
| 	} | ||||
| 	// Call the service method. | ||||
| 	reply := reflect.New(methodSpec.replyType) | ||||
| 	errValue := methodSpec.method.Func.Call([]reflect.Value{ | ||||
| 		serviceSpec.rcvr, | ||||
| 		reflect.ValueOf(r), | ||||
| 		args, | ||||
| 		reply, | ||||
| 	}) | ||||
| 	// Cast the result to error if needed. | ||||
| 	var errResult error | ||||
| 	errInter := errValue[0].Interface() | ||||
| 	if errInter != nil { | ||||
| 		errResult = errInter.(error) | ||||
| 	} | ||||
| 	// Prevents Internet Explorer from MIME-sniffing a response away | ||||
| 	// from the declared content-type | ||||
| 	w.Header().Set("x-content-type-options", "nosniff") | ||||
| 	// Encode the response. | ||||
| 	if errResult == nil { | ||||
| 		codecReq.WriteResponse(w, reply.Interface()) | ||||
| 	} else { | ||||
| 		codecReq.WriteError(w, 400, errResult) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func WriteError(w http.ResponseWriter, status int, msg string) { | ||||
| 	w.WriteHeader(status) | ||||
| 	w.Header().Set("Content-Type", "text/plain; charset=utf-8") | ||||
| 	fmt.Fprint(w, msg) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user