| // 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/runtime" |
| "github.com/go-openapi/spec" |
| "github.com/go-openapi/strfmt" |
| ) |
| |
| // RequestBinder 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 |
| } |
| |
| // NewRequestBinder 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 |
| } |