Search code examples
angularjsopenstackform-dataangularjs-httpopenstack-swift

Uploading file to openstack object storage from JavaScript


I have a openstack object storage container to which I'm trying to upload files directly from browser.

As per the documentation here, I can upload the file using a PUT request and I'm doing this using Angularjs provided $http.put method as shown below.

$http.put(temporaryUploadUrl,
    formData,
    {
        headers: {
            'Content-Type': undefined
        }
    }
).then(function (res) {
    console.log("Success");
});

The file uploads successfully and it has no problems in authentication and gives me a 201 Created response. However the file is now containing junk lines on the top and bottom of it because its a multipart request sent using FormData().

Sample file content before upload:

Some sample text 
here is more text 
here is some other text

File content after downloadiong back from openstack container :

------WebKitFormBoundaryTEeQZVW5hNSWtIqS
Content-Disposition: form-data; name="file"; filename="c.txt"
Content-Type: text/plain
Some sample text 
here is more text 
here is some other text
------WebKitFormBoundaryTEeQZVW5hNSWtIqS--

I tried the FileReader to read the selected file as a binary string and wrote the content to the request body instead of FormData and the request which works fine for text files but not the binary files like XLSX or PDF The data is entirely corrupted this way.


Solution

  • I tried the FileReader to read the selected file as a binary string and wrote the content to the request body instead of FormData and the request which works fine for text files but not the binary files like XLSX or PDF The data is entirely corrupted this way.

    The default operation for the $http service is to use Content-Type: application/json and to transform objects to JSON strings. For files from a FileList, the defaults need to be overridden:

    var config = { headers: {'Content-Type': undefined} };
    
    $http.put(url, fileList[0], config)
      .then(function(response) {
         console.log("Success");
    }).catch(function(response) {
         console.log("Error: ", response.status);
         throw response;
    });
    

    By setting Content-Type: undefined, the XHR send method will automatically set the content type header appropriately.

    Be aware that the base64 encoding of 'Content-Type': multipart/form-data adds 33% extra overhead. It is more efficient to send Blobs and File objects directly.

    Sending binary data as binary strings, will corrupt the data because the XHR API converts strings from DOMSTRING (UTF-16) to UTF-8. Avoid binary strings as they are non-standard and obsolete.