Uploading to S3 with a FileReference from Flex 3 on OS X
After working on a fairly simple upload from Flex to Amazon S3, a co-worker claimed it was "done". Ok. Then I tried uploading from from my mac. No dice. So this simple upload went from being "done" to "a significant OS X pain." Here are some of the things that helped.
After much googling, Wiresharking, and general debuggation, a co-worker found this Amazon S3 doc, which notes:
Some versions of the Adobe Flash Player do not properly handle HTTP responses that have an empty body. To configure POST to return a response that does not have an empty body, set success_action_status to 201. When set, Amazon S3 returns an XML document with a 201 status code. For information on the content of the XML document, see ???. For information on form fields, see HTML Form Fields.
Interesting. And small; it is a tiny message, almost a footnote, on some Amazon page. I wish Adobe could get their docs together. I particularly like "Some versions" and "???". Anyway, lesson learned, or at least we have something to try.
The S3/Flash interactions need a little massaging
It seems like the OS X Flash runtime (9.0.115.0) requires a non-empty server response from its POST. Amazon S3 conveniently has an additional parameter, success_action_status which can be set to "201" to have S3 respond to the post with a 201 CREATED response code. If you are uploading to Apache or IIS, you could have the same problem. Try to check the header response for your POST, and see it is is a) empty, or b) not a 201.
On S3, you can modify your upload policy to return the correct response. Your policy should look something like this:
{
'expiration': '2008-12-31T12:00:00.000Z',
'conditions': [
{'bucket': 'my_test_bucket'},
{'key': 'test1.jpg'},
['starts-with', '$Filename', ''],
['eq', '$success_action_status', '201']
]
}
Note that the success_action_status is not an object property, but an [Operator, Operand, Operand] array.
Problem Solved? Not quite: still not uploads.
S3 Upload Example
Someone at AWS posted a helpful Flex -> S3 example, or actually examples. One Flex project creates and signs a policy, and the other uploads a file using the generated policy. And whats more, they both work. Also, took a look at the code to make sure it wasn't sending my AWS key/password off to some email! Ha. I think it was also posted by an AWS employee, so that is reassuring.
#2038 FileIOError
I kept getting a #2038 FileIOError on my mac. Bummer. Taking a closer look at the working AWS example, I saw a funny comment. Not funny roflcopter, but funny smelly bug-fixy.
/*
* FileReference.upload likes to send cryptic IOErrors when it doesn't get a status code that it likes.
* If we already got an error HTTP status code, don't propagate this event since the HTTPStatusEvent
* event handler dispatches an IOErrorEvent.
*/
As it turns out, I could NOT stop these #2038 FIleIOErrors. They just kept coming. But, as the example code reminded me, if you are getting a successful server response, the file is already up there. Sure enough, the file was there.
So you can pretty much ignore the FileIOError, although you should handle it, and just ignore it if you have a successful HTTP response, something like this:
private function onIOError(event:IOErrorEvent):void
{
if(!recievedSuccessfulHTTPresponse)
{
this.dispatchEvent(event);
}
}
You get the idea. Ok. Handle but ignore FileIOErrors. Done? Almost. Single uploads work, but I get an "Error #2044: Unhandled IOErrorEvent:. text=Error #2038: File I/O Error" when doing multiple uploads, via a FileReferenceList. Marvelous. This turned out to be even more of a pain. It wasn't anything to do with the server side upload script as my google searches might have me believe.
After brainstorming with a co-worker, we came to a pretty good guess: Garbage Collection. Maybe the FileReference was going out of scope before the IOError could be handled, or some such. PC/OS X differences in the runtime could have different GC implementations. Worth a shot. I changed my event listeners from "weak" to "strong" references. Shahooya. Multiple file upload city.
Other fixes
Make sure you have a publicly accessable crossdomain policy on the server you are uploading to.
Also, S3 scales well but adds extra complexity. You might try uploading to somewhere else, like a simple rails uploader.
Hope that helps. Also, please comment. In fact, today only, every commenter gets a free XBox. You know, its just a little lonely out here in the cloud sometimes.
June 25th, 2008 - 20:33
Hi thanks for the notes. I have been struggling with this most of the day. I am getting a security 2049 error. I have a cross domain file in s3. I’m using Vista. I can do it with the form and I already found the 201 xml return status thing, but it is sure frustrating.
July 21st, 2008 - 03:08
I tried adding this to the policy and I’m getting a security error as well.
// mac fix
buffer.push(“['eq', '$success_action_status', '201'],”);
March 30th, 2009 - 03:32
Hi Thanks for the blog. We were struggling with this issue for two days and atlast search in google took us to your blog.Your tips helped us a lot in solving the issue.
May 27th, 2009 - 12:46
Thanks for the elaboration! This had me going today trying to track down why I kept getting all those IOErrorEvents even though the uploads were successful One suggestion ( based off the commented AWS code ) is to still handle IOErrorEvents but just do nothing… since based on the Flex/Flash language reference the HTTPStatusEvent always fires prior to an IOErrorEvent, you can do you forked logic there, like so (simplified for readability):
——————————————————
function onUploadIOError( _event: IOErrorEvent ): void {};
function onUploadHTTPStatus( _event: HTTPStatusEvent ): void
{
if ( _event.status == 200 || _event.status == 201 )
{
// do upload completed logic…
}
else
{
// do error logic…
}
}
—————————————-
using this approach you don’t have to keep a flag for checking across methods. Thanks again!
September 24th, 2009 - 14:51
Hi,
Thanks for your post. I have spend countless hours with a related problem.
The most basic fileupload example from the Adobe AS3 Flash CS4 reference doesn’t work in my localhost (os X – Apache). I just realize the example works flawlessly once uploaded to a server and tested there.
I’m afraid of implementing an flash uploader on a commercial project. I don’t know when it will work and when it wont.
I wonder if you would be so kind to describe an answer to address this issue. I’ve been 2 nights without sleep because of this problem.
How can we make sure a fileupload works on most servers? the solution will have to be on the client side because many shared servers don’t allow much tailoring with their settings.
Thanks so much.
June 16th, 2010 - 04:57
On nginx was getting this error for files greater then 1mb. Fixed using the client_max_body_size directive.