http urls monitor.

util.go 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. package validator
  2. import (
  3. "reflect"
  4. "strconv"
  5. "strings"
  6. )
  7. const (
  8. blank = ""
  9. namespaceSeparator = "."
  10. leftBracket = "["
  11. rightBracket = "]"
  12. restrictedTagChars = ".[],|=+()`~!@#$%^&*\\\"/?<>{}"
  13. restrictedAliasErr = "Alias '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation"
  14. restrictedTagErr = "Tag '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation"
  15. )
  16. var (
  17. restrictedTags = map[string]struct{}{
  18. diveTag: {},
  19. existsTag: {},
  20. structOnlyTag: {},
  21. omitempty: {},
  22. skipValidationTag: {},
  23. utf8HexComma: {},
  24. utf8Pipe: {},
  25. noStructLevelTag: {},
  26. }
  27. )
  28. // ExtractType gets the actual underlying type of field value.
  29. // It will dive into pointers, customTypes and return you the
  30. // underlying value and it's kind.
  31. // it is exposed for use within you Custom Functions
  32. func (v *Validate) ExtractType(current reflect.Value) (reflect.Value, reflect.Kind) {
  33. val, k, _ := v.extractTypeInternal(current, false)
  34. return val, k
  35. }
  36. // only exists to not break backward compatibility, needed to return the third param for a bug fix internally
  37. func (v *Validate) extractTypeInternal(current reflect.Value, nullable bool) (reflect.Value, reflect.Kind, bool) {
  38. switch current.Kind() {
  39. case reflect.Ptr:
  40. nullable = true
  41. if current.IsNil() {
  42. return current, reflect.Ptr, nullable
  43. }
  44. return v.extractTypeInternal(current.Elem(), nullable)
  45. case reflect.Interface:
  46. nullable = true
  47. if current.IsNil() {
  48. return current, reflect.Interface, nullable
  49. }
  50. return v.extractTypeInternal(current.Elem(), nullable)
  51. case reflect.Invalid:
  52. return current, reflect.Invalid, nullable
  53. default:
  54. if v.hasCustomFuncs {
  55. if fn, ok := v.customTypeFuncs[current.Type()]; ok {
  56. return v.extractTypeInternal(reflect.ValueOf(fn(current)), nullable)
  57. }
  58. }
  59. return current, current.Kind(), nullable
  60. }
  61. }
  62. // GetStructFieldOK traverses a struct to retrieve a specific field denoted by the provided namespace and
  63. // returns the field, field kind and whether is was successful in retrieving the field at all.
  64. // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field
  65. // could not be retrieved because it didn't exist.
  66. func (v *Validate) GetStructFieldOK(current reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) {
  67. current, kind := v.ExtractType(current)
  68. if kind == reflect.Invalid {
  69. return current, kind, false
  70. }
  71. if namespace == blank {
  72. return current, kind, true
  73. }
  74. switch kind {
  75. case reflect.Ptr, reflect.Interface:
  76. return current, kind, false
  77. case reflect.Struct:
  78. typ := current.Type()
  79. fld := namespace
  80. ns := namespace
  81. if typ != timeType && typ != timePtrType {
  82. idx := strings.Index(namespace, namespaceSeparator)
  83. if idx != -1 {
  84. fld = namespace[:idx]
  85. ns = namespace[idx+1:]
  86. } else {
  87. ns = blank
  88. }
  89. bracketIdx := strings.Index(fld, leftBracket)
  90. if bracketIdx != -1 {
  91. fld = fld[:bracketIdx]
  92. ns = namespace[bracketIdx:]
  93. }
  94. current = current.FieldByName(fld)
  95. return v.GetStructFieldOK(current, ns)
  96. }
  97. case reflect.Array, reflect.Slice:
  98. idx := strings.Index(namespace, leftBracket)
  99. idx2 := strings.Index(namespace, rightBracket)
  100. arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2])
  101. if arrIdx >= current.Len() {
  102. return current, kind, false
  103. }
  104. startIdx := idx2 + 1
  105. if startIdx < len(namespace) {
  106. if namespace[startIdx:startIdx+1] == namespaceSeparator {
  107. startIdx++
  108. }
  109. }
  110. return v.GetStructFieldOK(current.Index(arrIdx), namespace[startIdx:])
  111. case reflect.Map:
  112. idx := strings.Index(namespace, leftBracket) + 1
  113. idx2 := strings.Index(namespace, rightBracket)
  114. endIdx := idx2
  115. if endIdx+1 < len(namespace) {
  116. if namespace[endIdx+1:endIdx+2] == namespaceSeparator {
  117. endIdx++
  118. }
  119. }
  120. key := namespace[idx:idx2]
  121. switch current.Type().Key().Kind() {
  122. case reflect.Int:
  123. i, _ := strconv.Atoi(key)
  124. return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(i)), namespace[endIdx+1:])
  125. case reflect.Int8:
  126. i, _ := strconv.ParseInt(key, 10, 8)
  127. return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(int8(i))), namespace[endIdx+1:])
  128. case reflect.Int16:
  129. i, _ := strconv.ParseInt(key, 10, 16)
  130. return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(int16(i))), namespace[endIdx+1:])
  131. case reflect.Int32:
  132. i, _ := strconv.ParseInt(key, 10, 32)
  133. return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(int32(i))), namespace[endIdx+1:])
  134. case reflect.Int64:
  135. i, _ := strconv.ParseInt(key, 10, 64)
  136. return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(i)), namespace[endIdx+1:])
  137. case reflect.Uint:
  138. i, _ := strconv.ParseUint(key, 10, 0)
  139. return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(uint(i))), namespace[endIdx+1:])
  140. case reflect.Uint8:
  141. i, _ := strconv.ParseUint(key, 10, 8)
  142. return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(uint8(i))), namespace[endIdx+1:])
  143. case reflect.Uint16:
  144. i, _ := strconv.ParseUint(key, 10, 16)
  145. return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(uint16(i))), namespace[endIdx+1:])
  146. case reflect.Uint32:
  147. i, _ := strconv.ParseUint(key, 10, 32)
  148. return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(uint32(i))), namespace[endIdx+1:])
  149. case reflect.Uint64:
  150. i, _ := strconv.ParseUint(key, 10, 64)
  151. return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(i)), namespace[endIdx+1:])
  152. case reflect.Float32:
  153. f, _ := strconv.ParseFloat(key, 32)
  154. return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(float32(f))), namespace[endIdx+1:])
  155. case reflect.Float64:
  156. f, _ := strconv.ParseFloat(key, 64)
  157. return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(f)), namespace[endIdx+1:])
  158. case reflect.Bool:
  159. b, _ := strconv.ParseBool(key)
  160. return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(b)), namespace[endIdx+1:])
  161. // reflect.Type = string
  162. default:
  163. return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(key)), namespace[endIdx+1:])
  164. }
  165. }
  166. // if got here there was more namespace, cannot go any deeper
  167. panic("Invalid field namespace")
  168. }
  169. // asInt returns the parameter as a int64
  170. // or panics if it can't convert
  171. func asInt(param string) int64 {
  172. i, err := strconv.ParseInt(param, 0, 64)
  173. panicIf(err)
  174. return i
  175. }
  176. // asUint returns the parameter as a uint64
  177. // or panics if it can't convert
  178. func asUint(param string) uint64 {
  179. i, err := strconv.ParseUint(param, 0, 64)
  180. panicIf(err)
  181. return i
  182. }
  183. // asFloat returns the parameter as a float64
  184. // or panics if it can't convert
  185. func asFloat(param string) float64 {
  186. i, err := strconv.ParseFloat(param, 64)
  187. panicIf(err)
  188. return i
  189. }
  190. func panicIf(err error) {
  191. if err != nil {
  192. panic(err.Error())
  193. }
  194. }