You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
go-zero/rest/httpx/requests.go

121 lines
2.5 KiB
Go

package httpx
import (
"io"
"net/http"
"strings"
"github.com/tal-tech/go-zero/core/mapping"
"github.com/tal-tech/go-zero/rest/internal/context"
)
const (
multipartFormData = "multipart/form-data"
formKey = "form"
pathKey = "path"
emptyJson = "{}"
maxMemory = 32 << 20 // 32MB
maxBodyLen = 8 << 20 // 8MB
separator = ";"
tokensInAttribute = 2
)
var (
formUnmarshaler = mapping.NewUnmarshaler(formKey, mapping.WithStringValues())
pathUnmarshaler = mapping.NewUnmarshaler(pathKey, mapping.WithStringValues())
)
func Parse(r *http.Request, v interface{}) error {
if err := ParsePath(r, v); err != nil {
return err
}
if err := ParseForm(r, v); err != nil {
return err
}
if r.ContentLength > 0 {
return ParseJsonBody(r, v)
}
return nil
}
// Parses the form request.
func ParseForm(r *http.Request, v interface{}) error {
if strings.Contains(r.Header.Get(ContentType), multipartFormData) {
if err := r.ParseMultipartForm(maxMemory); err != nil {
return err
}
} else {
if err := r.ParseForm(); err != nil {
return err
}
}
params := make(map[string]interface{}, len(r.Form))
for name := range r.Form {
formValue := r.Form.Get(name)
if len(formValue) > 0 {
params[name] = formValue
}
}
return formUnmarshaler.Unmarshal(params, v)
}
func ParseHeader(headerValue string) map[string]string {
ret := make(map[string]string)
fields := strings.Split(headerValue, separator)
for _, field := range fields {
field = strings.TrimSpace(field)
if len(field) == 0 {
continue
}
kv := strings.SplitN(field, "=", tokensInAttribute)
if len(kv) != tokensInAttribute {
continue
}
ret[kv[0]] = kv[1]
}
return ret
}
// Parses the post request which contains json in body.
func ParseJsonBody(r *http.Request, v interface{}) error {
switch r.Method {
case http.MethodDelete, http.MethodPatch, http.MethodPost, http.MethodPut:
default:
return ErrBodylessRequest
}
var reader io.Reader
if withJsonBody(r) {
reader = io.LimitReader(r.Body, maxBodyLen)
} else {
reader = strings.NewReader(emptyJson)
}
return mapping.UnmarshalJsonReader(reader, v)
}
// Parses the symbols reside in url path.
// Like http://localhost/bag/:name
func ParsePath(r *http.Request, v interface{}) error {
vars := context.Vars(r)
m := make(map[string]interface{}, len(vars))
for k, v := range vars {
m[k] = v
}
return pathUnmarshaler.Unmarshal(m, v)
}
func withJsonBody(r *http.Request) bool {
return r.ContentLength > 0 && strings.Contains(r.Header.Get(ContentType), ApplicationJson)
}