How to Upload Files Directly to Amazon S3 with Uploadify

We have a client that needed to support multiple uploads, old browsers, and large files, in any combination. It turns out that this isn’t exactly the simplest combination of factors. For starters, using the Amazon S3 CORS feature won’t work because we need to support old browsers that don’t have HTML5 features.

We ended up deciding on a Flash plugin called Uploadify for a few reasons:

  • Pleasant UI
  • Upload via Flash works nicely cross-browser
  • Supports multiple files, cancelling, and queueing

We are also using Amazon S3 for file storage so we hit all 3 requirements with this solution.

Our project is setup in Rails 3.1 and despite there being a number of blog posts about this subject, none of the code examples worked out of the box. If you want to do this, here’s my step-by-step guide.

1. Setup Cross-Domain Authorization

You’ll need to set up a crossdomain.xml file in your Amazon S3 bucket. This file tells S3 that requests can be made cross-domain directly to this bucket. It goes in the root of the bucket and must be readable and downloadable by All Users. It looks like this:

Note that this configuration is suitable for development but probably not production. Setup your allow-access-from domain to something specific to your setup.

2. Request Signing

In order to POST files directly to S3, requests need to be signed with a policy and your Secret Access Key and consequently need to be performed server side. This configuration is very sensitive to mismatched values, incorrect formatting, and re-ordering.

The key attribute above deserves special attention. Uploading the same file more than once will simply overwrite the existing file which may not be the behavior you’d like. In that case, simply change your key to include random/date/time portions as you wish.

3. Integrate Into View

Be sure to implement uploadify_success to set attributes on your form (e.g. a hidden field with file information). I ended up pushing each successful file into a hidden field separated by a string unlikely to be used in a file name (‘@@@’ for example).

4. Asset Configuration (Rails 3.1+)

# config/application.rb
config.assets.paths << Rails.root.join("vendor","assets","flash")

Add your uploadify assets to vendor/assets. Make sure to put the flash file into your new flash directory under vendor/assets. You’ll also need to update the uploadify css file to point to the right image path depending on where you put uploadify’s images.

Bonus: Troubleshooting

The primary issues I ran into were:

  • Upload success reported but no file actually on S3
  • Error #2049
  • HTTP 403 Error

If you get any of these, it probably means you either changed the parameters I laid out above, your signature, policy, or JS request are not matching, or you have not setup the crossdomain file correctly. Double check everything.

This is the result of a number of hours trudging through Uploadify forum threads, outdated StackOverflow threads, a Django plugin, and numerous other blog posts.

Did this work for you? Leave me a note in the comments!

Hat Tip

http://www.kiakroas.com/blog/44/ – Initial configuration with slightly outdated code.
http://stackoverflow.com/questions/10463360/uploadify-3-1-trying-to-upload-to-amazon-s3-signaturedoesnotmatch – Help with updating to newest functionality.