github.com/wfusion/gofusion@v1.1.14/http/parser/multipart_formdata.go (about)

     1  package parser
     2  
     3  import (
     4  	"io"
     5  	"io/ioutil"
     6  	"mime/multipart"
     7  	"reflect"
     8  
     9  	"github.com/spf13/cast"
    10  
    11  	"github.com/wfusion/gofusion/common/utils"
    12  	"github.com/wfusion/gofusion/common/utils/serialize/json"
    13  )
    14  
    15  const (
    16  	keyBoundary = "boundary"
    17  )
    18  
    19  var (
    20  	byteSliceType = reflect.TypeOf(([]byte)(nil))
    21  )
    22  
    23  type MultipartFormDataParser struct {
    24  	boundary string
    25  }
    26  
    27  func (m *MultipartFormDataParser) PreParse(args map[string]string) error {
    28  	boundary, ok := args[keyBoundary]
    29  	if !ok {
    30  		return malformedRequest("missing boundary in multipart/form-data")
    31  	}
    32  	m.boundary = boundary
    33  	return nil
    34  }
    35  
    36  func (m *MultipartFormDataParser) Parse(src io.Reader, dst reflect.Value) (err error) {
    37  	for dst.Kind() == reflect.Ptr {
    38  		dst.Set(reflect.New(dst.Type().Elem()))
    39  		dst = dst.Elem()
    40  	}
    41  
    42  	var (
    43  		part   *multipart.Part
    44  		body   []byte
    45  		dt     = reflect.TypeOf(dst.Interface())
    46  		reader = multipart.NewReader(src, m.boundary)
    47  	)
    48  	defer func() {
    49  		if part != nil {
    50  			utils.CloseAnyway(part)
    51  		}
    52  	}()
    53  
    54  	for {
    55  		part, err = reader.NextPart()
    56  		if err != nil {
    57  			if err == io.EOF {
    58  				err = nil
    59  			}
    60  			break
    61  		}
    62  
    63  		k := part.FormName()
    64  		fNum := m.lookupFieldByTag(dt, k, "json")
    65  		if fNum == -1 {
    66  			continue
    67  		}
    68  		fv := dst.Field(fNum)
    69  		if !fv.IsValid() || !fv.CanSet() {
    70  			continue
    71  		}
    72  
    73  		// transform
    74  		if body, err = ioutil.ReadAll(part); err != nil {
    75  			break
    76  		} else if err = m.transformField(fv, body); err != nil {
    77  			break
    78  		} else if err = part.Close(); err != nil {
    79  			break
    80  		}
    81  	}
    82  
    83  	return
    84  }
    85  
    86  func (m *MultipartFormDataParser) lookupFieldByTag(t reflect.Type, key, tag string) (fNum int) {
    87  	n := t.NumField()
    88  	for i := 0; i < n; i++ {
    89  		f := t.Field(i)
    90  		if v, ok := f.Tag.Lookup(tag); ok && v == key {
    91  			return i
    92  		}
    93  	}
    94  	return -1
    95  }
    96  
    97  var (
    98  	castReflectTypeMap = map[reflect.Kind]func(reflect.Value, []byte) error{
    99  		reflect.Bool:    func(f reflect.Value, b []byte) (e error) { v, e := cast.ToBoolE(b); f.SetBool(v); return },
   100  		reflect.String:  func(f reflect.Value, b []byte) (e error) { v, e := cast.ToStringE(b); f.SetString(v); return },
   101  		reflect.Int:     func(f reflect.Value, b []byte) (e error) { v, e := cast.ToInt64E(b); f.SetInt(v); return },
   102  		reflect.Int8:    func(f reflect.Value, b []byte) (e error) { v, e := cast.ToInt64E(b); f.SetInt(v); return },
   103  		reflect.Int16:   func(f reflect.Value, b []byte) (e error) { v, e := cast.ToInt64E(b); f.SetInt(v); return },
   104  		reflect.Int32:   func(f reflect.Value, b []byte) (e error) { v, e := cast.ToInt64E(b); f.SetInt(v); return },
   105  		reflect.Int64:   func(f reflect.Value, b []byte) (e error) { v, e := cast.ToInt64E(b); f.SetInt(v); return },
   106  		reflect.Uint:    func(f reflect.Value, b []byte) (e error) { v, e := cast.ToUint64E(b); f.SetUint(v); return },
   107  		reflect.Uint8:   func(f reflect.Value, b []byte) (e error) { v, e := cast.ToUint64E(b); f.SetUint(v); return },
   108  		reflect.Uint16:  func(f reflect.Value, b []byte) (e error) { v, e := cast.ToUint64E(b); f.SetUint(v); return },
   109  		reflect.Uint32:  func(f reflect.Value, b []byte) (e error) { v, e := cast.ToUint64E(b); f.SetUint(v); return },
   110  		reflect.Uint64:  func(f reflect.Value, b []byte) (e error) { v, e := cast.ToUint64E(b); f.SetUint(v); return },
   111  		reflect.Float32: func(f reflect.Value, b []byte) (e error) { v, e := cast.ToFloat64E(b); f.SetFloat(v); return },
   112  		reflect.Float64: func(f reflect.Value, b []byte) (e error) { v, e := cast.ToFloat64E(b); f.SetFloat(v); return },
   113  	}
   114  )
   115  
   116  func (m *MultipartFormDataParser) transformField(f reflect.Value, param []byte) (err error) {
   117  	ft := f.Type()
   118  	if ft.Kind() == reflect.Ptr {
   119  		ft = ft.Elem()
   120  		if f.IsNil() {
   121  			f.Set(reflect.New(ft))
   122  		}
   123  		f = f.Elem()
   124  	}
   125  
   126  	if byteSliceType.ConvertibleTo(ft) {
   127  		f.Set(reflect.ValueOf(param).Convert(ft))
   128  		return
   129  	}
   130  
   131  	caster, ok := castReflectTypeMap[ft.Kind()]
   132  	if !ok {
   133  		return json.Unmarshal(param, f.Addr().Interface())
   134  	}
   135  
   136  	return caster(f, param)
   137  }