requests.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. package httpx
  2. import (
  3. "errors"
  4. "io"
  5. "net/http"
  6. "strings"
  7. "zero/core/httprouter"
  8. "zero/core/mapping"
  9. )
  10. const (
  11. multipartFormData = "multipart/form-data"
  12. xForwardFor = "X-Forward-For"
  13. formKey = "form"
  14. pathKey = "path"
  15. emptyJson = "{}"
  16. maxMemory = 32 << 20 // 32MB
  17. maxBodyLen = 8 << 20 // 8MB
  18. separator = ";"
  19. tokensInAttribute = 2
  20. )
  21. var (
  22. ErrBodylessRequest = errors.New("not a POST|PUT|PATCH request")
  23. formUnmarshaler = mapping.NewUnmarshaler(formKey, mapping.WithStringValues())
  24. pathUnmarshaler = mapping.NewUnmarshaler(pathKey, mapping.WithStringValues())
  25. )
  26. // Returns the peer address, supports X-Forward-For
  27. func GetRemoteAddr(r *http.Request) string {
  28. v := r.Header.Get(xForwardFor)
  29. if len(v) > 0 {
  30. return v
  31. }
  32. return r.RemoteAddr
  33. }
  34. func Parse(r *http.Request, v interface{}) error {
  35. if err := ParsePath(r, v); err != nil {
  36. return err
  37. }
  38. if err := ParseForm(r, v); err != nil {
  39. return err
  40. }
  41. return ParseJsonBody(r, v)
  42. }
  43. // Parses the form request.
  44. func ParseForm(r *http.Request, v interface{}) error {
  45. if strings.Index(r.Header.Get(ContentType), multipartFormData) != -1 {
  46. if err := r.ParseMultipartForm(maxMemory); err != nil {
  47. return err
  48. }
  49. } else {
  50. if err := r.ParseForm(); err != nil {
  51. return err
  52. }
  53. }
  54. params := make(map[string]interface{}, len(r.Form))
  55. for name := range r.Form {
  56. formValue := r.Form.Get(name)
  57. if len(formValue) > 0 {
  58. params[name] = formValue
  59. }
  60. }
  61. return formUnmarshaler.Unmarshal(params, v)
  62. }
  63. func ParseHeader(headerValue string) map[string]string {
  64. ret := make(map[string]string)
  65. fields := strings.Split(headerValue, separator)
  66. for _, field := range fields {
  67. field = strings.TrimSpace(field)
  68. if len(field) == 0 {
  69. continue
  70. }
  71. kv := strings.SplitN(field, "=", tokensInAttribute)
  72. if len(kv) != tokensInAttribute {
  73. continue
  74. }
  75. ret[kv[0]] = kv[1]
  76. }
  77. return ret
  78. }
  79. // Parses the post request which contains json in body.
  80. func ParseJsonBody(r *http.Request, v interface{}) error {
  81. var reader io.Reader
  82. if withJsonBody(r) {
  83. reader = io.LimitReader(r.Body, maxBodyLen)
  84. } else {
  85. reader = strings.NewReader(emptyJson)
  86. }
  87. return mapping.UnmarshalJsonReader(reader, v)
  88. }
  89. // Parses the symbols reside in url path.
  90. // Like http://localhost/bag/:name
  91. func ParsePath(r *http.Request, v interface{}) error {
  92. vars := httprouter.Vars(r)
  93. m := make(map[string]interface{}, len(vars))
  94. for k, v := range vars {
  95. m[k] = v
  96. }
  97. return pathUnmarshaler.Unmarshal(m, v)
  98. }
  99. func withJsonBody(r *http.Request) bool {
  100. return r.ContentLength > 0 && strings.Index(r.Header.Get(ContentType), ApplicationJson) != -1
  101. }