podman
485 строк · 12.1 Кб
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
15package middleware
16
17import (
18"encoding"
19"encoding/base64"
20"fmt"
21"io"
22"net/http"
23"reflect"
24"strconv"
25
26"github.com/go-openapi/errors"
27"github.com/go-openapi/spec"
28"github.com/go-openapi/strfmt"
29"github.com/go-openapi/swag"
30"github.com/go-openapi/validate"
31
32"github.com/go-openapi/runtime"
33)
34
35const defaultMaxMemory = 32 << 20
36
37var textUnmarshalType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem()
38
39func newUntypedParamBinder(param spec.Parameter, spec *spec.Swagger, formats strfmt.Registry) *untypedParamBinder {
40binder := new(untypedParamBinder)
41binder.Name = param.Name
42binder.parameter = ¶m
43binder.formats = formats
44if param.In != "body" {
45binder.validator = validate.NewParamValidator(¶m, formats)
46} else {
47binder.validator = validate.NewSchemaValidator(param.Schema, spec, param.Name, formats)
48}
49
50return binder
51}
52
53type untypedParamBinder struct {
54parameter *spec.Parameter
55formats strfmt.Registry
56Name string
57validator validate.EntityValidator
58}
59
60func (p *untypedParamBinder) Type() reflect.Type {
61return p.typeForSchema(p.parameter.Type, p.parameter.Format, p.parameter.Items)
62}
63
64func (p *untypedParamBinder) typeForSchema(tpe, format string, items *spec.Items) reflect.Type {
65switch tpe {
66case "boolean":
67return reflect.TypeOf(true)
68
69case "string":
70if tt, ok := p.formats.GetType(format); ok {
71return tt
72}
73return reflect.TypeOf("")
74
75case "integer":
76switch format {
77case "int8":
78return reflect.TypeOf(int8(0))
79case "int16":
80return reflect.TypeOf(int16(0))
81case "int32":
82return reflect.TypeOf(int32(0))
83case "int64":
84return reflect.TypeOf(int64(0))
85default:
86return reflect.TypeOf(int64(0))
87}
88
89case "number":
90switch format {
91case "float":
92return reflect.TypeOf(float32(0))
93case "double":
94return reflect.TypeOf(float64(0))
95}
96
97case "array":
98if items == nil {
99return nil
100}
101itemsType := p.typeForSchema(items.Type, items.Format, items.Items)
102if itemsType == nil {
103return nil
104}
105return reflect.MakeSlice(reflect.SliceOf(itemsType), 0, 0).Type()
106
107case "file":
108return reflect.TypeOf(&runtime.File{}).Elem()
109
110case "object":
111return reflect.TypeOf(map[string]interface{}{})
112}
113return nil
114}
115
116func (p *untypedParamBinder) allowsMulti() bool {
117return p.parameter.In == "query" || p.parameter.In == "formData"
118}
119
120func (p *untypedParamBinder) readValue(values runtime.Gettable, target reflect.Value) ([]string, bool, bool, error) {
121name, in, cf, tpe := p.parameter.Name, p.parameter.In, p.parameter.CollectionFormat, p.parameter.Type
122if tpe == "array" {
123if cf == "multi" {
124if !p.allowsMulti() {
125return nil, false, false, errors.InvalidCollectionFormat(name, in, cf)
126}
127vv, hasKey, _ := values.GetOK(name)
128return vv, false, hasKey, nil
129}
130
131v, hk, hv := values.GetOK(name)
132if !hv {
133return nil, false, hk, nil
134}
135d, c, e := p.readFormattedSliceFieldValue(v[len(v)-1], target)
136return d, c, hk, e
137}
138
139vv, hk, _ := values.GetOK(name)
140return vv, false, hk, nil
141}
142
143func (p *untypedParamBinder) Bind(request *http.Request, routeParams RouteParams, consumer runtime.Consumer, target reflect.Value) error {
144// fmt.Println("binding", p.name, "as", p.Type())
145switch p.parameter.In {
146case "query":
147data, custom, hasKey, err := p.readValue(runtime.Values(request.URL.Query()), target)
148if err != nil {
149return err
150}
151if custom {
152return nil
153}
154
155return p.bindValue(data, hasKey, target)
156
157case "header":
158data, custom, hasKey, err := p.readValue(runtime.Values(request.Header), target)
159if err != nil {
160return err
161}
162if custom {
163return nil
164}
165return p.bindValue(data, hasKey, target)
166
167case "path":
168data, custom, hasKey, err := p.readValue(routeParams, target)
169if err != nil {
170return err
171}
172if custom {
173return nil
174}
175return p.bindValue(data, hasKey, target)
176
177case "formData":
178var err error
179var mt string
180
181mt, _, e := runtime.ContentType(request.Header)
182if e != nil {
183// because of the interface conversion go thinks the error is not nil
184// so we first check for nil and then set the err var if it's not nil
185err = e
186}
187
188if err != nil {
189return errors.InvalidContentType("", []string{"multipart/form-data", "application/x-www-form-urlencoded"})
190}
191
192if mt != "multipart/form-data" && mt != "application/x-www-form-urlencoded" {
193return errors.InvalidContentType(mt, []string{"multipart/form-data", "application/x-www-form-urlencoded"})
194}
195
196if mt == "multipart/form-data" {
197if err = request.ParseMultipartForm(defaultMaxMemory); err != nil {
198return errors.NewParseError(p.Name, p.parameter.In, "", err)
199}
200}
201
202if err = request.ParseForm(); err != nil {
203return errors.NewParseError(p.Name, p.parameter.In, "", err)
204}
205
206if p.parameter.Type == "file" {
207file, header, ffErr := request.FormFile(p.parameter.Name)
208if ffErr != nil {
209if p.parameter.Required {
210return errors.NewParseError(p.Name, p.parameter.In, "", ffErr)
211} else {
212return nil
213}
214}
215target.Set(reflect.ValueOf(runtime.File{Data: file, Header: header}))
216return nil
217}
218
219if request.MultipartForm != nil {
220data, custom, hasKey, rvErr := p.readValue(runtime.Values(request.MultipartForm.Value), target)
221if rvErr != nil {
222return rvErr
223}
224if custom {
225return nil
226}
227return p.bindValue(data, hasKey, target)
228}
229data, custom, hasKey, err := p.readValue(runtime.Values(request.PostForm), target)
230if err != nil {
231return err
232}
233if custom {
234return nil
235}
236return p.bindValue(data, hasKey, target)
237
238case "body":
239newValue := reflect.New(target.Type())
240if !runtime.HasBody(request) {
241if p.parameter.Default != nil {
242target.Set(reflect.ValueOf(p.parameter.Default))
243}
244
245return nil
246}
247if err := consumer.Consume(request.Body, newValue.Interface()); err != nil {
248if err == io.EOF && p.parameter.Default != nil {
249target.Set(reflect.ValueOf(p.parameter.Default))
250return nil
251}
252tpe := p.parameter.Type
253if p.parameter.Format != "" {
254tpe = p.parameter.Format
255}
256return errors.InvalidType(p.Name, p.parameter.In, tpe, nil)
257}
258target.Set(reflect.Indirect(newValue))
259return nil
260default:
261return errors.New(500, fmt.Sprintf("invalid parameter location %q", p.parameter.In))
262}
263}
264
265func (p *untypedParamBinder) bindValue(data []string, hasKey bool, target reflect.Value) error {
266if p.parameter.Type == "array" {
267return p.setSliceFieldValue(target, p.parameter.Default, data, hasKey)
268}
269var d string
270if len(data) > 0 {
271d = data[len(data)-1]
272}
273return p.setFieldValue(target, p.parameter.Default, d, hasKey)
274}
275
276func (p *untypedParamBinder) setFieldValue(target reflect.Value, defaultValue interface{}, data string, hasKey bool) error {
277tpe := p.parameter.Type
278if p.parameter.Format != "" {
279tpe = p.parameter.Format
280}
281
282if (!hasKey || (!p.parameter.AllowEmptyValue && data == "")) && p.parameter.Required && p.parameter.Default == nil {
283return errors.Required(p.Name, p.parameter.In, data)
284}
285
286ok, err := p.tryUnmarshaler(target, defaultValue, data)
287if err != nil {
288return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
289}
290if ok {
291return nil
292}
293
294defVal := reflect.Zero(target.Type())
295if defaultValue != nil {
296defVal = reflect.ValueOf(defaultValue)
297}
298
299if tpe == "byte" {
300if data == "" {
301if target.CanSet() {
302target.SetBytes(defVal.Bytes())
303}
304return nil
305}
306
307b, err := base64.StdEncoding.DecodeString(data)
308if err != nil {
309b, err = base64.URLEncoding.DecodeString(data)
310if err != nil {
311return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
312}
313}
314if target.CanSet() {
315target.SetBytes(b)
316}
317return nil
318}
319
320switch target.Kind() {
321case reflect.Bool:
322if data == "" {
323if target.CanSet() {
324target.SetBool(defVal.Bool())
325}
326return nil
327}
328b, err := swag.ConvertBool(data)
329if err != nil {
330return err
331}
332if target.CanSet() {
333target.SetBool(b)
334}
335case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
336if data == "" {
337if target.CanSet() {
338rd := defVal.Convert(reflect.TypeOf(int64(0)))
339target.SetInt(rd.Int())
340}
341return nil
342}
343i, err := strconv.ParseInt(data, 10, 64)
344if err != nil {
345return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
346}
347if target.OverflowInt(i) {
348return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
349}
350if target.CanSet() {
351target.SetInt(i)
352}
353
354case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
355if data == "" {
356if target.CanSet() {
357rd := defVal.Convert(reflect.TypeOf(uint64(0)))
358target.SetUint(rd.Uint())
359}
360return nil
361}
362u, err := strconv.ParseUint(data, 10, 64)
363if err != nil {
364return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
365}
366if target.OverflowUint(u) {
367return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
368}
369if target.CanSet() {
370target.SetUint(u)
371}
372
373case reflect.Float32, reflect.Float64:
374if data == "" {
375if target.CanSet() {
376rd := defVal.Convert(reflect.TypeOf(float64(0)))
377target.SetFloat(rd.Float())
378}
379return nil
380}
381f, err := strconv.ParseFloat(data, 64)
382if err != nil {
383return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
384}
385if target.OverflowFloat(f) {
386return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
387}
388if target.CanSet() {
389target.SetFloat(f)
390}
391
392case reflect.String:
393value := data
394if value == "" {
395value = defVal.String()
396}
397// validate string
398if target.CanSet() {
399target.SetString(value)
400}
401
402case reflect.Ptr:
403if data == "" && defVal.Kind() == reflect.Ptr {
404if target.CanSet() {
405target.Set(defVal)
406}
407return nil
408}
409newVal := reflect.New(target.Type().Elem())
410if err := p.setFieldValue(reflect.Indirect(newVal), defVal, data, hasKey); err != nil {
411return err
412}
413if target.CanSet() {
414target.Set(newVal)
415}
416
417default:
418return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
419}
420return nil
421}
422
423func (p *untypedParamBinder) tryUnmarshaler(target reflect.Value, defaultValue interface{}, data string) (bool, error) {
424if !target.CanSet() {
425return false, nil
426}
427// When a type implements encoding.TextUnmarshaler we'll use that instead of reflecting some more
428if reflect.PtrTo(target.Type()).Implements(textUnmarshalType) {
429if defaultValue != nil && len(data) == 0 {
430target.Set(reflect.ValueOf(defaultValue))
431return true, nil
432}
433value := reflect.New(target.Type())
434if err := value.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(data)); err != nil {
435return true, err
436}
437target.Set(reflect.Indirect(value))
438return true, nil
439}
440return false, nil
441}
442
443func (p *untypedParamBinder) readFormattedSliceFieldValue(data string, target reflect.Value) ([]string, bool, error) {
444ok, err := p.tryUnmarshaler(target, p.parameter.Default, data)
445if err != nil {
446return nil, true, err
447}
448if ok {
449return nil, true, nil
450}
451
452return swag.SplitByFormat(data, p.parameter.CollectionFormat), false, nil
453}
454
455func (p *untypedParamBinder) setSliceFieldValue(target reflect.Value, defaultValue interface{}, data []string, hasKey bool) error {
456sz := len(data)
457if (!hasKey || (!p.parameter.AllowEmptyValue && (sz == 0 || (sz == 1 && data[0] == "")))) && p.parameter.Required && defaultValue == nil {
458return errors.Required(p.Name, p.parameter.In, data)
459}
460
461defVal := reflect.Zero(target.Type())
462if defaultValue != nil {
463defVal = reflect.ValueOf(defaultValue)
464}
465
466if !target.CanSet() {
467return nil
468}
469if sz == 0 {
470target.Set(defVal)
471return nil
472}
473
474value := reflect.MakeSlice(reflect.SliceOf(target.Type().Elem()), sz, sz)
475
476for i := 0; i < sz; i++ {
477if err := p.setFieldValue(value.Index(i), nil, data[i], hasKey); err != nil {
478return err
479}
480}
481
482target.Set(value)
483
484return nil
485}
486