You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

104 lines
3.0 KiB

  1. // 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. package middleware
  15. import (
  16. "net/http"
  17. "reflect"
  18. "github.com/go-openapi/errors"
  19. "github.com/go-openapi/spec"
  20. "github.com/go-openapi/strfmt"
  21. "github.com/go-openapi/runtime"
  22. )
  23. // UntypedRequestBinder binds and validates the data from a http request
  24. type UntypedRequestBinder struct {
  25. Spec *spec.Swagger
  26. Parameters map[string]spec.Parameter
  27. Formats strfmt.Registry
  28. paramBinders map[string]*untypedParamBinder
  29. }
  30. // NewUntypedRequestBinder creates a new binder for reading a request.
  31. func NewUntypedRequestBinder(parameters map[string]spec.Parameter, spec *spec.Swagger, formats strfmt.Registry) *UntypedRequestBinder {
  32. binders := make(map[string]*untypedParamBinder)
  33. for fieldName, param := range parameters {
  34. binders[fieldName] = newUntypedParamBinder(param, spec, formats)
  35. }
  36. return &UntypedRequestBinder{
  37. Parameters: parameters,
  38. paramBinders: binders,
  39. Spec: spec,
  40. Formats: formats,
  41. }
  42. }
  43. // Bind perform the databinding and validation
  44. func (o *UntypedRequestBinder) Bind(request *http.Request, routeParams RouteParams, consumer runtime.Consumer, data interface{}) error {
  45. val := reflect.Indirect(reflect.ValueOf(data))
  46. isMap := val.Kind() == reflect.Map
  47. var result []error
  48. debugLog("binding %d parameters for %s %s", len(o.Parameters), request.Method, request.URL.EscapedPath())
  49. for fieldName, param := range o.Parameters {
  50. binder := o.paramBinders[fieldName]
  51. debugLog("binding parameter %s for %s %s", fieldName, request.Method, request.URL.EscapedPath())
  52. var target reflect.Value
  53. if !isMap {
  54. binder.Name = fieldName
  55. target = val.FieldByName(fieldName)
  56. }
  57. if isMap {
  58. tpe := binder.Type()
  59. if tpe == nil {
  60. if param.Schema.Type.Contains("array") {
  61. tpe = reflect.TypeOf([]interface{}{})
  62. } else {
  63. tpe = reflect.TypeOf(map[string]interface{}{})
  64. }
  65. }
  66. target = reflect.Indirect(reflect.New(tpe))
  67. }
  68. if !target.IsValid() {
  69. result = append(result, errors.New(500, "parameter name %q is an unknown field", binder.Name))
  70. continue
  71. }
  72. if err := binder.Bind(request, routeParams, consumer, target); err != nil {
  73. result = append(result, err)
  74. continue
  75. }
  76. if binder.validator != nil {
  77. rr := binder.validator.Validate(target.Interface())
  78. if rr != nil && rr.HasErrors() {
  79. result = append(result, rr.AsError())
  80. }
  81. }
  82. if isMap {
  83. val.SetMapIndex(reflect.ValueOf(param.Name), target)
  84. }
  85. }
  86. if len(result) > 0 {
  87. return errors.CompositeValidationError(result...)
  88. }
  89. return nil
  90. }