/
receiver.go
137 lines (122 loc) · 2.78 KB
/
receiver.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package binding
import (
"net/http"
"net/url"
"strings"
"github.com/bytedance/go-tagexpr"
)
const (
auto uint8 = iota
query
path
header
cookie
body
raw_body
)
const (
unsupportBody uint8 = iota
jsonBody
formBody
)
type receiver struct {
hasAuto, hasQuery, hasCookie, hasPath, hasBody, hasRawBody, hasVd bool
params []*paramInfo
}
func (r *receiver) getParam(fieldSelector string) *paramInfo {
for _, p := range r.params {
if p.fieldSelector == fieldSelector {
return p
}
}
return nil
}
func (r *receiver) getOrAddParam(fh *tagexpr.FieldHandler, bindErrFactory func(failField, msg string) error) *paramInfo {
fieldSelector := fh.StringSelector()
p := r.getParam(fieldSelector)
if p != nil {
return p
}
p = new(paramInfo)
p.fieldSelector = fieldSelector
p.structField = fh.StructField()
p.bindErrFactory = bindErrFactory
r.params = append(r.params, p)
return p
}
func (r *receiver) getBodyCodec(req *http.Request) uint8 {
ct := req.Header.Get("Content-Type")
idx := strings.Index(ct, ";")
if idx != -1 {
ct = strings.TrimRight(ct[:idx], " ")
}
switch ct {
case "application/json":
return jsonBody
case "application/x-www-form-urlencoded", "multipart/form-data":
return formBody
default:
return unsupportBody
}
}
func (r *receiver) getBodyBytes(req *http.Request, must bool) ([]byte, error) {
if must || r.hasRawBody {
return copyBody(req)
}
return nil, nil
}
const (
defaultMaxMemory = 32 << 20 // 32 MB
)
func (r *receiver) getPostForm(req *http.Request, must bool) (url.Values, error) {
if must {
if req.PostForm == nil {
req.ParseMultipartForm(defaultMaxMemory)
}
return req.Form, nil
}
return nil, nil
}
func (r *receiver) getQuery(req *http.Request) url.Values {
if r.hasQuery {
return req.URL.Query()
}
return nil
}
func (r *receiver) getCookies(req *http.Request) []*http.Cookie {
if r.hasCookie {
return req.Cookies()
}
return nil
}
func (r *receiver) initParams() {
if !r.hasBody {
return
}
names := make(map[string]string, len(r.params))
for _, p := range r.params {
if !p.structField.Anonymous {
names[p.fieldSelector] = p.name
}
}
for _, p := range r.params {
paths, _ := tagexpr.FieldSelector(p.fieldSelector).Split()
var fs, namePath string
for _, s := range paths {
if fs == "" {
fs = s
} else {
fs = tagexpr.JoinFieldSelector(fs, s)
}
name := names[fs]
if name != "" {
namePath = name + "."
}
}
p.namePath = namePath + p.name
p.requiredError = p.bindErrFactory(p.namePath, "missing required parameter")
p.typeError = p.bindErrFactory(p.namePath, "parameter type does not match binding data")
p.cannotError = p.bindErrFactory(p.namePath, "parameter cannot be bound")
p.contentTypeError = p.bindErrFactory(p.namePath, "does not support binding to the content type body")
}
}