0

I try to send a multipart form data with a file by using only javascript. I write the request myself. So my javascript code is the following :

var data =
    '------------f8n51w2QYCsvNftihodgfJ\n' +
    'Content-Disposition: form-data; name="upload-id"\n' +
    '\n' +
    'uploadedFiles\n' +
    '------------f8n51w2QYCsvNftihodgfJ\n' +
    'Content-Disposition: form-data; name="file"; filename="doc1.txt"\n' +
    'Content-Type: text/plain\n' +
    '\n' +
    'azerty\n' +
    '------------f8n51w2QYCsvNftihodgfJ--\n';

    var xhr = new XMLHttpRequest();
    xhr.open('POST', '/upload');
    xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=----------f8n51w2QYCsvNftihodgfJ');
    xhr.sendAsBinary(data);

I run this javascript on Firefox 18. So i got a servlet on /upload. Here's the code :

protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    RequestContext request_context = new ServletRequestContext(request);
    boolean is_multipart = ServletFileUpload.isMultipartContent(request_context);
    if (is_multipart) {
        FileUpload file_upload = new FileUpload(fileItemFactory);
        List<FileItem> file_items = file_upload.parseRequest(request_context); // This line crash
    }
}

As the comment says, the line file_upload.parseRequest(request_context); crash and throws the following exception :

org.apache.commons.fileupload.MultipartStream$MalformedStreamException: Stream ended unexpectedly
    at org.apache.commons.fileupload.MultipartStream.readHeaders(MultipartStream.java:539)
    at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.findNextItem(FileUploadBase.java:976)
    at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:942)
    at org.apache.commons.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:331)
    at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:349)

And i just don't know why i got this exception ... Any idea ?

It seems like MultipartStream can't find the request headers. But if i log the headers, they are all here and they are correct.

My servlet code works with a "normal" form. I tried to log the request body and headers of a normal form, and they are the same (except the boundary, of course).

I also tried to change the data variable with a invalid content. The error is still the same, so there's definitively a problem with my headers but i don't see what.

Magus
  • 14,796
  • 3
  • 36
  • 51
  • Have you tried recording the actual POST request sent by a browser _if you didn't fake it with JavaScript_ (using Firebug for example) and compare it against your 'data' variable? – Marcel Stör Feb 19 '13 at 10:08
  • Yes i already tried that. And the request body and headers are the same (except the boundary, of course). I also tried to log the request generated by JumpLoader (a java applet). – Magus Feb 19 '13 at 10:13

3 Answers3

3

I found the solution.

\n IS NOT a valid separator for multipart form. You must use \r\n. Now my code works properly.

Magus
  • 14,796
  • 3
  • 36
  • 51
0

I don't understand why you use sendAsBinary. If not absolutely necessary I wouldn't assemble the payload (data variable) myself but use FormData.

https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/FormData/Using_FormData_Objects

var oMyForm = new FormData();

oMyForm.append("username", "Groucho");
oMyForm.append("accountnum", 123456); // number 123456 is immediately converted to string "123456"

// HTML file input user's choice...
oMyForm.append("userfile", fileInputElement.files[0]);

// JavaScript file-like object...
var oFileBody = '<a id="a"><b id="b">hey!</b></a>'; // the body of the new file...
var oBlob = new Blob([oFileBody], { type: "text/xml"});

oMyForm.append("webmasterfile", oBlob);

var oReq = new XMLHttpRequest();
oReq.open("POST", "http://foo.com/submitform.php");
oReq.send(oMyForm);
Marcel Stör
  • 22,695
  • 19
  • 92
  • 198
  • `sendAsBinary`was just a try. I got the same problem with `send`. But i don't want to use a file input. And i can't use Blob on Firefox because of a Firefox "choice" (or bug, i don't know). The filename is always "blob" and i don't want it. – Magus Feb 19 '13 at 10:44
0

try change f8n51w2QYCsvNftihodgfJ to f8n51w2QYCsvNftihodgfM

I've tried running your code with different random boundaries and turn out only f8n51w2QYCsvNftihodgfJ\n got issue. I reckon you can try a different boundary, since it is really just a random string.

spiritwalker
  • 2,257
  • 14
  • 9