views:

491

answers:

3

I am writing an app where I want the customer to be able to upload to Amazon S3 straight from the browser. I can make this work just fine. But when errors occur, I want to handle them more gracefully than splattering an XML document on the customer's screen.

I have a scheme that I think would work, but it's failing. Here's what I'm trying:

  1. Create a form to do the upload, and store the form on S3 itself, in the same domain as the "action" attribute of the form.
  2. Redirect the customer to this form. Now their browser is sitting on https://<bucket>.s3.amazonaws.com/something.
  3. The page contains a hidden iframe. The form sets its target to the iframe.
  4. The load event handler looks at the contents of the iframe, and acts upon it.

So, something like this:

<iframe id="foo" name="foo" style="display: none" />
<form target="foo" action="https://&lt;bucket&gt;.s3.amazonaws.com/"&gt;
    <input type="hidden" name="..." value="..." />
    <input type="file" name="file" />
</form>

with this javascript (using jquery):

function handler() {
    var message = $("#foo").contents().find('message').text();
    alert(message);
}
$("#foo").load(handler);

Using firebug, I can see that the iframe contains an XML document, that contains a "message" node. However, the .find('message') always fails to find anything within the XML document.

Notice that the action of the form has the same domain, port, and scheme as the document itself. So, I don't think that I should be running afoul of the same-origin policy. Right? But it fails every time. This is using Firefox and Google Chrome browsers.

Thanks for any advice!

+2  A: 

This should be just a comment, but can you post the response XML code?

EDIT: Just to narrow down a little, i made a simple test and worked really fine:

<div id="foo">
    <error> 
        <code>AccessDenied</code>
        <message>Invalid according to Policy: Policy expired.</message> 
        <hostid> SZuQn5hTyf32j79AWUym1/si48oqjPifrx4goDVDLYYxc6cJVbbHroLJYcAM89+T</hostid> 
    </error> 
</div>

Then I did some jQuery code on my firebug:

$("#foo").find("message").text()

Maybe you can give an alert($("#foo").html()) and check the response..

Israel Rodriguez
Sure: <error> <code>AccessDenied</code> <message>Invalid according to Policy: Policy expired.</message> <hostid> SZuQn5hTyf32j79AWUym1/si48oqjPifrx4goDVDLYYxc6cJVbbHroLJYcAM89+T</hostid> </error>
samf
Sorry, the formatting got mangled. But the idea is <error>...</error> containing <code>, <message>, <requestid>, and <hostid> fields.
samf
Yes, I believe that your test would work. The problem is traversing into the iframe. In general, iframes follow the same-origin policy, but I haven't found any documentation on the implications of having an iframe be the target of a form. I would think that since the action of the form is the same method/domain/port as the document itself, that I should be able to see into the iframe, but instead I'm not seeing anything.
samf
Sorry -- I didn't mean for that to sound dismissive! Thanks for looking at this! :-)
samf
+1  A: 

I think that you're trying to solve the wrong problem. The problem is not a detail one, with iframes and such, but that you want to have finer control over the upload. Upload the file to your server, then submit a request to the Amazon server, and you'll have absolute control over what's going on.

Significantly more complex, of course, but that's the price of control.

Chris B. Behrens
It's not the complexity that I worry about, it's getting billed for the bandwidth twice. That's the whole point of Amazon allowing a POST instead of just PUT -- so that an ordinary browser's file upload could go straight to S3, and you only get billed for bandwidth once.I now believe that the best answer is to use a flash uploader, such as SWFupload.
samf
+2  A: 

There are a number of jQuery plugins that effectively implement exactly what you are trying to do. Do a Google search for "jQuery ajax-upload", you could just use one of these controls out of the box to capture the result of the post or examine their code and roll your own.

You may also want to look into some of the Flash based uploaders if you are uploading large files. The pure form method of uploading does not have any way of implementing an upload progress, at least not until the new file functions are wide spread in browsers, which Flash does offer. http://github.com/slaskis/s3upload#readme is a good flash based file uploader specifically designed for S3 and gives you call back functions in JavaScript to handle errors, progress and more.

Kelly Anderson
Excellent -- thank you!
samf