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 }