go.mod: update to github.com/emicklei/go-restful/v3 v3.7.3
full diff: https://github.com/emicklei/go-restful/compare/v2.9.5...v3.7.3 - Switch to using go modules - Add check for wildcard to fix CORS filter - Add check on writer to prevent compression of response twice - Add OPTIONS shortcut WebService receiver - Add Route metadata to request attributes or allow adding attributes to routes - Add wroteHeader set - Enable content encoding on Handle and ServeHTTP - Feat: support google custom verb - Feature: override list of method allowed without content-type - Fix Allow header not set on '405: Method Not Allowed' responses - Fix Go 1.15: conversion from int to string yields a string of one rune - Fix WriteError return value - Fix: use request/response resulting from filter chain - handle path params with prefixes and suffixes - HTTP response body was broken, if struct to be converted to JSON has boolean value - List available representations in 406 body - Support describing response headers - Unwrap function in filter chain + remove unused dispatchWithFilters Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
		
							
								
								
									
										173
									
								
								vendor/github.com/emicklei/go-restful/v3/curly.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								vendor/github.com/emicklei/go-restful/v3/curly.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,173 @@ | ||||
| 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 ( | ||||
| 	"net/http" | ||||
| 	"regexp" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // CurlyRouter expects Routes with paths that contain zero or more parameters in curly brackets. | ||||
| type CurlyRouter struct{} | ||||
|  | ||||
| // SelectRoute is part of the Router interface and returns the best match | ||||
| // for the WebService and its Route for the given Request. | ||||
| func (c CurlyRouter) SelectRoute( | ||||
| 	webServices []*WebService, | ||||
| 	httpRequest *http.Request) (selectedService *WebService, selected *Route, err error) { | ||||
|  | ||||
| 	requestTokens := tokenizePath(httpRequest.URL.Path) | ||||
|  | ||||
| 	detectedService := c.detectWebService(requestTokens, webServices) | ||||
| 	if detectedService == nil { | ||||
| 		if trace { | ||||
| 			traceLogger.Printf("no WebService was found to match URL path:%s\n", httpRequest.URL.Path) | ||||
| 		} | ||||
| 		return nil, nil, NewError(http.StatusNotFound, "404: Page Not Found") | ||||
| 	} | ||||
| 	candidateRoutes := c.selectRoutes(detectedService, requestTokens) | ||||
| 	if len(candidateRoutes) == 0 { | ||||
| 		if trace { | ||||
| 			traceLogger.Printf("no Route in WebService with path %s was found to match URL path:%s\n", detectedService.rootPath, httpRequest.URL.Path) | ||||
| 		} | ||||
| 		return detectedService, nil, NewError(http.StatusNotFound, "404: Page Not Found") | ||||
| 	} | ||||
| 	selectedRoute, err := c.detectRoute(candidateRoutes, httpRequest) | ||||
| 	if selectedRoute == nil { | ||||
| 		return detectedService, nil, err | ||||
| 	} | ||||
| 	return detectedService, selectedRoute, nil | ||||
| } | ||||
|  | ||||
| // selectRoutes return a collection of Route from a WebService that matches the path tokens from the request. | ||||
| 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, each.hasCustomVerb) | ||||
| 		if matches { | ||||
| 			candidates.add(curlyRoute{each, paramCount, staticCount}) // TODO make sure Routes() return pointers? | ||||
| 		} | ||||
| 	} | ||||
| 	sort.Sort(candidates) | ||||
| 	return candidates | ||||
| } | ||||
|  | ||||
| // 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, 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) | ||||
| 		if count == 0 || !strings.HasSuffix(routeTokens[count-1], "*}") { | ||||
| 			return false, 0, 0 | ||||
| 		} | ||||
| 		// proceed | ||||
| 	} | ||||
| 	for i, routeToken := range routeTokens { | ||||
| 		if i == len(requestTokens) { | ||||
| 			// reached end of request path | ||||
| 			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 { | ||||
| 				// match by regex | ||||
| 				matchesToken, matchesRemainder := c.regularMatchesPathToken(routeToken, colon, requestToken) | ||||
| 				if !matchesToken { | ||||
| 					return false, 0, 0 | ||||
| 				} | ||||
| 				if matchesRemainder { | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 		} else { // no { prefix | ||||
| 			if requestToken != routeToken { | ||||
| 				return false, 0, 0 | ||||
| 			} | ||||
| 			staticCount++ | ||||
| 		} | ||||
| 	} | ||||
| 	return true, paramCount, staticCount | ||||
| } | ||||
|  | ||||
| // regularMatchesPathToken tests whether the regular expression part of routeToken matches the requestToken or all remaining tokens | ||||
| // format routeToken is {someVar:someExpression}, e.g. {zipcode:[\d][\d][\d][\d][A-Z][A-Z]} | ||||
| func (c CurlyRouter) regularMatchesPathToken(routeToken string, colon int, requestToken string) (matchesToken bool, matchesRemainder bool) { | ||||
| 	regPart := routeToken[colon+1 : len(routeToken)-1] | ||||
| 	if regPart == "*" { | ||||
| 		if trace { | ||||
| 			traceLogger.Printf("wildcard parameter detected in route token %s that matches %s\n", routeToken, requestToken) | ||||
| 		} | ||||
| 		return true, true | ||||
| 	} | ||||
| 	matched, err := regexp.MatchString(regPart, requestToken) | ||||
| 	return (matched && err == nil), false | ||||
| } | ||||
|  | ||||
| var jsr311Router = RouterJSR311{} | ||||
|  | ||||
| // detectRoute selectes from a list of Route the first match by inspecting both the Accept and Content-Type | ||||
| // headers of the Request. See also RouterJSR311 in jsr311.go | ||||
| func (c CurlyRouter) detectRoute(candidateRoutes sortableCurlyRoutes, httpRequest *http.Request) (*Route, error) { | ||||
| 	// tracing is done inside detectRoute | ||||
| 	return jsr311Router.detectRoute(candidateRoutes.routes(), httpRequest) | ||||
| } | ||||
|  | ||||
| // detectWebService returns the best matching webService given the list of path tokens. | ||||
| // see also computeWebserviceScore | ||||
| func (c CurlyRouter) detectWebService(requestTokens []string, webServices []*WebService) *WebService { | ||||
| 	var best *WebService | ||||
| 	score := -1 | ||||
| 	for _, each := range webServices { | ||||
| 		matches, eachScore := c.computeWebserviceScore(requestTokens, each.pathExpr.tokens) | ||||
| 		if matches && (eachScore > score) { | ||||
| 			best = each | ||||
| 			score = eachScore | ||||
| 		} | ||||
| 	} | ||||
| 	return best | ||||
| } | ||||
|  | ||||
| // computeWebserviceScore returns whether tokens match and | ||||
| // the weighted score of the longest matching consecutive tokens from the beginning. | ||||
| func (c CurlyRouter) computeWebserviceScore(requestTokens []string, tokens []string) (bool, int) { | ||||
| 	if len(tokens) > len(requestTokens) { | ||||
| 		return false, 0 | ||||
| 	} | ||||
| 	score := 0 | ||||
| 	for i := 0; i < len(tokens); i++ { | ||||
| 		each := requestTokens[i] | ||||
| 		other := tokens[i] | ||||
| 		if len(each) == 0 && len(other) == 0 { | ||||
| 			score++ | ||||
| 			continue | ||||
| 		} | ||||
| 		if len(other) > 0 && strings.HasPrefix(other, "{") { | ||||
| 			// no empty match | ||||
| 			if len(each) == 0 { | ||||
| 				return false, score | ||||
| 			} | ||||
| 			score += 1 | ||||
| 		} else { | ||||
| 			// not a parameter | ||||
| 			if each != other { | ||||
| 				return false, score | ||||
| 			} | ||||
| 			score += (len(tokens) - i) * 10 //fuzzy | ||||
| 		} | ||||
| 	} | ||||
| 	return true, score | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Sebastiaan van Stijn
					Sebastiaan van Stijn