summaryrefslogtreecommitdiff
path: root/vendor/github.com/emicklei/go-restful/route.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/emicklei/go-restful/route.go')
-rw-r--r--vendor/github.com/emicklei/go-restful/route.go186
1 files changed, 186 insertions, 0 deletions
diff --git a/vendor/github.com/emicklei/go-restful/route.go b/vendor/github.com/emicklei/go-restful/route.go
new file mode 100644
index 000000000..3dd520eec
--- /dev/null
+++ b/vendor/github.com/emicklei/go-restful/route.go
@@ -0,0 +1,186 @@
+package restful
+
+// Copyright 2013 Ernest Micklei. All rights reserved.
+// Use of this source code is governed by a license
+// that can be found in the LICENSE file.
+
+import (
+ "bytes"
+ "net/http"
+ "strings"
+)
+
+// RouteFunction declares the signature of a function that can be bound to a Route.
+type RouteFunction func(*Request, *Response)
+
+// Route binds a HTTP Method,Path,Consumes combination to a RouteFunction.
+type Route struct {
+ Method string
+ Produces []string
+ Consumes []string
+ Path string // webservice root path + described path
+ Function RouteFunction
+ Filters []FilterFunction
+
+ // cached values for dispatching
+ relativePath string
+ pathParts []string
+ pathExpr *pathExpression // cached compilation of relativePath as RegExp
+
+ // documentation
+ Doc string
+ Notes string
+ Operation string
+ ParameterDocs []*Parameter
+ ResponseErrors map[int]ResponseError
+ ReadSample, WriteSample interface{} // structs that model an example request or response payload
+
+ // Extra information used to store custom information about the route.
+ Metadata map[string]interface{}
+}
+
+// Initialize for Route
+func (r *Route) postBuild() {
+ r.pathParts = tokenizePath(r.Path)
+}
+
+// Create Request and Response from their http versions
+func (r *Route) wrapRequestResponse(httpWriter http.ResponseWriter, httpRequest *http.Request) (*Request, *Response) {
+ params := r.extractParameters(httpRequest.URL.Path)
+ wrappedRequest := NewRequest(httpRequest)
+ wrappedRequest.pathParameters = params
+ wrappedRequest.selectedRoutePath = r.Path
+ wrappedResponse := NewResponse(httpWriter)
+ wrappedResponse.requestAccept = httpRequest.Header.Get(HEADER_Accept)
+ wrappedResponse.routeProduces = r.Produces
+ return wrappedRequest, wrappedResponse
+}
+
+// dispatchWithFilters call the function after passing through its own filters
+func (r *Route) dispatchWithFilters(wrappedRequest *Request, wrappedResponse *Response) {
+ if len(r.Filters) > 0 {
+ chain := FilterChain{Filters: r.Filters, Target: r.Function}
+ chain.ProcessFilter(wrappedRequest, wrappedResponse)
+ } else {
+ // unfiltered
+ r.Function(wrappedRequest, wrappedResponse)
+ }
+}
+
+// Return whether the mimeType matches to what this Route can produce.
+func (r Route) matchesAccept(mimeTypesWithQuality string) bool {
+ parts := strings.Split(mimeTypesWithQuality, ",")
+ for _, each := range parts {
+ var withoutQuality string
+ if strings.Contains(each, ";") {
+ withoutQuality = strings.Split(each, ";")[0]
+ } else {
+ withoutQuality = each
+ }
+ // trim before compare
+ withoutQuality = strings.Trim(withoutQuality, " ")
+ if withoutQuality == "*/*" {
+ return true
+ }
+ for _, producibleType := range r.Produces {
+ if producibleType == "*/*" || producibleType == withoutQuality {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// Return whether this Route can consume content with a type specified by mimeTypes (can be empty).
+func (r Route) matchesContentType(mimeTypes string) bool {
+
+ if len(r.Consumes) == 0 {
+ // did not specify what it can consume ; any media type (“*/*”) is assumed
+ return true
+ }
+
+ if len(mimeTypes) == 0 {
+ // idempotent methods with (most-likely or garanteed) empty content match missing Content-Type
+ m := r.Method
+ if m == "GET" || m == "HEAD" || m == "OPTIONS" || m == "DELETE" || m == "TRACE" {
+ return true
+ }
+ // proceed with default
+ mimeTypes = MIME_OCTET
+ }
+
+ parts := strings.Split(mimeTypes, ",")
+ for _, each := range parts {
+ var contentType string
+ if strings.Contains(each, ";") {
+ contentType = strings.Split(each, ";")[0]
+ } else {
+ contentType = each
+ }
+ // trim before compare
+ contentType = strings.Trim(contentType, " ")
+ for _, consumeableType := range r.Consumes {
+ if consumeableType == "*/*" || consumeableType == contentType {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// Extract the parameters from the request url path
+func (r Route) extractParameters(urlPath string) map[string]string {
+ urlParts := tokenizePath(urlPath)
+ pathParameters := map[string]string{}
+ for i, key := range r.pathParts {
+ var value string
+ if i >= len(urlParts) {
+ value = ""
+ } else {
+ value = urlParts[i]
+ }
+ if strings.HasPrefix(key, "{") { // path-parameter
+ if colon := strings.Index(key, ":"); colon != -1 {
+ // extract by regex
+ regPart := key[colon+1 : len(key)-1]
+ keyPart := key[1:colon]
+ if regPart == "*" {
+ pathParameters[keyPart] = untokenizePath(i, urlParts)
+ break
+ } else {
+ pathParameters[keyPart] = value
+ }
+ } else {
+ // without enclosing {}
+ pathParameters[key[1:len(key)-1]] = value
+ }
+ }
+ }
+ return pathParameters
+}
+
+// Untokenize back into an URL path using the slash separator
+func untokenizePath(offset int, parts []string) string {
+ var buffer bytes.Buffer
+ for p := offset; p < len(parts); p++ {
+ buffer.WriteString(parts[p])
+ // do not end
+ if p < len(parts)-1 {
+ buffer.WriteString("/")
+ }
+ }
+ return buffer.String()
+}
+
+// Tokenize an URL path using the slash separator ; the result does not have empty tokens
+func tokenizePath(path string) []string {
+ if "/" == path {
+ return []string{}
+ }
+ return strings.Split(strings.Trim(path, "/"), "/")
+}
+
+// for debugging
+func (r Route) String() string {
+ return r.Method + " " + r.Path
+}