|
8 | 8 | "encoding/xml" |
9 | 9 | "errors" |
10 | 10 | "fmt" |
| 11 | + "mime/multipart" |
11 | 12 | "net/http" |
12 | 13 | "reflect" |
13 | 14 | "strconv" |
@@ -90,14 +91,22 @@ func (b *DefaultBinder) BindBody(c Context, i interface{}) (err error) { |
90 | 91 | } |
91 | 92 | return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err) |
92 | 93 | } |
93 | | - case strings.HasPrefix(ctype, MIMEApplicationForm), strings.HasPrefix(ctype, MIMEMultipartForm): |
| 94 | + case strings.HasPrefix(ctype, MIMEApplicationForm): |
94 | 95 | params, err := c.FormParams() |
95 | 96 | if err != nil { |
96 | 97 | return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err) |
97 | 98 | } |
98 | 99 | if err = b.bindData(i, params, "form"); err != nil { |
99 | 100 | return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err) |
100 | 101 | } |
| 102 | + case strings.HasPrefix(ctype, MIMEMultipartForm): |
| 103 | + params, err := c.MultipartForm() |
| 104 | + if err != nil { |
| 105 | + return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err) |
| 106 | + } |
| 107 | + if err = b.bindData(i, params.Value, "form", params.File); err != nil { |
| 108 | + return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err) |
| 109 | + } |
101 | 110 | default: |
102 | 111 | return ErrUnsupportedMediaType |
103 | 112 | } |
@@ -132,8 +141,8 @@ func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) { |
132 | 141 | } |
133 | 142 |
|
134 | 143 | // bindData will bind data ONLY fields in destination struct that have EXPLICIT tag |
135 | | -func (b *DefaultBinder) bindData(destination interface{}, data map[string][]string, tag string) error { |
136 | | - if destination == nil || len(data) == 0 { |
| 144 | +func (b *DefaultBinder) bindData(destination interface{}, data map[string][]string, tag string, files ...map[string][]*multipart.FileHeader) error { |
| 145 | + if destination == nil || (len(data) == 0 && len(files) == 0) { |
137 | 146 | return nil |
138 | 147 | } |
139 | 148 | typ := reflect.TypeOf(destination).Elem() |
@@ -209,6 +218,37 @@ func (b *DefaultBinder) bindData(destination interface{}, data map[string][]stri |
209 | 218 | continue |
210 | 219 | } |
211 | 220 |
|
| 221 | + // Handle multiple file uploads ([]*multipart.FileHeader, *multipart.FileHeader, []multipart.FileHeader) |
| 222 | + if len(files) > 0 { |
| 223 | + for _, fileMap := range files { |
| 224 | + fileHeaders, exists := fileMap[inputFieldName] |
| 225 | + if exists { |
| 226 | + if structField.Type() == reflect.TypeOf([]*multipart.FileHeader(nil)) { |
| 227 | + structField.Set(reflect.ValueOf(fileHeaders)) |
| 228 | + continue |
| 229 | + } else if structField.Type() == reflect.TypeOf([]multipart.FileHeader(nil)) { |
| 230 | + var headers []multipart.FileHeader |
| 231 | + for _, fileHeader := range fileHeaders { |
| 232 | + headers = append(headers, *fileHeader) |
| 233 | + } |
| 234 | + structField.Set(reflect.ValueOf(headers)) |
| 235 | + continue |
| 236 | + } else if structField.Type() == reflect.TypeOf(&multipart.FileHeader{}) { |
| 237 | + |
| 238 | + if len(fileHeaders) > 0 { |
| 239 | + structField.Set(reflect.ValueOf(fileHeaders[0])) |
| 240 | + } |
| 241 | + continue |
| 242 | + } else if structField.Type() == reflect.TypeOf(multipart.FileHeader{}) { |
| 243 | + if len(fileHeaders) > 0 { |
| 244 | + structField.Set(reflect.ValueOf(*fileHeaders[0])) |
| 245 | + } |
| 246 | + continue |
| 247 | + } |
| 248 | + } |
| 249 | + } |
| 250 | + } |
| 251 | + |
212 | 252 | inputValue, exists := data[inputFieldName] |
213 | 253 | if !exists { |
214 | 254 | // Go json.Unmarshal supports case insensitive binding. However the |
|
0 commit comments