You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

472 lines
15 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. // Copyright 2013 The Martini Contrib Authors. All rights reserved.
  2. // Copyright 2014 The Gogs Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package binding
  6. import (
  7. "encoding/json"
  8. "fmt"
  9. "io"
  10. "net/http"
  11. "reflect"
  12. "regexp"
  13. "strconv"
  14. "strings"
  15. "unicode/utf8"
  16. "github.com/Unknwon/macaron"
  17. "github.com/macaron-contrib/i18n"
  18. )
  19. /*
  20. To the land of Middle-ware Earth:
  21. One func to rule them all,
  22. One func to find them,
  23. One func to bring them all,
  24. And in this package BIND them.
  25. */
  26. // Bind accepts a copy of an empty struct and populates it with
  27. // values from the request (if deserialization is successful). It
  28. // wraps up the functionality of the Form and Json middleware
  29. // according to the Content-Type of the request, and it guesses
  30. // if no Content-Type is specified. Bind invokes the ErrorHandler
  31. // middleware to bail out if errors occurred. If you want to perform
  32. // your own error handling, use Form or Json middleware directly.
  33. // An interface pointer can be added as a second argument in order
  34. // to map the struct to a specific interface.
  35. func Bind(obj interface{}, ifacePtr ...interface{}) macaron.Handler {
  36. return func(ctx *macaron.Context) {
  37. contentType := ctx.Req.Header.Get("Content-Type")
  38. if strings.Contains(contentType, "form-urlencoded") {
  39. ctx.Invoke(Form(obj, ifacePtr...))
  40. } else if strings.Contains(contentType, "multipart/form-data") {
  41. ctx.Invoke(MultipartForm(obj, ifacePtr...))
  42. } else if strings.Contains(contentType, "json") {
  43. ctx.Invoke(Json(obj, ifacePtr...))
  44. } else {
  45. ctx.Invoke(Json(obj, ifacePtr...))
  46. if getErrors(ctx).Count() > 0 {
  47. ctx.Invoke(Form(obj, ifacePtr...))
  48. }
  49. }
  50. ctx.Invoke(ErrorHandler)
  51. }
  52. }
  53. // BindIgnErr will do the exactly same thing as Bind but without any
  54. // error handling, which user has freedom to deal with them.
  55. // This allows user take advantages of validation.
  56. func BindIgnErr(obj interface{}, ifacePtr ...interface{}) macaron.Handler {
  57. return func(ctx *macaron.Context, req *http.Request) {
  58. contentType := req.Header.Get("Content-Type")
  59. if strings.Contains(contentType, "form-urlencoded") {
  60. ctx.Invoke(Form(obj, ifacePtr...))
  61. } else if strings.Contains(contentType, "multipart/form-data") {
  62. ctx.Invoke(MultipartForm(obj, ifacePtr...))
  63. } else if strings.Contains(contentType, "json") {
  64. ctx.Invoke(Json(obj, ifacePtr...))
  65. } else {
  66. ctx.Invoke(Json(obj, ifacePtr...))
  67. if getErrors(ctx).Count() > 0 {
  68. ctx.Invoke(Form(obj, ifacePtr...))
  69. }
  70. }
  71. }
  72. }
  73. // Form is middleware to deserialize form-urlencoded data from the request.
  74. // It gets data from the form-urlencoded body, if present, or from the
  75. // query string. It uses the http.Request.ParseForm() method
  76. // to perform deserialization, then reflection is used to map each field
  77. // into the struct with the proper type. Structs with primitive slice types
  78. // (bool, float, int, string) can support deserialization of repeated form
  79. // keys, for example: key=val1&key=val2&key=val3
  80. // An interface pointer can be added as a second argument in order
  81. // to map the struct to a specific interface.
  82. func Form(formStruct interface{}, ifacePtr ...interface{}) macaron.Handler {
  83. return func(ctx *macaron.Context) {
  84. ensureNotPointer(formStruct)
  85. formStruct := reflect.New(reflect.TypeOf(formStruct))
  86. errors := newErrors()
  87. parseErr := ctx.Req.ParseForm()
  88. // Format validation of the request body or the URL would add considerable overhead,
  89. // and ParseForm does not complain when URL encoding is off.
  90. // Because an empty request body or url can also mean absence of all needed values,
  91. // it is not in all cases a bad request, so let's return 422.
  92. if parseErr != nil {
  93. errors.Overall[BindingDeserializationError] = parseErr.Error()
  94. }
  95. mapForm(formStruct, ctx.Req.Form, errors)
  96. validateAndMap(formStruct, ctx, errors, ifacePtr...)
  97. }
  98. }
  99. func MultipartForm(formStruct interface{}, ifacePtr ...interface{}) macaron.Handler {
  100. return func(ctx *macaron.Context) {
  101. ensureNotPointer(formStruct)
  102. formStruct := reflect.New(reflect.TypeOf(formStruct))
  103. errors := newErrors()
  104. // Workaround for multipart forms returning nil instead of an error
  105. // when content is not multipart
  106. // https://code.google.com/p/go/issues/detail?id=6334
  107. multipartReader, err := ctx.Req.MultipartReader()
  108. if err != nil {
  109. errors.Overall[BindingDeserializationError] = err.Error()
  110. } else {
  111. form, parseErr := multipartReader.ReadForm(MaxMemory)
  112. if parseErr != nil {
  113. errors.Overall[BindingDeserializationError] = parseErr.Error()
  114. }
  115. ctx.Req.MultipartForm = form
  116. }
  117. mapForm(formStruct, ctx.Req.MultipartForm.Value, errors)
  118. validateAndMap(formStruct, ctx, errors, ifacePtr...)
  119. }
  120. }
  121. // Json is middleware to deserialize a JSON payload from the request
  122. // into the struct that is passed in. The resulting struct is then
  123. // validated, but no error handling is actually performed here.
  124. // An interface pointer can be added as a second argument in order
  125. // to map the struct to a specific interface.
  126. func Json(jsonStruct interface{}, ifacePtr ...interface{}) macaron.Handler {
  127. return func(ctx *macaron.Context) {
  128. ensureNotPointer(jsonStruct)
  129. jsonStruct := reflect.New(reflect.TypeOf(jsonStruct))
  130. errors := newErrors()
  131. if ctx.Req.Body != nil {
  132. defer ctx.Req.Body.Close()
  133. }
  134. if err := json.NewDecoder(ctx.Req.Body).Decode(jsonStruct.Interface()); err != nil && err != io.EOF {
  135. errors.Overall[BindingDeserializationError] = err.Error()
  136. }
  137. validateAndMap(jsonStruct, ctx, errors, ifacePtr...)
  138. }
  139. }
  140. // Validate is middleware to enforce required fields. If the struct
  141. // passed in is a Validator, then the user-defined Validate method
  142. // is executed, and its errors are mapped to the context. This middleware
  143. // performs no error handling: it merely detects them and maps them.
  144. func Validate(obj interface{}) macaron.Handler {
  145. return func(ctx *macaron.Context, l i18n.Locale) {
  146. errors := newErrors()
  147. validateStruct(errors, obj)
  148. if validator, ok := obj.(Validator); ok {
  149. validator.Validate(ctx, errors, l)
  150. }
  151. ctx.Map(*errors)
  152. }
  153. }
  154. var (
  155. alphaDashPattern = regexp.MustCompile("[^\\d\\w-_]")
  156. alphaDashDotPattern = regexp.MustCompile("[^\\d\\w-_\\.]")
  157. emailPattern = regexp.MustCompile("[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[a-zA-Z0-9](?:[\\w-]*[\\w])?")
  158. urlPattern = regexp.MustCompile(`(http|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?`)
  159. )
  160. func validateStruct(errors *Errors, obj interface{}) {
  161. typ := reflect.TypeOf(obj)
  162. val := reflect.ValueOf(obj)
  163. if typ.Kind() == reflect.Ptr {
  164. typ = typ.Elem()
  165. val = val.Elem()
  166. }
  167. for i := 0; i < typ.NumField(); i++ {
  168. field := typ.Field(i)
  169. // Allow ignored fields in the struct
  170. if field.Tag.Get("form") == "-" {
  171. continue
  172. }
  173. fieldValue := val.Field(i).Interface()
  174. if field.Type.Kind() == reflect.Struct {
  175. validateStruct(errors, fieldValue)
  176. continue
  177. }
  178. zero := reflect.Zero(field.Type).Interface()
  179. // Match rules.
  180. for _, rule := range strings.Split(field.Tag.Get("binding"), ";") {
  181. if len(rule) == 0 {
  182. continue
  183. }
  184. switch {
  185. case rule == "Required":
  186. if reflect.DeepEqual(zero, fieldValue) {
  187. errors.Fields[field.Name] = BindingRequireError
  188. break
  189. }
  190. case rule == "AlphaDash":
  191. if alphaDashPattern.MatchString(fmt.Sprintf("%v", fieldValue)) {
  192. errors.Fields[field.Name] = BindingAlphaDashError
  193. break
  194. }
  195. case rule == "AlphaDashDot":
  196. if alphaDashDotPattern.MatchString(fmt.Sprintf("%v", fieldValue)) {
  197. errors.Fields[field.Name] = BindingAlphaDashDotError
  198. break
  199. }
  200. case strings.HasPrefix(rule, "MinSize("):
  201. min, err := strconv.Atoi(rule[8 : len(rule)-1])
  202. if err != nil {
  203. errors.Overall["MinSize"] = err.Error()
  204. break
  205. }
  206. if str, ok := fieldValue.(string); ok && utf8.RuneCountInString(str) < min {
  207. errors.Fields[field.Name] = BindingMinSizeError
  208. break
  209. }
  210. v := reflect.ValueOf(fieldValue)
  211. if v.Kind() == reflect.Slice && v.Len() < min {
  212. errors.Fields[field.Name] = BindingMinSizeError
  213. break
  214. }
  215. case strings.HasPrefix(rule, "MaxSize("):
  216. max, err := strconv.Atoi(rule[8 : len(rule)-1])
  217. if err != nil {
  218. errors.Overall["MaxSize"] = err.Error()
  219. break
  220. }
  221. if str, ok := fieldValue.(string); ok && utf8.RuneCountInString(str) > max {
  222. errors.Fields[field.Name] = BindingMaxSizeError
  223. break
  224. }
  225. v := reflect.ValueOf(fieldValue)
  226. if v.Kind() == reflect.Slice && v.Len() > max {
  227. errors.Fields[field.Name] = BindingMinSizeError
  228. break
  229. }
  230. case rule == "Email":
  231. if !emailPattern.MatchString(fmt.Sprintf("%v", fieldValue)) {
  232. errors.Fields[field.Name] = BindingEmailError
  233. break
  234. }
  235. case rule == "Url":
  236. str := fmt.Sprintf("%v", fieldValue)
  237. if len(str) == 0 {
  238. continue
  239. } else if !urlPattern.MatchString(str) {
  240. errors.Fields[field.Name] = BindingUrlError
  241. break
  242. }
  243. }
  244. }
  245. }
  246. }
  247. func mapForm(formStruct reflect.Value, form map[string][]string, errors *Errors) {
  248. typ := formStruct.Elem().Type()
  249. for i := 0; i < typ.NumField(); i++ {
  250. typeField := typ.Field(i)
  251. if inputFieldName := typeField.Tag.Get("form"); inputFieldName != "" {
  252. structField := formStruct.Elem().Field(i)
  253. if !structField.CanSet() {
  254. continue
  255. }
  256. inputValue, exists := form[inputFieldName]
  257. if !exists {
  258. continue
  259. }
  260. numElems := len(inputValue)
  261. if structField.Kind() == reflect.Slice && numElems > 0 {
  262. sliceOf := structField.Type().Elem().Kind()
  263. slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
  264. for i := 0; i < numElems; i++ {
  265. setWithProperType(sliceOf, inputValue[i], slice.Index(i), inputFieldName, errors)
  266. }
  267. formStruct.Elem().Field(i).Set(slice)
  268. } else {
  269. setWithProperType(typeField.Type.Kind(), inputValue[0], structField, inputFieldName, errors)
  270. }
  271. }
  272. }
  273. }
  274. // ErrorHandler simply counts the number of errors in the
  275. // context and, if more than 0, writes a 400 Bad Request
  276. // response and a JSON payload describing the errors with
  277. // the "Content-Type" set to "application/json".
  278. // Middleware remaining on the stack will not even see the request
  279. // if, by this point, there are any errors.
  280. // This is a "default" handler, of sorts, and you are
  281. // welcome to use your own instead. The Bind middleware
  282. // invokes this automatically for convenience.
  283. func ErrorHandler(errs Errors, resp http.ResponseWriter) {
  284. if errs.Count() > 0 {
  285. resp.Header().Set("Content-Type", "application/json; charset=utf-8")
  286. if _, ok := errs.Overall[BindingDeserializationError]; ok {
  287. resp.WriteHeader(http.StatusBadRequest)
  288. } else {
  289. resp.WriteHeader(422)
  290. }
  291. errOutput, _ := json.Marshal(errs)
  292. resp.Write(errOutput)
  293. return
  294. }
  295. }
  296. // This sets the value in a struct of an indeterminate type to the
  297. // matching value from the request (via Form middleware) in the
  298. // same type, so that not all deserialized values have to be strings.
  299. // Supported types are string, int, float, and bool.
  300. func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value, nameInTag string, errors *Errors) {
  301. switch valueKind {
  302. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  303. if val == "" {
  304. val = "0"
  305. }
  306. intVal, err := strconv.ParseInt(val, 10, 64)
  307. if err != nil {
  308. errors.Fields[nameInTag] = BindingIntegerTypeError
  309. } else {
  310. structField.SetInt(intVal)
  311. }
  312. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  313. if val == "" {
  314. val = "0"
  315. }
  316. uintVal, err := strconv.ParseUint(val, 10, 64)
  317. if err != nil {
  318. errors.Fields[nameInTag] = BindingIntegerTypeError
  319. } else {
  320. structField.SetUint(uintVal)
  321. }
  322. case reflect.Bool:
  323. structField.SetBool(val == "on")
  324. case reflect.Float32:
  325. if val == "" {
  326. val = "0.0"
  327. }
  328. floatVal, err := strconv.ParseFloat(val, 32)
  329. if err != nil {
  330. errors.Fields[nameInTag] = BindingFloatTypeError
  331. } else {
  332. structField.SetFloat(floatVal)
  333. }
  334. case reflect.Float64:
  335. if val == "" {
  336. val = "0.0"
  337. }
  338. floatVal, err := strconv.ParseFloat(val, 64)
  339. if err != nil {
  340. errors.Fields[nameInTag] = BindingFloatTypeError
  341. } else {
  342. structField.SetFloat(floatVal)
  343. }
  344. case reflect.String:
  345. structField.SetString(val)
  346. }
  347. }
  348. // Don't pass in pointers to bind to. Can lead to bugs.
  349. func ensureNotPointer(obj interface{}) {
  350. if reflect.TypeOf(obj).Kind() == reflect.Ptr {
  351. panic("Pointers are not accepted as binding models")
  352. }
  353. }
  354. // Performs validation and combines errors from validation
  355. // with errors from deserialization, then maps both the
  356. // resulting struct and the errors to the context.
  357. func validateAndMap(obj reflect.Value, ctx *macaron.Context, errors *Errors, ifacePtr ...interface{}) {
  358. ctx.Invoke(Validate(obj.Interface()))
  359. errors.Combine(getErrors(ctx))
  360. ctx.Map(*errors)
  361. ctx.Map(obj.Elem().Interface())
  362. if len(ifacePtr) > 0 {
  363. ctx.MapTo(obj.Elem().Interface(), ifacePtr[0])
  364. }
  365. }
  366. func newErrors() *Errors {
  367. return &Errors{make(map[string]string), make(map[string]string)}
  368. }
  369. func getErrors(ctx *macaron.Context) Errors {
  370. return ctx.GetVal(reflect.TypeOf(Errors{})).Interface().(Errors)
  371. }
  372. type (
  373. // Implement the Validator interface to define your own input
  374. // validation before the request even gets to your application.
  375. // The Validate method will be executed during the validation phase.
  376. Validator interface {
  377. Validate(*macaron.Context, *Errors, i18n.Locale)
  378. }
  379. )
  380. var (
  381. // Maximum amount of memory to use when parsing a multipart form.
  382. // Set this to whatever value you prefer; default is 10 MB.
  383. MaxMemory = int64(1024 * 1024 * 10)
  384. )
  385. // Errors represents the contract of the response body when the
  386. // binding step fails before getting to the application.
  387. type Errors struct {
  388. Overall map[string]string `json:"overall"`
  389. Fields map[string]string `json:"fields"`
  390. }
  391. // Total errors is the sum of errors with the request overall
  392. // and errors on individual fields.
  393. func (err Errors) Count() int {
  394. return len(err.Overall) + len(err.Fields)
  395. }
  396. func (this *Errors) Combine(other Errors) {
  397. for key, val := range other.Fields {
  398. if _, exists := this.Fields[key]; !exists {
  399. this.Fields[key] = val
  400. }
  401. }
  402. for key, val := range other.Overall {
  403. if _, exists := this.Overall[key]; !exists {
  404. this.Overall[key] = val
  405. }
  406. }
  407. }
  408. const (
  409. BindingRequireError string = "Required"
  410. BindingAlphaDashError string = "AlphaDash"
  411. BindingAlphaDashDotError string = "AlphaDashDot"
  412. BindingMinSizeError string = "MinSize"
  413. BindingMaxSizeError string = "MaxSize"
  414. BindingEmailError string = "Email"
  415. BindingUrlError string = "Url"
  416. BindingDeserializationError string = "DeserializationError"
  417. BindingIntegerTypeError string = "IntegerTypeError"
  418. BindingBooleanTypeError string = "BooleanTypeError"
  419. BindingFloatTypeError string = "FloatTypeError"
  420. )