mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Switch to v3 of github.com/emicklei/go-restful
Signed-off-by: Davanum Srinivas <davanum@gmail.com>
This commit is contained in:
		
							
								
								
									
										6
									
								
								vendor/github.com/emicklei/go-restful/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/emicklei/go-restful/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,6 +0,0 @@
 | 
			
		||||
language: go
 | 
			
		||||
 | 
			
		||||
go:
 | 
			
		||||
  - 1.x
 | 
			
		||||
 | 
			
		||||
script: go test -v
 | 
			
		||||
							
								
								
									
										7
									
								
								vendor/github.com/emicklei/go-restful/Makefile
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/emicklei/go-restful/Makefile
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,7 +0,0 @@
 | 
			
		||||
all: test
 | 
			
		||||
 | 
			
		||||
test:
 | 
			
		||||
	go test -v .
 | 
			
		||||
 | 
			
		||||
ex:
 | 
			
		||||
	cd examples && ls *.go | xargs go build -o /tmp/ignore
 | 
			
		||||
@@ -68,3 +68,4 @@ examples/restful-html-template
 | 
			
		||||
 | 
			
		||||
s.html
 | 
			
		||||
restful-path-tail
 | 
			
		||||
.idea
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/emicklei/go-restful/v3/.goconvey
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/emicklei/go-restful/v3/.goconvey
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
ignore
 | 
			
		||||
							
								
								
									
										13
									
								
								vendor/github.com/emicklei/go-restful/v3/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/emicklei/go-restful/v3/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
language: go
 | 
			
		||||
 | 
			
		||||
go:
 | 
			
		||||
  - 1.x
 | 
			
		||||
 | 
			
		||||
before_install:
 | 
			
		||||
  - go test -v
 | 
			
		||||
 | 
			
		||||
script:
 | 
			
		||||
  - go test -race -coverprofile=coverage.txt -covermode=atomic
 | 
			
		||||
 | 
			
		||||
after_success:
 | 
			
		||||
  - bash <(curl -s https://codecov.io/bash)
 | 
			
		||||
@@ -1,7 +1,96 @@
 | 
			
		||||
## Change history of go-restful
 | 
			
		||||
# Change history of go-restful
 | 
			
		||||
 | 
			
		||||
## [v3.7.2] - 2021-11-24
 | 
			
		||||
 | 
			
		||||
- restored FilterChain (#482 by SVilgelm)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## [v3.7.1] - 2021-10-04
 | 
			
		||||
 | 
			
		||||
- fix problem with contentEncodingEnabled setting (#479)
 | 
			
		||||
 | 
			
		||||
## [v3.7.0] - 2021-09-24
 | 
			
		||||
 | 
			
		||||
- feat(parameter): adds additional openapi mappings (#478)
 | 
			
		||||
 | 
			
		||||
## [v3.6.0] - 2021-09-18
 | 
			
		||||
 | 
			
		||||
- add support for vendor extensions (#477 thx erraggy)
 | 
			
		||||
 | 
			
		||||
## [v3.5.2] - 2021-07-14
 | 
			
		||||
 | 
			
		||||
- fix removing absent route from webservice (#472)
 | 
			
		||||
 | 
			
		||||
## [v3.5.1] - 2021-04-12
 | 
			
		||||
 | 
			
		||||
- fix handling no match access selected path
 | 
			
		||||
- remove obsolete field
 | 
			
		||||
 | 
			
		||||
## [v3.5.0] - 2021-04-10
 | 
			
		||||
 | 
			
		||||
- add check for wildcard (#463) in CORS
 | 
			
		||||
- add access to Route from Request, issue #459 (#462)
 | 
			
		||||
 | 
			
		||||
## [v3.4.0] - 2020-11-10
 | 
			
		||||
 | 
			
		||||
- Added OPTIONS to WebService
 | 
			
		||||
 | 
			
		||||
## [v3.3.2] - 2020-01-23
 | 
			
		||||
 | 
			
		||||
- Fixed duplicate compression in dispatch. #449
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## [v3.3.1] - 2020-08-31
 | 
			
		||||
 | 
			
		||||
- Added check on writer to prevent compression of response twice. #447
 | 
			
		||||
 | 
			
		||||
## [v3.3.0] - 2020-08-19
 | 
			
		||||
 | 
			
		||||
- Enable content encoding on Handle and ServeHTTP (#446)
 | 
			
		||||
- List available representations in 406 body (#437)
 | 
			
		||||
- Convert to string using rune() (#443)
 | 
			
		||||
 | 
			
		||||
## [v3.2.0] - 2020-06-21
 | 
			
		||||
 | 
			
		||||
- 405 Method Not Allowed must have Allow header (#436) (thx Bracken <abdawson@gmail.com>)
 | 
			
		||||
- add field allowedMethodsWithoutContentType (#424)
 | 
			
		||||
 | 
			
		||||
## [v3.1.0]
 | 
			
		||||
 | 
			
		||||
- support describing response headers (#426)
 | 
			
		||||
- fix openapi examples (#425)
 | 
			
		||||
 | 
			
		||||
v3.0.0
 | 
			
		||||
 | 
			
		||||
- fix: use request/response resulting from filter chain
 | 
			
		||||
- add Go module
 | 
			
		||||
  Module consumer should use github.com/emicklei/go-restful/v3 as import path
 | 
			
		||||
 | 
			
		||||
v2.10.0
 | 
			
		||||
 | 
			
		||||
- support for Custom Verbs (thanks Vinci Xu <277040271@qq.com>)
 | 
			
		||||
- fixed static example (thanks Arthur <yang_yapo@126.com>)
 | 
			
		||||
- simplify code (thanks Christian Muehlhaeuser <muesli@gmail.com>)
 | 
			
		||||
- added JWT HMAC with SHA-512 authentication code example (thanks Amim Knabben <amim.knabben@gmail.com>)
 | 
			
		||||
 | 
			
		||||
v2.9.6
 | 
			
		||||
 | 
			
		||||
- small optimization in filter code
 | 
			
		||||
 | 
			
		||||
v2.11.1
 | 
			
		||||
 | 
			
		||||
- fix WriteError return value (#415)
 | 
			
		||||
 | 
			
		||||
v2.11.0 
 | 
			
		||||
 | 
			
		||||
- allow prefix and suffix in path variable expression (#414)
 | 
			
		||||
 | 
			
		||||
v2.9.6
 | 
			
		||||
 | 
			
		||||
- support google custome verb (#413)
 | 
			
		||||
 | 
			
		||||
v2.9.5
 | 
			
		||||
 | 
			
		||||
- fix panic in Response.WriteError if err == nil
 | 
			
		||||
 | 
			
		||||
v2.9.4
 | 
			
		||||
							
								
								
									
										8
									
								
								vendor/github.com/emicklei/go-restful/v3/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/emicklei/go-restful/v3/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
all: test
 | 
			
		||||
 | 
			
		||||
test:
 | 
			
		||||
	go vet .
 | 
			
		||||
	go test -cover -v .
 | 
			
		||||
 | 
			
		||||
ex:
 | 
			
		||||
	find ./examples -type f -name "*.go" | xargs -I {} go build -o /tmp/ignore {}
 | 
			
		||||
@@ -4,9 +4,10 @@ package for building REST-style Web Services using Google Go
 | 
			
		||||
 | 
			
		||||
[](https://travis-ci.org/emicklei/go-restful)
 | 
			
		||||
[](https://goreportcard.com/report/github.com/emicklei/go-restful)
 | 
			
		||||
[](https://godoc.org/github.com/emicklei/go-restful)
 | 
			
		||||
[](https://pkg.go.dev/github.com/emicklei/go-restful)
 | 
			
		||||
[](https://codecov.io/gh/emicklei/go-restful)
 | 
			
		||||
 | 
			
		||||
- [Code examples](https://github.com/emicklei/go-restful/tree/master/examples)
 | 
			
		||||
- [Code examples use v3](https://github.com/emicklei/go-restful/tree/v3/examples)
 | 
			
		||||
 | 
			
		||||
REST asks developers to use HTTP methods explicitly and in a way that's consistent with the protocol definition. This basic REST design principle establishes a one-to-one mapping between create, read, update, and delete (CRUD) operations and HTTP methods. According to this mapping:
 | 
			
		||||
 | 
			
		||||
@@ -18,6 +19,28 @@ REST asks developers to use HTTP methods explicitly and in a way that's consiste
 | 
			
		||||
- PATCH = Update partial content of a resource
 | 
			
		||||
- OPTIONS = Get information about the communication options for the request URI
 | 
			
		||||
    
 | 
			
		||||
### Usage
 | 
			
		||||
 | 
			
		||||
#### Without Go Modules
 | 
			
		||||
 | 
			
		||||
All versions up to `v2.*.*` (on the master) are not supporting Go modules.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
import (
 | 
			
		||||
	restful "github.com/emicklei/go-restful"
 | 
			
		||||
)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Using Go Modules
 | 
			
		||||
 | 
			
		||||
As of version `v3.0.0` (on the v3 branch), this package supports Go modules.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
import (
 | 
			
		||||
	restful "github.com/emicklei/go-restful/v3"
 | 
			
		||||
)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Example
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
@@ -39,15 +62,15 @@ func (u UserResource) findUser(request *restful.Request, response *restful.Respo
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
	
 | 
			
		||||
[Full API of a UserResource](https://github.com/emicklei/go-restful/tree/master/examples/restful-user-resource.go) 
 | 
			
		||||
[Full API of a UserResource](https://github.com/emicklei/go-restful/blob/v3/examples/user-resource/restful-user-resource.go) 
 | 
			
		||||
		
 | 
			
		||||
### Features
 | 
			
		||||
 | 
			
		||||
- Routes for request → function mapping with path parameter (e.g. {id}) support
 | 
			
		||||
- Routes for request → function mapping with path parameter (e.g. {id} but also prefix_{var} and {var}_suffix) support
 | 
			
		||||
- Configurable router:
 | 
			
		||||
	- (default) Fast routing algorithm that allows static elements, regular expressions and dynamic parameters in the URL path (e.g. /meetings/{id} or /static/{subpath:*}
 | 
			
		||||
	- (default) Fast routing algorithm that allows static elements, [google custom method](https://cloud.google.com/apis/design/custom_methods), regular expressions and dynamic parameters in the URL path (e.g. /resource/name:customVerb, /meetings/{id} or /static/{subpath:*})
 | 
			
		||||
	- Routing algorithm after [JSR311](http://jsr311.java.net/nonav/releases/1.1/spec/spec.html) that is implemented using (but does **not** accept) regular expressions
 | 
			
		||||
- Request API for reading structs from JSON/XML and accesing parameters (path,query,header)
 | 
			
		||||
- Request API for reading structs from JSON/XML and accessing parameters (path,query,header)
 | 
			
		||||
- Response API for writing structs to JSON/XML and setting headers
 | 
			
		||||
- Customizable encoding using EntityReaderWriter registration
 | 
			
		||||
- Filters for intercepting the request → response flow on Service or Route level
 | 
			
		||||
@@ -85,4 +108,4 @@ TODO: write examples of these.
 | 
			
		||||
 | 
			
		||||
Type ```git shortlog -s``` for a full list of contributors.
 | 
			
		||||
 | 
			
		||||
© 2012 - 2018, http://ernestmicklei.com. MIT License. Contributions are welcome.
 | 
			
		||||
© 2012 - 2021, http://ernestmicklei.com. MIT License. Contributions are welcome.
 | 
			
		||||
							
								
								
									
										13
									
								
								vendor/github.com/emicklei/go-restful/v3/SECURITY.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/emicklei/go-restful/v3/SECURITY.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
# Security Policy
 | 
			
		||||
 | 
			
		||||
## Supported Versions
 | 
			
		||||
 | 
			
		||||
| Version | Supported          |
 | 
			
		||||
| ------- | ------------------ |
 | 
			
		||||
| v3.7.x     | :white_check_mark: |
 | 
			
		||||
| < v3.0.1   | :x:                |
 | 
			
		||||
 | 
			
		||||
## Reporting a Vulnerability
 | 
			
		||||
 | 
			
		||||
Create an Issue and put the label `[security]` in the title of the issue.
 | 
			
		||||
Valid reported security issues are expected to be solved within a week.
 | 
			
		||||
@@ -83,7 +83,11 @@ func (c *CompressingResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WantsCompressedResponse reads the Accept-Encoding header to see if and which encoding is requested.
 | 
			
		||||
func wantsCompressedResponse(httpRequest *http.Request) (bool, string) {
 | 
			
		||||
// It also inspects the httpWriter whether its content-encoding is already set (non-empty).
 | 
			
		||||
func wantsCompressedResponse(httpRequest *http.Request, httpWriter http.ResponseWriter) (bool, string) {
 | 
			
		||||
	if contentEncoding := httpWriter.Header().Get(HEADER_ContentEncoding); contentEncoding != "" {
 | 
			
		||||
		return false, ""
 | 
			
		||||
	}
 | 
			
		||||
	header := httpRequest.Header.Get(HEADER_AcceptEncoding)
 | 
			
		||||
	gi := strings.Index(header, ENCODING_GZIP)
 | 
			
		||||
	zi := strings.Index(header, ENCODING_DEFLATE)
 | 
			
		||||
@@ -14,7 +14,7 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/emicklei/go-restful/log"
 | 
			
		||||
	"github.com/emicklei/go-restful/v3/log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Container holds a collection of WebServices and a http.ServeMux to dispatch http requests.
 | 
			
		||||
@@ -185,6 +185,11 @@ func logStackOnRecover(panicReason interface{}, httpWriter http.ResponseWriter)
 | 
			
		||||
// when a ServiceError is returned during route selection. Default implementation
 | 
			
		||||
// calls resp.WriteErrorString(err.Code, err.Message)
 | 
			
		||||
func writeServiceError(err ServiceError, req *Request, resp *Response) {
 | 
			
		||||
	for header, values := range err.Header {
 | 
			
		||||
		for _, value := range values {
 | 
			
		||||
			resp.Header().Add(header, value)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	resp.WriteErrorString(err.Code, err.Message)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -201,6 +206,7 @@ func (c *Container) Dispatch(httpWriter http.ResponseWriter, httpRequest *http.R
 | 
			
		||||
 | 
			
		||||
// Dispatch the incoming Http Request to a matching WebService.
 | 
			
		||||
func (c *Container) dispatch(httpWriter http.ResponseWriter, httpRequest *http.Request) {
 | 
			
		||||
	// so we can assign a compressing one later
 | 
			
		||||
	writer := httpWriter
 | 
			
		||||
 | 
			
		||||
	// CompressingResponseWriter should be closed after all operations are done
 | 
			
		||||
@@ -231,28 +237,8 @@ func (c *Container) dispatch(httpWriter http.ResponseWriter, httpRequest *http.R
 | 
			
		||||
			c.webServices,
 | 
			
		||||
			httpRequest)
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	// Detect if compression is needed
 | 
			
		||||
	// assume without compression, test for override
 | 
			
		||||
	contentEncodingEnabled := c.contentEncodingEnabled
 | 
			
		||||
	if route != nil && route.contentEncodingEnabled != nil {
 | 
			
		||||
		contentEncodingEnabled = *route.contentEncodingEnabled
 | 
			
		||||
	}
 | 
			
		||||
	if contentEncodingEnabled {
 | 
			
		||||
		doCompress, encoding := wantsCompressedResponse(httpRequest)
 | 
			
		||||
		if doCompress {
 | 
			
		||||
			var err error
 | 
			
		||||
			writer, err = NewCompressingResponseWriter(httpWriter, encoding)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Print("unable to install compressor: ", err)
 | 
			
		||||
				httpWriter.WriteHeader(http.StatusInternalServerError)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// a non-200 response has already been written
 | 
			
		||||
		// a non-200 response (may be compressed) has already been written
 | 
			
		||||
		// run container filters anyway ; they should not touch the response...
 | 
			
		||||
		chain := FilterChain{Filters: c.containerFilters, Target: func(req *Request, resp *Response) {
 | 
			
		||||
			switch err.(type) {
 | 
			
		||||
@@ -265,6 +251,29 @@ func (c *Container) dispatch(httpWriter http.ResponseWriter, httpRequest *http.R
 | 
			
		||||
		chain.ProcessFilter(NewRequest(httpRequest), NewResponse(writer))
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Unless httpWriter is already an CompressingResponseWriter see if we need to install one
 | 
			
		||||
	if _, isCompressing := httpWriter.(*CompressingResponseWriter); !isCompressing {
 | 
			
		||||
		// Detect if compression is needed
 | 
			
		||||
		// assume without compression, test for override
 | 
			
		||||
		contentEncodingEnabled := c.contentEncodingEnabled
 | 
			
		||||
		if route != nil && route.contentEncodingEnabled != nil {
 | 
			
		||||
			contentEncodingEnabled = *route.contentEncodingEnabled
 | 
			
		||||
		}
 | 
			
		||||
		if contentEncodingEnabled {
 | 
			
		||||
			doCompress, encoding := wantsCompressedResponse(httpRequest, httpWriter)
 | 
			
		||||
			if doCompress {
 | 
			
		||||
				var err error
 | 
			
		||||
				writer, err = NewCompressingResponseWriter(httpWriter, encoding)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					log.Print("unable to install compressor: ", err)
 | 
			
		||||
					httpWriter.WriteHeader(http.StatusInternalServerError)
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pathProcessor, routerProcessesPath := c.router.(PathProcessor)
 | 
			
		||||
	if !routerProcessesPath {
 | 
			
		||||
		pathProcessor = defaultPathProcessor{}
 | 
			
		||||
@@ -272,16 +281,18 @@ func (c *Container) dispatch(httpWriter http.ResponseWriter, httpRequest *http.R
 | 
			
		||||
	pathParams := pathProcessor.ExtractParameters(route, webService, httpRequest.URL.Path)
 | 
			
		||||
	wrappedRequest, wrappedResponse := route.wrapRequestResponse(writer, httpRequest, pathParams)
 | 
			
		||||
	// pass through filters (if any)
 | 
			
		||||
	if len(c.containerFilters)+len(webService.filters)+len(route.Filters) > 0 {
 | 
			
		||||
	if size := len(c.containerFilters) + len(webService.filters) + len(route.Filters); size > 0 {
 | 
			
		||||
		// compose filter chain
 | 
			
		||||
		allFilters := []FilterFunction{}
 | 
			
		||||
		allFilters := make([]FilterFunction, 0, size)
 | 
			
		||||
		allFilters = append(allFilters, c.containerFilters...)
 | 
			
		||||
		allFilters = append(allFilters, webService.filters...)
 | 
			
		||||
		allFilters = append(allFilters, route.Filters...)
 | 
			
		||||
		chain := FilterChain{Filters: allFilters, Target: func(req *Request, resp *Response) {
 | 
			
		||||
			// handle request by route after passing all filters
 | 
			
		||||
			route.Function(wrappedRequest, wrappedResponse)
 | 
			
		||||
		}}
 | 
			
		||||
		chain := FilterChain{
 | 
			
		||||
			Filters:       allFilters,
 | 
			
		||||
			Target:        route.Function,
 | 
			
		||||
			ParameterDocs: route.ParameterDocs,
 | 
			
		||||
			Operation:     route.Operation,
 | 
			
		||||
		}
 | 
			
		||||
		chain.ProcessFilter(wrappedRequest, wrappedResponse)
 | 
			
		||||
	} else {
 | 
			
		||||
		// no filters, handle request by route
 | 
			
		||||
@@ -299,13 +310,75 @@ func fixedPrefixPath(pathspec string) string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ServeHTTP implements net/http.Handler therefore a Container can be a Handler in a http.Server
 | 
			
		||||
func (c *Container) ServeHTTP(httpwriter http.ResponseWriter, httpRequest *http.Request) {
 | 
			
		||||
	c.ServeMux.ServeHTTP(httpwriter, httpRequest)
 | 
			
		||||
func (c *Container) ServeHTTP(httpWriter http.ResponseWriter, httpRequest *http.Request) {
 | 
			
		||||
	// Skip, if content encoding is disabled
 | 
			
		||||
	if !c.contentEncodingEnabled {
 | 
			
		||||
		c.ServeMux.ServeHTTP(httpWriter, httpRequest)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	// content encoding is enabled
 | 
			
		||||
 | 
			
		||||
	// Skip, if httpWriter is already an CompressingResponseWriter
 | 
			
		||||
	if _, ok := httpWriter.(*CompressingResponseWriter); ok {
 | 
			
		||||
		c.ServeMux.ServeHTTP(httpWriter, httpRequest)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	writer := httpWriter
 | 
			
		||||
	// CompressingResponseWriter should be closed after all operations are done
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if compressWriter, ok := writer.(*CompressingResponseWriter); ok {
 | 
			
		||||
			compressWriter.Close()
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	doCompress, encoding := wantsCompressedResponse(httpRequest, httpWriter)
 | 
			
		||||
	if doCompress {
 | 
			
		||||
		var err error
 | 
			
		||||
		writer, err = NewCompressingResponseWriter(httpWriter, encoding)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Print("unable to install compressor: ", err)
 | 
			
		||||
			httpWriter.WriteHeader(http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.ServeMux.ServeHTTP(writer, httpRequest)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle registers the handler for the given pattern. If a handler already exists for pattern, Handle panics.
 | 
			
		||||
func (c *Container) Handle(pattern string, handler http.Handler) {
 | 
			
		||||
	c.ServeMux.Handle(pattern, handler)
 | 
			
		||||
	c.ServeMux.Handle(pattern, http.HandlerFunc(func(httpWriter http.ResponseWriter, httpRequest *http.Request) {
 | 
			
		||||
		// Skip, if httpWriter is already an CompressingResponseWriter
 | 
			
		||||
		if _, ok := httpWriter.(*CompressingResponseWriter); ok {
 | 
			
		||||
			handler.ServeHTTP(httpWriter, httpRequest)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		writer := httpWriter
 | 
			
		||||
 | 
			
		||||
		// CompressingResponseWriter should be closed after all operations are done
 | 
			
		||||
		defer func() {
 | 
			
		||||
			if compressWriter, ok := writer.(*CompressingResponseWriter); ok {
 | 
			
		||||
				compressWriter.Close()
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
 | 
			
		||||
		if c.contentEncodingEnabled {
 | 
			
		||||
			doCompress, encoding := wantsCompressedResponse(httpRequest, httpWriter)
 | 
			
		||||
			if doCompress {
 | 
			
		||||
				var err error
 | 
			
		||||
				writer, err = NewCompressingResponseWriter(httpWriter, encoding)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					log.Print("unable to install compressor: ", err)
 | 
			
		||||
					httpWriter.WriteHeader(http.StatusInternalServerError)
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		handler.ServeHTTP(writer, httpRequest)
 | 
			
		||||
	}))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HandleWithFilter registers the handler for the given pattern.
 | 
			
		||||
@@ -319,7 +392,7 @@ func (c *Container) HandleWithFilter(pattern string, handler http.Handler) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		chain := FilterChain{Filters: c.containerFilters, Target: func(req *Request, resp *Response) {
 | 
			
		||||
			handler.ServeHTTP(httpResponse, httpRequest)
 | 
			
		||||
			handler.ServeHTTP(resp, req.Request)
 | 
			
		||||
		}}
 | 
			
		||||
		chain.ProcessFilter(NewRequest(httpRequest), NewResponse(httpResponse))
 | 
			
		||||
	}
 | 
			
		||||
@@ -184,6 +184,9 @@ func (c CrossOriginResourceSharing) isValidAccessControlRequestHeader(header str
 | 
			
		||||
		if strings.ToLower(each) == strings.ToLower(header) {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		if each == "*" {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
@@ -47,7 +47,7 @@ func (c CurlyRouter) SelectRoute(
 | 
			
		||||
func (c CurlyRouter) selectRoutes(ws *WebService, requestTokens []string) sortableCurlyRoutes {
 | 
			
		||||
	candidates := make(sortableCurlyRoutes, 0, 8)
 | 
			
		||||
	for _, each := range ws.routes {
 | 
			
		||||
		matches, paramCount, staticCount := c.matchesRouteByPathTokens(each.pathParts, requestTokens)
 | 
			
		||||
		matches, paramCount, staticCount := c.matchesRouteByPathTokens(each.pathParts, requestTokens, each.hasCustomVerb)
 | 
			
		||||
		if matches {
 | 
			
		||||
			candidates.add(curlyRoute{each, paramCount, staticCount}) // TODO make sure Routes() return pointers?
 | 
			
		||||
		}
 | 
			
		||||
@@ -57,7 +57,7 @@ func (c CurlyRouter) selectRoutes(ws *WebService, requestTokens []string) sortab
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// matchesRouteByPathTokens computes whether it matches, howmany parameters do match and what the number of static path elements are.
 | 
			
		||||
func (c CurlyRouter) matchesRouteByPathTokens(routeTokens, requestTokens []string) (matches bool, paramCount int, staticCount int) {
 | 
			
		||||
func (c CurlyRouter) matchesRouteByPathTokens(routeTokens, requestTokens []string, routeHasCustomVerb bool) (matches bool, paramCount int, staticCount int) {
 | 
			
		||||
	if len(routeTokens) < len(requestTokens) {
 | 
			
		||||
		// proceed in matching only if last routeToken is wildcard
 | 
			
		||||
		count := len(routeTokens)
 | 
			
		||||
@@ -72,6 +72,15 @@ func (c CurlyRouter) matchesRouteByPathTokens(routeTokens, requestTokens []strin
 | 
			
		||||
			return false, 0, 0
 | 
			
		||||
		}
 | 
			
		||||
		requestToken := requestTokens[i]
 | 
			
		||||
		if routeHasCustomVerb && hasCustomVerb(routeToken){
 | 
			
		||||
			if !isMatchCustomVerb(routeToken, requestToken) {
 | 
			
		||||
				return false, 0, 0
 | 
			
		||||
			}
 | 
			
		||||
			staticCount++
 | 
			
		||||
			requestToken = removeCustomVerb(requestToken)
 | 
			
		||||
			routeToken = removeCustomVerb(routeToken)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if strings.HasPrefix(routeToken, "{") {
 | 
			
		||||
			paramCount++
 | 
			
		||||
			if colon := strings.Index(routeToken, ":"); colon != -1 {
 | 
			
		||||
							
								
								
									
										29
									
								
								vendor/github.com/emicklei/go-restful/v3/custom_verb.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/emicklei/go-restful/v3/custom_verb.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
package restful
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"regexp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	customVerbReg = regexp.MustCompile(":([A-Za-z]+)$")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func hasCustomVerb(routeToken string) bool {
 | 
			
		||||
	return customVerbReg.MatchString(routeToken)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isMatchCustomVerb(routeToken string, pathToken string) bool {
 | 
			
		||||
	rs := customVerbReg.FindStringSubmatch(routeToken)
 | 
			
		||||
	if len(rs) < 2 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	customVerb := rs[1]
 | 
			
		||||
	specificVerbReg := regexp.MustCompile(fmt.Sprintf(":%s$", customVerb))
 | 
			
		||||
	return specificVerbReg.MatchString(pathToken)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func removeCustomVerb(str string) string {
 | 
			
		||||
	return customVerbReg.ReplaceAllString(str, "")
 | 
			
		||||
}
 | 
			
		||||
@@ -28,7 +28,7 @@ This package has the logic to find the best matching Route and if found, call it
 | 
			
		||||
 | 
			
		||||
The (*Request, *Response) arguments provide functions for reading information from the request and writing information back to the response.
 | 
			
		||||
 | 
			
		||||
See the example https://github.com/emicklei/go-restful/blob/master/examples/restful-user-resource.go with a full implementation.
 | 
			
		||||
See the example https://github.com/emicklei/go-restful/blob/v3/examples/user-resource/restful-user-resource.go with a full implementation.
 | 
			
		||||
 | 
			
		||||
Regular expression matching Routes
 | 
			
		||||
 | 
			
		||||
@@ -82,7 +82,7 @@ These are processed before calling the function associated with the Route.
 | 
			
		||||
	// install 2 chained route filters (processed before calling findUser)
 | 
			
		||||
	ws.Route(ws.GET("/{user-id}").Filter(routeLogging).Filter(NewCountFilter().routeCounter).To(findUser))
 | 
			
		||||
 | 
			
		||||
See the example https://github.com/emicklei/go-restful/blob/master/examples/restful-filters.go with full implementations.
 | 
			
		||||
See the example https://github.com/emicklei/go-restful/blob/v3/examples/filters/restful-filters.go with full implementations.
 | 
			
		||||
 | 
			
		||||
Response Encoding
 | 
			
		||||
 | 
			
		||||
@@ -93,7 +93,7 @@ Two encodings are supported: gzip and deflate. To enable this for all responses:
 | 
			
		||||
If a Http request includes the Accept-Encoding header then the response content will be compressed using the specified encoding.
 | 
			
		||||
Alternatively, you can create a Filter that performs the encoding and install it per WebService or Route.
 | 
			
		||||
 | 
			
		||||
See the example https://github.com/emicklei/go-restful/blob/master/examples/restful-encoding-filter.go
 | 
			
		||||
See the example https://github.com/emicklei/go-restful/blob/v3/examples/encoding/restful-encoding-filter.go
 | 
			
		||||
 | 
			
		||||
OPTIONS support
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										21
									
								
								vendor/github.com/emicklei/go-restful/v3/extensions.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/emicklei/go-restful/v3/extensions.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
package restful
 | 
			
		||||
 | 
			
		||||
// Copyright 2021 Ernest Micklei. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a license
 | 
			
		||||
// that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// ExtensionProperties provides storage of vendor extensions for entities
 | 
			
		||||
type ExtensionProperties struct {
 | 
			
		||||
	// Extensions vendor extensions used to describe extra functionality
 | 
			
		||||
	// (https://swagger.io/docs/specification/2-0/swagger-extensions/)
 | 
			
		||||
	Extensions map[string]interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddExtension adds or updates a key=value pair to the extension map.
 | 
			
		||||
func (ep *ExtensionProperties) AddExtension(key string, value interface{}) {
 | 
			
		||||
	if ep.Extensions == nil {
 | 
			
		||||
		ep.Extensions = map[string]interface{}{key: value}
 | 
			
		||||
	} else {
 | 
			
		||||
		ep.Extensions[key] = value
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -6,9 +6,11 @@ package restful
 | 
			
		||||
 | 
			
		||||
// FilterChain is a request scoped object to process one or more filters before calling the target RouteFunction.
 | 
			
		||||
type FilterChain struct {
 | 
			
		||||
	Filters []FilterFunction // ordered list of FilterFunction
 | 
			
		||||
	Index   int              // index into filters that is currently in progress
 | 
			
		||||
	Target  RouteFunction    // function to call after passing all filters
 | 
			
		||||
	Filters       []FilterFunction // ordered list of FilterFunction
 | 
			
		||||
	Index         int              // index into filters that is currently in progress
 | 
			
		||||
	Target        RouteFunction    // function to call after passing all filters
 | 
			
		||||
	ParameterDocs []*Parameter     // the parameter docs for the route
 | 
			
		||||
	Operation     string           // the name of the operation
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ProcessFilter passes the request,response pair through the next of Filters.
 | 
			
		||||
@@ -9,6 +9,7 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// RouterJSR311 implements the flow for matching Requests to Routes (and consequently Resource Functions)
 | 
			
		||||
@@ -98,7 +99,18 @@ func (r RouterJSR311) detectRoute(routes []Route, httpRequest *http.Request) (*R
 | 
			
		||||
		if trace {
 | 
			
		||||
			traceLogger.Printf("no Route found (in %d routes) that matches HTTP method %s\n", len(previous), httpRequest.Method)
 | 
			
		||||
		}
 | 
			
		||||
		return nil, NewError(http.StatusMethodNotAllowed, "405: Method Not Allowed")
 | 
			
		||||
		allowed := []string{}
 | 
			
		||||
	allowedLoop:
 | 
			
		||||
		for _, candidate := range previous {
 | 
			
		||||
			for _, method := range allowed {
 | 
			
		||||
				if method == candidate.Method {
 | 
			
		||||
					continue allowedLoop
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			allowed = append(allowed, candidate.Method)
 | 
			
		||||
		}
 | 
			
		||||
		header := http.Header{"Allow": []string{strings.Join(allowed, ", ")}}
 | 
			
		||||
		return nil, NewErrorWithHeader(http.StatusMethodNotAllowed, "405: Method Not Allowed", header)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// content-type
 | 
			
		||||
@@ -135,7 +147,14 @@ func (r RouterJSR311) detectRoute(routes []Route, httpRequest *http.Request) (*R
 | 
			
		||||
		if trace {
 | 
			
		||||
			traceLogger.Printf("no Route found (from %d) that matches HTTP Accept: %s\n", len(previous), accept)
 | 
			
		||||
		}
 | 
			
		||||
		return nil, NewError(http.StatusNotAcceptable, "406: Not Acceptable")
 | 
			
		||||
		available := []string{}
 | 
			
		||||
		for _, candidate := range previous {
 | 
			
		||||
			available = append(available, candidate.Produces...)
 | 
			
		||||
		}
 | 
			
		||||
		return nil, NewError(
 | 
			
		||||
			http.StatusNotAcceptable,
 | 
			
		||||
			fmt.Sprintf("406: Not Acceptable\n\nAvailable representations: %s", strings.Join(available, ", ")),
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
	// return r.bestMatchByMedia(outputMediaOk, contentType, accept), nil
 | 
			
		||||
	return candidates[0], nil
 | 
			
		||||
@@ -4,7 +4,7 @@ package restful
 | 
			
		||||
// Use of this source code is governed by a license
 | 
			
		||||
// that can be found in the LICENSE file.
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/emicklei/go-restful/log"
 | 
			
		||||
	"github.com/emicklei/go-restful/v3/log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var trace bool = false
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
package restful
 | 
			
		||||
 | 
			
		||||
import "sort"
 | 
			
		||||
 | 
			
		||||
// 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.
 | 
			
		||||
@@ -52,13 +54,25 @@ type Parameter struct {
 | 
			
		||||
// ParameterData represents the state of a Parameter.
 | 
			
		||||
// It is made public to make it accessible to e.g. the Swagger package.
 | 
			
		||||
type ParameterData struct {
 | 
			
		||||
	ExtensionProperties
 | 
			
		||||
	Name, Description, DataType, DataFormat string
 | 
			
		||||
	Kind                                    int
 | 
			
		||||
	Required                                bool
 | 
			
		||||
	AllowableValues                         map[string]string
 | 
			
		||||
	AllowMultiple                           bool
 | 
			
		||||
	DefaultValue                            string
 | 
			
		||||
	CollectionFormat                        string
 | 
			
		||||
	// AllowableValues is deprecated. Use PossibleValues instead
 | 
			
		||||
	AllowableValues  map[string]string
 | 
			
		||||
	PossibleValues   []string
 | 
			
		||||
	AllowMultiple    bool
 | 
			
		||||
	AllowEmptyValue  bool
 | 
			
		||||
	DefaultValue     string
 | 
			
		||||
	CollectionFormat string
 | 
			
		||||
	Pattern          string
 | 
			
		||||
	Minimum          *float64
 | 
			
		||||
	Maximum          *float64
 | 
			
		||||
	MinLength        *int64
 | 
			
		||||
	MaxLength        *int64
 | 
			
		||||
	MinItems         *int64
 | 
			
		||||
	MaxItems         *int64
 | 
			
		||||
	UniqueItems      bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Data returns the state of the Parameter
 | 
			
		||||
@@ -106,9 +120,38 @@ func (p *Parameter) AllowMultiple(multiple bool) *Parameter {
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AllowableValues sets the allowableValues field and returns the receiver
 | 
			
		||||
// AddExtension adds or updates a key=value pair to the extension map
 | 
			
		||||
func (p *Parameter) AddExtension(key string, value interface{}) *Parameter {
 | 
			
		||||
	p.data.AddExtension(key, value)
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AllowEmptyValue sets the AllowEmptyValue field and returns the receiver
 | 
			
		||||
func (p *Parameter) AllowEmptyValue(multiple bool) *Parameter {
 | 
			
		||||
	p.data.AllowEmptyValue = multiple
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AllowableValues is deprecated. Use PossibleValues instead. Both will be set.
 | 
			
		||||
func (p *Parameter) AllowableValues(values map[string]string) *Parameter {
 | 
			
		||||
	p.data.AllowableValues = values
 | 
			
		||||
 | 
			
		||||
	allowableSortedKeys := make([]string, 0, len(values))
 | 
			
		||||
	for k := range values {
 | 
			
		||||
		allowableSortedKeys = append(allowableSortedKeys, k)
 | 
			
		||||
	}
 | 
			
		||||
	sort.Strings(allowableSortedKeys)
 | 
			
		||||
 | 
			
		||||
	p.data.PossibleValues = make([]string, 0, len(values))
 | 
			
		||||
	for _, k := range allowableSortedKeys {
 | 
			
		||||
		p.data.PossibleValues = append(p.data.PossibleValues, values[k])
 | 
			
		||||
	}
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PossibleValues sets the possible values field and returns the receiver
 | 
			
		||||
func (p *Parameter) PossibleValues(values []string) *Parameter {
 | 
			
		||||
	p.data.PossibleValues = values
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -141,3 +184,51 @@ func (p *Parameter) CollectionFormat(format CollectionFormat) *Parameter {
 | 
			
		||||
	p.data.CollectionFormat = format.String()
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Pattern sets the pattern field and returns the receiver
 | 
			
		||||
func (p *Parameter) Pattern(pattern string) *Parameter {
 | 
			
		||||
	p.data.Pattern = pattern
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Minimum sets the minimum field and returns the receiver
 | 
			
		||||
func (p *Parameter) Minimum(minimum float64) *Parameter {
 | 
			
		||||
	p.data.Minimum = &minimum
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Maximum sets the maximum field and returns the receiver
 | 
			
		||||
func (p *Parameter) Maximum(maximum float64) *Parameter {
 | 
			
		||||
	p.data.Maximum = &maximum
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MinLength sets the minLength field and returns the receiver
 | 
			
		||||
func (p *Parameter) MinLength(minLength int64) *Parameter {
 | 
			
		||||
	p.data.MinLength = &minLength
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MaxLength sets the maxLength field and returns the receiver
 | 
			
		||||
func (p *Parameter) MaxLength(maxLength int64) *Parameter {
 | 
			
		||||
	p.data.MaxLength = &maxLength
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MinItems sets the minItems field and returns the receiver
 | 
			
		||||
func (p *Parameter) MinItems(minItems int64) *Parameter {
 | 
			
		||||
	p.data.MinItems = &minItems
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MaxItems sets the maxItems field and returns the receiver
 | 
			
		||||
func (p *Parameter) MaxItems(maxItems int64) *Parameter {
 | 
			
		||||
	p.data.MaxItems = &maxItems
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UniqueItems sets the uniqueItems field and returns the receiver
 | 
			
		||||
func (p *Parameter) UniqueItems(uniqueItems bool) *Parameter {
 | 
			
		||||
	p.data.UniqueItems = uniqueItems
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
@@ -29,7 +29,12 @@ func (d defaultPathProcessor) ExtractParameters(r *Route, _ *WebService, urlPath
 | 
			
		||||
		} else {
 | 
			
		||||
			value = urlParts[i]
 | 
			
		||||
		}
 | 
			
		||||
		if strings.HasPrefix(key, "{") { // path-parameter
 | 
			
		||||
		if r.hasCustomVerb && hasCustomVerb(key) {
 | 
			
		||||
			key = removeCustomVerb(key)
 | 
			
		||||
			value = removeCustomVerb(value)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if strings.Index(key, "{") > -1 { // path-parameter
 | 
			
		||||
			if colon := strings.Index(key, ":"); colon != -1 {
 | 
			
		||||
				// extract by regex
 | 
			
		||||
				regPart := key[colon+1 : len(key)-1]
 | 
			
		||||
@@ -42,7 +47,13 @@ func (d defaultPathProcessor) ExtractParameters(r *Route, _ *WebService, urlPath
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				// without enclosing {}
 | 
			
		||||
				pathParameters[key[1:len(key)-1]] = value
 | 
			
		||||
				startIndex := strings.Index(key, "{")
 | 
			
		||||
				endKeyIndex := strings.Index(key, "}")
 | 
			
		||||
 | 
			
		||||
				suffixLength := len(key) - endKeyIndex - 1
 | 
			
		||||
				endValueIndex := len(value) - suffixLength
 | 
			
		||||
 | 
			
		||||
				pathParameters[key[startIndex+1:endKeyIndex]] = value[startIndex:endValueIndex]
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -13,10 +13,10 @@ var defaultRequestContentType string
 | 
			
		||||
 | 
			
		||||
// Request is a wrapper for a http Request that provides convenience methods
 | 
			
		||||
type Request struct {
 | 
			
		||||
	Request           *http.Request
 | 
			
		||||
	pathParameters    map[string]string
 | 
			
		||||
	attributes        map[string]interface{} // for storing request-scoped values
 | 
			
		||||
	selectedRoutePath string                 // root path + route path that matched the request, e.g. /meetings/{id}/attendees
 | 
			
		||||
	Request        *http.Request
 | 
			
		||||
	pathParameters map[string]string
 | 
			
		||||
	attributes     map[string]interface{} // for storing request-scoped values
 | 
			
		||||
	selectedRoute  *Route                 // is nil when no route was matched
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewRequest(httpRequest *http.Request) *Request {
 | 
			
		||||
@@ -113,6 +113,20 @@ func (r Request) Attribute(name string) interface{} {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SelectedRoutePath root path + route path that matched the request, e.g. /meetings/{id}/attendees
 | 
			
		||||
// If no route was matched then return an empty string.
 | 
			
		||||
func (r Request) SelectedRoutePath() string {
 | 
			
		||||
	return r.selectedRoutePath
 | 
			
		||||
	if r.selectedRoute == nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	// skip creating an accessor
 | 
			
		||||
	return r.selectedRoute.Path
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SelectedRoute returns a reader to access the selected Route by the container
 | 
			
		||||
// Returns nil if no route was matched.
 | 
			
		||||
func (r Request) SelectedRoute() RouteReader {
 | 
			
		||||
	if r.selectedRoute == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return routeAccessor{route: r.selectedRoute}
 | 
			
		||||
}
 | 
			
		||||
@@ -174,15 +174,16 @@ func (r *Response) WriteHeaderAndJson(status int, value interface{}, contentType
 | 
			
		||||
	return writeJSON(r, status, contentType, value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteError write the http status and the error string on the response. err can be nil.
 | 
			
		||||
func (r *Response) WriteError(httpStatus int, err error) error {
 | 
			
		||||
// WriteError writes the http status and the error string on the response. err can be nil.
 | 
			
		||||
// Return an error if writing was not successful.
 | 
			
		||||
func (r *Response) WriteError(httpStatus int, err error) (writeErr error) {
 | 
			
		||||
	r.err = err
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		r.WriteErrorString(httpStatus, "")
 | 
			
		||||
		writeErr = r.WriteErrorString(httpStatus, "")
 | 
			
		||||
	} else {
 | 
			
		||||
		r.WriteErrorString(httpStatus, err.Error())
 | 
			
		||||
		writeErr = r.WriteErrorString(httpStatus, err.Error())
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
	return writeErr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteServiceError is a convenience method for a responding with a status and a ServiceError
 | 
			
		||||
@@ -19,6 +19,7 @@ type RouteSelectionConditionFunction func(httpRequest *http.Request) bool
 | 
			
		||||
 | 
			
		||||
// Route binds a HTTP Method,Path,Consumes combination to a RouteFunction.
 | 
			
		||||
type Route struct {
 | 
			
		||||
	ExtensionProperties
 | 
			
		||||
	Method   string
 | 
			
		||||
	Produces []string
 | 
			
		||||
	Consumes []string
 | 
			
		||||
@@ -49,35 +50,33 @@ type Route struct {
 | 
			
		||||
 | 
			
		||||
	//Overrides the container.contentEncodingEnabled
 | 
			
		||||
	contentEncodingEnabled *bool
 | 
			
		||||
 | 
			
		||||
	// indicate route path has custom verb
 | 
			
		||||
	hasCustomVerb bool
 | 
			
		||||
 | 
			
		||||
	// if a request does not include a content-type header then
 | 
			
		||||
	// depending on the method, it may return a 415 Unsupported Media
 | 
			
		||||
	// Must have uppercase HTTP Method names such as GET,HEAD,OPTIONS,...
 | 
			
		||||
	allowedMethodsWithoutContentType []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Initialize for Route
 | 
			
		||||
func (r *Route) postBuild() {
 | 
			
		||||
	r.pathParts = tokenizePath(r.Path)
 | 
			
		||||
	r.hasCustomVerb = hasCustomVerb(r.Path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Create Request and Response from their http versions
 | 
			
		||||
func (r *Route) wrapRequestResponse(httpWriter http.ResponseWriter, httpRequest *http.Request, pathParams map[string]string) (*Request, *Response) {
 | 
			
		||||
	wrappedRequest := NewRequest(httpRequest)
 | 
			
		||||
	wrappedRequest.pathParameters = pathParams
 | 
			
		||||
	wrappedRequest.selectedRoutePath = r.Path
 | 
			
		||||
	wrappedRequest.selectedRoute = r
 | 
			
		||||
	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)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func stringTrimSpaceCutset(r rune) bool {
 | 
			
		||||
	return r == ' '
 | 
			
		||||
}
 | 
			
		||||
@@ -121,8 +120,17 @@ func (r Route) matchesContentType(mimeTypes string) bool {
 | 
			
		||||
	if len(mimeTypes) == 0 {
 | 
			
		||||
		// idempotent methods with (most-likely or guaranteed) empty content match missing Content-Type
 | 
			
		||||
		m := r.Method
 | 
			
		||||
		if m == "GET" || m == "HEAD" || m == "OPTIONS" || m == "DELETE" || m == "TRACE" {
 | 
			
		||||
			return true
 | 
			
		||||
		// if route specifies less or non-idempotent methods then use that
 | 
			
		||||
		if len(r.allowedMethodsWithoutContentType) > 0 {
 | 
			
		||||
			for _, each := range r.allowedMethodsWithoutContentType {
 | 
			
		||||
				if m == each {
 | 
			
		||||
					return true
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if m == "GET" || m == "HEAD" || m == "OPTIONS" || m == "DELETE" || m == "TRACE" {
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		// proceed with default
 | 
			
		||||
		mimeTypes = MIME_OCTET
 | 
			
		||||
@@ -165,6 +173,6 @@ func (r Route) String() string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EnableContentEncoding (default=false) allows for GZIP or DEFLATE encoding of responses. Overrides the container.contentEncodingEnabled value.
 | 
			
		||||
func (r Route) EnableContentEncoding(enabled bool) {
 | 
			
		||||
func (r *Route) EnableContentEncoding(enabled bool) {
 | 
			
		||||
	r.contentEncodingEnabled = &enabled
 | 
			
		||||
}
 | 
			
		||||
@@ -12,19 +12,20 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync/atomic"
 | 
			
		||||
 | 
			
		||||
	"github.com/emicklei/go-restful/log"
 | 
			
		||||
	"github.com/emicklei/go-restful/v3/log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// RouteBuilder is a helper to construct Routes.
 | 
			
		||||
type RouteBuilder struct {
 | 
			
		||||
	rootPath    string
 | 
			
		||||
	currentPath string
 | 
			
		||||
	produces    []string
 | 
			
		||||
	consumes    []string
 | 
			
		||||
	httpMethod  string        // required
 | 
			
		||||
	function    RouteFunction // required
 | 
			
		||||
	filters     []FilterFunction
 | 
			
		||||
	conditions  []RouteSelectionConditionFunction
 | 
			
		||||
	rootPath                         string
 | 
			
		||||
	currentPath                      string
 | 
			
		||||
	produces                         []string
 | 
			
		||||
	consumes                         []string
 | 
			
		||||
	httpMethod                       string        // required
 | 
			
		||||
	function                         RouteFunction // required
 | 
			
		||||
	filters                          []FilterFunction
 | 
			
		||||
	conditions                       []RouteSelectionConditionFunction
 | 
			
		||||
	allowedMethodsWithoutContentType []string // see Route
 | 
			
		||||
 | 
			
		||||
	typeNameHandleFunc TypeNameHandleFunction // required
 | 
			
		||||
 | 
			
		||||
@@ -37,6 +38,7 @@ type RouteBuilder struct {
 | 
			
		||||
	errorMap                map[int]ResponseError
 | 
			
		||||
	defaultResponse         *ResponseError
 | 
			
		||||
	metadata                map[string]interface{}
 | 
			
		||||
	extensions              map[string]interface{}
 | 
			
		||||
	deprecated              bool
 | 
			
		||||
	contentEncodingEnabled  *bool
 | 
			
		||||
}
 | 
			
		||||
@@ -176,6 +178,15 @@ func (b *RouteBuilder) Returns(code int, message string, model interface{}) *Rou
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReturnsWithHeaders is similar to Returns, but can specify response headers
 | 
			
		||||
func (b *RouteBuilder) ReturnsWithHeaders(code int, message string, model interface{}, headers map[string]Header) *RouteBuilder {
 | 
			
		||||
	b.Returns(code, message, model)
 | 
			
		||||
	err := b.errorMap[code]
 | 
			
		||||
	err.Headers = headers
 | 
			
		||||
	b.errorMap[code] = err
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DefaultReturns is a special Returns call that sets the default of the response.
 | 
			
		||||
func (b *RouteBuilder) DefaultReturns(message string, model interface{}) *RouteBuilder {
 | 
			
		||||
	b.defaultResponse = &ResponseError{
 | 
			
		||||
@@ -194,20 +205,57 @@ func (b *RouteBuilder) Metadata(key string, value interface{}) *RouteBuilder {
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddExtension adds or updates a key=value pair to the extensions map.
 | 
			
		||||
func (b *RouteBuilder) AddExtension(key string, value interface{}) *RouteBuilder {
 | 
			
		||||
	if b.extensions == nil {
 | 
			
		||||
		b.extensions = map[string]interface{}{}
 | 
			
		||||
	}
 | 
			
		||||
	b.extensions[key] = value
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Deprecate sets the value of deprecated to true.  Deprecated routes have a special UI treatment to warn against use
 | 
			
		||||
func (b *RouteBuilder) Deprecate() *RouteBuilder {
 | 
			
		||||
	b.deprecated = true
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AllowedMethodsWithoutContentType overrides the default list GET,HEAD,OPTIONS,DELETE,TRACE
 | 
			
		||||
// If a request does not include a content-type header then
 | 
			
		||||
// depending on the method, it may return a 415 Unsupported Media.
 | 
			
		||||
// Must have uppercase HTTP Method names such as GET,HEAD,OPTIONS,...
 | 
			
		||||
func (b *RouteBuilder) AllowedMethodsWithoutContentType(methods []string) *RouteBuilder {
 | 
			
		||||
	b.allowedMethodsWithoutContentType = methods
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ResponseError represents a response; not necessarily an error.
 | 
			
		||||
type ResponseError struct {
 | 
			
		||||
	ExtensionProperties
 | 
			
		||||
	Code      int
 | 
			
		||||
	Message   string
 | 
			
		||||
	Model     interface{}
 | 
			
		||||
	Headers   map[string]Header
 | 
			
		||||
	IsDefault bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Header describes a header for a response of the API
 | 
			
		||||
//
 | 
			
		||||
// For more information: http://goo.gl/8us55a#headerObject
 | 
			
		||||
type Header struct {
 | 
			
		||||
	*Items
 | 
			
		||||
	Description string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Items describe swagger simple schemas for headers
 | 
			
		||||
type Items struct {
 | 
			
		||||
	Type             string
 | 
			
		||||
	Format           string
 | 
			
		||||
	Items            *Items
 | 
			
		||||
	CollectionFormat string
 | 
			
		||||
	Default          interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *RouteBuilder) servicePath(path string) *RouteBuilder {
 | 
			
		||||
	b.rootPath = path
 | 
			
		||||
	return b
 | 
			
		||||
@@ -276,27 +324,29 @@ func (b *RouteBuilder) Build() Route {
 | 
			
		||||
		operationName = nameOfFunction(b.function)
 | 
			
		||||
	}
 | 
			
		||||
	route := Route{
 | 
			
		||||
		Method:                 b.httpMethod,
 | 
			
		||||
		Path:                   concatPath(b.rootPath, b.currentPath),
 | 
			
		||||
		Produces:               b.produces,
 | 
			
		||||
		Consumes:               b.consumes,
 | 
			
		||||
		Function:               b.function,
 | 
			
		||||
		Filters:                b.filters,
 | 
			
		||||
		If:                     b.conditions,
 | 
			
		||||
		relativePath:           b.currentPath,
 | 
			
		||||
		pathExpr:               pathExpr,
 | 
			
		||||
		Doc:                    b.doc,
 | 
			
		||||
		Notes:                  b.notes,
 | 
			
		||||
		Operation:              operationName,
 | 
			
		||||
		ParameterDocs:          b.parameters,
 | 
			
		||||
		ResponseErrors:         b.errorMap,
 | 
			
		||||
		DefaultResponse:        b.defaultResponse,
 | 
			
		||||
		ReadSample:             b.readSample,
 | 
			
		||||
		WriteSample:            b.writeSample,
 | 
			
		||||
		Metadata:               b.metadata,
 | 
			
		||||
		Deprecated:             b.deprecated,
 | 
			
		||||
		contentEncodingEnabled: b.contentEncodingEnabled,
 | 
			
		||||
		Method:                           b.httpMethod,
 | 
			
		||||
		Path:                             concatPath(b.rootPath, b.currentPath),
 | 
			
		||||
		Produces:                         b.produces,
 | 
			
		||||
		Consumes:                         b.consumes,
 | 
			
		||||
		Function:                         b.function,
 | 
			
		||||
		Filters:                          b.filters,
 | 
			
		||||
		If:                               b.conditions,
 | 
			
		||||
		relativePath:                     b.currentPath,
 | 
			
		||||
		pathExpr:                         pathExpr,
 | 
			
		||||
		Doc:                              b.doc,
 | 
			
		||||
		Notes:                            b.notes,
 | 
			
		||||
		Operation:                        operationName,
 | 
			
		||||
		ParameterDocs:                    b.parameters,
 | 
			
		||||
		ResponseErrors:                   b.errorMap,
 | 
			
		||||
		DefaultResponse:                  b.defaultResponse,
 | 
			
		||||
		ReadSample:                       b.readSample,
 | 
			
		||||
		WriteSample:                      b.writeSample,
 | 
			
		||||
		Metadata:                         b.metadata,
 | 
			
		||||
		Deprecated:                       b.deprecated,
 | 
			
		||||
		contentEncodingEnabled:           b.contentEncodingEnabled,
 | 
			
		||||
		allowedMethodsWithoutContentType: b.allowedMethodsWithoutContentType,
 | 
			
		||||
	}
 | 
			
		||||
	route.Extensions = b.extensions
 | 
			
		||||
	route.postBuild()
 | 
			
		||||
	return route
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										66
									
								
								vendor/github.com/emicklei/go-restful/v3/route_reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								vendor/github.com/emicklei/go-restful/v3/route_reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
package restful
 | 
			
		||||
 | 
			
		||||
// Copyright 2021 Ernest Micklei. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a license
 | 
			
		||||
// that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
type RouteReader interface {
 | 
			
		||||
	Method() string
 | 
			
		||||
	Consumes() []string
 | 
			
		||||
	Path() string
 | 
			
		||||
	Doc() string
 | 
			
		||||
	Notes() string
 | 
			
		||||
	Operation() string
 | 
			
		||||
	ParameterDocs() []*Parameter
 | 
			
		||||
	// Returns a copy
 | 
			
		||||
	Metadata() map[string]interface{}
 | 
			
		||||
	Deprecated() bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type routeAccessor struct {
 | 
			
		||||
	route *Route
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r routeAccessor) Method() string {
 | 
			
		||||
	return r.route.Method
 | 
			
		||||
}
 | 
			
		||||
func (r routeAccessor) Consumes() []string {
 | 
			
		||||
	return r.route.Consumes[:]
 | 
			
		||||
}
 | 
			
		||||
func (r routeAccessor) Path() string {
 | 
			
		||||
	return r.route.Path
 | 
			
		||||
}
 | 
			
		||||
func (r routeAccessor) Doc() string {
 | 
			
		||||
	return r.route.Doc
 | 
			
		||||
}
 | 
			
		||||
func (r routeAccessor) Notes() string {
 | 
			
		||||
	return r.route.Notes
 | 
			
		||||
}
 | 
			
		||||
func (r routeAccessor) Operation() string {
 | 
			
		||||
	return r.route.Operation
 | 
			
		||||
}
 | 
			
		||||
func (r routeAccessor) ParameterDocs() []*Parameter {
 | 
			
		||||
	return r.route.ParameterDocs[:]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns a copy
 | 
			
		||||
func (r routeAccessor) Metadata() map[string]interface{} {
 | 
			
		||||
	return copyMap(r.route.Metadata)
 | 
			
		||||
}
 | 
			
		||||
func (r routeAccessor) Deprecated() bool {
 | 
			
		||||
	return r.route.Deprecated
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// https://stackoverflow.com/questions/23057785/how-to-copy-a-map
 | 
			
		||||
func copyMap(m map[string]interface{}) map[string]interface{} {
 | 
			
		||||
	cp := make(map[string]interface{})
 | 
			
		||||
	for k, v := range m {
 | 
			
		||||
		vm, ok := v.(map[string]interface{})
 | 
			
		||||
		if ok {
 | 
			
		||||
			cp[k] = copyMap(vm)
 | 
			
		||||
		} else {
 | 
			
		||||
			cp[k] = v
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return cp
 | 
			
		||||
}
 | 
			
		||||
@@ -4,12 +4,16 @@ package restful
 | 
			
		||||
// Use of this source code is governed by a license
 | 
			
		||||
// that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
import "fmt"
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ServiceError is a transport object to pass information about a non-Http error occurred in a WebService while processing a request.
 | 
			
		||||
type ServiceError struct {
 | 
			
		||||
	Code    int
 | 
			
		||||
	Message string
 | 
			
		||||
	Header  http.Header
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewError returns a ServiceError using the code and reason
 | 
			
		||||
@@ -17,6 +21,11 @@ func NewError(code int, message string) ServiceError {
 | 
			
		||||
	return ServiceError{Code: code, Message: message}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewErrorWithHeader returns a ServiceError using the code, reason and header
 | 
			
		||||
func NewErrorWithHeader(code int, message string, header http.Header) ServiceError {
 | 
			
		||||
	return ServiceError{Code: code, Message: message, Header: header}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Error returns a text representation of the service error
 | 
			
		||||
func (s ServiceError) Error() string {
 | 
			
		||||
	return fmt.Sprintf("[ServiceError:%v] %v", s.Code, s.Message)
 | 
			
		||||
@@ -6,7 +6,7 @@ import (
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/emicklei/go-restful/log"
 | 
			
		||||
	"github.com/emicklei/go-restful/v3/log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Copyright 2013 Ernest Micklei. All rights reserved.
 | 
			
		||||
@@ -176,22 +176,20 @@ func (w *WebService) Route(builder *RouteBuilder) *WebService {
 | 
			
		||||
 | 
			
		||||
// RemoveRoute removes the specified route, looks for something that matches 'path' and 'method'
 | 
			
		||||
func (w *WebService) RemoveRoute(path, method string) error {
 | 
			
		||||
	if !w.dynamicRoutes {
 | 
			
		||||
		return errors.New("dynamic routes are not enabled.")
 | 
			
		||||
	}
 | 
			
		||||
	w.routesLock.Lock()
 | 
			
		||||
	defer w.routesLock.Unlock()
 | 
			
		||||
	newRoutes := make([]Route, (len(w.routes) - 1))
 | 
			
		||||
	current := 0
 | 
			
		||||
	for ix := range w.routes {
 | 
			
		||||
		if w.routes[ix].Method == method && w.routes[ix].Path == path {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		newRoutes[current] = w.routes[ix]
 | 
			
		||||
		current = current + 1
 | 
			
		||||
	}
 | 
			
		||||
	w.routes = newRoutes
 | 
			
		||||
	return nil
 | 
			
		||||
    if !w.dynamicRoutes {
 | 
			
		||||
        return errors.New("dynamic routes are not enabled.")
 | 
			
		||||
    }
 | 
			
		||||
    w.routesLock.Lock()
 | 
			
		||||
    defer w.routesLock.Unlock()
 | 
			
		||||
    newRoutes := []Route{}
 | 
			
		||||
    for _, route := range w.routes {
 | 
			
		||||
        if route.Method == method && route.Path == path {
 | 
			
		||||
            continue
 | 
			
		||||
        }
 | 
			
		||||
        newRoutes = append(newRoutes, route)
 | 
			
		||||
    }
 | 
			
		||||
    w.routes = newRoutes
 | 
			
		||||
    return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Method creates a new RouteBuilder and initialize its http method
 | 
			
		||||
@@ -288,3 +286,8 @@ func (w *WebService) PATCH(subPath string) *RouteBuilder {
 | 
			
		||||
func (w *WebService) DELETE(subPath string) *RouteBuilder {
 | 
			
		||||
	return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("DELETE").Path(subPath)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OPTIONS is a shortcut for .Method("OPTIONS").Path(subPath)
 | 
			
		||||
func (w *WebService) OPTIONS(subPath string) *RouteBuilder {
 | 
			
		||||
	return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("OPTIONS").Path(subPath)
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user