1/* 2Package validation provides methods for validating parameter value using reflection. 3*/ 4package validation 5 6// Copyright 2017 Microsoft Corporation 7// 8// Licensed under the Apache License, Version 2.0 (the "License"); 9// you may not use this file except in compliance with the License. 10// You may obtain a copy of the License at 11// 12// http://www.apache.org/licenses/LICENSE-2.0 13// 14// Unless required by applicable law or agreed to in writing, software 15// distributed under the License is distributed on an "AS IS" BASIS, 16// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17// See the License for the specific language governing permissions and 18// limitations under the License. 19 20import ( 21 "fmt" 22 "reflect" 23 "regexp" 24 "strings" 25) 26 27// Constraint stores constraint name, target field name 28// Rule and chain validations. 29type Constraint struct { 30 31 // Target field name for validation. 32 Target string 33 34 // Constraint name e.g. minLength, MaxLength, Pattern, etc. 35 Name string 36 37 // Rule for constraint e.g. greater than 10, less than 5 etc. 38 Rule interface{} 39 40 // Chain Validations for struct type 41 Chain []Constraint 42} 43 44// Validation stores parameter-wise validation. 45type Validation struct { 46 TargetValue interface{} 47 Constraints []Constraint 48} 49 50// Constraint list 51const ( 52 Empty = "Empty" 53 Null = "Null" 54 ReadOnly = "ReadOnly" 55 Pattern = "Pattern" 56 MaxLength = "MaxLength" 57 MinLength = "MinLength" 58 MaxItems = "MaxItems" 59 MinItems = "MinItems" 60 MultipleOf = "MultipleOf" 61 UniqueItems = "UniqueItems" 62 InclusiveMaximum = "InclusiveMaximum" 63 ExclusiveMaximum = "ExclusiveMaximum" 64 ExclusiveMinimum = "ExclusiveMinimum" 65 InclusiveMinimum = "InclusiveMinimum" 66) 67 68// Validate method validates constraints on parameter 69// passed in validation array. 70func Validate(m []Validation) error { 71 for _, item := range m { 72 v := reflect.ValueOf(item.TargetValue) 73 for _, constraint := range item.Constraints { 74 var err error 75 switch v.Kind() { 76 case reflect.Ptr: 77 err = validatePtr(v, constraint) 78 case reflect.String: 79 err = validateString(v, constraint) 80 case reflect.Struct: 81 err = validateStruct(v, constraint) 82 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 83 err = validateInt(v, constraint) 84 case reflect.Float32, reflect.Float64: 85 err = validateFloat(v, constraint) 86 case reflect.Array, reflect.Slice, reflect.Map: 87 err = validateArrayMap(v, constraint) 88 default: 89 err = createError(v, constraint, fmt.Sprintf("unknown type %v", v.Kind())) 90 } 91 92 if err != nil { 93 return err 94 } 95 } 96 } 97 return nil 98} 99 100func validateStruct(x reflect.Value, v Constraint, name ...string) error { 101 //Get field name from target name which is in format a.b.c 102 s := strings.Split(v.Target, ".") 103 f := x.FieldByName(s[len(s)-1]) 104 if isZero(f) { 105 return createError(x, v, fmt.Sprintf("field %q doesn't exist", v.Target)) 106 } 107 108 return Validate([]Validation{ 109 { 110 TargetValue: getInterfaceValue(f), 111 Constraints: []Constraint{v}, 112 }, 113 }) 114} 115 116func validatePtr(x reflect.Value, v Constraint) error { 117 if v.Name == ReadOnly { 118 if !x.IsNil() { 119 return createError(x.Elem(), v, "readonly parameter; must send as nil or empty in request") 120 } 121 return nil 122 } 123 if x.IsNil() { 124 return checkNil(x, v) 125 } 126 if v.Chain != nil { 127 return Validate([]Validation{ 128 { 129 TargetValue: getInterfaceValue(x.Elem()), 130 Constraints: v.Chain, 131 }, 132 }) 133 } 134 return nil 135} 136 137func validateInt(x reflect.Value, v Constraint) error { 138 i := x.Int() 139 r, ok := toInt64(v.Rule) 140 if !ok { 141 return createError(x, v, fmt.Sprintf("rule must be integer value for %v constraint; got: %v", v.Name, v.Rule)) 142 } 143 switch v.Name { 144 case MultipleOf: 145 if i%r != 0 { 146 return createError(x, v, fmt.Sprintf("value must be a multiple of %v", r)) 147 } 148 case ExclusiveMinimum: 149 if i <= r { 150 return createError(x, v, fmt.Sprintf("value must be greater than %v", r)) 151 } 152 case ExclusiveMaximum: 153 if i >= r { 154 return createError(x, v, fmt.Sprintf("value must be less than %v", r)) 155 } 156 case InclusiveMinimum: 157 if i < r { 158 return createError(x, v, fmt.Sprintf("value must be greater than or equal to %v", r)) 159 } 160 case InclusiveMaximum: 161 if i > r { 162 return createError(x, v, fmt.Sprintf("value must be less than or equal to %v", r)) 163 } 164 default: 165 return createError(x, v, fmt.Sprintf("constraint %v is not applicable for type integer", v.Name)) 166 } 167 return nil 168} 169 170func validateFloat(x reflect.Value, v Constraint) error { 171 f := x.Float() 172 r, ok := v.Rule.(float64) 173 if !ok { 174 return createError(x, v, fmt.Sprintf("rule must be float value for %v constraint; got: %v", v.Name, v.Rule)) 175 } 176 switch v.Name { 177 case ExclusiveMinimum: 178 if f <= r { 179 return createError(x, v, fmt.Sprintf("value must be greater than %v", r)) 180 } 181 case ExclusiveMaximum: 182 if f >= r { 183 return createError(x, v, fmt.Sprintf("value must be less than %v", r)) 184 } 185 case InclusiveMinimum: 186 if f < r { 187 return createError(x, v, fmt.Sprintf("value must be greater than or equal to %v", r)) 188 } 189 case InclusiveMaximum: 190 if f > r { 191 return createError(x, v, fmt.Sprintf("value must be less than or equal to %v", r)) 192 } 193 default: 194 return createError(x, v, fmt.Sprintf("constraint %s is not applicable for type float", v.Name)) 195 } 196 return nil 197} 198 199func validateString(x reflect.Value, v Constraint) error { 200 s := x.String() 201 switch v.Name { 202 case Empty: 203 if len(s) == 0 { 204 return checkEmpty(x, v) 205 } 206 case Pattern: 207 reg, err := regexp.Compile(v.Rule.(string)) 208 if err != nil { 209 return createError(x, v, err.Error()) 210 } 211 if !reg.MatchString(s) { 212 return createError(x, v, fmt.Sprintf("value doesn't match pattern %v", v.Rule)) 213 } 214 case MaxLength: 215 if _, ok := v.Rule.(int); !ok { 216 return createError(x, v, fmt.Sprintf("rule must be integer value for %v constraint; got: %v", v.Name, v.Rule)) 217 } 218 if len(s) > v.Rule.(int) { 219 return createError(x, v, fmt.Sprintf("value length must be less than or equal to %v", v.Rule)) 220 } 221 case MinLength: 222 if _, ok := v.Rule.(int); !ok { 223 return createError(x, v, fmt.Sprintf("rule must be integer value for %v constraint; got: %v", v.Name, v.Rule)) 224 } 225 if len(s) < v.Rule.(int) { 226 return createError(x, v, fmt.Sprintf("value length must be greater than or equal to %v", v.Rule)) 227 } 228 case ReadOnly: 229 if len(s) > 0 { 230 return createError(reflect.ValueOf(s), v, "readonly parameter; must send as nil or empty in request") 231 } 232 default: 233 return createError(x, v, fmt.Sprintf("constraint %s is not applicable to string type", v.Name)) 234 } 235 236 if v.Chain != nil { 237 return Validate([]Validation{ 238 { 239 TargetValue: getInterfaceValue(x), 240 Constraints: v.Chain, 241 }, 242 }) 243 } 244 return nil 245} 246 247func validateArrayMap(x reflect.Value, v Constraint) error { 248 switch v.Name { 249 case Null: 250 if x.IsNil() { 251 return checkNil(x, v) 252 } 253 case Empty: 254 if x.IsNil() || x.Len() == 0 { 255 return checkEmpty(x, v) 256 } 257 case MaxItems: 258 if _, ok := v.Rule.(int); !ok { 259 return createError(x, v, fmt.Sprintf("rule must be integer for %v constraint; got: %v", v.Name, v.Rule)) 260 } 261 if x.Len() > v.Rule.(int) { 262 return createError(x, v, fmt.Sprintf("maximum item limit is %v; got: %v", v.Rule, x.Len())) 263 } 264 case MinItems: 265 if _, ok := v.Rule.(int); !ok { 266 return createError(x, v, fmt.Sprintf("rule must be integer for %v constraint; got: %v", v.Name, v.Rule)) 267 } 268 if x.Len() < v.Rule.(int) { 269 return createError(x, v, fmt.Sprintf("minimum item limit is %v; got: %v", v.Rule, x.Len())) 270 } 271 case UniqueItems: 272 if x.Kind() == reflect.Array || x.Kind() == reflect.Slice { 273 if !checkForUniqueInArray(x) { 274 return createError(x, v, fmt.Sprintf("all items in parameter %q must be unique; got:%v", v.Target, x)) 275 } 276 } else if x.Kind() == reflect.Map { 277 if !checkForUniqueInMap(x) { 278 return createError(x, v, fmt.Sprintf("all items in parameter %q must be unique; got:%v", v.Target, x)) 279 } 280 } else { 281 return createError(x, v, fmt.Sprintf("type must be array, slice or map for constraint %v; got: %v", v.Name, x.Kind())) 282 } 283 case ReadOnly: 284 if x.Len() != 0 { 285 return createError(x, v, "readonly parameter; must send as nil or empty in request") 286 } 287 case Pattern: 288 reg, err := regexp.Compile(v.Rule.(string)) 289 if err != nil { 290 return createError(x, v, err.Error()) 291 } 292 keys := x.MapKeys() 293 for _, k := range keys { 294 if !reg.MatchString(k.String()) { 295 return createError(k, v, fmt.Sprintf("map key doesn't match pattern %v", v.Rule)) 296 } 297 } 298 default: 299 return createError(x, v, fmt.Sprintf("constraint %v is not applicable to array, slice and map type", v.Name)) 300 } 301 302 if v.Chain != nil { 303 return Validate([]Validation{ 304 { 305 TargetValue: getInterfaceValue(x), 306 Constraints: v.Chain, 307 }, 308 }) 309 } 310 return nil 311} 312 313func checkNil(x reflect.Value, v Constraint) error { 314 if _, ok := v.Rule.(bool); !ok { 315 return createError(x, v, fmt.Sprintf("rule must be bool value for %v constraint; got: %v", v.Name, v.Rule)) 316 } 317 if v.Rule.(bool) { 318 return createError(x, v, "value can not be null; required parameter") 319 } 320 return nil 321} 322 323func checkEmpty(x reflect.Value, v Constraint) error { 324 if _, ok := v.Rule.(bool); !ok { 325 return createError(x, v, fmt.Sprintf("rule must be bool value for %v constraint; got: %v", v.Name, v.Rule)) 326 } 327 328 if v.Rule.(bool) { 329 return createError(x, v, "value can not be null or empty; required parameter") 330 } 331 return nil 332} 333 334func checkForUniqueInArray(x reflect.Value) bool { 335 if x == reflect.Zero(reflect.TypeOf(x)) || x.Len() == 0 { 336 return false 337 } 338 arrOfInterface := make([]interface{}, x.Len()) 339 340 for i := 0; i < x.Len(); i++ { 341 arrOfInterface[i] = x.Index(i).Interface() 342 } 343 344 m := make(map[interface{}]bool) 345 for _, val := range arrOfInterface { 346 if m[val] { 347 return false 348 } 349 m[val] = true 350 } 351 return true 352} 353 354func checkForUniqueInMap(x reflect.Value) bool { 355 if x == reflect.Zero(reflect.TypeOf(x)) || x.Len() == 0 { 356 return false 357 } 358 mapOfInterface := make(map[interface{}]interface{}, x.Len()) 359 360 keys := x.MapKeys() 361 for _, k := range keys { 362 mapOfInterface[k.Interface()] = x.MapIndex(k).Interface() 363 } 364 365 m := make(map[interface{}]bool) 366 for _, val := range mapOfInterface { 367 if m[val] { 368 return false 369 } 370 m[val] = true 371 } 372 return true 373} 374 375func getInterfaceValue(x reflect.Value) interface{} { 376 if x.Kind() == reflect.Invalid { 377 return nil 378 } 379 return x.Interface() 380} 381 382func isZero(x interface{}) bool { 383 return x == reflect.Zero(reflect.TypeOf(x)).Interface() 384} 385 386func createError(x reflect.Value, v Constraint, err string) error { 387 return fmt.Errorf("autorest/validation: validation failed: parameter=%s constraint=%s value=%#v details: %s", 388 v.Target, v.Name, getInterfaceValue(x), err) 389} 390 391func toInt64(v interface{}) (int64, bool) { 392 if i64, ok := v.(int64); ok { 393 return i64, true 394 } 395 // older generators emit max constants as int, so if int64 fails fall back to int 396 if i32, ok := v.(int); ok { 397 return int64(i32), true 398 } 399 return 0, false 400} 401