martini-contrib / binding

Martini handler for mapping and validating a raw request into a structure.
MIT License
140 stars 47 forks source link

Fix upload array files. #53

Closed ghostiam closed 8 years ago

ghostiam commented 8 years ago

If the fields have the same name and at least one of them is not filled, the files are not uploaded.

example:

package main

import (
    "github.com/go-martini/martini"
    "github.com/martini-contrib/binding"
    "mime/multipart"
    "net/http"
    "encoding/json"
)

type UploadForm struct {
    UploadFiles []*multipart.FileHeader `form:"uploadFiles"`
}

func main() {
    m := martini.Classic()

    m.Get("", func(w http.ResponseWriter, r *http.Request) {
        html := `
<form method="post" enctype="multipart/form-data">
    <input type="file" name="uploadFiles"><br>
        <input type="file" name="uploadFiles"><br>
        <input type="file" name="uploadFiles"><br>
        <input type="file" name="uploadFiles"><br>
        <button type="submit" name="save">Save</button>
</form>
        `

        w.Header().Set("Content-Type", "text/html; charset=UTF-8")
        w.WriteHeader(200)
        w.Write([]byte(html))
    })

    m.Post("", binding.Bind(UploadForm{}), func(r *http.Request, uf UploadForm) string {
        formJson, _ := json.MarshalIndent(r.MultipartForm, "", " ")
        filesJson, _ := json.MarshalIndent(uf, "", " ")

        return string(formJson) + "\n" + string(filesJson)
    })

    m.RunOnAddr(":3001")
}

If we fill in only one field of 4 we get the 3 null and 0 files in the variable "uf", although "r.MultipartForm" all files are available. While we do not fill in all fields 4 "input [type = file]", the files will not be the transmitted through Binding.

The reason for this, filling the data to null when the data bindings of "r.MultipartForm.Value"

Before this fix, we get this (upload file 1 of 4):

// r.MultipartForm
{
 "Value": {
  "save": [
   ""
  ],
  "uploadFiles": [
   "",
   "",
   ""
  ]
 },
 "File": {
  "uploadFiles": [
   {
    "Filename": "main.go",
    "Header": {
     "Content-Disposition": [
      "form-data; name=\"uploadFiles\"; filename=\"main.go\""
     ],
     "Content-Type": [
      "application/octet-stream"
     ]
    }
   }
  ]
 }
}
// UploadForm
{
 "UploadFiles": [ // 3 null
  null,
  null,
  null
 ]
}

After this fix (upload file 1 of 4):

// r.MultipartForm
{
 "Value": {
  "save": [
   ""
  ],
  "uploadFiles": [
   "",
   "",
   ""
  ]
 },
 "File": {
  "uploadFiles": [
   {
    "Filename": "main.go",
    "Header": {
     "Content-Disposition": [
      "form-data; name=\"uploadFiles\"; filename=\"main.go\""
     ],
     "Content-Type": [
      "application/octet-stream"
     ]
    }
   }
  ]
 }
}
// UploadForm
{
 "UploadFiles": [ // Not null, yay!
  {
   "Filename": "main.go",
   "Header": {
    "Content-Disposition": [
     "form-data; name=\"uploadFiles\"; filename=\"main.go\""
    ],
    "Content-Type": [
     "application/octet-stream"
    ]
   }
  }
 ]
}
mholt commented 8 years ago

Thanks!