vendorify
diff --git a/go/vendor/github.com/go-openapi/runtime/middleware/context.go b/go/vendor/github.com/go-openapi/runtime/middleware/context.go
new file mode 100644
index 0000000..48d7150
--- /dev/null
+++ b/go/vendor/github.com/go-openapi/runtime/middleware/context.go
@@ -0,0 +1,582 @@
+// Copyright 2015 go-swagger maintainers
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package middleware
+
+import (
+ stdContext "context"
+ "net/http"
+ "strings"
+ "sync"
+
+ "github.com/go-openapi/analysis"
+ "github.com/go-openapi/errors"
+ "github.com/go-openapi/loads"
+ "github.com/go-openapi/runtime"
+ "github.com/go-openapi/runtime/logger"
+ "github.com/go-openapi/runtime/middleware/untyped"
+ "github.com/go-openapi/spec"
+ "github.com/go-openapi/strfmt"
+)
+
+// Debug when true turns on verbose logging
+var Debug = logger.DebugEnabled()
+var Logger logger.Logger = logger.StandardLogger{}
+
+func debugLog(format string, args ...interface{}) {
+ if Debug {
+ Logger.Printf(format, args...)
+ }
+}
+
+// A Builder can create middlewares
+type Builder func(http.Handler) http.Handler
+
+// PassthroughBuilder returns the handler, aka the builder identity function
+func PassthroughBuilder(handler http.Handler) http.Handler { return handler }
+
+// RequestBinder is an interface for types to implement
+// when they want to be able to bind from a request
+type RequestBinder interface {
+ BindRequest(*http.Request, *MatchedRoute) error
+}
+
+// Responder is an interface for types to implement
+// when they want to be considered for writing HTTP responses
+type Responder interface {
+ WriteResponse(http.ResponseWriter, runtime.Producer)
+}
+
+// ResponderFunc wraps a func as a Responder interface
+type ResponderFunc func(http.ResponseWriter, runtime.Producer)
+
+// WriteResponse writes to the response
+func (fn ResponderFunc) WriteResponse(rw http.ResponseWriter, pr runtime.Producer) {
+ fn(rw, pr)
+}
+
+// Context is a type safe wrapper around an untyped request context
+// used throughout to store request context with the standard context attached
+// to the http.Request
+type Context struct {
+ spec *loads.Document
+ analyzer *analysis.Spec
+ api RoutableAPI
+ router Router
+}
+
+type routableUntypedAPI struct {
+ api *untyped.API
+ hlock *sync.Mutex
+ handlers map[string]map[string]http.Handler
+ defaultConsumes string
+ defaultProduces string
+}
+
+func newRoutableUntypedAPI(spec *loads.Document, api *untyped.API, context *Context) *routableUntypedAPI {
+ var handlers map[string]map[string]http.Handler
+ if spec == nil || api == nil {
+ return nil
+ }
+ analyzer := analysis.New(spec.Spec())
+ for method, hls := range analyzer.Operations() {
+ um := strings.ToUpper(method)
+ for path, op := range hls {
+ schemes := analyzer.SecurityRequirementsFor(op)
+
+ if oh, ok := api.OperationHandlerFor(method, path); ok {
+ if handlers == nil {
+ handlers = make(map[string]map[string]http.Handler)
+ }
+ if b, ok := handlers[um]; !ok || b == nil {
+ handlers[um] = make(map[string]http.Handler)
+ }
+
+ var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ // lookup route info in the context
+ route, rCtx, _ := context.RouteInfo(r)
+ if rCtx != nil {
+ r = rCtx
+ }
+
+ // bind and validate the request using reflection
+ var bound interface{}
+ var validation error
+ bound, r, validation = context.BindAndValidate(r, route)
+ if validation != nil {
+ context.Respond(w, r, route.Produces, route, validation)
+ return
+ }
+
+ // actually handle the request
+ result, err := oh.Handle(bound)
+ if err != nil {
+ // respond with failure
+ context.Respond(w, r, route.Produces, route, err)
+ return
+ }
+
+ // respond with success
+ context.Respond(w, r, route.Produces, route, result)
+ })
+
+ if len(schemes) > 0 {
+ handler = newSecureAPI(context, handler)
+ }
+ handlers[um][path] = handler
+ }
+ }
+ }
+
+ return &routableUntypedAPI{
+ api: api,
+ hlock: new(sync.Mutex),
+ handlers: handlers,
+ defaultProduces: api.DefaultProduces,
+ defaultConsumes: api.DefaultConsumes,
+ }
+}
+
+func (r *routableUntypedAPI) HandlerFor(method, path string) (http.Handler, bool) {
+ r.hlock.Lock()
+ paths, ok := r.handlers[strings.ToUpper(method)]
+ if !ok {
+ r.hlock.Unlock()
+ return nil, false
+ }
+ handler, ok := paths[path]
+ r.hlock.Unlock()
+ return handler, ok
+}
+func (r *routableUntypedAPI) ServeErrorFor(operationID string) func(http.ResponseWriter, *http.Request, error) {
+ return r.api.ServeError
+}
+func (r *routableUntypedAPI) ConsumersFor(mediaTypes []string) map[string]runtime.Consumer {
+ return r.api.ConsumersFor(mediaTypes)
+}
+func (r *routableUntypedAPI) ProducersFor(mediaTypes []string) map[string]runtime.Producer {
+ return r.api.ProducersFor(mediaTypes)
+}
+func (r *routableUntypedAPI) AuthenticatorsFor(schemes map[string]spec.SecurityScheme) map[string]runtime.Authenticator {
+ return r.api.AuthenticatorsFor(schemes)
+}
+func (r *routableUntypedAPI) Authorizer() runtime.Authorizer {
+ return r.api.Authorizer()
+}
+func (r *routableUntypedAPI) Formats() strfmt.Registry {
+ return r.api.Formats()
+}
+
+func (r *routableUntypedAPI) DefaultProduces() string {
+ return r.defaultProduces
+}
+
+func (r *routableUntypedAPI) DefaultConsumes() string {
+ return r.defaultConsumes
+}
+
+// NewRoutableContext creates a new context for a routable API
+func NewRoutableContext(spec *loads.Document, routableAPI RoutableAPI, routes Router) *Context {
+ var an *analysis.Spec
+ if spec != nil {
+ an = analysis.New(spec.Spec())
+ }
+ ctx := &Context{spec: spec, api: routableAPI, analyzer: an, router: routes}
+ return ctx
+}
+
+// NewContext creates a new context wrapper
+func NewContext(spec *loads.Document, api *untyped.API, routes Router) *Context {
+ var an *analysis.Spec
+ if spec != nil {
+ an = analysis.New(spec.Spec())
+ }
+ ctx := &Context{spec: spec, analyzer: an}
+ ctx.api = newRoutableUntypedAPI(spec, api, ctx)
+ ctx.router = routes
+ return ctx
+}
+
+// Serve serves the specified spec with the specified api registrations as a http.Handler
+func Serve(spec *loads.Document, api *untyped.API) http.Handler {
+ return ServeWithBuilder(spec, api, PassthroughBuilder)
+}
+
+// ServeWithBuilder serves the specified spec with the specified api registrations as a http.Handler that is decorated
+// by the Builder
+func ServeWithBuilder(spec *loads.Document, api *untyped.API, builder Builder) http.Handler {
+ context := NewContext(spec, api, nil)
+ return context.APIHandler(builder)
+}
+
+type contextKey int8
+
+const (
+ _ contextKey = iota
+ ctxContentType
+ ctxResponseFormat
+ ctxMatchedRoute
+ ctxBoundParams
+ ctxSecurityPrincipal
+ ctxSecurityScopes
+)
+
+// MatchedRouteFrom request context value.
+func MatchedRouteFrom(req *http.Request) *MatchedRoute {
+ mr := req.Context().Value(ctxMatchedRoute)
+ if mr == nil {
+ return nil
+ }
+ if res, ok := mr.(*MatchedRoute); ok {
+ return res
+ }
+ return nil
+}
+
+// SecurityPrincipalFrom request context value.
+func SecurityPrincipalFrom(req *http.Request) interface{} {
+ return req.Context().Value(ctxSecurityPrincipal)
+}
+
+// SecurityScopesFrom request context value.
+func SecurityScopesFrom(req *http.Request) []string {
+ rs := req.Context().Value(ctxSecurityScopes)
+ if res, ok := rs.([]string); ok {
+ return res
+ }
+ return nil
+}
+
+type contentTypeValue struct {
+ MediaType string
+ Charset string
+}
+
+// BasePath returns the base path for this API
+func (c *Context) BasePath() string {
+ return c.spec.BasePath()
+}
+
+// RequiredProduces returns the accepted content types for responses
+func (c *Context) RequiredProduces() []string {
+ return c.analyzer.RequiredProduces()
+}
+
+// BindValidRequest binds a params object to a request but only when the request is valid
+// if the request is not valid an error will be returned
+func (c *Context) BindValidRequest(request *http.Request, route *MatchedRoute, binder RequestBinder) error {
+ var res []error
+
+ requestContentType := "*/*"
+ // check and validate content type, select consumer
+ if runtime.HasBody(request) {
+ ct, _, err := runtime.ContentType(request.Header)
+ if err != nil {
+ res = append(res, err)
+ } else {
+ if err := validateContentType(route.Consumes, ct); err != nil {
+ res = append(res, err)
+ }
+ if len(res) == 0 {
+ cons, ok := route.Consumers[ct]
+ if !ok {
+ res = append(res, errors.New(500, "no consumer registered for %s", ct))
+ } else {
+ route.Consumer = cons
+ requestContentType = ct
+ }
+ }
+ }
+ }
+
+ // check and validate the response format
+ if len(res) == 0 && runtime.HasBody(request) {
+ if str := NegotiateContentType(request, route.Produces, requestContentType); str == "" {
+ res = append(res, errors.InvalidResponseFormat(request.Header.Get(runtime.HeaderAccept), route.Produces))
+ }
+ }
+
+ // now bind the request with the provided binder
+ // it's assumed the binder will also validate the request and return an error if the
+ // request is invalid
+ if binder != nil && len(res) == 0 {
+ if err := binder.BindRequest(request, route); err != nil {
+ return err
+ }
+ }
+
+ if len(res) > 0 {
+ return errors.CompositeValidationError(res...)
+ }
+ return nil
+}
+
+// ContentType gets the parsed value of a content type
+// Returns the media type, its charset and a shallow copy of the request
+// when its context doesn't contain the content type value, otherwise it returns
+// the same request
+// Returns the error that runtime.ContentType may retunrs.
+func (c *Context) ContentType(request *http.Request) (string, string, *http.Request, error) {
+ var rCtx = request.Context()
+
+ if v, ok := rCtx.Value(ctxContentType).(*contentTypeValue); ok {
+ return v.MediaType, v.Charset, request, nil
+ }
+
+ mt, cs, err := runtime.ContentType(request.Header)
+ if err != nil {
+ return "", "", nil, err
+ }
+ rCtx = stdContext.WithValue(rCtx, ctxContentType, &contentTypeValue{mt, cs})
+ return mt, cs, request.WithContext(rCtx), nil
+}
+
+// LookupRoute looks a route up and returns true when it is found
+func (c *Context) LookupRoute(request *http.Request) (*MatchedRoute, bool) {
+ if route, ok := c.router.Lookup(request.Method, request.URL.EscapedPath()); ok {
+ return route, ok
+ }
+ return nil, false
+}
+
+// RouteInfo tries to match a route for this request
+// Returns the matched route, a shallow copy of the request if its context
+// contains the matched router, otherwise the same request, and a bool to
+// indicate if it the request matches one of the routes, if it doesn't
+// then it returns false and nil for the other two return values
+func (c *Context) RouteInfo(request *http.Request) (*MatchedRoute, *http.Request, bool) {
+ var rCtx = request.Context()
+
+ if v, ok := rCtx.Value(ctxMatchedRoute).(*MatchedRoute); ok {
+ return v, request, ok
+ }
+
+ if route, ok := c.LookupRoute(request); ok {
+ rCtx = stdContext.WithValue(rCtx, ctxMatchedRoute, route)
+ return route, request.WithContext(rCtx), ok
+ }
+
+ return nil, nil, false
+}
+
+// ResponseFormat negotiates the response content type
+// Returns the response format and a shallow copy of the request if its context
+// doesn't contain the response format, otherwise the same request
+func (c *Context) ResponseFormat(r *http.Request, offers []string) (string, *http.Request) {
+ var rCtx = r.Context()
+
+ if v, ok := rCtx.Value(ctxResponseFormat).(string); ok {
+ debugLog("[%s %s] found response format %q in context", r.Method, r.URL.Path, v)
+ return v, r
+ }
+
+ format := NegotiateContentType(r, offers, "")
+ if format != "" {
+ debugLog("[%s %s] set response format %q in context", r.Method, r.URL.Path, format)
+ r = r.WithContext(stdContext.WithValue(rCtx, ctxResponseFormat, format))
+ }
+ debugLog("[%s %s] negotiated response format %q", r.Method, r.URL.Path, format)
+ return format, r
+}
+
+// AllowedMethods gets the allowed methods for the path of this request
+func (c *Context) AllowedMethods(request *http.Request) []string {
+ return c.router.OtherMethods(request.Method, request.URL.EscapedPath())
+}
+
+// ResetAuth removes the current principal from the request context
+func (c *Context) ResetAuth(request *http.Request) *http.Request {
+ rctx := request.Context()
+ rctx = stdContext.WithValue(rctx, ctxSecurityPrincipal, nil)
+ rctx = stdContext.WithValue(rctx, ctxSecurityScopes, nil)
+ return request.WithContext(rctx)
+}
+
+// Authorize authorizes the request
+// Returns the principal object and a shallow copy of the request when its
+// context doesn't contain the principal, otherwise the same request or an error
+// (the last) if one of the authenticators returns one or an Unauthenticated error
+func (c *Context) Authorize(request *http.Request, route *MatchedRoute) (interface{}, *http.Request, error) {
+ if route == nil || !route.HasAuth() {
+ return nil, nil, nil
+ }
+
+ var rCtx = request.Context()
+ if v := rCtx.Value(ctxSecurityPrincipal); v != nil {
+ return v, request, nil
+ }
+
+ applies, usr, err := route.Authenticators.Authenticate(request, route)
+ if !applies || err != nil || !route.Authenticators.AllowsAnonymous() && usr == nil {
+ if err != nil {
+ return nil, nil, err
+ }
+ return nil, nil, errors.Unauthenticated("invalid credentials")
+ }
+ if route.Authorizer != nil {
+ if err := route.Authorizer.Authorize(request, usr); err != nil {
+ return nil, nil, errors.New(http.StatusForbidden, err.Error())
+ }
+ }
+
+ rCtx = stdContext.WithValue(rCtx, ctxSecurityPrincipal, usr)
+ rCtx = stdContext.WithValue(rCtx, ctxSecurityScopes, route.Authenticator.AllScopes())
+ return usr, request.WithContext(rCtx), nil
+}
+
+// BindAndValidate binds and validates the request
+// Returns the validation map and a shallow copy of the request when its context
+// doesn't contain the validation, otherwise it returns the same request or an
+// CompositeValidationError error
+func (c *Context) BindAndValidate(request *http.Request, matched *MatchedRoute) (interface{}, *http.Request, error) {
+ var rCtx = request.Context()
+
+ if v, ok := rCtx.Value(ctxBoundParams).(*validation); ok {
+ debugLog("got cached validation (valid: %t)", len(v.result) == 0)
+ if len(v.result) > 0 {
+ return v.bound, request, errors.CompositeValidationError(v.result...)
+ }
+ return v.bound, request, nil
+ }
+ result := validateRequest(c, request, matched)
+ rCtx = stdContext.WithValue(rCtx, ctxBoundParams, result)
+ request = request.WithContext(rCtx)
+ if len(result.result) > 0 {
+ return result.bound, request, errors.CompositeValidationError(result.result...)
+ }
+ debugLog("no validation errors found")
+ return result.bound, request, nil
+}
+
+// NotFound the default not found responder for when no route has been matched yet
+func (c *Context) NotFound(rw http.ResponseWriter, r *http.Request) {
+ c.Respond(rw, r, []string{c.api.DefaultProduces()}, nil, errors.NotFound("not found"))
+}
+
+// Respond renders the response after doing some content negotiation
+func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []string, route *MatchedRoute, data interface{}) {
+ debugLog("responding to %s %s with produces: %v", r.Method, r.URL.Path, produces)
+ offers := []string{}
+ for _, mt := range produces {
+ if mt != c.api.DefaultProduces() {
+ offers = append(offers, mt)
+ }
+ }
+ // the default producer is last so more specific producers take precedence
+ offers = append(offers, c.api.DefaultProduces())
+ debugLog("offers: %v", offers)
+
+ var format string
+ format, r = c.ResponseFormat(r, offers)
+ rw.Header().Set(runtime.HeaderContentType, format)
+
+ if resp, ok := data.(Responder); ok {
+ producers := route.Producers
+ prod, ok := producers[format]
+ if !ok {
+ prods := c.api.ProducersFor(normalizeOffers([]string{c.api.DefaultProduces()}))
+ pr, ok := prods[c.api.DefaultProduces()]
+ if !ok {
+ panic(errors.New(http.StatusInternalServerError, "can't find a producer for "+format))
+ }
+ prod = pr
+ }
+ resp.WriteResponse(rw, prod)
+ return
+ }
+
+ if err, ok := data.(error); ok {
+ if format == "" {
+ rw.Header().Set(runtime.HeaderContentType, runtime.JSONMime)
+ }
+ if route == nil || route.Operation == nil {
+ c.api.ServeErrorFor("")(rw, r, err)
+ return
+ }
+ c.api.ServeErrorFor(route.Operation.ID)(rw, r, err)
+ return
+ }
+
+ if route == nil || route.Operation == nil {
+ rw.WriteHeader(200)
+ if r.Method == "HEAD" {
+ return
+ }
+ producers := c.api.ProducersFor(normalizeOffers(offers))
+ prod, ok := producers[format]
+ if !ok {
+ panic(errors.New(http.StatusInternalServerError, "can't find a producer for "+format))
+ }
+ if err := prod.Produce(rw, data); err != nil {
+ panic(err) // let the recovery middleware deal with this
+ }
+ return
+ }
+
+ if _, code, ok := route.Operation.SuccessResponse(); ok {
+ rw.WriteHeader(code)
+ if code == 204 || r.Method == "HEAD" {
+ return
+ }
+
+ producers := route.Producers
+ prod, ok := producers[format]
+ if !ok {
+ if !ok {
+ prods := c.api.ProducersFor(normalizeOffers([]string{c.api.DefaultProduces()}))
+ pr, ok := prods[c.api.DefaultProduces()]
+ if !ok {
+ panic(errors.New(http.StatusInternalServerError, "can't find a producer for "+format))
+ }
+ prod = pr
+ }
+ }
+ if err := prod.Produce(rw, data); err != nil {
+ panic(err) // let the recovery middleware deal with this
+ }
+ return
+ }
+
+ c.api.ServeErrorFor(route.Operation.ID)(rw, r, errors.New(http.StatusInternalServerError, "can't produce response"))
+}
+
+// APIHandler returns a handler to serve the API, this includes a swagger spec, router and the contract defined in the swagger spec
+func (c *Context) APIHandler(builder Builder) http.Handler {
+ b := builder
+ if b == nil {
+ b = PassthroughBuilder
+ }
+
+ var title string
+ sp := c.spec.Spec()
+ if sp != nil && sp.Info != nil && sp.Info.Title != "" {
+ title = sp.Info.Title
+ }
+
+ redocOpts := RedocOpts{
+ BasePath: c.BasePath(),
+ Title: title,
+ }
+
+ return Spec("", c.spec.Raw(), Redoc(redocOpts, c.RoutesHandler(b)))
+}
+
+// RoutesHandler returns a handler to serve the API, just the routes and the contract defined in the swagger spec
+func (c *Context) RoutesHandler(builder Builder) http.Handler {
+ b := builder
+ if b == nil {
+ b = PassthroughBuilder
+ }
+ return NewRouter(c, b(NewOperationExecutor(c)))
+}