POSTing Multipart/Form-Data from an XMLHttpRequest

I’m working on an add-on where I have a need to POST JSON data to the server. Unfortunately that JSON contains ampersands, so in order to use POST, I would have to encode the data in some way that the server could decode. This seemed like extra unnecessary work to me. I decided to use the “multipart/form-data” header which would allow me to send the data unmodified. Unfortunately, documentation on this was lacking. So this post is just to put up sample code on how to do this in case someone else needs it. In this case, I am simply passing data=foo where foo is the JSON.

var xhr = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Components.interfaces.nsIXMLHttpRequest);

xhr.open("POST", url, true);

var boundary = '---------------------------';
boundary += Math.floor(Math.random()*32768);
boundary += Math.floor(Math.random()*32768);
boundary += Math.floor(Math.random()*32768);
xhr.setRequestHeader("Content-Type", 'multipart/form-data; boundary=' + boundary);
var body = '';
body += '--' + boundary + '\r\n' + 'Content-Disposition: form-data; name="';
body += "data";
body += '"\r\n\r\n';
body += JSON.stringify(JAVASCRIPT OBJECT);
body += '\r\n'
body += '--' + boundary + '--';
xhr.setRequestHeader('Content-length', body.length);
xhr.onload = function() {
}
xhr.send(body);

There were no server changes required at all. The PHP handled the data the same way it would have if it was an “application/x-www-form-urlencoded” POST.

Belorussian provided by Patricia

Please note: I reserve the right to delete comments that are offensive or off-topic.

Leave a Reply

Your email address will not be published. Required fields are marked *

13 thoughts on “POSTing Multipart/Form-Data from an XMLHttpRequest

  1. What’s so difficult about using encodeURIComponent? It will encode your &’s as %26, and the server will automatically decode it.

    • It’s not done automatically, you still need to decode in PHP. The problem is there is no PHP equivalent to encodeURIComponent so things can end up different. Spaces can be a problem and so could different encodings.

      My goal was to send the JSON data exactly as I had it to the server with no encoding/decoding.

      Reading all the comments here show the various problems:

      http://php.net/manual/en/function.urldecode.php

      Shows the various problems.

  2. I modified the code a little bit so that php can read file uploads, now my only problem is to get that Content-length in there and correct…
    file is retrieved by the script over here: http://www.thecssninja.com/javascript/drag-and-drop-upload

    xhr.open("POST", "upload.php");
    var boundary = '---------------------------';
    boundary += Math.floor(Math.random()*32768);
    boundary += Math.floor(Math.random()*32768);
    boundary += Math.floor(Math.random()*32768);
    xhr.setRequestHeader("Content-Type", 'multipart/form-data; boundary=' + boundary);
    var body = '';
    body += 'Content-Type: multipart/form-data; boundary=' + boundary;
    //body += '\r\nContent-length: '+body.length;
    body += '\r\n\r\n--' + boundary + '\r\n' + 'Content-Disposition: form-data; name="';
    body += 'myfile"; filename="'+file.fileName+'" \r\n';
    body += "Content-Type: "+file.type;
    body += '\r\n\r\n';
    body += file.getAsBinary();
    body += '\r\n'
    body += '--' + boundary + '\r\n' + 'Content-Disposition: form-data; name="submitBtn"\r\n\r\nUpload\r\n';
    body += '--' + boundary + '--';
    xhr.setRequestHeader('Content-length', body.length);

    xhr.overrideMimeType('text/plain; charset=x-user-defined-binary');
    xhr.sendAsBinary(body);