Search code examples
javascriptangularjsmultipartform-datamultipartform-data

Set content-length header on individual parts of a multipart/form-data upload


I would like to upload multiple files using a post request of type multipart/form-data and for each file I need to know the file size (content-length) on the server side.

To construct the POST request in javascript I use a FormData object and append the File objects for the upload to it. This works fine, but only a Content-type header is added to each part, in addition to the Content-Disposition header, but no Content-length header, though this information is available from the individual File objects.

Is there a way to achieve that that Content-length headers are set for every part from the FormData object when sending the request?

Below is the code I use, including my work-around to the problem. It actually uses angular-js to send the request, but I think this is not relevant to the question.

var form = new window.FormData();

form.append('additional-field-1', new Blob(['some plain text'], {type : 'text/plain'}));

for (var file in fileList) {
    var fileObj = fileList[file];
    var count = 1 + parseInt(file, null);
    form.append('file-size-' + count, new Blob([fileObj.size], {type : 'text/plain'}));
    form.append('file-' + count, fileObj);
}

$http.post(url, form, {
    transformRequest: angular.identity,
    headers: {'Content-Type': undefined}
}).success(.....

Solution

  • I don't believe there is a way to actually add a custom header for each form data element. However why don't you add it to the content disposition header, as part of the file name:

    data = new FormData();
    data.append('additional-field-1', new Blob(['some plain text'], {type : 'text/plain'}));
    
    for (var i = 0; i< $( '#file' )[0].files.length; i++) {
       var fileObj = $( '#file' )[0].files[i];
       data.append( '{ size : ' + fileObj.size + ' }' , $( '#file' [0].files[i], $( '#file' )[0].files[i].name );
    }
    

    I'm not sure how you are handling this on the server, but the request would look like this:

    ------WebKitFormBoundarysZxMHYOzMkqDmOvR
    Content-Disposition: form-data; name="additional-field-1"; filename="blob"
    Content-Type: text/plain
    
    
    ------WebKitFormBoundarysZxMHYOzMkqDmOvR
    Content-Disposition: form-data; name="{ size : 22984 }"; filename="MatrixArithmetic.vshost.exe"
    Content-Type: application/x-msdownload
    
    
    ------WebKitFormBoundarysZxMHYOzMkqDmOvR
    Content-Disposition: form-data; name="{ size : 187 }"; filename="MatrixArithmetic.vshost.exe.config"
    Content-Type: application/xml
    
    
    ------WebKitFormBoundarysZxMHYOzMkqDmOvR--