github.com/bytedance/go-tagexpr/v2@v2.9.8/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/v2" 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, hasDefaultVal, 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 case default_val: 72 r.hasDefaultVal = r.hasDefaultVal || v 73 } 74 } 75 76 func (r *receiver) getParam(fieldSelector string) *paramInfo { 77 for _, p := range r.params { 78 if p.fieldSelector == fieldSelector { 79 return p 80 } 81 } 82 return nil 83 } 84 85 func (r *receiver) getOrAddParam(fh *tagexpr.FieldHandler, bindErrFactory func(failField, msg string) error) *paramInfo { 86 fieldSelector := fh.StringSelector() 87 p := r.getParam(fieldSelector) 88 if p != nil { 89 return p 90 } 91 p = ¶mInfo{ 92 fieldSelector: fieldSelector, 93 structField: fh.StructField(), 94 omitIns: make(map[in]bool, maxIn), 95 bindErrFactory: bindErrFactory, 96 looseZeroMode: r.looseZeroMode, 97 } 98 r.params = append(r.params, p) 99 return p 100 } 101 102 func (r *receiver) getBodyInfo(req Request) (codec, []byte, error) { 103 if r.hasBody { 104 c := getBodyCodec(req) 105 b, err := req.GetBody() 106 return c, b, err 107 } 108 return bodyUnsupport, nil, nil 109 } 110 111 func (b *Binding) prebindBody(pointer interface{}, val reflect.Value, bodyCodec codec, bodyBytes []byte) error { 112 switch bodyCodec { 113 case bodyJSON: 114 return b.bindJSON(pointer, bodyBytes) 115 case bodyProtobuf: 116 return bindProtobuf(pointer, bodyBytes) 117 default: 118 return nil 119 } 120 } 121 122 const ( 123 defaultMaxMemory = 32 << 20 // 32 MB 124 ) 125 126 func (r *receiver) getQuery(req Request) url.Values { 127 if r.hasQuery { 128 return req.GetQuery() 129 } 130 return nil 131 } 132 133 func (r *receiver) getCookies(req Request) []*http.Cookie { 134 if r.hasCookie { 135 return req.GetCookies() 136 } 137 return nil 138 } 139 140 func (r *receiver) initParams() { 141 names := make(map[string][maxIn]string, len(r.params)) 142 for _, p := range r.params { 143 if p.structField.Anonymous { 144 continue 145 } 146 a := [maxIn]string{} 147 for _, paramIn := range allIn { 148 a[paramIn] = p.name(paramIn) 149 } 150 names[p.fieldSelector] = a 151 } 152 153 for _, p := range r.params { 154 paths, _ := tagexpr.FieldSelector(p.fieldSelector).Split() 155 for _, info := range p.tagInfos { 156 var fs string 157 for _, s := range paths { 158 if fs == "" { 159 fs = s 160 } else { 161 fs = tagexpr.JoinFieldSelector(fs, s) 162 } 163 name := names[fs][info.paramIn] 164 if name != "" { 165 info.namePath += name + "." 166 } 167 } 168 info.namePath = info.namePath + p.name(info.paramIn) 169 info.requiredError = p.bindErrFactory(info.namePath, "missing required parameter") 170 info.typeError = p.bindErrFactory(info.namePath, "parameter type does not match binding data") 171 info.cannotError = p.bindErrFactory(info.namePath, "parameter cannot be bound") 172 info.contentTypeError = p.bindErrFactory(info.namePath, "does not support binding to the content type body") 173 } 174 p.setDefaultVal() 175 } 176 }