Skip to content
This repository has been archived by the owner on Nov 19, 2018. It is now read-only.

Multipart form data not working on Firefox #90

Open
ciasaboark opened this issue Mar 28, 2017 · 5 comments
Open

Multipart form data not working on Firefox #90

ciasaboark opened this issue Mar 28, 2017 · 5 comments

Comments

@ciasaboark
Copy link

I have not been able to get ajax-form to play nice with Firefox when uploading files as multipart/form-data encoding. Uploads work just fine in Chrome and Safari.

I am using ajax-form version 2.1.4 within a Polymer project (v1.8.1) using webcomponents-lite polyfil (0.7.24).

When the data comes to the backend (Java servlet using Jersey) the fileDetail has null values and the entire contents of the InputStream will be file filename string value. On Chrome and Safari the filename is attached to the fileDetail, and the InputStream is the contents of the file (like it should be).

The html is just a basic ajax-form using elements.

<form id="form" is="ajax-form" action="/api/locations/generate_case_caps" method="post"
                  enctype="multipart/form-data">
                <div class="layout horizontal wrap">
                    <paper-input id="fileInput" label="Select .csv flow report" type="file"
                                 required auto-validate error-message="Please select a file" name="file"
                                 accepts="text/csv,text/plain" on-change="_validateFile" size="50">
                    </paper-input>

                    <paper-input label="How many inches vertical padding to leave" type="number"
                                 name="vert-padding" placeholder="1"></paper-input>

                    <paper-input label="Max vertical stacking" type="number" name="max-stack"
                                 placeholder="3"></paper-input>
***snip***

The javascript attached to the form is not doing any pre-processing on the upload, just watching for a response

form.addEventListener('submitting', function (event) {
                    that.submitActive = true;
                    that._reportResponse = null;
                    that.fileGenerated = false;
                    that.fileId = "";
                    that.fileName = "";
                    that.message = "";
                    that.err = "";
                    that.$.errorbox.opened = false;
                });

                form.addEventListener('submitted', function (event) {
                    that.submitActive = false;
                    if (event.detail.status > 299) {
                        //if we received a 400 level error during submission then we won't have a JSON
                        //+ response to work with, just show the raw response
                        if (event.detail.status > 399) {
                            that.message = "Error generating case cap file";
                            that.err = event.detail.response;
                        } else {
                            //otherwise we should have some JSON to work with to give a better error message
                            var response = JSON.parse(event.detail.response);
                            that._reportResponse = response;
                            that.message = response.message;
                            that.err = response.err;
                        }
                        that.$.errorbox.opened = true;
                    } else {
                        var response = JSON.parse(event.detail.response);
                        that._reportResponse = response;
                        that.fileGenerated = response.fileGenerated;
                        that.fileId = response.fileId;
                        that.fileName = response.fileName;
                    }
                });

The backend java code is pretty simple as well.

@POST
    @Path("generate_case_caps")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @Produces(MediaType.APPLICATION_JSON)
    public Response generateCaseCaps(@FormDataParam("file") InputStream uploadedInputStream,
                                     @FormDataParam("file") FormDataContentDisposition fileDetail,
                                     @FormDataParam("vert-padding") Integer vertPadding,
                                     @FormDataParam("max-stack") Integer maxStack,
                                     @FormDataParam("depth-remain-percent") Integer depthRemainInt,
                                     @FormDataParam("only-changed") Boolean onlyShowChanged,
                                     @FormDataParam("file-type") Integer fileType,
                                     @FormDataParam("extra-columns") Boolean extraColumns,
                                     @FormDataParam("highlight") Boolean highlight) {

When using firefox the backend will receive data that looks something like this. The content of the input stream will just be the string Case Cap Report v1.1.csv (the file name), not the content of the file. The file detail does not contain the filename.

uploadedInputStream = {DataHead$ReadMultiStream@7016} 
 current = {Chunk@7023} 
 offset = 0
 len = 24
 buf = {byte[9255]@7024} 
 closed = false
 this$0 = {DataHead@7025} 
 MAX_SKIP_BUFFER_SIZE = 2048

fileDetail = {FormDataContentDisposition@7017} "form-data; name="file""
 name = "file"
 type = "form-data"
 parameters = {Collections$UnmodifiableMap@7028}  size = 1
 fileName = null
 creationDate = null
 modificationDate = null
 readDate = null
 size = -1

When using Chrome or Safari the filename is attached to the fileDetail correctly and the input stream has the contents of the file.

uploadedInputStream = {DataHead$ReadMultiStream@7031} 
 current = {Chunk@7040} 
 offset = 0
 len = 8192
 buf = {byte[8192]@7041} 
 closed = false
 this$0 = {DataHead@7042} 
 MAX_SKIP_BUFFER_SIZE = 2048

fileDetail = {FormDataContentDisposition@7032} "form-data; filename="Case Cap Report v1.1.csv"; name="file""
 name = "file"
 type = "form-data"
 parameters = {Collections$UnmodifiableMap@7045}  size = 2
 fileName = "Case Cap Report v1.1.csv"
 creationDate = null
 modificationDate = null
 readDate = null
 size = -1
@rnicholus
Copy link
Owner

what does the request payload look according to the browser's dev tools?

@ciasaboark
Copy link
Author

Firefox request headers:

POST /api/locations/generate_case_caps HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:51.0) Gecko/20100101 Firefox/51.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:8080/
Content-Length: 784
Content-Type: multipart/form-data; boundary=---------------------------55963512519566556621094624723
DNT: 1
Connection: keep-alive

Firefox params:

-----------------------------55963512519566556621094624723
Content-Disposition: form-data; name="file-type"

0
-----------------------------55963512519566556621094624723
Content-Disposition: form-data; name="file"

Case Cap Report v1.1.csv
-----------------------------55963512519566556621094624723
Content-Disposition: form-data; name="file"

[object File]
-----------------------------55963512519566556621094624723
Content-Disposition: form-data; name="vert-padding"


-----------------------------55963512519566556621094624723
Content-Disposition: form-data; name="max-stack"


-----------------------------55963512519566556621094624723
Content-Disposition: form-data; name="only-changed"

true
-----------------------------55963512519566556621094624723--

Chrome (all in one):

General
Request URL:http://localhost:8080/api/locations/generate_case_caps

Request Headers
Provisional headers are shown
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryTXcBOF7iIBAsKAMD
Origin:http://localhost:8080
Referer:http://localhost:8080/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36

Request Payload
------WebKitFormBoundaryTXcBOF7iIBAsKAMD
Content-Disposition: form-data; name="file-type"

0
------WebKitFormBoundaryTXcBOF7iIBAsKAMD
Content-Disposition: form-data; name="file"; filename="Case Cap Report v1.1.csv"
Content-Type: text/csv


------WebKitFormBoundaryTXcBOF7iIBAsKAMD
Content-Disposition: form-data; name="vert-padding"


------WebKitFormBoundaryTXcBOF7iIBAsKAMD
Content-Disposition: form-data; name="max-stack"


------WebKitFormBoundaryTXcBOF7iIBAsKAMD
Content-Disposition: form-data; name="only-changed"

true
------WebKitFormBoundaryTXcBOF7iIBAsKAMD--

@rnicholus
Copy link
Owner

rnicholus commented Mar 28, 2017

Interesting. I'd be curious to know if the underlying FormData object (which is used to construct the MPE request payload based on the form fields) looks the same in Chrome and Firefox. Apologies as I'm not sure when I'll be able to fit in looking at ajax-form code or starting up the codebase to troubleshoot next (as Fine Uploader, React Fine Uploader, along with a number of other professional commitments have higher priorities at the moment) but I'm able to offer guidance in the near-term.

@ciasaboark
Copy link
Author

No worries.

I haven't found a great way to get this data out of the devtools as JSON, but you can see the event.detail.formData exposed during the submitting event looks different in Chrome and Firefox.

Chrome has a file array with a single entry.
screenshot 2017-03-28 16 17 04

Using Firefox the file is a two dimensional array with two entries. The first array contains the filename, the second contains the file data
screenshot 2017-03-28 16 17 32

I don't do much front end work, but considering Jersey can parse the format used by Chrome I'm assuming that is the correct one.

If need be I'll try manually building the file parts of formData in the event listener.

@rnicholus
Copy link
Owner

Using Firefox the file is a two dimensional array with two entries.

That definitely seems like the issue. Not sure when or how this happened. Sounds like a browser-specific bug in ajax-form. Setting breakpoints in the code when FormData is constructed may shine more light on the exact cause.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants