-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Upload to Amazon S3 using HTML5 runtime
Being able to upload files to Amazon S3, especially in HTML5, has been a goal for quite some time and while it was somehow possible in Flash and Silverlight, HTML5 was out of the game. Amazon S3 simply refused to add support for Access-Control-Allow-Origin
- that single miraculous header that helps cross-domain AJAX requests to reach the server. Finally, after continuous lament from users, with bleeding shouts like: "Two and a half year later, still no cigar... AWS, Y U MAKIN ME CRY? :'(", Amazon made it happen.
So now it's possible. And here we will tell you how.
- This is a working draft;
- Silverlight has not been tested. This article focuses on HTML5 and Flash runtimes;
- There are several workarounds for this method to work. I'm hoping we can work together to improve plupload to make this process easier.
- This guide assumes intermediate-to-advanced overall knowledge. Don't expect to copy-paste the examples and things to just work.
In order for this to work, CORS configs and crossdomain.xml
are required.
HTML : Edit the CORS cofig in your S3 Console (guide) with something like :
<CORSConfiguration>
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedHeader>*</AllowedHeader>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
</CORSRule>
</CORSConfiguration>
Flash : Create a public file named crossdomain.xml
at the root of your bucket with this content :
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM
"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-access-from domain="*" secure="false" />
</cross-domain-policy>
Uploading to S3 with multipart requires a policy and a signature. See this article for detailed information. These two will be passed to Plupload as multipart params (more on this later).
Heres a working policy generator written in Ruby. The code is intentionnaly simple and uses globals, please do not blindly copy-paste) :
require 'base64'
require 'json'
require 'digest/sha1'
$ACL = 'public-read' # Change this according to your needs
$BUCKET = 'YOUR_BUCKET'
$AWS_SECRET = 'YOUR_SECRET'
def policy
conditions = [
["starts-with", "$utf8", ""],
# Change this path if you need, but adjust the javascript config
["starts-with", "$key", "uploads"],
["starts-with", "$filename", ""],
{ "bucket" => $BUCKET },
{ "acl" => $ACL }
]
policy = {
# Valid for 3 hours. Change according to your needs
'expiration' => (Time.now.utc + 3600 * 3).iso8601,
'conditions' => conditions
}
Base64.encode64(JSON.dump(policy)).gsub("\n","")
end
def signature
Base64.encode64(
OpenSSL::HMAC.digest(
OpenSSL::Digest::Digest.new('sha1'),
$AWS_SECRET, policy
)
).gsub("\n","")
end
{
// General settings
runtimes : 'flash,html5',
// Flash settings
flash_swf_url : '/plupload/src/moxie/bin/flash/Moxie.swf',
// S3 specific settings
url : "https://<%= $BUCKET %>.s3.amazonaws.com:443/",
file_name_name: false, // Custom option to our fork to remove file_name_name
multipart: true,
multipart_params : {
// Dummy filename to ensure the field is sent in HTML just like Flash
// This allow to have a consistent AWS policy for both HTML and Flash
filename: 'filename',
utf8: true,
AWSAccessKeyId: "YOUR_AWS_ACCESS_KEY_ID",
acl: "public-read", // See http://docs.aws.amazon.com/AmazonS3/latest/dev/ACLOverview.html#CannedACL
// See Generating a policy and a signature
policy: "YOUR_POLICY",
signature: "YOUR_SIGNATURE",
// This is basically the resulting location of the file on S3.
// See http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html#RESTObjectPOST-requests-form-fields
//
// WARNING : Change this to suite your needs.
// You need to insert some sort of unique identifier to avoid
// overriding files if they share the same filename.
key: "uploads/${filename}",
}
}
I made a little Sinatra one-file-app that shows how to use all of this together.
- S3's
success_action_redirect
does not work in Chrome. I think the problem is that Moxie's XHR does not handle well redirect codes, but investigation is needed. - This demo requires a patched version of Plupload. Pull request #750 has to be merged for this to work with master.