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