blob: ee725f587a3c119a03757625b2cd4f5730f88c72 [file] [log] [blame]
Serge Bazanskicc25bdf2018-10-25 14:02:58 +02001// Copyright 2015 go-swagger maintainers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package middleware
16
17import (
18 "net/http"
19 "reflect"
20
21 "github.com/go-openapi/errors"
22 "github.com/go-openapi/runtime"
23 "github.com/go-openapi/spec"
24 "github.com/go-openapi/strfmt"
25)
26
27// RequestBinder binds and validates the data from a http request
28type untypedRequestBinder struct {
29 Spec *spec.Swagger
30 Parameters map[string]spec.Parameter
31 Formats strfmt.Registry
32 paramBinders map[string]*untypedParamBinder
33}
34
35// NewRequestBinder creates a new binder for reading a request.
36func newUntypedRequestBinder(parameters map[string]spec.Parameter, spec *spec.Swagger, formats strfmt.Registry) *untypedRequestBinder {
37 binders := make(map[string]*untypedParamBinder)
38 for fieldName, param := range parameters {
39 binders[fieldName] = newUntypedParamBinder(param, spec, formats)
40 }
41 return &untypedRequestBinder{
42 Parameters: parameters,
43 paramBinders: binders,
44 Spec: spec,
45 Formats: formats,
46 }
47}
48
49// Bind perform the databinding and validation
50func (o *untypedRequestBinder) Bind(request *http.Request, routeParams RouteParams, consumer runtime.Consumer, data interface{}) error {
51 val := reflect.Indirect(reflect.ValueOf(data))
52 isMap := val.Kind() == reflect.Map
53 var result []error
54 debugLog("binding %d parameters for %s %s", len(o.Parameters), request.Method, request.URL.EscapedPath())
55 for fieldName, param := range o.Parameters {
56 binder := o.paramBinders[fieldName]
57 debugLog("binding parameter %s for %s %s", fieldName, request.Method, request.URL.EscapedPath())
58 var target reflect.Value
59 if !isMap {
60 binder.Name = fieldName
61 target = val.FieldByName(fieldName)
62 }
63
64 if isMap {
65 tpe := binder.Type()
66 if tpe == nil {
67 if param.Schema.Type.Contains("array") {
68 tpe = reflect.TypeOf([]interface{}{})
69 } else {
70 tpe = reflect.TypeOf(map[string]interface{}{})
71 }
72 }
73 target = reflect.Indirect(reflect.New(tpe))
74
75 }
76
77 if !target.IsValid() {
78 result = append(result, errors.New(500, "parameter name %q is an unknown field", binder.Name))
79 continue
80 }
81
82 if err := binder.Bind(request, routeParams, consumer, target); err != nil {
83 result = append(result, err)
84 continue
85 }
86
87 if binder.validator != nil {
88 rr := binder.validator.Validate(target.Interface())
89 if rr != nil && rr.HasErrors() {
90 result = append(result, rr.AsError())
91 }
92 }
93
94 if isMap {
95 val.SetMapIndex(reflect.ValueOf(param.Name), target)
96 }
97 }
98
99 if len(result) > 0 {
100 return errors.CompositeValidationError(result...)
101 }
102
103 return nil
104}