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/container.go b/metrics-server/vendor/github.com/emicklei/go-restful/container.go
new file mode 100644
index 0000000..b4ad153
--- /dev/null
+++ b/metrics-server/vendor/github.com/emicklei/go-restful/container.go
@@ -0,0 +1,371 @@
+package restful
+
+// Copyright 2013 Ernest Micklei. All rights reserved.
+// Use of this source code is governed by a license
+// that can be found in the LICENSE file.
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"net/http"
+	"os"
+	"runtime"
+	"strings"
+	"sync"
+
+	"github.com/emicklei/go-restful/log"
+)
+
+// Container holds a collection of WebServices and a http.ServeMux to dispatch http requests.
+// The requests are further dispatched to routes of WebServices using a RouteSelector
+type Container struct {
+	webServicesLock        sync.RWMutex
+	webServices            []*WebService
+	ServeMux               *http.ServeMux
+	isRegisteredOnRoot     bool
+	containerFilters       []FilterFunction
+	doNotRecover           bool // default is true
+	recoverHandleFunc      RecoverHandleFunction
+	serviceErrorHandleFunc ServiceErrorHandleFunction
+	router                 RouteSelector // default is a CurlyRouter (RouterJSR311 is a slower alternative)
+	contentEncodingEnabled bool          // default is false
+}
+
+// NewContainer creates a new Container using a new ServeMux and default router (CurlyRouter)
+func NewContainer() *Container {
+	return &Container{
+		webServices:            []*WebService{},
+		ServeMux:               http.NewServeMux(),
+		isRegisteredOnRoot:     false,
+		containerFilters:       []FilterFunction{},
+		doNotRecover:           true,
+		recoverHandleFunc:      logStackOnRecover,
+		serviceErrorHandleFunc: writeServiceError,
+		router:                 CurlyRouter{},
+		contentEncodingEnabled: false}
+}
+
+// RecoverHandleFunction declares functions that can be used to handle a panic situation.
+// The first argument is what recover() returns. The second must be used to communicate an error response.
+type RecoverHandleFunction func(interface{}, http.ResponseWriter)
+
+// RecoverHandler changes the default function (logStackOnRecover) to be called
+// when a panic is detected. DoNotRecover must be have its default value (=false).
+func (c *Container) RecoverHandler(handler RecoverHandleFunction) {
+	c.recoverHandleFunc = handler
+}
+
+// ServiceErrorHandleFunction declares functions that can be used to handle a service error situation.
+// The first argument is the service error, the second is the request that resulted in the error and
+// the third must be used to communicate an error response.
+type ServiceErrorHandleFunction func(ServiceError, *Request, *Response)
+
+// ServiceErrorHandler changes the default function (writeServiceError) to be called
+// when a ServiceError is detected.
+func (c *Container) ServiceErrorHandler(handler ServiceErrorHandleFunction) {
+	c.serviceErrorHandleFunc = handler
+}
+
+// DoNotRecover controls whether panics will be caught to return HTTP 500.
+// If set to true, Route functions are responsible for handling any error situation.
+// Default value is true.
+func (c *Container) DoNotRecover(doNot bool) {
+	c.doNotRecover = doNot
+}
+
+// Router changes the default Router (currently CurlyRouter)
+func (c *Container) Router(aRouter RouteSelector) {
+	c.router = aRouter
+}
+
+// EnableContentEncoding (default=false) allows for GZIP or DEFLATE encoding of responses.
+func (c *Container) EnableContentEncoding(enabled bool) {
+	c.contentEncodingEnabled = enabled
+}
+
+// Add a WebService to the Container. It will detect duplicate root paths and exit in that case.
+func (c *Container) Add(service *WebService) *Container {
+	c.webServicesLock.Lock()
+	defer c.webServicesLock.Unlock()
+
+	// if rootPath was not set then lazy initialize it
+	if len(service.rootPath) == 0 {
+		service.Path("/")
+	}
+
+	// cannot have duplicate root paths
+	for _, each := range c.webServices {
+		if each.RootPath() == service.RootPath() {
+			log.Printf("[restful] WebService with duplicate root path detected:['%v']", each)
+			os.Exit(1)
+		}
+	}
+
+	// If not registered on root then add specific mapping
+	if !c.isRegisteredOnRoot {
+		c.isRegisteredOnRoot = c.addHandler(service, c.ServeMux)
+	}
+	c.webServices = append(c.webServices, service)
+	return c
+}
+
+// addHandler may set a new HandleFunc for the serveMux
+// this function must run inside the critical region protected by the webServicesLock.
+// returns true if the function was registered on root ("/")
+func (c *Container) addHandler(service *WebService, serveMux *http.ServeMux) bool {
+	pattern := fixedPrefixPath(service.RootPath())
+	// check if root path registration is needed
+	if "/" == pattern || "" == pattern {
+		serveMux.HandleFunc("/", c.dispatch)
+		return true
+	}
+	// detect if registration already exists
+	alreadyMapped := false
+	for _, each := range c.webServices {
+		if each.RootPath() == service.RootPath() {
+			alreadyMapped = true
+			break
+		}
+	}
+	if !alreadyMapped {
+		serveMux.HandleFunc(pattern, c.dispatch)
+		if !strings.HasSuffix(pattern, "/") {
+			serveMux.HandleFunc(pattern+"/", c.dispatch)
+		}
+	}
+	return false
+}
+
+func (c *Container) Remove(ws *WebService) error {
+	if c.ServeMux == http.DefaultServeMux {
+		errMsg := fmt.Sprintf("[restful] cannot remove a WebService from a Container using the DefaultServeMux: ['%v']", ws)
+		log.Print(errMsg)
+		return errors.New(errMsg)
+	}
+	c.webServicesLock.Lock()
+	defer c.webServicesLock.Unlock()
+	// build a new ServeMux and re-register all WebServices
+	newServeMux := http.NewServeMux()
+	newServices := []*WebService{}
+	newIsRegisteredOnRoot := false
+	for _, each := range c.webServices {
+		if each.rootPath != ws.rootPath {
+			// If not registered on root then add specific mapping
+			if !newIsRegisteredOnRoot {
+				newIsRegisteredOnRoot = c.addHandler(each, newServeMux)
+			}
+			newServices = append(newServices, each)
+		}
+	}
+	c.webServices, c.ServeMux, c.isRegisteredOnRoot = newServices, newServeMux, newIsRegisteredOnRoot
+	return nil
+}
+
+// logStackOnRecover is the default RecoverHandleFunction and is called
+// when DoNotRecover is false and the recoverHandleFunc is not set for the container.
+// Default implementation logs the stacktrace and writes the stacktrace on the response.
+// This may be a security issue as it exposes sourcecode information.
+func logStackOnRecover(panicReason interface{}, httpWriter http.ResponseWriter) {
+	var buffer bytes.Buffer
+	buffer.WriteString(fmt.Sprintf("[restful] recover from panic situation: - %v\r\n", panicReason))
+	for i := 2; ; i += 1 {
+		_, file, line, ok := runtime.Caller(i)
+		if !ok {
+			break
+		}
+		buffer.WriteString(fmt.Sprintf("    %s:%d\r\n", file, line))
+	}
+	log.Print(buffer.String())
+	httpWriter.WriteHeader(http.StatusInternalServerError)
+	httpWriter.Write(buffer.Bytes())
+}
+
+// writeServiceError is the default ServiceErrorHandleFunction and is called
+// 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) {
+	resp.WriteErrorString(err.Code, err.Message)
+}
+
+// Dispatch the incoming Http Request to a matching WebService.
+func (c *Container) Dispatch(httpWriter http.ResponseWriter, httpRequest *http.Request) {
+	if httpWriter == nil {
+		panic("httpWriter cannot be nil")
+	}
+	if httpRequest == nil {
+		panic("httpRequest cannot be nil")
+	}
+	c.dispatch(httpWriter, httpRequest)
+}
+
+// Dispatch the incoming Http Request to a matching WebService.
+func (c *Container) dispatch(httpWriter http.ResponseWriter, httpRequest *http.Request) {
+	writer := httpWriter
+
+	// CompressingResponseWriter should be closed after all operations are done
+	defer func() {
+		if compressWriter, ok := writer.(*CompressingResponseWriter); ok {
+			compressWriter.Close()
+		}
+	}()
+
+	// Instal panic recovery unless told otherwise
+	if !c.doNotRecover { // catch all for 500 response
+		defer func() {
+			if r := recover(); r != nil {
+				c.recoverHandleFunc(r, writer)
+				return
+			}
+		}()
+	}
+
+	// Detect if compression is needed
+	// assume without compression, test for override
+	if c.contentEncodingEnabled {
+		doCompress, encoding := wantsCompressedResponse(httpRequest)
+		if doCompress {
+			var err error
+			writer, err = NewCompressingResponseWriter(httpWriter, encoding)
+			if err != nil {
+				log.Print("[restful] unable to install compressor: ", err)
+				httpWriter.WriteHeader(http.StatusInternalServerError)
+				return
+			}
+		}
+	}
+	// Find best match Route ; err is non nil if no match was found
+	var webService *WebService
+	var route *Route
+	var err error
+	func() {
+		c.webServicesLock.RLock()
+		defer c.webServicesLock.RUnlock()
+		webService, route, err = c.router.SelectRoute(
+			c.webServices,
+			httpRequest)
+	}()
+	if err != nil {
+		// a non-200 response 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) {
+			case ServiceError:
+				ser := err.(ServiceError)
+				c.serviceErrorHandleFunc(ser, req, resp)
+			}
+			// TODO
+		}}
+		chain.ProcessFilter(NewRequest(httpRequest), NewResponse(writer))
+		return
+	}
+	pathProcessor, routerProcessesPath := c.router.(PathProcessor)
+	if !routerProcessesPath {
+		pathProcessor = defaultPathProcessor{}
+	}
+	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 {
+		// compose filter chain
+		allFilters := []FilterFunction{}
+		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.ProcessFilter(wrappedRequest, wrappedResponse)
+	} else {
+		// no filters, handle request by route
+		route.Function(wrappedRequest, wrappedResponse)
+	}
+}
+
+// fixedPrefixPath returns the fixed part of the partspec ; it may include template vars {}
+func fixedPrefixPath(pathspec string) string {
+	varBegin := strings.Index(pathspec, "{")
+	if -1 == varBegin {
+		return pathspec
+	}
+	return pathspec[:varBegin]
+}
+
+// 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)
+}
+
+// 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)
+}
+
+// HandleWithFilter registers the handler for the given pattern.
+// Container's filter chain is applied for handler.
+// If a handler already exists for pattern, HandleWithFilter panics.
+func (c *Container) HandleWithFilter(pattern string, handler http.Handler) {
+	f := func(httpResponse http.ResponseWriter, httpRequest *http.Request) {
+		if len(c.containerFilters) == 0 {
+			handler.ServeHTTP(httpResponse, httpRequest)
+			return
+		}
+
+		chain := FilterChain{Filters: c.containerFilters, Target: func(req *Request, resp *Response) {
+			handler.ServeHTTP(httpResponse, httpRequest)
+		}}
+		chain.ProcessFilter(NewRequest(httpRequest), NewResponse(httpResponse))
+	}
+
+	c.Handle(pattern, http.HandlerFunc(f))
+}
+
+// Filter appends a container FilterFunction. These are called before dispatching
+// a http.Request to a WebService from the container
+func (c *Container) Filter(filter FilterFunction) {
+	c.containerFilters = append(c.containerFilters, filter)
+}
+
+// RegisteredWebServices returns the collections of added WebServices
+func (c *Container) RegisteredWebServices() []*WebService {
+	c.webServicesLock.RLock()
+	defer c.webServicesLock.RUnlock()
+	result := make([]*WebService, len(c.webServices))
+	for ix := range c.webServices {
+		result[ix] = c.webServices[ix]
+	}
+	return result
+}
+
+// computeAllowedMethods returns a list of HTTP methods that are valid for a Request
+func (c *Container) computeAllowedMethods(req *Request) []string {
+	// Go through all RegisteredWebServices() and all its Routes to collect the options
+	methods := []string{}
+	requestPath := req.Request.URL.Path
+	for _, ws := range c.RegisteredWebServices() {
+		matches := ws.pathExpr.Matcher.FindStringSubmatch(requestPath)
+		if matches != nil {
+			finalMatch := matches[len(matches)-1]
+			for _, rt := range ws.Routes() {
+				matches := rt.pathExpr.Matcher.FindStringSubmatch(finalMatch)
+				if matches != nil {
+					lastMatch := matches[len(matches)-1]
+					if lastMatch == "" || lastMatch == "/" { // do not include if value is neither empty nor ‘/’.
+						methods = append(methods, rt.Method)
+					}
+				}
+			}
+		}
+	}
+	// methods = append(methods, "OPTIONS")  not sure about this
+	return methods
+}
+
+// newBasicRequestResponse creates a pair of Request,Response from its http versions.
+// It is basic because no parameter or (produces) content-type information is given.
+func newBasicRequestResponse(httpWriter http.ResponseWriter, httpRequest *http.Request) (*Request, *Response) {
+	resp := NewResponse(httpWriter)
+	resp.requestAccept = httpRequest.Header.Get(HEADER_Accept)
+	return NewRequest(httpRequest), resp
+}