3

I'm writing a Chrome extension, and need to build a custom Form data to upload a Zip file (I can't 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 - Dealing with binary data).

It works fine with clear text files, but I want to send Zip which is binary.

It seems that JavaScript can't handle concatenation of binary and non binary, and adds some 0Xc2 chars 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 usable in Chrome extension.

How can I concatenate a binary zip file with a string and upload it to a 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's 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); // <----
  }

1 Answer 1

2

Have you read the section about FormData in the article that you've linked? Because that is the best solution for sending files via the XMLHttpRequest API. The advantage of this API over string concatenation is that files can be uploaded in a streamed fashion, instead of having to be entirely being buffered in memory before being sent off.

Assuming that zipBinary is a Blob or File object, you can upload a file as follows:

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's response status code and response body.
    };
    xhr.onerror = function() {
         // Aw. Network error.
    };
    xhr.open('POST', 'https://example.com/');
    xhr.send(fd);
}

If zipBinary is not a Blob or File object, but a string of binary data, then you can convert it to a Blob with a 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: application/zip is the official MIME-type for zip files, not application/x-zip-compressed)


If you are an expert of the HTTP protocol and really want to write the HTTP request body fully by hand, then you need to send a typed array instead of a string, because the XMLHttpRequest API will encode a regular string as UTF-8 before passing off the data to the server. This can be done using the TextEncoder API since Chrome 38+, applied to your code as follows:

// Was: XHR.send(prefix + zipBinary + postfix);
// New
XHR.send(new TextEncoder().encode(prefix + zipBinary + postfix));

Note: You rarely need to construct the request body by hand. Unless you know what you're doing, having to manually construct the request body is usually an indicator that you are doing it wrong.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.