OSDN Git Service

new repo
[bytom/vapor.git] / vendor / gopkg.in / go-playground / validator.v9 / baked_in.go
1 package validator
2
3 import (
4         "context"
5         "fmt"
6         "net"
7         "net/url"
8         "reflect"
9         "strings"
10         "time"
11         "unicode/utf8"
12 )
13
14 // Func accepts a FieldLevel interface for all validation needs. The return
15 // value should be true when validation succeeds.
16 type Func func(fl FieldLevel) bool
17
18 // FuncCtx accepts a context.Context and FieldLevel interface for all
19 // validation needs. The return value should be true when validation succeeds.
20 type FuncCtx func(ctx context.Context, fl FieldLevel) bool
21
22 // wrapFunc wraps noramal Func makes it compatible with FuncCtx
23 func wrapFunc(fn Func) FuncCtx {
24         if fn == nil {
25                 return nil // be sure not to wrap a bad function.
26         }
27         return func(ctx context.Context, fl FieldLevel) bool {
28                 return fn(fl)
29         }
30 }
31
32 var (
33         restrictedTags = map[string]struct{}{
34                 diveTag:           {},
35                 structOnlyTag:     {},
36                 omitempty:         {},
37                 skipValidationTag: {},
38                 utf8HexComma:      {},
39                 utf8Pipe:          {},
40                 noStructLevelTag:  {},
41                 requiredTag:       {},
42                 isdefault:         {},
43         }
44
45         // BakedInAliasValidators is a default mapping of a single validation tag that
46         // defines a common or complex set of validation(s) to simplify
47         // adding validation to structs.
48         bakedInAliases = map[string]string{
49                 "iscolor": "hexcolor|rgb|rgba|hsl|hsla",
50         }
51
52         // BakedInValidators is the default map of ValidationFunc
53         // you can add, remove or even replace items to suite your needs,
54         // or even disregard and use your own map if so desired.
55         bakedInValidators = map[string]Func{
56                 "required":        hasValue,
57                 "isdefault":       isDefault,
58                 "len":             hasLengthOf,
59                 "min":             hasMinOf,
60                 "max":             hasMaxOf,
61                 "eq":              isEq,
62                 "ne":              isNe,
63                 "lt":              isLt,
64                 "lte":             isLte,
65                 "gt":              isGt,
66                 "gte":             isGte,
67                 "eqfield":         isEqField,
68                 "eqcsfield":       isEqCrossStructField,
69                 "necsfield":       isNeCrossStructField,
70                 "gtcsfield":       isGtCrossStructField,
71                 "gtecsfield":      isGteCrossStructField,
72                 "ltcsfield":       isLtCrossStructField,
73                 "ltecsfield":      isLteCrossStructField,
74                 "nefield":         isNeField,
75                 "gtefield":        isGteField,
76                 "gtfield":         isGtField,
77                 "ltefield":        isLteField,
78                 "ltfield":         isLtField,
79                 "alpha":           isAlpha,
80                 "alphanum":        isAlphanum,
81                 "alphaunicode":    isAlphaUnicode,
82                 "alphanumunicode": isAlphanumUnicode,
83                 "numeric":         isNumeric,
84                 "number":          isNumber,
85                 "hexadecimal":     isHexadecimal,
86                 "hexcolor":        isHEXColor,
87                 "rgb":             isRGB,
88                 "rgba":            isRGBA,
89                 "hsl":             isHSL,
90                 "hsla":            isHSLA,
91                 "email":           isEmail,
92                 "url":             isURL,
93                 "uri":             isURI,
94                 "base64":          isBase64,
95                 "contains":        contains,
96                 "containsany":     containsAny,
97                 "containsrune":    containsRune,
98                 "excludes":        excludes,
99                 "excludesall":     excludesAll,
100                 "excludesrune":    excludesRune,
101                 "isbn":            isISBN,
102                 "isbn10":          isISBN10,
103                 "isbn13":          isISBN13,
104                 "uuid":            isUUID,
105                 "uuid3":           isUUID3,
106                 "uuid4":           isUUID4,
107                 "uuid5":           isUUID5,
108                 "ascii":           isASCII,
109                 "printascii":      isPrintableASCII,
110                 "multibyte":       hasMultiByteCharacter,
111                 "datauri":         isDataURI,
112                 "latitude":        isLatitude,
113                 "longitude":       isLongitude,
114                 "ssn":             isSSN,
115                 "ipv4":            isIPv4,
116                 "ipv6":            isIPv6,
117                 "ip":              isIP,
118                 "cidrv4":          isCIDRv4,
119                 "cidrv6":          isCIDRv6,
120                 "cidr":            isCIDR,
121                 "tcp4_addr":       isTCP4AddrResolvable,
122                 "tcp6_addr":       isTCP6AddrResolvable,
123                 "tcp_addr":        isTCPAddrResolvable,
124                 "udp4_addr":       isUDP4AddrResolvable,
125                 "udp6_addr":       isUDP6AddrResolvable,
126                 "udp_addr":        isUDPAddrResolvable,
127                 "ip4_addr":        isIP4AddrResolvable,
128                 "ip6_addr":        isIP6AddrResolvable,
129                 "ip_addr":         isIPAddrResolvable,
130                 "unix_addr":       isUnixAddrResolvable,
131                 "mac":             isMAC,
132                 "hostname":        isHostname,
133                 "fqdn":            isFQDN,
134                 "unique":          isUnique,
135         }
136 )
137
138 // isUnique is the validation function for validating if each array|slice element is unique
139 func isUnique(fl FieldLevel) bool {
140
141         field := fl.Field()
142         v := reflect.ValueOf(struct{}{})
143
144         switch field.Kind() {
145         case reflect.Slice, reflect.Array:
146                 m := reflect.MakeMap(reflect.MapOf(fl.Field().Type().Elem(), v.Type()))
147
148                 for i := 0; i < field.Len(); i++ {
149                         m.SetMapIndex(field.Index(i), v)
150                 }
151                 return field.Len() == m.Len()
152         default:
153                 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
154         }
155 }
156
157 // IsMAC is the validation function for validating if the field's value is a valid MAC address.
158 func isMAC(fl FieldLevel) bool {
159
160         _, err := net.ParseMAC(fl.Field().String())
161
162         return err == nil
163 }
164
165 // IsCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address.
166 func isCIDRv4(fl FieldLevel) bool {
167
168         ip, _, err := net.ParseCIDR(fl.Field().String())
169
170         return err == nil && ip.To4() != nil
171 }
172
173 // IsCIDRv6 is the validation function for validating if the field's value is a valid v6 CIDR address.
174 func isCIDRv6(fl FieldLevel) bool {
175
176         ip, _, err := net.ParseCIDR(fl.Field().String())
177
178         return err == nil && ip.To4() == nil
179 }
180
181 // IsCIDR is the validation function for validating if the field's value is a valid v4 or v6 CIDR address.
182 func isCIDR(fl FieldLevel) bool {
183
184         _, _, err := net.ParseCIDR(fl.Field().String())
185
186         return err == nil
187 }
188
189 // IsIPv4 is the validation function for validating if a value is a valid v4 IP address.
190 func isIPv4(fl FieldLevel) bool {
191
192         ip := net.ParseIP(fl.Field().String())
193
194         return ip != nil && ip.To4() != nil
195 }
196
197 // IsIPv6 is the validation function for validating if the field's value is a valid v6 IP address.
198 func isIPv6(fl FieldLevel) bool {
199
200         ip := net.ParseIP(fl.Field().String())
201
202         return ip != nil && ip.To4() == nil
203 }
204
205 // IsIP is the validation function for validating if the field's value is a valid v4 or v6 IP address.
206 func isIP(fl FieldLevel) bool {
207
208         ip := net.ParseIP(fl.Field().String())
209
210         return ip != nil
211 }
212
213 // IsSSN is the validation function for validating if the field's value is a valid SSN.
214 func isSSN(fl FieldLevel) bool {
215
216         field := fl.Field()
217
218         if field.Len() != 11 {
219                 return false
220         }
221
222         return sSNRegex.MatchString(field.String())
223 }
224
225 // IsLongitude is the validation function for validating if the field's value is a valid longitude coordinate.
226 func isLongitude(fl FieldLevel) bool {
227         return longitudeRegex.MatchString(fl.Field().String())
228 }
229
230 // IsLatitude is the validation function for validating if the field's value is a valid latitude coordinate.
231 func isLatitude(fl FieldLevel) bool {
232         return latitudeRegex.MatchString(fl.Field().String())
233 }
234
235 // IsDataURI is the validation function for validating if the field's value is a valid data URI.
236 func isDataURI(fl FieldLevel) bool {
237
238         uri := strings.SplitN(fl.Field().String(), ",", 2)
239
240         if len(uri) != 2 {
241                 return false
242         }
243
244         if !dataURIRegex.MatchString(uri[0]) {
245                 return false
246         }
247
248         return base64Regex.MatchString(uri[1])
249 }
250
251 // HasMultiByteCharacter is the validation function for validating if the field's value has a multi byte character.
252 func hasMultiByteCharacter(fl FieldLevel) bool {
253
254         field := fl.Field()
255
256         if field.Len() == 0 {
257                 return true
258         }
259
260         return multibyteRegex.MatchString(field.String())
261 }
262
263 // IsPrintableASCII is the validation function for validating if the field's value is a valid printable ASCII character.
264 func isPrintableASCII(fl FieldLevel) bool {
265         return printableASCIIRegex.MatchString(fl.Field().String())
266 }
267
268 // IsASCII is the validation function for validating if the field's value is a valid ASCII character.
269 func isASCII(fl FieldLevel) bool {
270         return aSCIIRegex.MatchString(fl.Field().String())
271 }
272
273 // IsUUID5 is the validation function for validating if the field's value is a valid v5 UUID.
274 func isUUID5(fl FieldLevel) bool {
275         return uUID5Regex.MatchString(fl.Field().String())
276 }
277
278 // IsUUID4 is the validation function for validating if the field's value is a valid v4 UUID.
279 func isUUID4(fl FieldLevel) bool {
280         return uUID4Regex.MatchString(fl.Field().String())
281 }
282
283 // IsUUID3 is the validation function for validating if the field's value is a valid v3 UUID.
284 func isUUID3(fl FieldLevel) bool {
285         return uUID3Regex.MatchString(fl.Field().String())
286 }
287
288 // IsUUID is the validation function for validating if the field's value is a valid UUID of any version.
289 func isUUID(fl FieldLevel) bool {
290         return uUIDRegex.MatchString(fl.Field().String())
291 }
292
293 // IsISBN is the validation function for validating if the field's value is a valid v10 or v13 ISBN.
294 func isISBN(fl FieldLevel) bool {
295         return isISBN10(fl) || isISBN13(fl)
296 }
297
298 // IsISBN13 is the validation function for validating if the field's value is a valid v13 ISBN.
299 func isISBN13(fl FieldLevel) bool {
300
301         s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 4), " ", "", 4)
302
303         if !iSBN13Regex.MatchString(s) {
304                 return false
305         }
306
307         var checksum int32
308         var i int32
309
310         factor := []int32{1, 3}
311
312         for i = 0; i < 12; i++ {
313                 checksum += factor[i%2] * int32(s[i]-'0')
314         }
315
316         return (int32(s[12]-'0'))-((10-(checksum%10))%10) == 0
317 }
318
319 // IsISBN10 is the validation function for validating if the field's value is a valid v10 ISBN.
320 func isISBN10(fl FieldLevel) bool {
321
322         s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 3), " ", "", 3)
323
324         if !iSBN10Regex.MatchString(s) {
325                 return false
326         }
327
328         var checksum int32
329         var i int32
330
331         for i = 0; i < 9; i++ {
332                 checksum += (i + 1) * int32(s[i]-'0')
333         }
334
335         if s[9] == 'X' {
336                 checksum += 10 * 10
337         } else {
338                 checksum += 10 * int32(s[9]-'0')
339         }
340
341         return checksum%11 == 0
342 }
343
344 // ExcludesRune is the validation function for validating that the field's value does not contain the rune specified within the param.
345 func excludesRune(fl FieldLevel) bool {
346         return !containsRune(fl)
347 }
348
349 // ExcludesAll is the validation function for validating that the field's value does not contain any of the characters specified within the param.
350 func excludesAll(fl FieldLevel) bool {
351         return !containsAny(fl)
352 }
353
354 // Excludes is the validation function for validating that the field's value does not contain the text specified within the param.
355 func excludes(fl FieldLevel) bool {
356         return !contains(fl)
357 }
358
359 // ContainsRune is the validation function for validating that the field's value contains the rune specified within the param.
360 func containsRune(fl FieldLevel) bool {
361
362         r, _ := utf8.DecodeRuneInString(fl.Param())
363
364         return strings.ContainsRune(fl.Field().String(), r)
365 }
366
367 // ContainsAny is the validation function for validating that the field's value contains any of the characters specified within the param.
368 func containsAny(fl FieldLevel) bool {
369         return strings.ContainsAny(fl.Field().String(), fl.Param())
370 }
371
372 // Contains is the validation function for validating that the field's value contains the text specified within the param.
373 func contains(fl FieldLevel) bool {
374         return strings.Contains(fl.Field().String(), fl.Param())
375 }
376
377 // IsNeField is the validation function for validating if the current field's value is not equal to the field specified by the param's value.
378 func isNeField(fl FieldLevel) bool {
379
380         field := fl.Field()
381         kind := field.Kind()
382
383         currentField, currentKind, ok := fl.GetStructFieldOK()
384
385         if !ok || currentKind != kind {
386                 return true
387         }
388
389         switch kind {
390
391         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
392                 return field.Int() != currentField.Int()
393
394         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
395                 return field.Uint() != currentField.Uint()
396
397         case reflect.Float32, reflect.Float64:
398                 return field.Float() != currentField.Float()
399
400         case reflect.Slice, reflect.Map, reflect.Array:
401                 return int64(field.Len()) != int64(currentField.Len())
402
403         case reflect.Struct:
404
405                 fieldType := field.Type()
406
407                 // Not Same underlying type i.e. struct and time
408                 if fieldType != currentField.Type() {
409                         return true
410                 }
411
412                 if fieldType == timeType {
413
414                         t := currentField.Interface().(time.Time)
415                         fieldTime := field.Interface().(time.Time)
416
417                         return !fieldTime.Equal(t)
418                 }
419
420         }
421
422         // default reflect.String:
423         return field.String() != currentField.String()
424 }
425
426 // IsNe is the validation function for validating that the field's value does not equal the provided param value.
427 func isNe(fl FieldLevel) bool {
428         return !isEq(fl)
429 }
430
431 // IsLteCrossStructField is the validation function for validating if the current field's value is less than or equal to the field, within a separate struct, specified by the param's value.
432 func isLteCrossStructField(fl FieldLevel) bool {
433
434         field := fl.Field()
435         kind := field.Kind()
436
437         topField, topKind, ok := fl.GetStructFieldOK()
438         if !ok || topKind != kind {
439                 return false
440         }
441
442         switch kind {
443
444         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
445                 return field.Int() <= topField.Int()
446
447         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
448                 return field.Uint() <= topField.Uint()
449
450         case reflect.Float32, reflect.Float64:
451                 return field.Float() <= topField.Float()
452
453         case reflect.Slice, reflect.Map, reflect.Array:
454                 return int64(field.Len()) <= int64(topField.Len())
455
456         case reflect.Struct:
457
458                 fieldType := field.Type()
459
460                 // Not Same underlying type i.e. struct and time
461                 if fieldType != topField.Type() {
462                         return false
463                 }
464
465                 if fieldType == timeType {
466
467                         fieldTime := field.Interface().(time.Time)
468                         topTime := topField.Interface().(time.Time)
469
470                         return fieldTime.Before(topTime) || fieldTime.Equal(topTime)
471                 }
472         }
473
474         // default reflect.String:
475         return field.String() <= topField.String()
476 }
477
478 // IsLtCrossStructField is the validation function for validating if the current field's value is less than the field, within a separate struct, specified by the param's value.
479 // NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
480 func isLtCrossStructField(fl FieldLevel) bool {
481
482         field := fl.Field()
483         kind := field.Kind()
484
485         topField, topKind, ok := fl.GetStructFieldOK()
486         if !ok || topKind != kind {
487                 return false
488         }
489
490         switch kind {
491
492         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
493                 return field.Int() < topField.Int()
494
495         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
496                 return field.Uint() < topField.Uint()
497
498         case reflect.Float32, reflect.Float64:
499                 return field.Float() < topField.Float()
500
501         case reflect.Slice, reflect.Map, reflect.Array:
502                 return int64(field.Len()) < int64(topField.Len())
503
504         case reflect.Struct:
505
506                 fieldType := field.Type()
507
508                 // Not Same underlying type i.e. struct and time
509                 if fieldType != topField.Type() {
510                         return false
511                 }
512
513                 if fieldType == timeType {
514
515                         fieldTime := field.Interface().(time.Time)
516                         topTime := topField.Interface().(time.Time)
517
518                         return fieldTime.Before(topTime)
519                 }
520         }
521
522         // default reflect.String:
523         return field.String() < topField.String()
524 }
525
526 // IsGteCrossStructField is the validation function for validating if the current field's value is greater than or equal to the field, within a separate struct, specified by the param's value.
527 func isGteCrossStructField(fl FieldLevel) bool {
528
529         field := fl.Field()
530         kind := field.Kind()
531
532         topField, topKind, ok := fl.GetStructFieldOK()
533         if !ok || topKind != kind {
534                 return false
535         }
536
537         switch kind {
538
539         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
540                 return field.Int() >= topField.Int()
541
542         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
543                 return field.Uint() >= topField.Uint()
544
545         case reflect.Float32, reflect.Float64:
546                 return field.Float() >= topField.Float()
547
548         case reflect.Slice, reflect.Map, reflect.Array:
549                 return int64(field.Len()) >= int64(topField.Len())
550
551         case reflect.Struct:
552
553                 fieldType := field.Type()
554
555                 // Not Same underlying type i.e. struct and time
556                 if fieldType != topField.Type() {
557                         return false
558                 }
559
560                 if fieldType == timeType {
561
562                         fieldTime := field.Interface().(time.Time)
563                         topTime := topField.Interface().(time.Time)
564
565                         return fieldTime.After(topTime) || fieldTime.Equal(topTime)
566                 }
567         }
568
569         // default reflect.String:
570         return field.String() >= topField.String()
571 }
572
573 // IsGtCrossStructField is the validation function for validating if the current field's value is greater than the field, within a separate struct, specified by the param's value.
574 func isGtCrossStructField(fl FieldLevel) bool {
575
576         field := fl.Field()
577         kind := field.Kind()
578
579         topField, topKind, ok := fl.GetStructFieldOK()
580         if !ok || topKind != kind {
581                 return false
582         }
583
584         switch kind {
585
586         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
587                 return field.Int() > topField.Int()
588
589         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
590                 return field.Uint() > topField.Uint()
591
592         case reflect.Float32, reflect.Float64:
593                 return field.Float() > topField.Float()
594
595         case reflect.Slice, reflect.Map, reflect.Array:
596                 return int64(field.Len()) > int64(topField.Len())
597
598         case reflect.Struct:
599
600                 fieldType := field.Type()
601
602                 // Not Same underlying type i.e. struct and time
603                 if fieldType != topField.Type() {
604                         return false
605                 }
606
607                 if fieldType == timeType {
608
609                         fieldTime := field.Interface().(time.Time)
610                         topTime := topField.Interface().(time.Time)
611
612                         return fieldTime.After(topTime)
613                 }
614         }
615
616         // default reflect.String:
617         return field.String() > topField.String()
618 }
619
620 // IsNeCrossStructField is the validation function for validating that the current field's value is not equal to the field, within a separate struct, specified by the param's value.
621 func isNeCrossStructField(fl FieldLevel) bool {
622
623         field := fl.Field()
624         kind := field.Kind()
625
626         topField, currentKind, ok := fl.GetStructFieldOK()
627         if !ok || currentKind != kind {
628                 return true
629         }
630
631         switch kind {
632
633         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
634                 return topField.Int() != field.Int()
635
636         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
637                 return topField.Uint() != field.Uint()
638
639         case reflect.Float32, reflect.Float64:
640                 return topField.Float() != field.Float()
641
642         case reflect.Slice, reflect.Map, reflect.Array:
643                 return int64(topField.Len()) != int64(field.Len())
644
645         case reflect.Struct:
646
647                 fieldType := field.Type()
648
649                 // Not Same underlying type i.e. struct and time
650                 if fieldType != topField.Type() {
651                         return true
652                 }
653
654                 if fieldType == timeType {
655
656                         t := field.Interface().(time.Time)
657                         fieldTime := topField.Interface().(time.Time)
658
659                         return !fieldTime.Equal(t)
660                 }
661         }
662
663         // default reflect.String:
664         return topField.String() != field.String()
665 }
666
667 // IsEqCrossStructField is the validation function for validating that the current field's value is equal to the field, within a separate struct, specified by the param's value.
668 func isEqCrossStructField(fl FieldLevel) bool {
669
670         field := fl.Field()
671         kind := field.Kind()
672
673         topField, topKind, ok := fl.GetStructFieldOK()
674         if !ok || topKind != kind {
675                 return false
676         }
677
678         switch kind {
679
680         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
681                 return topField.Int() == field.Int()
682
683         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
684                 return topField.Uint() == field.Uint()
685
686         case reflect.Float32, reflect.Float64:
687                 return topField.Float() == field.Float()
688
689         case reflect.Slice, reflect.Map, reflect.Array:
690                 return int64(topField.Len()) == int64(field.Len())
691
692         case reflect.Struct:
693
694                 fieldType := field.Type()
695
696                 // Not Same underlying type i.e. struct and time
697                 if fieldType != topField.Type() {
698                         return false
699                 }
700
701                 if fieldType == timeType {
702
703                         t := field.Interface().(time.Time)
704                         fieldTime := topField.Interface().(time.Time)
705
706                         return fieldTime.Equal(t)
707                 }
708         }
709
710         // default reflect.String:
711         return topField.String() == field.String()
712 }
713
714 // IsEqField is the validation function for validating if the current field's value is equal to the field specified by the param's value.
715 func isEqField(fl FieldLevel) bool {
716
717         field := fl.Field()
718         kind := field.Kind()
719
720         currentField, currentKind, ok := fl.GetStructFieldOK()
721         if !ok || currentKind != kind {
722                 return false
723         }
724
725         switch kind {
726
727         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
728                 return field.Int() == currentField.Int()
729
730         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
731                 return field.Uint() == currentField.Uint()
732
733         case reflect.Float32, reflect.Float64:
734                 return field.Float() == currentField.Float()
735
736         case reflect.Slice, reflect.Map, reflect.Array:
737                 return int64(field.Len()) == int64(currentField.Len())
738
739         case reflect.Struct:
740
741                 fieldType := field.Type()
742
743                 // Not Same underlying type i.e. struct and time
744                 if fieldType != currentField.Type() {
745                         return false
746                 }
747
748                 if fieldType == timeType {
749
750                         t := currentField.Interface().(time.Time)
751                         fieldTime := field.Interface().(time.Time)
752
753                         return fieldTime.Equal(t)
754                 }
755
756         }
757
758         // default reflect.String:
759         return field.String() == currentField.String()
760 }
761
762 // IsEq is the validation function for validating if the current field's value is equal to the param's value.
763 func isEq(fl FieldLevel) bool {
764
765         field := fl.Field()
766         param := fl.Param()
767
768         switch field.Kind() {
769
770         case reflect.String:
771                 return field.String() == param
772
773         case reflect.Slice, reflect.Map, reflect.Array:
774                 p := asInt(param)
775
776                 return int64(field.Len()) == p
777
778         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
779                 p := asInt(param)
780
781                 return field.Int() == p
782
783         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
784                 p := asUint(param)
785
786                 return field.Uint() == p
787
788         case reflect.Float32, reflect.Float64:
789                 p := asFloat(param)
790
791                 return field.Float() == p
792         }
793
794         panic(fmt.Sprintf("Bad field type %T", field.Interface()))
795 }
796
797 // IsBase64 is the validation function for validating if the current field's value is a valid base 64.
798 func isBase64(fl FieldLevel) bool {
799         return base64Regex.MatchString(fl.Field().String())
800 }
801
802 // IsURI is the validation function for validating if the current field's value is a valid URI.
803 func isURI(fl FieldLevel) bool {
804
805         field := fl.Field()
806
807         switch field.Kind() {
808
809         case reflect.String:
810
811                 s := field.String()
812
813                 // checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195
814                 // emulate browser and strip the '#' suffix prior to validation. see issue-#237
815                 if i := strings.Index(s, "#"); i > -1 {
816                         s = s[:i]
817                 }
818
819                 if len(s) == 0 {
820                         return false
821                 }
822
823                 _, err := url.ParseRequestURI(s)
824
825                 return err == nil
826         }
827
828         panic(fmt.Sprintf("Bad field type %T", field.Interface()))
829 }
830
831 // IsURL is the validation function for validating if the current field's value is a valid URL.
832 func isURL(fl FieldLevel) bool {
833
834         field := fl.Field()
835
836         switch field.Kind() {
837
838         case reflect.String:
839
840                 var i int
841                 s := field.String()
842
843                 // checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195
844                 // emulate browser and strip the '#' suffix prior to validation. see issue-#237
845                 if i = strings.Index(s, "#"); i > -1 {
846                         s = s[:i]
847                 }
848
849                 if len(s) == 0 {
850                         return false
851                 }
852
853                 url, err := url.ParseRequestURI(s)
854
855                 if err != nil || url.Scheme == "" {
856                         return false
857                 }
858
859                 return err == nil
860         }
861
862         panic(fmt.Sprintf("Bad field type %T", field.Interface()))
863 }
864
865 // IsEmail is the validation function for validating if the current field's value is a valid email address.
866 func isEmail(fl FieldLevel) bool {
867         return emailRegex.MatchString(fl.Field().String())
868 }
869
870 // IsHSLA is the validation function for validating if the current field's value is a valid HSLA color.
871 func isHSLA(fl FieldLevel) bool {
872         return hslaRegex.MatchString(fl.Field().String())
873 }
874
875 // IsHSL is the validation function for validating if the current field's value is a valid HSL color.
876 func isHSL(fl FieldLevel) bool {
877         return hslRegex.MatchString(fl.Field().String())
878 }
879
880 // IsRGBA is the validation function for validating if the current field's value is a valid RGBA color.
881 func isRGBA(fl FieldLevel) bool {
882         return rgbaRegex.MatchString(fl.Field().String())
883 }
884
885 // IsRGB is the validation function for validating if the current field's value is a valid RGB color.
886 func isRGB(fl FieldLevel) bool {
887         return rgbRegex.MatchString(fl.Field().String())
888 }
889
890 // IsHEXColor is the validation function for validating if the current field's value is a valid HEX color.
891 func isHEXColor(fl FieldLevel) bool {
892         return hexcolorRegex.MatchString(fl.Field().String())
893 }
894
895 // IsHexadecimal is the validation function for validating if the current field's value is a valid hexadecimal.
896 func isHexadecimal(fl FieldLevel) bool {
897         return hexadecimalRegex.MatchString(fl.Field().String())
898 }
899
900 // IsNumber is the validation function for validating if the current field's value is a valid number.
901 func isNumber(fl FieldLevel) bool {
902         return numberRegex.MatchString(fl.Field().String())
903 }
904
905 // IsNumeric is the validation function for validating if the current field's value is a valid numeric value.
906 func isNumeric(fl FieldLevel) bool {
907         return numericRegex.MatchString(fl.Field().String())
908 }
909
910 // IsAlphanum is the validation function for validating if the current field's value is a valid alphanumeric value.
911 func isAlphanum(fl FieldLevel) bool {
912         return alphaNumericRegex.MatchString(fl.Field().String())
913 }
914
915 // IsAlpha is the validation function for validating if the current field's value is a valid alpha value.
916 func isAlpha(fl FieldLevel) bool {
917         return alphaRegex.MatchString(fl.Field().String())
918 }
919
920 // IsAlphanumUnicode is the validation function for validating if the current field's value is a valid alphanumeric unicode value.
921 func isAlphanumUnicode(fl FieldLevel) bool {
922         return alphaUnicodeNumericRegex.MatchString(fl.Field().String())
923 }
924
925 // IsAlphaUnicode is the validation function for validating if the current field's value is a valid alpha unicode value.
926 func isAlphaUnicode(fl FieldLevel) bool {
927         return alphaUnicodeRegex.MatchString(fl.Field().String())
928 }
929
930 // isDefault is the opposite of required aka hasValue
931 func isDefault(fl FieldLevel) bool {
932         return !hasValue(fl)
933 }
934
935 // HasValue is the validation function for validating if the current field's value is not the default static value.
936 func hasValue(fl FieldLevel) bool {
937
938         field := fl.Field()
939
940         switch field.Kind() {
941         case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
942                 return !field.IsNil()
943         default:
944
945                 if fl.(*validate).fldIsPointer && field.Interface() != nil {
946                         return true
947                 }
948
949                 return field.IsValid() && field.Interface() != reflect.Zero(field.Type()).Interface()
950         }
951 }
952
953 // IsGteField is the validation function for validating if the current field's value is greater than or equal to the field specified by the param's value.
954 func isGteField(fl FieldLevel) bool {
955
956         field := fl.Field()
957         kind := field.Kind()
958
959         currentField, currentKind, ok := fl.GetStructFieldOK()
960         if !ok || currentKind != kind {
961                 return false
962         }
963
964         switch kind {
965
966         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
967
968                 return field.Int() >= currentField.Int()
969
970         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
971
972                 return field.Uint() >= currentField.Uint()
973
974         case reflect.Float32, reflect.Float64:
975
976                 return field.Float() >= currentField.Float()
977
978         case reflect.Struct:
979
980                 fieldType := field.Type()
981
982                 // Not Same underlying type i.e. struct and time
983                 if fieldType != currentField.Type() {
984                         return false
985                 }
986
987                 if fieldType == timeType {
988
989                         t := currentField.Interface().(time.Time)
990                         fieldTime := field.Interface().(time.Time)
991
992                         return fieldTime.After(t) || fieldTime.Equal(t)
993                 }
994         }
995
996         // default reflect.String
997         return len(field.String()) >= len(currentField.String())
998 }
999
1000 // IsGtField is the validation function for validating if the current field's value is greater than the field specified by the param's value.
1001 func isGtField(fl FieldLevel) bool {
1002
1003         field := fl.Field()
1004         kind := field.Kind()
1005
1006         currentField, currentKind, ok := fl.GetStructFieldOK()
1007         if !ok || currentKind != kind {
1008                 return false
1009         }
1010
1011         switch kind {
1012
1013         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1014
1015                 return field.Int() > currentField.Int()
1016
1017         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1018
1019                 return field.Uint() > currentField.Uint()
1020
1021         case reflect.Float32, reflect.Float64:
1022
1023                 return field.Float() > currentField.Float()
1024
1025         case reflect.Struct:
1026
1027                 fieldType := field.Type()
1028
1029                 // Not Same underlying type i.e. struct and time
1030                 if fieldType != currentField.Type() {
1031                         return false
1032                 }
1033
1034                 if fieldType == timeType {
1035
1036                         t := currentField.Interface().(time.Time)
1037                         fieldTime := field.Interface().(time.Time)
1038
1039                         return fieldTime.After(t)
1040                 }
1041         }
1042
1043         // default reflect.String
1044         return len(field.String()) > len(currentField.String())
1045 }
1046
1047 // IsGte is the validation function for validating if the current field's value is greater than or equal to the param's value.
1048 func isGte(fl FieldLevel) bool {
1049
1050         field := fl.Field()
1051         param := fl.Param()
1052
1053         switch field.Kind() {
1054
1055         case reflect.String:
1056                 p := asInt(param)
1057
1058                 return int64(utf8.RuneCountInString(field.String())) >= p
1059
1060         case reflect.Slice, reflect.Map, reflect.Array:
1061                 p := asInt(param)
1062
1063                 return int64(field.Len()) >= p
1064
1065         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1066                 p := asInt(param)
1067
1068                 return field.Int() >= p
1069
1070         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1071                 p := asUint(param)
1072
1073                 return field.Uint() >= p
1074
1075         case reflect.Float32, reflect.Float64:
1076                 p := asFloat(param)
1077
1078                 return field.Float() >= p
1079
1080         case reflect.Struct:
1081
1082                 if field.Type() == timeType {
1083
1084                         now := time.Now().UTC()
1085                         t := field.Interface().(time.Time)
1086
1087                         return t.After(now) || t.Equal(now)
1088                 }
1089         }
1090
1091         panic(fmt.Sprintf("Bad field type %T", field.Interface()))
1092 }
1093
1094 // IsGt is the validation function for validating if the current field's value is greater than the param's value.
1095 func isGt(fl FieldLevel) bool {
1096
1097         field := fl.Field()
1098         param := fl.Param()
1099
1100         switch field.Kind() {
1101
1102         case reflect.String:
1103                 p := asInt(param)
1104
1105                 return int64(utf8.RuneCountInString(field.String())) > p
1106
1107         case reflect.Slice, reflect.Map, reflect.Array:
1108                 p := asInt(param)
1109
1110                 return int64(field.Len()) > p
1111
1112         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1113                 p := asInt(param)
1114
1115                 return field.Int() > p
1116
1117         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1118                 p := asUint(param)
1119
1120                 return field.Uint() > p
1121
1122         case reflect.Float32, reflect.Float64:
1123                 p := asFloat(param)
1124
1125                 return field.Float() > p
1126         case reflect.Struct:
1127
1128                 if field.Type() == timeType {
1129
1130                         return field.Interface().(time.Time).After(time.Now().UTC())
1131                 }
1132         }
1133
1134         panic(fmt.Sprintf("Bad field type %T", field.Interface()))
1135 }
1136
1137 // HasLengthOf is the validation function for validating if the current field's value is equal to the param's value.
1138 func hasLengthOf(fl FieldLevel) bool {
1139
1140         field := fl.Field()
1141         param := fl.Param()
1142
1143         switch field.Kind() {
1144
1145         case reflect.String:
1146                 p := asInt(param)
1147
1148                 return int64(utf8.RuneCountInString(field.String())) == p
1149
1150         case reflect.Slice, reflect.Map, reflect.Array:
1151                 p := asInt(param)
1152
1153                 return int64(field.Len()) == p
1154
1155         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1156                 p := asInt(param)
1157
1158                 return field.Int() == p
1159
1160         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1161                 p := asUint(param)
1162
1163                 return field.Uint() == p
1164
1165         case reflect.Float32, reflect.Float64:
1166                 p := asFloat(param)
1167
1168                 return field.Float() == p
1169         }
1170
1171         panic(fmt.Sprintf("Bad field type %T", field.Interface()))
1172 }
1173
1174 // HasMinOf is the validation function for validating if the current field's value is greater than or equal to the param's value.
1175 func hasMinOf(fl FieldLevel) bool {
1176         return isGte(fl)
1177 }
1178
1179 // IsLteField is the validation function for validating if the current field's value is less than or equal to the field specified by the param's value.
1180 func isLteField(fl FieldLevel) bool {
1181
1182         field := fl.Field()
1183         kind := field.Kind()
1184
1185         currentField, currentKind, ok := fl.GetStructFieldOK()
1186         if !ok || currentKind != kind {
1187                 return false
1188         }
1189
1190         switch kind {
1191
1192         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1193
1194                 return field.Int() <= currentField.Int()
1195
1196         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1197
1198                 return field.Uint() <= currentField.Uint()
1199
1200         case reflect.Float32, reflect.Float64:
1201
1202                 return field.Float() <= currentField.Float()
1203
1204         case reflect.Struct:
1205
1206                 fieldType := field.Type()
1207
1208                 // Not Same underlying type i.e. struct and time
1209                 if fieldType != currentField.Type() {
1210                         return false
1211                 }
1212
1213                 if fieldType == timeType {
1214
1215                         t := currentField.Interface().(time.Time)
1216                         fieldTime := field.Interface().(time.Time)
1217
1218                         return fieldTime.Before(t) || fieldTime.Equal(t)
1219                 }
1220         }
1221
1222         // default reflect.String
1223         return len(field.String()) <= len(currentField.String())
1224 }
1225
1226 // IsLtField is the validation function for validating if the current field's value is less than the field specified by the param's value.
1227 func isLtField(fl FieldLevel) bool {
1228
1229         field := fl.Field()
1230         kind := field.Kind()
1231
1232         currentField, currentKind, ok := fl.GetStructFieldOK()
1233         if !ok || currentKind != kind {
1234                 return false
1235         }
1236
1237         switch kind {
1238
1239         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1240
1241                 return field.Int() < currentField.Int()
1242
1243         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1244
1245                 return field.Uint() < currentField.Uint()
1246
1247         case reflect.Float32, reflect.Float64:
1248
1249                 return field.Float() < currentField.Float()
1250
1251         case reflect.Struct:
1252
1253                 fieldType := field.Type()
1254
1255                 // Not Same underlying type i.e. struct and time
1256                 if fieldType != currentField.Type() {
1257                         return false
1258                 }
1259
1260                 if fieldType == timeType {
1261
1262                         t := currentField.Interface().(time.Time)
1263                         fieldTime := field.Interface().(time.Time)
1264
1265                         return fieldTime.Before(t)
1266                 }
1267         }
1268
1269         // default reflect.String
1270         return len(field.String()) < len(currentField.String())
1271 }
1272
1273 // IsLte is the validation function for validating if the current field's value is less than or equal to the param's value.
1274 func isLte(fl FieldLevel) bool {
1275
1276         field := fl.Field()
1277         param := fl.Param()
1278
1279         switch field.Kind() {
1280
1281         case reflect.String:
1282                 p := asInt(param)
1283
1284                 return int64(utf8.RuneCountInString(field.String())) <= p
1285
1286         case reflect.Slice, reflect.Map, reflect.Array:
1287                 p := asInt(param)
1288
1289                 return int64(field.Len()) <= p
1290
1291         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1292                 p := asInt(param)
1293
1294                 return field.Int() <= p
1295
1296         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1297                 p := asUint(param)
1298
1299                 return field.Uint() <= p
1300
1301         case reflect.Float32, reflect.Float64:
1302                 p := asFloat(param)
1303
1304                 return field.Float() <= p
1305
1306         case reflect.Struct:
1307
1308                 if field.Type() == timeType {
1309
1310                         now := time.Now().UTC()
1311                         t := field.Interface().(time.Time)
1312
1313                         return t.Before(now) || t.Equal(now)
1314                 }
1315         }
1316
1317         panic(fmt.Sprintf("Bad field type %T", field.Interface()))
1318 }
1319
1320 // IsLt is the validation function for validating if the current field's value is less than the param's value.
1321 func isLt(fl FieldLevel) bool {
1322
1323         field := fl.Field()
1324         param := fl.Param()
1325
1326         switch field.Kind() {
1327
1328         case reflect.String:
1329                 p := asInt(param)
1330
1331                 return int64(utf8.RuneCountInString(field.String())) < p
1332
1333         case reflect.Slice, reflect.Map, reflect.Array:
1334                 p := asInt(param)
1335
1336                 return int64(field.Len()) < p
1337
1338         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1339                 p := asInt(param)
1340
1341                 return field.Int() < p
1342
1343         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1344                 p := asUint(param)
1345
1346                 return field.Uint() < p
1347
1348         case reflect.Float32, reflect.Float64:
1349                 p := asFloat(param)
1350
1351                 return field.Float() < p
1352
1353         case reflect.Struct:
1354
1355                 if field.Type() == timeType {
1356
1357                         return field.Interface().(time.Time).Before(time.Now().UTC())
1358                 }
1359         }
1360
1361         panic(fmt.Sprintf("Bad field type %T", field.Interface()))
1362 }
1363
1364 // HasMaxOf is the validation function for validating if the current field's value is less than or equal to the param's value.
1365 func hasMaxOf(fl FieldLevel) bool {
1366         return isLte(fl)
1367 }
1368
1369 // IsTCP4AddrResolvable is the validation function for validating if the field's value is a resolvable tcp4 address.
1370 func isTCP4AddrResolvable(fl FieldLevel) bool {
1371
1372         if !isIP4Addr(fl) {
1373                 return false
1374         }
1375
1376         _, err := net.ResolveTCPAddr("tcp4", fl.Field().String())
1377         return err == nil
1378 }
1379
1380 // IsTCP6AddrResolvable is the validation function for validating if the field's value is a resolvable tcp6 address.
1381 func isTCP6AddrResolvable(fl FieldLevel) bool {
1382
1383         if !isIP6Addr(fl) {
1384                 return false
1385         }
1386
1387         _, err := net.ResolveTCPAddr("tcp6", fl.Field().String())
1388
1389         return err == nil
1390 }
1391
1392 // IsTCPAddrResolvable is the validation function for validating if the field's value is a resolvable tcp address.
1393 func isTCPAddrResolvable(fl FieldLevel) bool {
1394
1395         if !isIP4Addr(fl) && !isIP6Addr(fl) {
1396                 return false
1397         }
1398
1399         _, err := net.ResolveTCPAddr("tcp", fl.Field().String())
1400
1401         return err == nil
1402 }
1403
1404 // IsUDP4AddrResolvable is the validation function for validating if the field's value is a resolvable udp4 address.
1405 func isUDP4AddrResolvable(fl FieldLevel) bool {
1406
1407         if !isIP4Addr(fl) {
1408                 return false
1409         }
1410
1411         _, err := net.ResolveUDPAddr("udp4", fl.Field().String())
1412
1413         return err == nil
1414 }
1415
1416 // IsUDP6AddrResolvable is the validation function for validating if the field's value is a resolvable udp6 address.
1417 func isUDP6AddrResolvable(fl FieldLevel) bool {
1418
1419         if !isIP6Addr(fl) {
1420                 return false
1421         }
1422
1423         _, err := net.ResolveUDPAddr("udp6", fl.Field().String())
1424
1425         return err == nil
1426 }
1427
1428 // IsUDPAddrResolvable is the validation function for validating if the field's value is a resolvable udp address.
1429 func isUDPAddrResolvable(fl FieldLevel) bool {
1430
1431         if !isIP4Addr(fl) && !isIP6Addr(fl) {
1432                 return false
1433         }
1434
1435         _, err := net.ResolveUDPAddr("udp", fl.Field().String())
1436
1437         return err == nil
1438 }
1439
1440 // IsIP4AddrResolvable is the validation function for validating if the field's value is a resolvable ip4 address.
1441 func isIP4AddrResolvable(fl FieldLevel) bool {
1442
1443         if !isIPv4(fl) {
1444                 return false
1445         }
1446
1447         _, err := net.ResolveIPAddr("ip4", fl.Field().String())
1448
1449         return err == nil
1450 }
1451
1452 // IsIP6AddrResolvable is the validation function for validating if the field's value is a resolvable ip6 address.
1453 func isIP6AddrResolvable(fl FieldLevel) bool {
1454
1455         if !isIPv6(fl) {
1456                 return false
1457         }
1458
1459         _, err := net.ResolveIPAddr("ip6", fl.Field().String())
1460
1461         return err == nil
1462 }
1463
1464 // IsIPAddrResolvable is the validation function for validating if the field's value is a resolvable ip address.
1465 func isIPAddrResolvable(fl FieldLevel) bool {
1466
1467         if !isIP(fl) {
1468                 return false
1469         }
1470
1471         _, err := net.ResolveIPAddr("ip", fl.Field().String())
1472
1473         return err == nil
1474 }
1475
1476 // IsUnixAddrResolvable is the validation function for validating if the field's value is a resolvable unix address.
1477 func isUnixAddrResolvable(fl FieldLevel) bool {
1478
1479         _, err := net.ResolveUnixAddr("unix", fl.Field().String())
1480
1481         return err == nil
1482 }
1483
1484 func isIP4Addr(fl FieldLevel) bool {
1485
1486         val := fl.Field().String()
1487
1488         if idx := strings.LastIndex(val, ":"); idx != -1 {
1489                 val = val[0:idx]
1490         }
1491
1492         ip := net.ParseIP(val)
1493
1494         return ip != nil && ip.To4() != nil
1495 }
1496
1497 func isIP6Addr(fl FieldLevel) bool {
1498
1499         val := fl.Field().String()
1500
1501         if idx := strings.LastIndex(val, ":"); idx != -1 {
1502                 if idx != 0 && val[idx-1:idx] == "]" {
1503                         val = val[1 : idx-1]
1504                 }
1505         }
1506
1507         ip := net.ParseIP(val)
1508
1509         return ip != nil && ip.To4() == nil
1510 }
1511
1512 func isHostname(fl FieldLevel) bool {
1513         return hostnameRegex.MatchString(fl.Field().String())
1514 }
1515
1516 func isFQDN(fl FieldLevel) bool {
1517         val := fl.Field().String()
1518
1519         if val == "" {
1520                 return false
1521         }
1522
1523         if val[len(val)-1] == '.' {
1524                 val = val[0 : len(val)-1]
1525         }
1526
1527         return (strings.IndexAny(val, ".") > -1) &&
1528                 hostnameRegex.MatchString(val)
1529 }