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 = &paramInfo{
    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  }