1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package validate
16
17 import (
18 "reflect"
19 "strings"
20
21 "github.com/go-openapi/errors"
22 "github.com/go-openapi/spec"
23 "github.com/go-openapi/strfmt"
24 "github.com/go-openapi/swag"
25 )
26
27 type typeValidator struct {
28 Path string
29 In string
30 Type spec.StringOrArray
31 Nullable bool
32 Format string
33 Options *SchemaValidatorOptions
34 }
35
36 func newTypeValidator(path, in string, typ spec.StringOrArray, nullable bool, format string, opts *SchemaValidatorOptions) *typeValidator {
37 if opts == nil {
38 opts = new(SchemaValidatorOptions)
39 }
40
41 var t *typeValidator
42 if opts.recycleValidators {
43 t = pools.poolOfTypeValidators.BorrowValidator()
44 } else {
45 t = new(typeValidator)
46 }
47
48 t.Path = path
49 t.In = in
50 t.Type = typ
51 t.Nullable = nullable
52 t.Format = format
53 t.Options = opts
54
55 return t
56 }
57
58 func (t *typeValidator) schemaInfoForType(data interface{}) (string, string) {
59
60
61
62 switch data.(type) {
63 case []byte, strfmt.Base64, *strfmt.Base64:
64 return stringType, stringFormatByte
65 case strfmt.CreditCard, *strfmt.CreditCard:
66 return stringType, stringFormatCreditCard
67 case strfmt.Date, *strfmt.Date:
68 return stringType, stringFormatDate
69 case strfmt.DateTime, *strfmt.DateTime:
70 return stringType, stringFormatDateTime
71 case strfmt.Duration, *strfmt.Duration:
72 return stringType, stringFormatDuration
73 case swag.File, *swag.File:
74 return fileType, ""
75 case strfmt.Email, *strfmt.Email:
76 return stringType, stringFormatEmail
77 case strfmt.HexColor, *strfmt.HexColor:
78 return stringType, stringFormatHexColor
79 case strfmt.Hostname, *strfmt.Hostname:
80 return stringType, stringFormatHostname
81 case strfmt.IPv4, *strfmt.IPv4:
82 return stringType, stringFormatIPv4
83 case strfmt.IPv6, *strfmt.IPv6:
84 return stringType, stringFormatIPv6
85 case strfmt.ISBN, *strfmt.ISBN:
86 return stringType, stringFormatISBN
87 case strfmt.ISBN10, *strfmt.ISBN10:
88 return stringType, stringFormatISBN10
89 case strfmt.ISBN13, *strfmt.ISBN13:
90 return stringType, stringFormatISBN13
91 case strfmt.MAC, *strfmt.MAC:
92 return stringType, stringFormatMAC
93 case strfmt.ObjectId, *strfmt.ObjectId:
94 return stringType, stringFormatBSONObjectID
95 case strfmt.Password, *strfmt.Password:
96 return stringType, stringFormatPassword
97 case strfmt.RGBColor, *strfmt.RGBColor:
98 return stringType, stringFormatRGBColor
99 case strfmt.SSN, *strfmt.SSN:
100 return stringType, stringFormatSSN
101 case strfmt.URI, *strfmt.URI:
102 return stringType, stringFormatURI
103 case strfmt.UUID, *strfmt.UUID:
104 return stringType, stringFormatUUID
105 case strfmt.UUID3, *strfmt.UUID3:
106 return stringType, stringFormatUUID3
107 case strfmt.UUID4, *strfmt.UUID4:
108 return stringType, stringFormatUUID4
109 case strfmt.UUID5, *strfmt.UUID5:
110 return stringType, stringFormatUUID5
111
112
113 default:
114 val := reflect.ValueOf(data)
115 tpe := val.Type()
116 switch tpe.Kind() {
117 case reflect.Bool:
118 return booleanType, ""
119 case reflect.String:
120 return stringType, ""
121 case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint8, reflect.Uint16, reflect.Uint32:
122
123 return integerType, integerFormatInt32
124 case reflect.Int, reflect.Int64, reflect.Uint, reflect.Uint64:
125 return integerType, integerFormatInt64
126 case reflect.Float32:
127
128 return numberType, numberFormatFloat32
129 case reflect.Float64:
130
131 return numberType, numberFormatFloat64
132
133 case reflect.Slice:
134 return arrayType, ""
135 case reflect.Map, reflect.Struct:
136 return objectType, ""
137 case reflect.Interface:
138
139 panic("dunno what to do here")
140 case reflect.Ptr:
141 return t.schemaInfoForType(reflect.Indirect(val).Interface())
142 }
143 }
144 return "", ""
145 }
146
147 func (t *typeValidator) SetPath(path string) {
148 t.Path = path
149 }
150
151 func (t *typeValidator) Applies(source interface{}, _ reflect.Kind) bool {
152
153 switch source.(type) {
154 case *spec.Schema:
155 case *spec.Parameter:
156 case *spec.Header:
157 default:
158 return false
159 }
160
161 return (len(t.Type) > 0 || t.Format != "")
162 }
163
164 func (t *typeValidator) Validate(data interface{}) *Result {
165 if t.Options.recycleValidators {
166 defer func() {
167 t.redeem()
168 }()
169 }
170
171 if data == nil {
172
173 if len(t.Type) > 0 && !t.Type.Contains(nullType) && !t.Nullable {
174 return errorHelp.sErr(errors.InvalidType(t.Path, t.In, strings.Join(t.Type, ","), nullType), t.Options.recycleResult)
175 }
176
177 return emptyResult
178 }
179
180
181 val := reflect.Indirect(reflect.ValueOf(data))
182 kind := val.Kind()
183
184
185 schType, format := t.schemaInfoForType(data)
186
187
188
189
190 isLowerInt := t.Format == integerFormatInt64 && format == integerFormatInt32
191 isLowerFloat := t.Format == numberFormatFloat64 && format == numberFormatFloat32
192 isFloatInt := schType == numberType && swag.IsFloat64AJSONInteger(val.Float()) && t.Type.Contains(integerType)
193 isIntFloat := schType == integerType && t.Type.Contains(numberType)
194
195 if kind != reflect.String && kind != reflect.Slice && t.Format != "" && !(t.Type.Contains(schType) || format == t.Format || isFloatInt || isIntFloat || isLowerInt || isLowerFloat) {
196
197 return errorHelp.sErr(errors.InvalidType(t.Path, t.In, t.Format, format), t.Options.recycleResult)
198 }
199
200 if !(t.Type.Contains(numberType) || t.Type.Contains(integerType)) && t.Format != "" && (kind == reflect.String || kind == reflect.Slice) {
201 return emptyResult
202 }
203
204 if !(t.Type.Contains(schType) || isFloatInt || isIntFloat) {
205 return errorHelp.sErr(errors.InvalidType(t.Path, t.In, strings.Join(t.Type, ","), schType), t.Options.recycleResult)
206 }
207
208 return emptyResult
209 }
210
211 func (t *typeValidator) redeem() {
212 pools.poolOfTypeValidators.RedeemValidator(t)
213 }
214
View as plain text