Search code examples
reactjsgomultipartform-data

Filename stripped of prefix in form data


I am sendind files from js to my golang server:

for (var value of formData.values()) {
   console.log(value);

}
// File {name: 'img/<hash_key>.png', lastModified: 1635043863231, lastModifiedDate: Sat Oct 23 2021 23:51:03 GMT-0300 (Brasilia Standard Time), webkitRelativePath: '', size: 969, …}
// ...

var request = new Request( serverEndpoint, { body: formData, method: "POST", ... })

return fetch(request).then(response => { ... })

In my golang server, I am using the following code to deal with multipart form data from a request to read files

if err := r.ParseMultipartForm(32 << 20); err != nil {
    ...
}

for _, fileHeader := range r.MultipartForm.File["files"] {
    ...
}

I expected to read the files in Go with the same filenames, like img/<hash_key>.png but my server is reading multipart-form to the following struct:

f = {*mime/multipart.Form | 0xc000426090} 
├── Value = {map[string][]string} 
└── File = {map[string][]*mime/multipart.FileHeader} 
    ├── 0 = files -> len:1, cap:1
    │   ├── key = {string} "files"
    │   └── value = {[]*mime/multipart.FileHeader} len:1, cap:1
    │       └── 0 = {*mime/multipart.FileHeader | 0xc000440000} 
    │           ├── Filename = {string} "<hash_key>.png" // notice how FileName is missing 'img/' prefix
    │           └── ...
    └── ...

I am trying to figure out how this is happening and how to prevent this strip prefix as I need this prefix to correctly resolve upload path for my files

Edit:

Closer inspection revealed that my server IS in fact getting the files with the correct name. After calling r.ParseMultipartForm(32 << 20), I get the following in r.Body.src.R.buf:

------WebKitFormBoundary1uanPdXqZeL8IPUH
Content-Disposition: form-data; name="files"; filename="img/upload.svg" 
                                           ---- notice the img/ prefix
Content-Type: image/svg+xml

<svg height="512pt" viewBox= ...

However, in r.MultipartForm.File["files"][0].FileName, it shows as upload.svg


Solution

  • The directory is removed in in Part.FileName():

    // RFC 7578, Section 4.2 requires that if a filename is provided, the
    // directory path information must not be used.
    return filepath.Base(filename)
    

    Workaround Part.FileName() by parsing the content disposition header directly.

    for _, fileHeader := range r.MultipartForm.File["files"] {
        _, params, _ := mime.ParseMediaType(fileHeader.Header.Get("Content-Disposition"))
        filename := params["filename"]
        if filename == "" {
             // TODO: Handle unexpected content disposition 
             // header (missing header, parse error, missing param).
        }