Javascript binary string conjugation for form data in XMLHttpRequest
I am writing a Chrome extension and I need to create custom form data to upload a Zip file (I cannot use a real HTML form) to a server (not mine). I found a way to do it here - https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Forms/Sending_forms_through_JavaScript (last section is binary data handling).
It works fine with text-to-text files, but I want to send a Zip which is binary.
JavaScript seems to be unable to handle the concatenation of binaries and non-binaries and adds multiple characters 0Xc2) - to my file:
I also found a solution at http://footle.org/2007/07/31/binary-multipart-posts-in-javascript/ but it uses Components.classes["@mozilla.org/io/string-input-stream;1"]
which is not used in chrome extension.
How can I concatenate a binary zip file with a string and upload it to the server?
function sendData(zipBinary) {
var XHR = new XMLHttpRequest();
var boundary = "----WebKitFormBoundary3n9vu9ZOkCPW4HAw";
var prefix = "";
var postfix = "";
prefix += "--" + boundary + "\r\n";
prefix += 'content-disposition: form-data; '
+ 'name="' + 'UploadedFile' + '"; '
+ 'filename="' + 'hello.zip' + '"\r\n';
prefix += 'Content-Type: ' + 'application/x-zip-compressed' + '\r\n';
prefix += '\r\n';
postfix += '\r\n';
// Once we are done, we "close" the body request
postfix += "--" + boundary + "--";
postfix += '\r\n';
XHR.addEventListener('load', function(event) {
alert('Yeah! Data sent and response loaded.');
});
XHR.addEventListener('error', function(event) {
alert('Oups! Something goes wrong.');
});
XHR.open('POST', 'https://example.com');
XHR.setRequestHeader('Content-Type','multipart/form-data; boundary=' + boundary);
XHR.send(prefix + zipBinary + postfix); // <----
}
source to share
Have you read the section on FormData in the article you linked? Because it is the best solution for sending files via XMLHttpRequest API. The advantage of this API in string concatenation is that files can be streamed uploaded instead of being fully buffered in memory before being sent.
Assuming that zipBinary
is an object Blob
or File
, you can load the file like this:
function sendData(zipBinary) {
var xhr = new XMLHttpRequest();
var fd = new Formdata();
fd.append('hello.zip', zipBinary);
xhr.onload = function() {
// Request completed! Use xhr.status and/or xhr.responseText to
// check the server response status code and response body.
};
xhr.onerror = function() {
// Aw. Network error.
};
xhr.open('POST', 'https://example.com/');
xhr.send(fd);
}
If zipBinary
not Blob or File , but a string of binary data, then you can convert it to Blob with the specified MIME type as follows:
function sendData(zipBinary) {
var zipBinaryBytes = new Uint8Array(zipBinary.length);
for (var i = 0; i < zipBinary.length; ++i) {
zipBinaryBytes[i] = zipBinary.charCodeAt(i);
}
zipBinary = new Blob([zipBinaryBytes], { type: 'application/zip' });
// rest of code as I suggested above...
(note: this application/zip
is the official MIME type for zip files, not application/x-zip-compressed
)
If you are an HTTP protocol expert and really want to write the entire HTTP request body by hand, you need to send a typed array instead of a string, because the XMLHttpRequest API will encode a normal string as UTF-8 before sending the data to the server. This can be done using TextEncoder
the Chrome 38+ API applied to your code like this:
// Was: XHR.send(prefix + zipBinary + postfix);
// New
XHR.send(new TextEncoder().encode(prefix + zipBinary + postfix));
Note. You rarely have to manually create the request body. If you don't know what you are doing to manually create the request body, this is usually an indicator that you are doing it wrong .
source to share