Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / github.com / emicklei / go-restful / route.go
1 package restful
2
3 // Copyright 2013 Ernest Micklei. All rights reserved.
4 // Use of this source code is governed by a license
5 // that can be found in the LICENSE file.
6
7 import (
8         "net/http"
9         "strings"
10 )
11
12 // RouteFunction declares the signature of a function that can be bound to a Route.
13 type RouteFunction func(*Request, *Response)
14
15 // RouteSelectionConditionFunction declares the signature of a function that
16 // can be used to add extra conditional logic when selecting whether the route
17 // matches the HTTP request.
18 type RouteSelectionConditionFunction func(httpRequest *http.Request) bool
19
20 // Route binds a HTTP Method,Path,Consumes combination to a RouteFunction.
21 type Route struct {
22         Method   string
23         Produces []string
24         Consumes []string
25         Path     string // webservice root path + described path
26         Function RouteFunction
27         Filters  []FilterFunction
28         If       []RouteSelectionConditionFunction
29
30         // cached values for dispatching
31         relativePath string
32         pathParts    []string
33         pathExpr     *pathExpression // cached compilation of relativePath as RegExp
34
35         // documentation
36         Doc                     string
37         Notes                   string
38         Operation               string
39         ParameterDocs           []*Parameter
40         ResponseErrors          map[int]ResponseError
41         DefaultResponse         *ResponseError
42         ReadSample, WriteSample interface{} // structs that model an example request or response payload
43
44         // Extra information used to store custom information about the route.
45         Metadata map[string]interface{}
46
47         // marks a route as deprecated
48         Deprecated bool
49
50         //Overrides the container.contentEncodingEnabled
51         contentEncodingEnabled *bool
52 }
53
54 // Initialize for Route
55 func (r *Route) postBuild() {
56         r.pathParts = tokenizePath(r.Path)
57 }
58
59 // Create Request and Response from their http versions
60 func (r *Route) wrapRequestResponse(httpWriter http.ResponseWriter, httpRequest *http.Request, pathParams map[string]string) (*Request, *Response) {
61         wrappedRequest := NewRequest(httpRequest)
62         wrappedRequest.pathParameters = pathParams
63         wrappedRequest.selectedRoutePath = r.Path
64         wrappedResponse := NewResponse(httpWriter)
65         wrappedResponse.requestAccept = httpRequest.Header.Get(HEADER_Accept)
66         wrappedResponse.routeProduces = r.Produces
67         return wrappedRequest, wrappedResponse
68 }
69
70 // dispatchWithFilters call the function after passing through its own filters
71 func (r *Route) dispatchWithFilters(wrappedRequest *Request, wrappedResponse *Response) {
72         if len(r.Filters) > 0 {
73                 chain := FilterChain{Filters: r.Filters, Target: r.Function}
74                 chain.ProcessFilter(wrappedRequest, wrappedResponse)
75         } else {
76                 // unfiltered
77                 r.Function(wrappedRequest, wrappedResponse)
78         }
79 }
80
81 func stringTrimSpaceCutset(r rune) bool {
82         return r == ' '
83 }
84
85 // Return whether the mimeType matches to what this Route can produce.
86 func (r Route) matchesAccept(mimeTypesWithQuality string) bool {
87         remaining := mimeTypesWithQuality
88         for {
89                 var mimeType string
90                 if end := strings.Index(remaining, ","); end == -1 {
91                         mimeType, remaining = remaining, ""
92                 } else {
93                         mimeType, remaining = remaining[:end], remaining[end+1:]
94                 }
95                 if quality := strings.Index(mimeType, ";"); quality != -1 {
96                         mimeType = mimeType[:quality]
97                 }
98                 mimeType = strings.TrimFunc(mimeType, stringTrimSpaceCutset)
99                 if mimeType == "*/*" {
100                         return true
101                 }
102                 for _, producibleType := range r.Produces {
103                         if producibleType == "*/*" || producibleType == mimeType {
104                                 return true
105                         }
106                 }
107                 if len(remaining) == 0 {
108                         return false
109                 }
110         }
111 }
112
113 // Return whether this Route can consume content with a type specified by mimeTypes (can be empty).
114 func (r Route) matchesContentType(mimeTypes string) bool {
115
116         if len(r.Consumes) == 0 {
117                 // did not specify what it can consume ;  any media type (“*/*”) is assumed
118                 return true
119         }
120
121         if len(mimeTypes) == 0 {
122                 // idempotent methods with (most-likely or guaranteed) empty content match missing Content-Type
123                 m := r.Method
124                 if m == "GET" || m == "HEAD" || m == "OPTIONS" || m == "DELETE" || m == "TRACE" {
125                         return true
126                 }
127                 // proceed with default
128                 mimeTypes = MIME_OCTET
129         }
130
131         remaining := mimeTypes
132         for {
133                 var mimeType string
134                 if end := strings.Index(remaining, ","); end == -1 {
135                         mimeType, remaining = remaining, ""
136                 } else {
137                         mimeType, remaining = remaining[:end], remaining[end+1:]
138                 }
139                 if quality := strings.Index(mimeType, ";"); quality != -1 {
140                         mimeType = mimeType[:quality]
141                 }
142                 mimeType = strings.TrimFunc(mimeType, stringTrimSpaceCutset)
143                 for _, consumeableType := range r.Consumes {
144                         if consumeableType == "*/*" || consumeableType == mimeType {
145                                 return true
146                         }
147                 }
148                 if len(remaining) == 0 {
149                         return false
150                 }
151         }
152 }
153
154 // Tokenize an URL path using the slash separator ; the result does not have empty tokens
155 func tokenizePath(path string) []string {
156         if "/" == path {
157                 return nil
158         }
159         return strings.Split(strings.Trim(path, "/"), "/")
160 }
161
162 // for debugging
163 func (r Route) String() string {
164         return r.Method + " " + r.Path
165 }
166
167 // EnableContentEncoding (default=false) allows for GZIP or DEFLATE encoding of responses. Overrides the container.contentEncodingEnabled value.
168 func (r Route) EnableContentEncoding(enabled bool) {
169         r.contentEncodingEnabled = &enabled
170 }