Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Webkit JavaScript PUT or POST an image REST-style as pure binary?

When my browser downloads an image from a web site, there is no base64 encoding involved. It issues an HTTP command like GET /image.jpg and receives an HTTP response whose Content-Type is something like image/jpg, whose Content-Length is the number of bytes in the image, and whose body is the raw binary image data itself. The data is neither encoded using a character set, nor encoded using a scheme like base64.

Writing RESTful resources has trained me to expect symmetry between HTTP GET and PUT so that, for example, a URL that delivers JSON data when I do a GET will then accept JSON data when it is presented with a PUT. In neither case is form encoding involved; in both cases there is simply a Content-Length giving the number of bytes in the payload, a Content-Type header declaring that the payload is JSON in some character set, and then the character data sits alone and unadorned as the body of the GET or PUT.

I am writing a PhoneGap application that lets users take photographs and them upload them using my application. I had expected that I could design a RESTful interface for this, that supports symmetric GET and PUT — so that PUT commands involve no special encoding, nor involve any idea of a character set, but simply have a Content-Type of image/jpg and then a mass of binary JPG data as their payload. Obviously this is a more efficient use of bandwidth than trying to encode the image inside of a form. And this approach works fine when I PUT to a URL using a tool like curl.

But I am having no luck in doing a clean RESTful PUT from PhoneGap WebKit JavaScript! PhoneGap is willing to return the image to my JavaScript as either a local file: URL, or else as a data: URL that carries the image data inline courtesy of base64 encoding. But in neither case can I find a clear way to convert the image into a pure binary format (would I use one of those newfangled Blob objects for this? if so, how?) and then cause a PUT that, without festooning the request with extra layers of form or encoding cruft, will simply transmit the raw image across the wire to my web server as the HTTP request payload.

Does anyone know how to induce WebKit to PUT an AJAX request with a raw image as its body? Thanks for any pointers — or even any useful answers to the effect that I am approaching this all wrong!

like image 360
Brandon Rhodes Avatar asked Dec 28 '11 00:12

Brandon Rhodes


1 Answers

As for the binary image processing, the Binary File Inspector demo might be helpful as an end-to-end example.

There's some tutorial information on the subject of getting Blobs from the filesystem at MDN. This blog post describes how to turn a base64 URI into an ArrayBuffer and then a Blob.

Finally, either an ArrayBuffer or a Blob can be uploaded using the XMLHttpRequest2 interface.

The XHR2 spec seems to imply that PUT is supported, along with a bunch of other HTTP methods. So combining all this you could stuff files in Blobs and send them up using XHR2.


Untested code sample using the base64 decoding method with some help from base64-binary.js:

var BASE_64_PREFIX = "base64,";
function getBase64Content(base64Uri) {
   var index = base64Uri.indexOf(BASE_64_PREFIX);
   return base64Uri.substring(index + BASE_64_PREFIX.length);
}

function put(uri, data, onComplete) {
    var xhr = new XMLHttpRequest();
    xhr.open("PUT", uri, true);
    xhr.onload = onComplete;

    xhr.send(data);
}

var base64Uri = fromPhoneGap();
var base64Content = getBase64Content(base64Uri);
var arrayBuffer = Base64Binary.decodeArrayBuffer(base64Content);

put("/some/uri", arrayBuffer, function () {
    console.log("All done");
});

That said, I doubt much of this works on even the latest desktop WebKit, much less the version you're going to be saddled with via PhoneGap. You're probably not in good shape to take advantage of these draft specifications.

like image 51
Domenic Avatar answered Nov 02 '22 12:11

Domenic