git subrepo clone (merge) https://github.com/kubernetes-incubator/metrics-server.git metrics-server
subrepo:
subdir: "metrics-server"
merged: "92d8412"
upstream:
origin: "https://github.com/kubernetes-incubator/metrics-server.git"
branch: "master"
commit: "92d8412"
git-subrepo:
version: "0.4.0"
origin: "???"
commit: "???"
diff --git a/metrics-server/vendor/github.com/emicklei/go-restful/jsr311.go b/metrics-server/vendor/github.com/emicklei/go-restful/jsr311.go
new file mode 100644
index 0000000..4360b49
--- /dev/null
+++ b/metrics-server/vendor/github.com/emicklei/go-restful/jsr311.go
@@ -0,0 +1,293 @@
+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 (
+ "errors"
+ "fmt"
+ "net/http"
+ "sort"
+)
+
+// RouterJSR311 implements the flow for matching Requests to Routes (and consequently Resource Functions)
+// as specified by the JSR311 http://jsr311.java.net/nonav/releases/1.1/spec/spec.html.
+// RouterJSR311 implements the Router interface.
+// Concept of locators is not implemented.
+type RouterJSR311 struct{}
+
+// SelectRoute is part of the Router interface and returns the best match
+// for the WebService and its Route for the given Request.
+func (r RouterJSR311) SelectRoute(
+ webServices []*WebService,
+ httpRequest *http.Request) (selectedService *WebService, selectedRoute *Route, err error) {
+
+ // Identify the root resource class (WebService)
+ dispatcher, finalMatch, err := r.detectDispatcher(httpRequest.URL.Path, webServices)
+ if err != nil {
+ return nil, nil, NewError(http.StatusNotFound, "")
+ }
+ // Obtain the set of candidate methods (Routes)
+ routes := r.selectRoutes(dispatcher, finalMatch)
+ if len(routes) == 0 {
+ return dispatcher, nil, NewError(http.StatusNotFound, "404: Page Not Found")
+ }
+
+ // Identify the method (Route) that will handle the request
+ route, ok := r.detectRoute(routes, httpRequest)
+ return dispatcher, route, ok
+}
+
+// ExtractParameters is used to obtain the path parameters from the route using the same matching
+// engine as the JSR 311 router.
+func (r RouterJSR311) ExtractParameters(route *Route, webService *WebService, urlPath string) map[string]string {
+ webServiceExpr := webService.pathExpr
+ webServiceMatches := webServiceExpr.Matcher.FindStringSubmatch(urlPath)
+ pathParameters := r.extractParams(webServiceExpr, webServiceMatches)
+ routeExpr := route.pathExpr
+ routeMatches := routeExpr.Matcher.FindStringSubmatch(webServiceMatches[len(webServiceMatches)-1])
+ routeParams := r.extractParams(routeExpr, routeMatches)
+ for key, value := range routeParams {
+ pathParameters[key] = value
+ }
+ return pathParameters
+}
+
+func (RouterJSR311) extractParams(pathExpr *pathExpression, matches []string) map[string]string {
+ params := map[string]string{}
+ for i := 1; i < len(matches); i++ {
+ if len(pathExpr.VarNames) >= i {
+ params[pathExpr.VarNames[i-1]] = matches[i]
+ }
+ }
+ return params
+}
+
+// http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-360003.7.2
+func (r RouterJSR311) detectRoute(routes []Route, httpRequest *http.Request) (*Route, error) {
+ ifOk := []Route{}
+ for _, each := range routes {
+ ok := true
+ for _, fn := range each.If {
+ if !fn(httpRequest) {
+ ok = false
+ break
+ }
+ }
+ if ok {
+ ifOk = append(ifOk, each)
+ }
+ }
+ if len(ifOk) == 0 {
+ if trace {
+ traceLogger.Printf("no Route found (from %d) that passes conditional checks", len(routes))
+ }
+ return nil, NewError(http.StatusNotFound, "404: Not Found")
+ }
+
+ // http method
+ methodOk := []Route{}
+ for _, each := range ifOk {
+ if httpRequest.Method == each.Method {
+ methodOk = append(methodOk, each)
+ }
+ }
+ if len(methodOk) == 0 {
+ if trace {
+ traceLogger.Printf("no Route found (in %d routes) that matches HTTP method %s\n", len(routes), httpRequest.Method)
+ }
+ return nil, NewError(http.StatusMethodNotAllowed, "405: Method Not Allowed")
+ }
+ inputMediaOk := methodOk
+
+ // content-type
+ contentType := httpRequest.Header.Get(HEADER_ContentType)
+ inputMediaOk = []Route{}
+ for _, each := range methodOk {
+ if each.matchesContentType(contentType) {
+ inputMediaOk = append(inputMediaOk, each)
+ }
+ }
+ if len(inputMediaOk) == 0 {
+ if trace {
+ traceLogger.Printf("no Route found (from %d) that matches HTTP Content-Type: %s\n", len(methodOk), contentType)
+ }
+ return nil, NewError(http.StatusUnsupportedMediaType, "415: Unsupported Media Type")
+ }
+
+ // accept
+ outputMediaOk := []Route{}
+ accept := httpRequest.Header.Get(HEADER_Accept)
+ if len(accept) == 0 {
+ accept = "*/*"
+ }
+ for _, each := range inputMediaOk {
+ if each.matchesAccept(accept) {
+ outputMediaOk = append(outputMediaOk, each)
+ }
+ }
+ if len(outputMediaOk) == 0 {
+ if trace {
+ traceLogger.Printf("no Route found (from %d) that matches HTTP Accept: %s\n", len(inputMediaOk), accept)
+ }
+ return nil, NewError(http.StatusNotAcceptable, "406: Not Acceptable")
+ }
+ // return r.bestMatchByMedia(outputMediaOk, contentType, accept), nil
+ return &outputMediaOk[0], nil
+}
+
+// http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-360003.7.2
+// n/m > n/* > */*
+func (r RouterJSR311) bestMatchByMedia(routes []Route, contentType string, accept string) *Route {
+ // TODO
+ return &routes[0]
+}
+
+// http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-360003.7.2 (step 2)
+func (r RouterJSR311) selectRoutes(dispatcher *WebService, pathRemainder string) []Route {
+ filtered := &sortableRouteCandidates{}
+ for _, each := range dispatcher.Routes() {
+ pathExpr := each.pathExpr
+ matches := pathExpr.Matcher.FindStringSubmatch(pathRemainder)
+ if matches != nil {
+ lastMatch := matches[len(matches)-1]
+ if len(lastMatch) == 0 || lastMatch == "/" { // do not include if value is neither empty nor ‘/’.
+ filtered.candidates = append(filtered.candidates,
+ routeCandidate{each, len(matches) - 1, pathExpr.LiteralCount, pathExpr.VarCount})
+ }
+ }
+ }
+ if len(filtered.candidates) == 0 {
+ if trace {
+ traceLogger.Printf("WebService on path %s has no routes that match URL path remainder:%s\n", dispatcher.rootPath, pathRemainder)
+ }
+ return []Route{}
+ }
+ sort.Sort(sort.Reverse(filtered))
+
+ // select other routes from candidates whoes expression matches rmatch
+ matchingRoutes := []Route{filtered.candidates[0].route}
+ for c := 1; c < len(filtered.candidates); c++ {
+ each := filtered.candidates[c]
+ if each.route.pathExpr.Matcher.MatchString(pathRemainder) {
+ matchingRoutes = append(matchingRoutes, each.route)
+ }
+ }
+ return matchingRoutes
+}
+
+// http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-360003.7.2 (step 1)
+func (r RouterJSR311) detectDispatcher(requestPath string, dispatchers []*WebService) (*WebService, string, error) {
+ filtered := &sortableDispatcherCandidates{}
+ for _, each := range dispatchers {
+ matches := each.pathExpr.Matcher.FindStringSubmatch(requestPath)
+ if matches != nil {
+ filtered.candidates = append(filtered.candidates,
+ dispatcherCandidate{each, matches[len(matches)-1], len(matches), each.pathExpr.LiteralCount, each.pathExpr.VarCount})
+ }
+ }
+ if len(filtered.candidates) == 0 {
+ if trace {
+ traceLogger.Printf("no WebService was found to match URL path:%s\n", requestPath)
+ }
+ return nil, "", errors.New("not found")
+ }
+ sort.Sort(sort.Reverse(filtered))
+ return filtered.candidates[0].dispatcher, filtered.candidates[0].finalMatch, nil
+}
+
+// Types and functions to support the sorting of Routes
+
+type routeCandidate struct {
+ route Route
+ matchesCount int // the number of capturing groups
+ literalCount int // the number of literal characters (means those not resulting from template variable substitution)
+ nonDefaultCount int // the number of capturing groups with non-default regular expressions (i.e. not ‘([^ /]+?)’)
+}
+
+func (r routeCandidate) expressionToMatch() string {
+ return r.route.pathExpr.Source
+}
+
+func (r routeCandidate) String() string {
+ return fmt.Sprintf("(m=%d,l=%d,n=%d)", r.matchesCount, r.literalCount, r.nonDefaultCount)
+}
+
+type sortableRouteCandidates struct {
+ candidates []routeCandidate
+}
+
+func (rcs *sortableRouteCandidates) Len() int {
+ return len(rcs.candidates)
+}
+func (rcs *sortableRouteCandidates) Swap(i, j int) {
+ rcs.candidates[i], rcs.candidates[j] = rcs.candidates[j], rcs.candidates[i]
+}
+func (rcs *sortableRouteCandidates) Less(i, j int) bool {
+ ci := rcs.candidates[i]
+ cj := rcs.candidates[j]
+ // primary key
+ if ci.literalCount < cj.literalCount {
+ return true
+ }
+ if ci.literalCount > cj.literalCount {
+ return false
+ }
+ // secundary key
+ if ci.matchesCount < cj.matchesCount {
+ return true
+ }
+ if ci.matchesCount > cj.matchesCount {
+ return false
+ }
+ // tertiary key
+ if ci.nonDefaultCount < cj.nonDefaultCount {
+ return true
+ }
+ if ci.nonDefaultCount > cj.nonDefaultCount {
+ return false
+ }
+ // quaternary key ("source" is interpreted as Path)
+ return ci.route.Path < cj.route.Path
+}
+
+// Types and functions to support the sorting of Dispatchers
+
+type dispatcherCandidate struct {
+ dispatcher *WebService
+ finalMatch string
+ matchesCount int // the number of capturing groups
+ literalCount int // the number of literal characters (means those not resulting from template variable substitution)
+ nonDefaultCount int // the number of capturing groups with non-default regular expressions (i.e. not ‘([^ /]+?)’)
+}
+type sortableDispatcherCandidates struct {
+ candidates []dispatcherCandidate
+}
+
+func (dc *sortableDispatcherCandidates) Len() int {
+ return len(dc.candidates)
+}
+func (dc *sortableDispatcherCandidates) Swap(i, j int) {
+ dc.candidates[i], dc.candidates[j] = dc.candidates[j], dc.candidates[i]
+}
+func (dc *sortableDispatcherCandidates) Less(i, j int) bool {
+ ci := dc.candidates[i]
+ cj := dc.candidates[j]
+ // primary key
+ if ci.matchesCount < cj.matchesCount {
+ return true
+ }
+ if ci.matchesCount > cj.matchesCount {
+ return false
+ }
+ // secundary key
+ if ci.literalCount < cj.literalCount {
+ return true
+ }
+ if ci.literalCount > cj.literalCount {
+ return false
+ }
+ // tertiary key
+ return ci.nonDefaultCount < cj.nonDefaultCount
+}