// 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 ( "net/http" "reflect" "github.com/go-openapi/errors" "github.com/go-openapi/spec" "github.com/go-openapi/strfmt" "github.com/go-openapi/runtime" ) // UntypedRequestBinder binds and validates the data from a http request type UntypedRequestBinder struct { Spec *spec.Swagger Parameters map[string]spec.Parameter Formats strfmt.Registry paramBinders map[string]*untypedParamBinder } // NewUntypedRequestBinder creates a new binder for reading a request. func NewUntypedRequestBinder(parameters map[string]spec.Parameter, spec *spec.Swagger, formats strfmt.Registry) *UntypedRequestBinder { binders := make(map[string]*untypedParamBinder) for fieldName, param := range parameters { binders[fieldName] = newUntypedParamBinder(param, spec, formats) } return &UntypedRequestBinder{ Parameters: parameters, paramBinders: binders, Spec: spec, Formats: formats, } } // Bind perform the databinding and validation func (o *UntypedRequestBinder) Bind(request *http.Request, routeParams RouteParams, consumer runtime.Consumer, data interface{}) error { val := reflect.Indirect(reflect.ValueOf(data)) isMap := val.Kind() == reflect.Map var result []error debugLog("binding %d parameters for %s %s", len(o.Parameters), request.Method, request.URL.EscapedPath()) for fieldName, param := range o.Parameters { binder := o.paramBinders[fieldName] debugLog("binding parameter %s for %s %s", fieldName, request.Method, request.URL.EscapedPath()) var target reflect.Value if !isMap { binder.Name = fieldName target = val.FieldByName(fieldName) } if isMap { tpe := binder.Type() if tpe == nil { if param.Schema.Type.Contains("array") { tpe = reflect.TypeOf([]interface{}{}) } else { tpe = reflect.TypeOf(map[string]interface{}{}) } } target = reflect.Indirect(reflect.New(tpe)) } if !target.IsValid() { result = append(result, errors.New(500, "parameter name %q is an unknown field", binder.Name)) continue } if err := binder.Bind(request, routeParams, consumer, target); err != nil { result = append(result, err) continue } if binder.validator != nil { rr := binder.validator.Validate(target.Interface()) if rr != nil && rr.HasErrors() { result = append(result, rr.AsError()) } } if isMap { val.SetMapIndex(reflect.ValueOf(param.Name), target) } } if len(result) > 0 { return errors.CompositeValidationError(result...) } return nil }