github.com/bytedance/go-tagexpr@v2.7.5-0.20210114074101-de5b8743ad85+incompatible/binding/receiver.go (about) 1 package binding 2 3 import ( 4 "net/http" 5 "net/url" 6 "reflect" 7 8 "github.com/bytedance/go-tagexpr" 9 ) 10 11 type in uint8 12 13 const ( 14 undefined in = iota 15 path 16 form 17 query 18 cookie 19 header 20 protobuf 21 json 22 raw_body 23 default_val 24 maxIn 25 ) 26 27 var ( 28 allIn = func() []in { 29 a := []in{} 30 for i := undefined + 1; i < maxIn; i++ { 31 a = append(a, i) 32 } 33 return a 34 }() 35 sortedDefaultIn = func() []in { 36 var a []in 37 for i := undefined + 1; i < raw_body; i++ { 38 a = append(a, i) 39 } 40 return a 41 }() 42 ) 43 44 type codec in 45 46 const ( 47 bodyUnsupport = codec(0) 48 bodyForm = codec(form) 49 bodyJSON = codec(json) 50 bodyProtobuf = codec(protobuf) 51 ) 52 53 type receiver struct { 54 hasPath, hasQuery, hasBody, hasCookie, hasVd bool 55 56 params []*paramInfo 57 58 looseZeroMode bool 59 } 60 61 func (r *receiver) assginIn(i in, v bool) { 62 switch i { 63 case path: 64 r.hasPath = r.hasPath || v 65 case query: 66 r.hasQuery = r.hasQuery || v 67 case form, json, protobuf, raw_body: 68 r.hasBody = r.hasBody || v 69 case cookie: 70 r.hasCookie = r.hasCookie || v 71 } 72 } 73 74 func (r *receiver) getParam(fieldSelector string) *paramInfo { 75 for _, p := range r.params { 76 if p.fieldSelector == fieldSelector { 77 return p 78 } 79 } 80 return nil 81 } 82 83 func (r *receiver) getOrAddParam(fh *tagexpr.FieldHandler, bindErrFactory func(failField, msg string) error) *paramInfo { 84 fieldSelector := fh.StringSelector() 85 p := r.getParam(fieldSelector) 86 if p != nil { 87 return p 88 } 89 p = ¶mInfo{ 90 fieldSelector: fieldSelector, 91 structField: fh.StructField(), 92 omitIns: make(map[in]bool, maxIn), 93 bindErrFactory: bindErrFactory, 94 looseZeroMode: r.looseZeroMode, 95 } 96 r.params = append(r.params, p) 97 return p 98 } 99 100 func (r *receiver) getBodyInfo(req Request) (codec, []byte, error) { 101 if r.hasBody { 102 c := getBodyCodec(req) 103 b, err := req.GetBody() 104 return c, b, err 105 } 106 return bodyUnsupport, nil, nil 107 } 108 109 func (r *receiver) prebindBody(pointer interface{}, val reflect.Value, bodyCodec codec, bodyBytes []byte) error { 110 switch bodyCodec { 111 case bodyJSON: 112 return bindJSON(pointer, bodyBytes) 113 case bodyProtobuf: 114 return bindProtobuf(pointer, bodyBytes) 115 default: 116 return nil 117 } 118 } 119 120 const ( 121 defaultMaxMemory = 32 << 20 // 32 MB 122 ) 123 124 func (r *receiver) getQuery(req Request) url.Values { 125 if r.hasQuery { 126 return req.GetQuery() 127 } 128 return nil 129 } 130 131 func (r *receiver) getCookies(req Request) []*http.Cookie { 132 if r.hasCookie { 133 return req.GetCookies() 134 } 135 return nil 136 } 137 138 func (r *receiver) initParams() { 139 names := make(map[string][maxIn]string, len(r.params)) 140 for _, p := range r.params { 141 if p.structField.Anonymous { 142 continue 143 } 144 a := [maxIn]string{} 145 for _, paramIn := range allIn { 146 a[paramIn] = p.name(paramIn) 147 } 148 names[p.fieldSelector] = a 149 } 150 151 for _, p := range r.params { 152 paths, _ := tagexpr.FieldSelector(p.fieldSelector).Split() 153 for _, info := range p.tagInfos { 154 var fs string 155 for _, s := range paths { 156 if fs == "" { 157 fs = s 158 } else { 159 fs = tagexpr.JoinFieldSelector(fs, s) 160 } 161 name := names[fs][info.paramIn] 162 if name != "" { 163 info.namePath = name + "." 164 } 165 } 166 info.namePath = info.namePath + p.name(info.paramIn) 167 info.requiredError = p.bindErrFactory(info.namePath, "missing required parameter") 168 info.typeError = p.bindErrFactory(info.namePath, "parameter type does not match binding data") 169 info.cannotError = p.bindErrFactory(info.namePath, "parameter cannot be bound") 170 info.contentTypeError = p.bindErrFactory(info.namePath, "does not support binding to the content type body") 171 } 172 p.setDefaultVal() 173 } 174 }