Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does FileReader.readAsBinaryString return binary or an ASCII-based character set?

In short, I want to send the binary data of the image to my handler that will get saved in the DB as a byte array. Reading the value of a file input using readAsBinaryString(f) in my Javascript, I'll get output like this:

GIF89a,úæÿÿÿ2c½3fÌ Smaäµééúþc«T.[ÈéùAtεÚõ[ãXßÆî*[µc³8Ûõüÿfj¥æ§ÈïÛå÷ËØñI}ÓQ×
*\»q£E}Ûÿå§ÓõþÿIÛv¤Þ´Åè«æ ³][us¬çAy×MÞ,a½«ÔóZÝL2äëùQ×(Eq<pË5V¨·ÏIÓ¨»åQßY¥3bØÈ
æ¬z³é<uÓ3£ÎñE¾á÷RÛR¢K­®ÎØØìÍAtÓÑÔØrÀ-hݪÑïôõüR|ÎäóÖUËåæçXÔw»^s®ëI}ÛQ}ÔEÛ·Îñ½Óêd»Ì
ÌëöåóôöÖàñE×Cr¿C¤3óúëLÍYÜ3fõûöÑðû Øûÿõw²ñ`ª»ßÀy|Á¿ÃIuÔM×ûñû{¹R4¼ìe¡äl«ç!ÿNETSCA
PE2.0!ÿXMP DataXMP<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpm
eta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.3-c011 66.145661, 2012/02
/06-14:56:27   // etc..  

That data is sent via AJAX:

$.ajax({
    url: theUrl,
    type: 'POST',
    data: { Image: image } // image = data above
});

This is a binary string? When I send this string to my handler (IHttpHandler), in order to store it into a byte array, I may only get the bytes if I set the encoding to ISO-8859-1.

public void ProcessRequest (HttpContext aContext) 
{ 
    // This works as long as requestValidationMode = "2.0" in web.config
    // Is there a way to bypass HttpRequestValidationException  just on 
    // THIS data?
    byte[] imageBytes = System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(_Context.Request["Image"]);

    //...
}

Is this normal? This also throws an HttpRequestValidationException (A potentially dangerous Request.Form value was detected from the..). I'd rather not change the requestValidationMode since it opens up to XSS, so how does one escape the binary string? Does Base64 encoding cover this, and if so, does converting from Base64 in the handler contain metadata about its data type?

like image 522
Josh Avatar asked May 17 '13 15:05

Josh


1 Answers

It really helps to see what you are doing in code, that's why I asked you to show it. I guess your code looks like this:

var f = $("image").files[0];
var reader = new FileReader();
reader.readAsBinaryString(f);
var image = reader.result;

$.ajax({
    url: theUrl,
    type: 'POST',
    data: { Image: image }
});

Now when you say:

I'll get output like this:

GIF89a,úæÿÿÿ2c½3...

Is my output [...] binary data?

Well yes, but you can read it, so it is text. The difference between binary and textual data is a bit confusing, read this if you want to get more confused. The cause of your problem is encoding, as explained in that article.

It depends on how you output it to your page, but the browser may or may not apply a certain encoding to the data it receives (a Fiddler inspection can teach you more on what's being sent over the HTTP wire) and display it as more or less readable text.

This does not apply to your image variable though, which contains the actual, binary data from the readAsBinaryString() result, in the form of "raw binary data[sic]". Oh, loosely-typed, who cares what you return. I guess/hope a byte array. You now need to send this to a server. Preferably, file uploads are handled by <input type="file" /> elements, but sometimes you'll need to do things using AJAX. You can't really do real file uploads through JavaScript, although as far as I know browser support seems to be increasing.

So you'll need to POST with the file contents as one of the posted form's parameters. In order for this to happen successfully with binary data, you'll need to properly encode it for form submission.

First make sure the request is made with the content-type of application/x-www-form-urlencoded. You can check this in Fiddler or by consulting the manual. The latter does not mention any encoding at all, you have to figure that out.

Now you need to url-encode the binary data in order to post it. This function returns the input bytes, interpreted as UTF-8, as an URL-encoded string that can safely be posted. Then serverside, you can replace

System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(_Context.Request["Image"]);

With

System.Text.Encoding.UTF8.GetBytes(_Context.Request["Image"]);

But why do you have the file's contents in that form anyway? As this answer mentions, the FileReader also contains a readAsDataURL method, which allows you to use reader.result directly as POST variable.

So, your code becomes like this:

var f = $("image").files[0];
var reader = new FileReader();
reader.readAsDataURL(f);
var image = reader.result;

$.ajax({
    url: theUrl,
    type: 'POST',
    data: { Image: image }
});

Then serverside, you will have to decode the data from base 64:

byte[] imageBytes = System.Convert.FromBase64String(_Context.Request["Image"]);

How does that work?

like image 171
CodeCaster Avatar answered Nov 03 '22 01:11

CodeCaster