本站源代码
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

762 lines
25KB

  1. // Copyright 2014 Martini Authors
  2. // Copyright 2014 The Macaron Authors
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License"): you may
  5. // not use this file except in compliance with the License. You may obtain
  6. // a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. // License for the specific language governing permissions and limitations
  14. // under the License.
  15. // Package binding is a middleware that provides request data binding and validation for Macaron.
  16. package binding
  17. import (
  18. "encoding/json"
  19. "fmt"
  20. "io"
  21. "mime/multipart"
  22. "net/http"
  23. "net/url"
  24. "reflect"
  25. "regexp"
  26. "strconv"
  27. "strings"
  28. "unicode/utf8"
  29. "gitea.com/macaron/macaron"
  30. "github.com/unknwon/com"
  31. )
  32. const _VERSION = "0.6.0"
  33. func Version() string {
  34. return _VERSION
  35. }
  36. func bind(ctx *macaron.Context, obj interface{}, ifacePtr ...interface{}) {
  37. contentType := ctx.Req.Header.Get("Content-Type")
  38. if ctx.Req.Method == "POST" || ctx.Req.Method == "PUT" || len(contentType) > 0 {
  39. switch {
  40. case strings.Contains(contentType, "form-urlencoded"):
  41. ctx.Invoke(Form(obj, ifacePtr...))
  42. case strings.Contains(contentType, "multipart/form-data"):
  43. ctx.Invoke(MultipartForm(obj, ifacePtr...))
  44. case strings.Contains(contentType, "json"):
  45. ctx.Invoke(Json(obj, ifacePtr...))
  46. default:
  47. var errors Errors
  48. if contentType == "" {
  49. errors.Add([]string{}, ERR_CONTENT_TYPE, "Empty Content-Type")
  50. } else {
  51. errors.Add([]string{}, ERR_CONTENT_TYPE, "Unsupported Content-Type")
  52. }
  53. ctx.Map(errors)
  54. ctx.Map(obj) // Map a fake struct so handler won't panic.
  55. }
  56. } else {
  57. ctx.Invoke(Form(obj, ifacePtr...))
  58. }
  59. }
  60. const (
  61. _JSON_CONTENT_TYPE = "application/json; charset=utf-8"
  62. STATUS_UNPROCESSABLE_ENTITY = 422
  63. )
  64. // errorHandler simply counts the number of errors in the
  65. // context and, if more than 0, writes a response with an
  66. // error code and a JSON payload describing the errors.
  67. // The response will have a JSON content-type.
  68. // Middleware remaining on the stack will not even see the request
  69. // if, by this point, there are any errors.
  70. // This is a "default" handler, of sorts, and you are
  71. // welcome to use your own instead. The Bind middleware
  72. // invokes this automatically for convenience.
  73. func errorHandler(errs Errors, rw http.ResponseWriter) {
  74. if len(errs) > 0 {
  75. rw.Header().Set("Content-Type", _JSON_CONTENT_TYPE)
  76. if errs.Has(ERR_DESERIALIZATION) {
  77. rw.WriteHeader(http.StatusBadRequest)
  78. } else if errs.Has(ERR_CONTENT_TYPE) {
  79. rw.WriteHeader(http.StatusUnsupportedMediaType)
  80. } else {
  81. rw.WriteHeader(STATUS_UNPROCESSABLE_ENTITY)
  82. }
  83. errOutput, _ := json.Marshal(errs)
  84. rw.Write(errOutput)
  85. return
  86. }
  87. }
  88. // Bind wraps up the functionality of the Form and Json middleware
  89. // according to the Content-Type and verb of the request.
  90. // A Content-Type is required for POST and PUT requests.
  91. // Bind invokes the ErrorHandler middleware to bail out if errors
  92. // occurred. If you want to perform your own error handling, use
  93. // Form or Json middleware directly. An interface pointer can
  94. // be added as a second argument in order to map the struct to
  95. // a specific interface.
  96. func Bind(obj interface{}, ifacePtr ...interface{}) macaron.Handler {
  97. return func(ctx *macaron.Context) {
  98. bind(ctx, obj, ifacePtr...)
  99. if handler, ok := obj.(ErrorHandler); ok {
  100. ctx.Invoke(handler.Error)
  101. } else {
  102. ctx.Invoke(errorHandler)
  103. }
  104. }
  105. }
  106. // BindIgnErr will do the exactly same thing as Bind but without any
  107. // error handling, which user has freedom to deal with them.
  108. // This allows user take advantages of validation.
  109. func BindIgnErr(obj interface{}, ifacePtr ...interface{}) macaron.Handler {
  110. return func(ctx *macaron.Context) {
  111. bind(ctx, obj, ifacePtr...)
  112. }
  113. }
  114. // Form is middleware to deserialize form-urlencoded data from the request.
  115. // It gets data from the form-urlencoded body, if present, or from the
  116. // query string. It uses the http.Request.ParseForm() method
  117. // to perform deserialization, then reflection is used to map each field
  118. // into the struct with the proper type. Structs with primitive slice types
  119. // (bool, float, int, string) can support deserialization of repeated form
  120. // keys, for example: key=val1&key=val2&key=val3
  121. // An interface pointer can be added as a second argument in order
  122. // to map the struct to a specific interface.
  123. func Form(formStruct interface{}, ifacePtr ...interface{}) macaron.Handler {
  124. return func(ctx *macaron.Context) {
  125. var errors Errors
  126. ensureNotPointer(formStruct)
  127. formStruct := reflect.New(reflect.TypeOf(formStruct))
  128. parseErr := ctx.Req.ParseForm()
  129. // Format validation of the request body or the URL would add considerable overhead,
  130. // and ParseForm does not complain when URL encoding is off.
  131. // Because an empty request body or url can also mean absence of all needed values,
  132. // it is not in all cases a bad request, so let's return 422.
  133. if parseErr != nil {
  134. errors.Add([]string{}, ERR_DESERIALIZATION, parseErr.Error())
  135. }
  136. errors = mapForm(formStruct, ctx.Req.Form, nil, errors)
  137. validateAndMap(formStruct, ctx, errors, ifacePtr...)
  138. }
  139. }
  140. // Maximum amount of memory to use when parsing a multipart form.
  141. // Set this to whatever value you prefer; default is 10 MB.
  142. var MaxMemory = int64(1024 * 1024 * 10)
  143. // MultipartForm works much like Form, except it can parse multipart forms
  144. // and handle file uploads. Like the other deserialization middleware handlers,
  145. // you can pass in an interface to make the interface available for injection
  146. // into other handlers later.
  147. func MultipartForm(formStruct interface{}, ifacePtr ...interface{}) macaron.Handler {
  148. return func(ctx *macaron.Context) {
  149. var errors Errors
  150. ensureNotPointer(formStruct)
  151. formStruct := reflect.New(reflect.TypeOf(formStruct))
  152. // This if check is necessary due to https://github.com/martini-contrib/csrf/issues/6
  153. if ctx.Req.MultipartForm == nil {
  154. // Workaround for multipart forms returning nil instead of an error
  155. // when content is not multipart; see https://code.google.com/p/go/issues/detail?id=6334
  156. if multipartReader, err := ctx.Req.MultipartReader(); err != nil {
  157. errors.Add([]string{}, ERR_DESERIALIZATION, err.Error())
  158. } else {
  159. form, parseErr := multipartReader.ReadForm(MaxMemory)
  160. if parseErr != nil {
  161. errors.Add([]string{}, ERR_DESERIALIZATION, parseErr.Error())
  162. }
  163. if ctx.Req.Form == nil {
  164. ctx.Req.ParseForm()
  165. }
  166. for k, v := range form.Value {
  167. ctx.Req.Form[k] = append(ctx.Req.Form[k], v...)
  168. }
  169. ctx.Req.MultipartForm = form
  170. }
  171. }
  172. errors = mapForm(formStruct, ctx.Req.MultipartForm.Value, ctx.Req.MultipartForm.File, errors)
  173. validateAndMap(formStruct, ctx, errors, ifacePtr...)
  174. }
  175. }
  176. // Json is middleware to deserialize a JSON payload from the request
  177. // into the struct that is passed in. The resulting struct is then
  178. // validated, but no error handling is actually performed here.
  179. // An interface pointer can be added as a second argument in order
  180. // to map the struct to a specific interface.
  181. func Json(jsonStruct interface{}, ifacePtr ...interface{}) macaron.Handler {
  182. return func(ctx *macaron.Context) {
  183. var errors Errors
  184. ensureNotPointer(jsonStruct)
  185. jsonStruct := reflect.New(reflect.TypeOf(jsonStruct))
  186. if ctx.Req.Request.Body != nil {
  187. defer ctx.Req.Request.Body.Close()
  188. err := json.NewDecoder(ctx.Req.Request.Body).Decode(jsonStruct.Interface())
  189. if err != nil && err != io.EOF {
  190. errors.Add([]string{}, ERR_DESERIALIZATION, err.Error())
  191. }
  192. }
  193. validateAndMap(jsonStruct, ctx, errors, ifacePtr...)
  194. }
  195. }
  196. // RawValidate is same as Validate but does not require a HTTP context,
  197. // and can be used independently just for validation.
  198. // This function does not support Validator interface.
  199. func RawValidate(obj interface{}) Errors {
  200. var errs Errors
  201. v := reflect.ValueOf(obj)
  202. k := v.Kind()
  203. if k == reflect.Interface || k == reflect.Ptr {
  204. v = v.Elem()
  205. k = v.Kind()
  206. }
  207. if k == reflect.Slice || k == reflect.Array {
  208. for i := 0; i < v.Len(); i++ {
  209. e := v.Index(i).Interface()
  210. errs = validateStruct(errs, e)
  211. }
  212. } else {
  213. errs = validateStruct(errs, obj)
  214. }
  215. return errs
  216. }
  217. // Validate is middleware to enforce required fields. If the struct
  218. // passed in implements Validator, then the user-defined Validate method
  219. // is executed, and its errors are mapped to the context. This middleware
  220. // performs no error handling: it merely detects errors and maps them.
  221. func Validate(obj interface{}) macaron.Handler {
  222. return func(ctx *macaron.Context) {
  223. var errs Errors
  224. v := reflect.ValueOf(obj)
  225. k := v.Kind()
  226. if k == reflect.Interface || k == reflect.Ptr {
  227. v = v.Elem()
  228. k = v.Kind()
  229. }
  230. if k == reflect.Slice || k == reflect.Array {
  231. for i := 0; i < v.Len(); i++ {
  232. e := v.Index(i).Interface()
  233. errs = validateStruct(errs, e)
  234. if validator, ok := e.(Validator); ok {
  235. errs = validator.Validate(ctx, errs)
  236. }
  237. }
  238. } else {
  239. errs = validateStruct(errs, obj)
  240. if validator, ok := obj.(Validator); ok {
  241. errs = validator.Validate(ctx, errs)
  242. }
  243. }
  244. ctx.Map(errs)
  245. }
  246. }
  247. var (
  248. AlphaDashPattern = regexp.MustCompile("[^\\d\\w-_]")
  249. AlphaDashDotPattern = regexp.MustCompile("[^\\d\\w-_\\.]")
  250. EmailPattern = regexp.MustCompile("[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[a-zA-Z0-9](?:[\\w-]*[\\w])?")
  251. )
  252. // Copied from github.com/asaskevich/govalidator.
  253. const _MAX_URL_RUNE_COUNT = 2083
  254. const _MIN_URL_RUNE_COUNT = 3
  255. var (
  256. urlSchemaRx = `((ftp|tcp|udp|wss?|https?):\/\/)`
  257. urlUsernameRx = `(\S+(:\S*)?@)`
  258. urlIPRx = `([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))`
  259. ipRx = `(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))`
  260. urlSubdomainRx = `((www\.)|([a-zA-Z0-9]([-\.][-\._a-zA-Z0-9]+)*))`
  261. urlPortRx = `(:(\d{1,5}))`
  262. urlPathRx = `((\/|\?|#)[^\s]*)`
  263. URLPattern = regexp.MustCompile(`^` + urlSchemaRx + `?` + urlUsernameRx + `?` + `((` + urlIPRx + `|(\[` + ipRx + `\])|(([a-zA-Z0-9]([a-zA-Z0-9-_]+)?[a-zA-Z0-9]([-\.][a-zA-Z0-9]+)*)|(` + urlSubdomainRx + `?))?(([a-zA-Z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-zA-Z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-zA-Z\x{00a1}-\x{ffff}]{1,}))?))\.?` + urlPortRx + `?` + urlPathRx + `?$`)
  264. )
  265. // IsURL check if the string is an URL.
  266. func isURL(str string) bool {
  267. if str == "" || utf8.RuneCountInString(str) >= _MAX_URL_RUNE_COUNT || len(str) <= _MIN_URL_RUNE_COUNT || strings.HasPrefix(str, ".") {
  268. return false
  269. }
  270. u, err := url.Parse(str)
  271. if err != nil {
  272. return false
  273. }
  274. if strings.HasPrefix(u.Host, ".") {
  275. return false
  276. }
  277. if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) {
  278. return false
  279. }
  280. return URLPattern.MatchString(str)
  281. }
  282. type (
  283. // Rule represents a validation rule.
  284. Rule struct {
  285. // IsMatch checks if rule matches.
  286. IsMatch func(string) bool
  287. // IsValid applies validation rule to condition.
  288. IsValid func(Errors, string, interface{}) (bool, Errors)
  289. }
  290. // ParamRule does same thing as Rule but passes rule itself to IsValid method.
  291. ParamRule struct {
  292. // IsMatch checks if rule matches.
  293. IsMatch func(string) bool
  294. // IsValid applies validation rule to condition.
  295. IsValid func(Errors, string, string, interface{}) (bool, Errors)
  296. }
  297. // RuleMapper and ParamRuleMapper represent validation rule mappers,
  298. // it allwos users to add custom validation rules.
  299. RuleMapper []*Rule
  300. ParamRuleMapper []*ParamRule
  301. )
  302. var ruleMapper RuleMapper
  303. var paramRuleMapper ParamRuleMapper
  304. // AddRule adds new validation rule.
  305. func AddRule(r *Rule) {
  306. ruleMapper = append(ruleMapper, r)
  307. }
  308. // AddParamRule adds new validation rule.
  309. func AddParamRule(r *ParamRule) {
  310. paramRuleMapper = append(paramRuleMapper, r)
  311. }
  312. func in(fieldValue interface{}, arr string) bool {
  313. val := fmt.Sprintf("%v", fieldValue)
  314. vals := strings.Split(arr, ",")
  315. isIn := false
  316. for _, v := range vals {
  317. if v == val {
  318. isIn = true
  319. break
  320. }
  321. }
  322. return isIn
  323. }
  324. func parseFormName(raw, actual string) string {
  325. if len(actual) > 0 {
  326. return actual
  327. }
  328. return nameMapper(raw)
  329. }
  330. // Performs required field checking on a struct
  331. func validateStruct(errors Errors, obj interface{}) Errors {
  332. typ := reflect.TypeOf(obj)
  333. val := reflect.ValueOf(obj)
  334. if typ.Kind() == reflect.Ptr {
  335. typ = typ.Elem()
  336. val = val.Elem()
  337. }
  338. for i := 0; i < typ.NumField(); i++ {
  339. field := typ.Field(i)
  340. // Allow ignored fields in the struct
  341. if field.Tag.Get("form") == "-" || !val.Field(i).CanInterface() {
  342. continue
  343. }
  344. fieldVal := val.Field(i)
  345. fieldValue := fieldVal.Interface()
  346. zero := reflect.Zero(field.Type).Interface()
  347. // Validate nested and embedded structs (if pointer, only do so if not nil)
  348. if field.Type.Kind() == reflect.Struct ||
  349. (field.Type.Kind() == reflect.Ptr && !reflect.DeepEqual(zero, fieldValue) &&
  350. field.Type.Elem().Kind() == reflect.Struct) {
  351. errors = validateStruct(errors, fieldValue)
  352. }
  353. errors = validateField(errors, zero, field, fieldVal, fieldValue)
  354. }
  355. return errors
  356. }
  357. func validateField(errors Errors, zero interface{}, field reflect.StructField, fieldVal reflect.Value, fieldValue interface{}) Errors {
  358. if fieldVal.Kind() == reflect.Slice {
  359. for i := 0; i < fieldVal.Len(); i++ {
  360. sliceVal := fieldVal.Index(i)
  361. if sliceVal.Kind() == reflect.Ptr {
  362. sliceVal = sliceVal.Elem()
  363. }
  364. sliceValue := sliceVal.Interface()
  365. zero := reflect.Zero(sliceVal.Type()).Interface()
  366. if sliceVal.Kind() == reflect.Struct ||
  367. (sliceVal.Kind() == reflect.Ptr && !reflect.DeepEqual(zero, sliceValue) &&
  368. sliceVal.Elem().Kind() == reflect.Struct) {
  369. errors = validateStruct(errors, sliceValue)
  370. }
  371. /* Apply validation rules to each item in a slice. ISSUE #3
  372. else {
  373. errors = validateField(errors, zero, field, sliceVal, sliceValue)
  374. }*/
  375. }
  376. }
  377. VALIDATE_RULES:
  378. for _, rule := range strings.Split(field.Tag.Get("binding"), ";") {
  379. if len(rule) == 0 {
  380. continue
  381. }
  382. switch {
  383. case rule == "OmitEmpty":
  384. if reflect.DeepEqual(zero, fieldValue) {
  385. break VALIDATE_RULES
  386. }
  387. case rule == "Required":
  388. v := reflect.ValueOf(fieldValue)
  389. if v.Kind() == reflect.Slice {
  390. if v.Len() == 0 {
  391. errors.Add([]string{field.Name}, ERR_REQUIRED, "Required")
  392. break VALIDATE_RULES
  393. }
  394. continue
  395. }
  396. if reflect.DeepEqual(zero, fieldValue) {
  397. errors.Add([]string{field.Name}, ERR_REQUIRED, "Required")
  398. break VALIDATE_RULES
  399. }
  400. case rule == "AlphaDash":
  401. if AlphaDashPattern.MatchString(fmt.Sprintf("%v", fieldValue)) {
  402. errors.Add([]string{field.Name}, ERR_ALPHA_DASH, "AlphaDash")
  403. break VALIDATE_RULES
  404. }
  405. case rule == "AlphaDashDot":
  406. if AlphaDashDotPattern.MatchString(fmt.Sprintf("%v", fieldValue)) {
  407. errors.Add([]string{field.Name}, ERR_ALPHA_DASH_DOT, "AlphaDashDot")
  408. break VALIDATE_RULES
  409. }
  410. case strings.HasPrefix(rule, "Size("):
  411. size, _ := strconv.Atoi(rule[5 : len(rule)-1])
  412. if str, ok := fieldValue.(string); ok && utf8.RuneCountInString(str) != size {
  413. errors.Add([]string{field.Name}, ERR_SIZE, "Size")
  414. break VALIDATE_RULES
  415. }
  416. v := reflect.ValueOf(fieldValue)
  417. if v.Kind() == reflect.Slice && v.Len() != size {
  418. errors.Add([]string{field.Name}, ERR_SIZE, "Size")
  419. break VALIDATE_RULES
  420. }
  421. case strings.HasPrefix(rule, "MinSize("):
  422. min, _ := strconv.Atoi(rule[8 : len(rule)-1])
  423. if str, ok := fieldValue.(string); ok && utf8.RuneCountInString(str) < min {
  424. errors.Add([]string{field.Name}, ERR_MIN_SIZE, "MinSize")
  425. break VALIDATE_RULES
  426. }
  427. v := reflect.ValueOf(fieldValue)
  428. if v.Kind() == reflect.Slice && v.Len() < min {
  429. errors.Add([]string{field.Name}, ERR_MIN_SIZE, "MinSize")
  430. break VALIDATE_RULES
  431. }
  432. case strings.HasPrefix(rule, "MaxSize("):
  433. max, _ := strconv.Atoi(rule[8 : len(rule)-1])
  434. if str, ok := fieldValue.(string); ok && utf8.RuneCountInString(str) > max {
  435. errors.Add([]string{field.Name}, ERR_MAX_SIZE, "MaxSize")
  436. break VALIDATE_RULES
  437. }
  438. v := reflect.ValueOf(fieldValue)
  439. if v.Kind() == reflect.Slice && v.Len() > max {
  440. errors.Add([]string{field.Name}, ERR_MAX_SIZE, "MaxSize")
  441. break VALIDATE_RULES
  442. }
  443. case strings.HasPrefix(rule, "Range("):
  444. nums := strings.Split(rule[6:len(rule)-1], ",")
  445. if len(nums) != 2 {
  446. break VALIDATE_RULES
  447. }
  448. val := com.StrTo(fmt.Sprintf("%v", fieldValue)).MustInt()
  449. if val < com.StrTo(nums[0]).MustInt() || val > com.StrTo(nums[1]).MustInt() {
  450. errors.Add([]string{field.Name}, ERR_RANGE, "Range")
  451. break VALIDATE_RULES
  452. }
  453. case rule == "Email":
  454. if !EmailPattern.MatchString(fmt.Sprintf("%v", fieldValue)) {
  455. errors.Add([]string{field.Name}, ERR_EMAIL, "Email")
  456. break VALIDATE_RULES
  457. }
  458. case rule == "Url":
  459. str := fmt.Sprintf("%v", fieldValue)
  460. if len(str) == 0 {
  461. continue
  462. } else if !isURL(str) {
  463. errors.Add([]string{field.Name}, ERR_URL, "Url")
  464. break VALIDATE_RULES
  465. }
  466. case strings.HasPrefix(rule, "In("):
  467. if !in(fieldValue, rule[3:len(rule)-1]) {
  468. errors.Add([]string{field.Name}, ERR_IN, "In")
  469. break VALIDATE_RULES
  470. }
  471. case strings.HasPrefix(rule, "NotIn("):
  472. if in(fieldValue, rule[6:len(rule)-1]) {
  473. errors.Add([]string{field.Name}, ERR_NOT_INT, "NotIn")
  474. break VALIDATE_RULES
  475. }
  476. case strings.HasPrefix(rule, "Include("):
  477. if !strings.Contains(fmt.Sprintf("%v", fieldValue), rule[8:len(rule)-1]) {
  478. errors.Add([]string{field.Name}, ERR_INCLUDE, "Include")
  479. break VALIDATE_RULES
  480. }
  481. case strings.HasPrefix(rule, "Exclude("):
  482. if strings.Contains(fmt.Sprintf("%v", fieldValue), rule[8:len(rule)-1]) {
  483. errors.Add([]string{field.Name}, ERR_EXCLUDE, "Exclude")
  484. break VALIDATE_RULES
  485. }
  486. case strings.HasPrefix(rule, "Default("):
  487. if reflect.DeepEqual(zero, fieldValue) {
  488. if fieldVal.CanAddr() {
  489. errors = setWithProperType(field.Type.Kind(), rule[8:len(rule)-1], fieldVal, field.Tag.Get("form"), errors)
  490. } else {
  491. errors.Add([]string{field.Name}, ERR_EXCLUDE, "Default")
  492. break VALIDATE_RULES
  493. }
  494. }
  495. default:
  496. // Apply custom validation rules
  497. var isValid bool
  498. for i := range ruleMapper {
  499. if ruleMapper[i].IsMatch(rule) {
  500. isValid, errors = ruleMapper[i].IsValid(errors, field.Name, fieldValue)
  501. if !isValid {
  502. break VALIDATE_RULES
  503. }
  504. }
  505. }
  506. for i := range paramRuleMapper {
  507. if paramRuleMapper[i].IsMatch(rule) {
  508. isValid, errors = paramRuleMapper[i].IsValid(errors, rule, field.Name, fieldValue)
  509. if !isValid {
  510. break VALIDATE_RULES
  511. }
  512. }
  513. }
  514. }
  515. }
  516. return errors
  517. }
  518. // NameMapper represents a form tag name mapper.
  519. type NameMapper func(string) string
  520. var (
  521. nameMapper = func(field string) string {
  522. newstr := make([]rune, 0, len(field))
  523. for i, chr := range field {
  524. if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
  525. if i > 0 {
  526. newstr = append(newstr, '_')
  527. }
  528. chr -= ('A' - 'a')
  529. }
  530. newstr = append(newstr, chr)
  531. }
  532. return string(newstr)
  533. }
  534. )
  535. // SetNameMapper sets name mapper.
  536. func SetNameMapper(nm NameMapper) {
  537. nameMapper = nm
  538. }
  539. // Takes values from the form data and puts them into a struct
  540. func mapForm(formStruct reflect.Value, form map[string][]string,
  541. formfile map[string][]*multipart.FileHeader, errors Errors) Errors {
  542. if formStruct.Kind() == reflect.Ptr {
  543. formStruct = formStruct.Elem()
  544. }
  545. typ := formStruct.Type()
  546. for i := 0; i < typ.NumField(); i++ {
  547. typeField := typ.Field(i)
  548. structField := formStruct.Field(i)
  549. if typeField.Type.Kind() == reflect.Ptr && typeField.Anonymous {
  550. structField.Set(reflect.New(typeField.Type.Elem()))
  551. errors = mapForm(structField.Elem(), form, formfile, errors)
  552. if reflect.DeepEqual(structField.Elem().Interface(), reflect.Zero(structField.Elem().Type()).Interface()) {
  553. structField.Set(reflect.Zero(structField.Type()))
  554. }
  555. } else if typeField.Type.Kind() == reflect.Struct {
  556. errors = mapForm(structField, form, formfile, errors)
  557. }
  558. inputFieldName := parseFormName(typeField.Name, typeField.Tag.Get("form"))
  559. if len(inputFieldName) == 0 || !structField.CanSet() {
  560. continue
  561. }
  562. inputValue, exists := form[inputFieldName]
  563. if exists {
  564. numElems := len(inputValue)
  565. if structField.Kind() == reflect.Slice && numElems > 0 {
  566. sliceOf := structField.Type().Elem().Kind()
  567. slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
  568. for i := 0; i < numElems; i++ {
  569. errors = setWithProperType(sliceOf, inputValue[i], slice.Index(i), inputFieldName, errors)
  570. }
  571. formStruct.Field(i).Set(slice)
  572. } else {
  573. errors = setWithProperType(typeField.Type.Kind(), inputValue[0], structField, inputFieldName, errors)
  574. }
  575. continue
  576. }
  577. inputFile, exists := formfile[inputFieldName]
  578. if !exists {
  579. continue
  580. }
  581. fhType := reflect.TypeOf((*multipart.FileHeader)(nil))
  582. numElems := len(inputFile)
  583. if structField.Kind() == reflect.Slice && numElems > 0 && structField.Type().Elem() == fhType {
  584. slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
  585. for i := 0; i < numElems; i++ {
  586. slice.Index(i).Set(reflect.ValueOf(inputFile[i]))
  587. }
  588. structField.Set(slice)
  589. } else if structField.Type() == fhType {
  590. structField.Set(reflect.ValueOf(inputFile[0]))
  591. }
  592. }
  593. return errors
  594. }
  595. // This sets the value in a struct of an indeterminate type to the
  596. // matching value from the request (via Form middleware) in the
  597. // same type, so that not all deserialized values have to be strings.
  598. // Supported types are string, int, float, and bool.
  599. func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value, nameInTag string, errors Errors) Errors {
  600. switch valueKind {
  601. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  602. if val == "" {
  603. val = "0"
  604. }
  605. intVal, err := strconv.ParseInt(val, 10, 64)
  606. if err != nil {
  607. errors.Add([]string{nameInTag}, ERR_INTERGER_TYPE, "Value could not be parsed as integer")
  608. } else {
  609. structField.SetInt(intVal)
  610. }
  611. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  612. if val == "" {
  613. val = "0"
  614. }
  615. uintVal, err := strconv.ParseUint(val, 10, 64)
  616. if err != nil {
  617. errors.Add([]string{nameInTag}, ERR_INTERGER_TYPE, "Value could not be parsed as unsigned integer")
  618. } else {
  619. structField.SetUint(uintVal)
  620. }
  621. case reflect.Bool:
  622. if val == "on" {
  623. structField.SetBool(true)
  624. break
  625. }
  626. if val == "" {
  627. val = "false"
  628. }
  629. boolVal, err := strconv.ParseBool(val)
  630. if err != nil {
  631. errors.Add([]string{nameInTag}, ERR_BOOLEAN_TYPE, "Value could not be parsed as boolean")
  632. } else if boolVal {
  633. structField.SetBool(true)
  634. }
  635. case reflect.Float32:
  636. if val == "" {
  637. val = "0.0"
  638. }
  639. floatVal, err := strconv.ParseFloat(val, 32)
  640. if err != nil {
  641. errors.Add([]string{nameInTag}, ERR_FLOAT_TYPE, "Value could not be parsed as 32-bit float")
  642. } else {
  643. structField.SetFloat(floatVal)
  644. }
  645. case reflect.Float64:
  646. if val == "" {
  647. val = "0.0"
  648. }
  649. floatVal, err := strconv.ParseFloat(val, 64)
  650. if err != nil {
  651. errors.Add([]string{nameInTag}, ERR_FLOAT_TYPE, "Value could not be parsed as 64-bit float")
  652. } else {
  653. structField.SetFloat(floatVal)
  654. }
  655. case reflect.String:
  656. structField.SetString(val)
  657. }
  658. return errors
  659. }
  660. // Don't pass in pointers to bind to. Can lead to bugs.
  661. func ensureNotPointer(obj interface{}) {
  662. if reflect.TypeOf(obj).Kind() == reflect.Ptr {
  663. panic("Pointers are not accepted as binding models")
  664. }
  665. }
  666. // Performs validation and combines errors from validation
  667. // with errors from deserialization, then maps both the
  668. // resulting struct and the errors to the context.
  669. func validateAndMap(obj reflect.Value, ctx *macaron.Context, errors Errors, ifacePtr ...interface{}) {
  670. ctx.Invoke(Validate(obj.Interface()))
  671. errors = append(errors, getErrors(ctx)...)
  672. ctx.Map(errors)
  673. ctx.Map(obj.Elem().Interface())
  674. if len(ifacePtr) > 0 {
  675. ctx.MapTo(obj.Elem().Interface(), ifacePtr[0])
  676. }
  677. }
  678. // getErrors simply gets the errors from the context (it's kind of a chore)
  679. func getErrors(ctx *macaron.Context) Errors {
  680. return ctx.GetVal(reflect.TypeOf(Errors{})).Interface().(Errors)
  681. }
  682. type (
  683. // ErrorHandler is the interface that has custom error handling process.
  684. ErrorHandler interface {
  685. // Error handles validation errors with custom process.
  686. Error(*macaron.Context, Errors)
  687. }
  688. // Validator is the interface that handles some rudimentary
  689. // request validation logic so your application doesn't have to.
  690. Validator interface {
  691. // Validate validates that the request is OK. It is recommended
  692. // that validation be limited to checking values for syntax and
  693. // semantics, enough to know that you can make sense of the request
  694. // in your application. For example, you might verify that a credit
  695. // card number matches a valid pattern, but you probably wouldn't
  696. // perform an actual credit card authorization here.
  697. Validate(*macaron.Context, Errors) Errors
  698. }
  699. )
上海开阖软件有限公司 沪ICP备12045867号-1