s3_swf_upload 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/CHANGELOG +26 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +20 -0
- data/Manifest +34 -0
- data/README.textile +223 -0
- data/Rakefile +14 -0
- data/flex_src/bin-release/flex-config.xml +361 -0
- data/flex_src/compile +2 -0
- data/flex_src/src/Globals.as +15 -0
- data/flex_src/src/S3Uploader.as +204 -0
- data/flex_src/src/com/adobe/net/MimeTypeMap.as +196 -0
- data/flex_src/src/com/elctech/S3UploadOptions.as +32 -0
- data/flex_src/src/com/elctech/S3UploadRequest.as +259 -0
- data/flex_src/src/com/nathancolgate/s3_swf_upload/BrowseButton.as +55 -0
- data/flex_src/src/com/nathancolgate/s3_swf_upload/S3Queue.as +117 -0
- data/flex_src/src/com/nathancolgate/s3_swf_upload/S3Signature.as +118 -0
- data/flex_src/src/com/nathancolgate/s3_swf_upload/S3Upload.as +111 -0
- data/lib/patch/integer.rb +12 -0
- data/lib/s3_swf_upload/railtie.rb +16 -0
- data/lib/s3_swf_upload/railties/generators/s3_swf_upload.rb +19 -0
- data/lib/s3_swf_upload/railties/generators/uploader/USAGE +10 -0
- data/lib/s3_swf_upload/railties/generators/uploader/templates/amazon_s3.yml +20 -0
- data/lib/s3_swf_upload/railties/generators/uploader/templates/s3_down_button.gif +0 -0
- data/lib/s3_swf_upload/railties/generators/uploader/templates/s3_over_button.gif +0 -0
- data/lib/s3_swf_upload/railties/generators/uploader/templates/s3_up_button.gif +0 -0
- data/lib/s3_swf_upload/railties/generators/uploader/templates/s3_upload.js +118 -0
- data/lib/s3_swf_upload/railties/generators/uploader/templates/s3_upload.swf +0 -0
- data/lib/s3_swf_upload/railties/generators/uploader/templates/s3_uploads_controller.rb +53 -0
- data/lib/s3_swf_upload/railties/generators/uploader/uploader_generator.rb +20 -0
- data/lib/s3_swf_upload/railties/tasks/crossdomain.xml +5 -0
- data/lib/s3_swf_upload/s3_config.rb +43 -0
- data/lib/s3_swf_upload/signature.rb +203 -0
- data/lib/s3_swf_upload/view_helpers.rb +171 -0
- data/lib/s3_swf_upload.rb +10 -0
- data/s3_swf_upload.gemspec +29 -0
- metadata +103 -0
@@ -0,0 +1,196 @@
|
|
1
|
+
/*
|
2
|
+
Copyright (c) 2008, Adobe Systems Incorporated
|
3
|
+
All rights reserved.
|
4
|
+
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
6
|
+
modification, are permitted provided that the following conditions are
|
7
|
+
met:
|
8
|
+
|
9
|
+
* Redistributions of source code must retain the above copyright notice,
|
10
|
+
this list of conditions and the following disclaimer.
|
11
|
+
|
12
|
+
* Redistributions in binary form must reproduce the above copyright
|
13
|
+
notice, this list of conditions and the following disclaimer in the
|
14
|
+
documentation and/or other materials provided with the distribution.
|
15
|
+
|
16
|
+
* Neither the name of Adobe Systems Incorporated nor the names of its
|
17
|
+
contributors may be used to endorse or promote products derived from
|
18
|
+
this software without specific prior written permission.
|
19
|
+
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
21
|
+
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
22
|
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
23
|
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
24
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
25
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
26
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
27
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
28
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
29
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
30
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
*/
|
32
|
+
package com.adobe.net
|
33
|
+
{
|
34
|
+
public class MimeTypeMap
|
35
|
+
{
|
36
|
+
private var types:Array =
|
37
|
+
[["application/andrew-inset","ez"],
|
38
|
+
["application/atom+xml","atom"],
|
39
|
+
["application/mac-binhex40","hqx"],
|
40
|
+
["application/mac-compactpro","cpt"],
|
41
|
+
["application/mathml+xml","mathml"],
|
42
|
+
["application/msword","doc"],
|
43
|
+
["application/octet-stream","bin","dms","lha","lzh","exe","class","so","dll","dmg"],
|
44
|
+
["application/oda","oda"],
|
45
|
+
["application/ogg","ogg"],
|
46
|
+
["application/pdf","pdf"],
|
47
|
+
["application/postscript","ai","eps","ps"],
|
48
|
+
["application/rdf+xml","rdf"],
|
49
|
+
["application/smil","smi","smil"],
|
50
|
+
["application/srgs","gram"],
|
51
|
+
["application/srgs+xml","grxml"],
|
52
|
+
["application/vnd.adobe.apollo-application-installer-package+zip","air"],
|
53
|
+
["application/vnd.mif","mif"],
|
54
|
+
["application/vnd.mozilla.xul+xml","xul"],
|
55
|
+
["application/vnd.ms-excel","xls"],
|
56
|
+
["application/vnd.ms-powerpoint","ppt"],
|
57
|
+
["application/vnd.rn-realmedia","rm"],
|
58
|
+
["application/vnd.wap.wbxml","wbxml"],
|
59
|
+
["application/vnd.wap.wmlc","wmlc"],
|
60
|
+
["application/vnd.wap.wmlscriptc","wmlsc"],
|
61
|
+
["application/voicexml+xml","vxml"],
|
62
|
+
["application/x-bcpio","bcpio"],
|
63
|
+
["application/x-cdlink","vcd"],
|
64
|
+
["application/x-chess-pgn","pgn"],
|
65
|
+
["application/x-cpio","cpio"],
|
66
|
+
["application/x-csh","csh"],
|
67
|
+
["application/x-director","dcr","dir","dxr"],
|
68
|
+
["application/x-dvi","dvi"],
|
69
|
+
["application/x-futuresplash","spl"],
|
70
|
+
["application/x-gtar","gtar"],
|
71
|
+
["application/x-hdf","hdf"],
|
72
|
+
["application/x-javascript","js"],
|
73
|
+
["application/x-koan","skp","skd","skt","skm"],
|
74
|
+
["application/x-latex","latex"],
|
75
|
+
["application/x-netcdf","nc","cdf"],
|
76
|
+
["application/x-sh","sh"],
|
77
|
+
["application/x-shar","shar"],
|
78
|
+
["application/x-shockwave-flash","swf"],
|
79
|
+
["application/x-stuffit","sit"],
|
80
|
+
["application/x-sv4cpio","sv4cpio"],
|
81
|
+
["application/x-sv4crc","sv4crc"],
|
82
|
+
["application/x-tar","tar"],
|
83
|
+
["application/x-tcl","tcl"],
|
84
|
+
["application/x-tex","tex"],
|
85
|
+
["application/x-texinfo","texinfo","texi"],
|
86
|
+
["application/x-troff","t","tr","roff"],
|
87
|
+
["application/x-troff-man","man"],
|
88
|
+
["application/x-troff-me","me"],
|
89
|
+
["application/x-troff-ms","ms"],
|
90
|
+
["application/x-ustar","ustar"],
|
91
|
+
["application/x-wais-source","src"],
|
92
|
+
["application/xhtml+xml","xhtml","xht"],
|
93
|
+
["application/xml","xml","xsl"],
|
94
|
+
["application/xml-dtd","dtd"],
|
95
|
+
["application/xslt+xml","xslt"],
|
96
|
+
["application/zip","zip"],
|
97
|
+
["audio/basic","au","snd"],
|
98
|
+
["audio/midi","mid","midi","kar"],
|
99
|
+
["audio/mpeg","mp3","mpga","mp2"],
|
100
|
+
["audio/x-aiff","aif","aiff","aifc"],
|
101
|
+
["audio/x-mpegurl","m3u"],
|
102
|
+
["audio/x-pn-realaudio","ram","ra"],
|
103
|
+
["audio/x-wav","wav"],
|
104
|
+
["chemical/x-pdb","pdb"],
|
105
|
+
["chemical/x-xyz","xyz"],
|
106
|
+
["image/bmp","bmp"],
|
107
|
+
["image/cgm","cgm"],
|
108
|
+
["image/gif","gif"],
|
109
|
+
["image/ief","ief"],
|
110
|
+
["image/jpeg","jpg","jpeg","jpe"],
|
111
|
+
["image/png","png"],
|
112
|
+
["image/svg+xml","svg"],
|
113
|
+
["image/tiff","tiff","tif"],
|
114
|
+
["image/vnd.djvu","djvu","djv"],
|
115
|
+
["image/vnd.wap.wbmp","wbmp"],
|
116
|
+
["image/x-cmu-raster","ras"],
|
117
|
+
["image/x-icon","ico"],
|
118
|
+
["image/x-portable-anymap","pnm"],
|
119
|
+
["image/x-portable-bitmap","pbm"],
|
120
|
+
["image/x-portable-graymap","pgm"],
|
121
|
+
["image/x-portable-pixmap","ppm"],
|
122
|
+
["image/x-rgb","rgb"],
|
123
|
+
["image/x-xbitmap","xbm"],
|
124
|
+
["image/x-xpixmap","xpm"],
|
125
|
+
["image/x-xwindowdump","xwd"],
|
126
|
+
["model/iges","igs","iges"],
|
127
|
+
["model/mesh","msh","mesh","silo"],
|
128
|
+
["model/vrml","wrl","vrml"],
|
129
|
+
["text/calendar","ics","ifb"],
|
130
|
+
["text/css","css"],
|
131
|
+
["text/html","html","htm"],
|
132
|
+
["text/plain","txt","asc"],
|
133
|
+
["text/richtext","rtx"],
|
134
|
+
["text/rtf","rtf"],
|
135
|
+
["text/sgml","sgml","sgm"],
|
136
|
+
["text/tab-separated-values","tsv"],
|
137
|
+
["text/vnd.wap.wml","wml"],
|
138
|
+
["text/vnd.wap.wmlscript","wmls"],
|
139
|
+
["text/x-setext","etx"],
|
140
|
+
["video/mpeg","mpg","mpeg","mpe"],
|
141
|
+
["video/quicktime","mov","qt"],
|
142
|
+
["video/vnd.mpegurl","m4u","mxu"],
|
143
|
+
["video/x-flv","flv"],
|
144
|
+
["video/x-msvideo","avi"],
|
145
|
+
["video/x-sgi-movie","movie"],
|
146
|
+
["x-conference/x-cooltalk","ice"]];
|
147
|
+
|
148
|
+
/**
|
149
|
+
* Returns the mimetype for the given extension.
|
150
|
+
*/
|
151
|
+
public function getMimeType(extension:String):String
|
152
|
+
{
|
153
|
+
extension = extension.toLocaleLowerCase();
|
154
|
+
for each (var a:Array in types)
|
155
|
+
{
|
156
|
+
for each (var b:String in a)
|
157
|
+
{
|
158
|
+
if (b == extension)
|
159
|
+
{
|
160
|
+
return a[0];
|
161
|
+
}
|
162
|
+
}
|
163
|
+
}
|
164
|
+
return null;
|
165
|
+
}
|
166
|
+
|
167
|
+
/**
|
168
|
+
* Returns the prefered extension for the given mimetype.
|
169
|
+
*/
|
170
|
+
public function getExtension(mimetype:String):String
|
171
|
+
{
|
172
|
+
mimetype = mimetype.toLocaleLowerCase();
|
173
|
+
for each (var a:Array in types)
|
174
|
+
{
|
175
|
+
if (a[0] == mimetype)
|
176
|
+
{
|
177
|
+
return a[1];
|
178
|
+
}
|
179
|
+
}
|
180
|
+
return null;
|
181
|
+
}
|
182
|
+
|
183
|
+
/**
|
184
|
+
* Adds a mimetype to the map. The order of the extensions matters. The most preferred should come first.
|
185
|
+
*/
|
186
|
+
public function addMimeType(mimetype:String, extensions:Array):void
|
187
|
+
{
|
188
|
+
var newType:Array = [mimetype];
|
189
|
+
for each (var a:String in extensions)
|
190
|
+
{
|
191
|
+
newType.push(a);
|
192
|
+
}
|
193
|
+
types.push(newType);
|
194
|
+
}
|
195
|
+
}
|
196
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
package com.elctech {
|
2
|
+
public class S3UploadOptions {
|
3
|
+
/**
|
4
|
+
* Options specified at:
|
5
|
+
* http://docs.amazonwebservices.com/AmazonS3/2006-03-01/HTTPPOSTForms.html
|
6
|
+
*/
|
7
|
+
public var AWSAccessKeyId:String;
|
8
|
+
public var acl:String;
|
9
|
+
public var bucket:String;
|
10
|
+
public var CacheControl:String;
|
11
|
+
public var ContentType:String;
|
12
|
+
public var ContentDisposition:String;
|
13
|
+
public var ContentEncoding:String;
|
14
|
+
public var Expires:String;
|
15
|
+
public var key:String;
|
16
|
+
public var newKey:String;
|
17
|
+
public var policy:String;
|
18
|
+
public var successactionredirect:String;
|
19
|
+
public var redirect:String;
|
20
|
+
public var successactionstatus:String;
|
21
|
+
public var signature:String;
|
22
|
+
public var xamzsecuritytoken:String;
|
23
|
+
public var file:String;
|
24
|
+
|
25
|
+
/**
|
26
|
+
* Addition field
|
27
|
+
*/
|
28
|
+
public var Secure:String; /* A flag indicating whether HTTPS should be used. */
|
29
|
+
public var FileName:String;
|
30
|
+
public var FileSize:String;
|
31
|
+
}
|
32
|
+
}
|
@@ -0,0 +1,259 @@
|
|
1
|
+
package com.elctech {
|
2
|
+
|
3
|
+
// import flash.events.*;
|
4
|
+
import flash.events.EventDispatcher;
|
5
|
+
import flash.events.ProgressEvent;
|
6
|
+
import flash.events.Event;
|
7
|
+
import flash.events.IOErrorEvent;
|
8
|
+
import flash.events.SecurityErrorEvent;
|
9
|
+
import flash.events.HTTPStatusEvent;
|
10
|
+
import flash.events.DataEvent;
|
11
|
+
|
12
|
+
// import flash.net.*;
|
13
|
+
import flash.net.FileReference;
|
14
|
+
import flash.net.URLVariables;
|
15
|
+
import flash.net.URLRequest;
|
16
|
+
import flash.net.URLRequestMethod;
|
17
|
+
|
18
|
+
import flash.system.Security;
|
19
|
+
import flash.xml.XMLDocument;
|
20
|
+
import flash.xml.XMLNode;
|
21
|
+
// import mx.controls.Alert;
|
22
|
+
|
23
|
+
/**
|
24
|
+
* This class encapsulates a POST request to S3.
|
25
|
+
*
|
26
|
+
* After you create an S3PostRequest, invoke S3PostRequest::upload(fileReference:FileReference).
|
27
|
+
*
|
28
|
+
*/
|
29
|
+
public class S3UploadRequest extends EventDispatcher {
|
30
|
+
|
31
|
+
[Event(name="open", type="flash.events.Event.OPEN")]
|
32
|
+
[Event(name="uploadCompleteData", type="flash.events.DataEvent.UPLOAD_COMPLETE_DATA")]
|
33
|
+
[Event(name="ioError", type="flash.events.IOErrorEvent.IO_ERROR")]
|
34
|
+
[Event(name="securityError", type="flash.events.SecurityErrorEvent.SECURITY_ERROR")]
|
35
|
+
[Event(name="progress", type="flash.events.ProgressEvent.PROGRESS")]
|
36
|
+
|
37
|
+
private var _accessKeyId:String;
|
38
|
+
private var _bucket:String;
|
39
|
+
private var _key:String;
|
40
|
+
private var _options:S3UploadOptions;
|
41
|
+
private var _httpStatusErrorReceived:Boolean;
|
42
|
+
private var _uploadStarted:Boolean;
|
43
|
+
private var fileReference:FileReference;
|
44
|
+
|
45
|
+
private const ENDPOINT:String = "s3.amazonaws.com";
|
46
|
+
private const MIN_BUCKET_LENGTH:int = 3;
|
47
|
+
private const MAX_BUCKET_LENGTH:int = 63;
|
48
|
+
|
49
|
+
|
50
|
+
/**
|
51
|
+
* Creates and initializes a new S3PostRequest object.
|
52
|
+
* @param accessKeyId The AWS access key id to authenticate the request
|
53
|
+
* @param bucket The bucket to POST into
|
54
|
+
* @param key The key to create
|
55
|
+
* @param options Options for this request
|
56
|
+
*/
|
57
|
+
public function S3UploadRequest(options:S3UploadOptions) {
|
58
|
+
|
59
|
+
_accessKeyId = options.AWSAccessKeyId;
|
60
|
+
_bucket = options.bucket;
|
61
|
+
_key = options.key;
|
62
|
+
_options = options;
|
63
|
+
|
64
|
+
if (options.newKey) { //NOTE that we stop caring about the specified prefix if we have a newkey.
|
65
|
+
_key = options.newKey;
|
66
|
+
options.key = options.newKey; //so we output the right value in callbacks, etc.
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
private function buildUrl():String {
|
71
|
+
|
72
|
+
var canUseVanityStyle:Boolean = canUseVanityStyle(_bucket);
|
73
|
+
|
74
|
+
if(_options.Secure!="false" && canUseVanityStyle && _bucket.match(/\./)) {
|
75
|
+
// We cannot use SSL for bucket names containing "."
|
76
|
+
// The certificate won't match "my.bucket.s3.amazonaws.com"
|
77
|
+
throw new SecurityError("Cannot use SSL with bucket name containing '.': " + _bucket);
|
78
|
+
}
|
79
|
+
|
80
|
+
var postUrl:String = "http" + ((_options.Secure == 'true') ? "s" : "") + "://";
|
81
|
+
|
82
|
+
if(canUseVanityStyle) {
|
83
|
+
postUrl += _bucket + "." + ENDPOINT;
|
84
|
+
} else {
|
85
|
+
postUrl += ENDPOINT + "/" + _bucket;
|
86
|
+
}
|
87
|
+
|
88
|
+
return postUrl;
|
89
|
+
}
|
90
|
+
|
91
|
+
private function canUseVanityStyle(bucket:String):Boolean {
|
92
|
+
if( bucket.length < MIN_BUCKET_LENGTH ||
|
93
|
+
bucket.length > MAX_BUCKET_LENGTH ||
|
94
|
+
bucket.match(/^\./) ||
|
95
|
+
bucket.match(/\.$/) ) {
|
96
|
+
return false;
|
97
|
+
}
|
98
|
+
|
99
|
+
// must be lower case
|
100
|
+
if(bucket.toLowerCase() != bucket) {
|
101
|
+
return false;
|
102
|
+
}
|
103
|
+
|
104
|
+
// Check not IPv4-like
|
105
|
+
if (bucket.match(/^[0-9]|+\.[0-9]|+\.[0-9]|+\.[0-9]|+$/)) {
|
106
|
+
return false;
|
107
|
+
}
|
108
|
+
|
109
|
+
// Check each label
|
110
|
+
if(bucket.match(/\./)) {
|
111
|
+
var labels:Array = bucket.split(/\./);
|
112
|
+
for (var i:int = 0;i < labels.length; i++) {
|
113
|
+
if(!labels[i].match(/^[a-z0-9]([a-z0-9\-]*[a-z0-9])?$/)) {
|
114
|
+
return false;
|
115
|
+
}
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
return true;
|
120
|
+
}
|
121
|
+
|
122
|
+
private function loadPolicyFile(postUrl:String):void {
|
123
|
+
/*
|
124
|
+
* Due to the restrictions imposed by the Adobe Flash security sandbox,
|
125
|
+
* the bucket being uploaded to must contain a public-readable crossdomain.xml
|
126
|
+
* file that allows access from the domain that served the SWF hosting this code.
|
127
|
+
*
|
128
|
+
* Read Adobe's documentation on the Flash security sandbox for more information.
|
129
|
+
*
|
130
|
+
*/
|
131
|
+
|
132
|
+
Security.loadPolicyFile(postUrl + "/crossdomain.xml");
|
133
|
+
}
|
134
|
+
|
135
|
+
|
136
|
+
public function removeListeners():void {
|
137
|
+
trace('removeListeners');
|
138
|
+
fileReference.removeEventListener(Event.OPEN, onOpen);
|
139
|
+
fileReference.removeEventListener(ProgressEvent.PROGRESS, onProgress);
|
140
|
+
fileReference.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
|
141
|
+
fileReference.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
|
142
|
+
fileReference.removeEventListener(DataEvent.UPLOAD_COMPLETE_DATA, onUploadCompleteData);
|
143
|
+
fileReference.removeEventListener(HTTPStatusEvent.HTTP_STATUS, onHttpStatus);
|
144
|
+
}
|
145
|
+
/**
|
146
|
+
* Initiates a POST upload request to S3
|
147
|
+
* @param fileReference A FileReference object referencing the file to upload to S3.
|
148
|
+
*/
|
149
|
+
public function upload(_fileReference:FileReference):void {
|
150
|
+
|
151
|
+
if(_uploadStarted) {
|
152
|
+
throw new Error("S3PostRequest object cannot be reused. Create another S3PostRequest object to send another request to Amazon S3.");
|
153
|
+
}
|
154
|
+
_uploadStarted = true;
|
155
|
+
|
156
|
+
// Save the FileReference object so that it doesn't get GCed.
|
157
|
+
// If this happens, we can lose events that should be dispatched.
|
158
|
+
fileReference = _fileReference;
|
159
|
+
|
160
|
+
var postUrl:String = buildUrl();
|
161
|
+
loadPolicyFile(postUrl);
|
162
|
+
var urlRequest:URLRequest = new URLRequest(postUrl);
|
163
|
+
urlRequest.method = URLRequestMethod.POST;
|
164
|
+
urlRequest.data = buildPostVariables();
|
165
|
+
|
166
|
+
// set up event handlers *****************************************************
|
167
|
+
fileReference.addEventListener(Event.OPEN, onOpen);
|
168
|
+
fileReference.addEventListener(ProgressEvent.PROGRESS, onProgress);
|
169
|
+
fileReference.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
|
170
|
+
fileReference.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
|
171
|
+
fileReference.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, onUploadCompleteData);
|
172
|
+
fileReference.addEventListener(HTTPStatusEvent.HTTP_STATUS, onHttpStatus);
|
173
|
+
// *****************************************************************************
|
174
|
+
|
175
|
+
// send the request
|
176
|
+
fileReference.upload(urlRequest, "file", false);
|
177
|
+
}
|
178
|
+
|
179
|
+
private function buildPostVariables():URLVariables {
|
180
|
+
|
181
|
+
var postVariables:URLVariables = new URLVariables();
|
182
|
+
|
183
|
+
postVariables.key = _key;
|
184
|
+
postVariables.acl = _options.acl;
|
185
|
+
postVariables.AWSAccessKeyId = _accessKeyId;
|
186
|
+
postVariables.signature = _options.signature;
|
187
|
+
postVariables["Content-Type"] = _options.ContentType;
|
188
|
+
postVariables["Content-Disposition"] = "attachment";
|
189
|
+
postVariables.policy = _options.policy;
|
190
|
+
|
191
|
+
/**
|
192
|
+
* Certain combinations of Flash player version and platform don't handle
|
193
|
+
* HTTP responses with the header 'Content-Length: 0'. These clients do not
|
194
|
+
* dispatch completion or error events when such a response is received.
|
195
|
+
* Therefore it is impossible to tell when the upload has completed or failed.
|
196
|
+
*
|
197
|
+
* Flash clients should always set the success_action_status parameter to 201
|
198
|
+
* so that Amazon S3 returns a response with Content-Length being non-zero.
|
199
|
+
*
|
200
|
+
*/
|
201
|
+
postVariables.success_action_status = "201";
|
202
|
+
|
203
|
+
return postVariables;
|
204
|
+
}
|
205
|
+
|
206
|
+
private function onOpen(event:Event):void {
|
207
|
+
trace('onOpen: '+this._key);
|
208
|
+
this.dispatchEvent(event);
|
209
|
+
}
|
210
|
+
private function onIOError(event:IOErrorEvent):void {
|
211
|
+
/*
|
212
|
+
* FileReference.upload likes to send cryptic IOErrors when it doesn't get a status code that it likes.
|
213
|
+
* If we already got an error HTTP status code, don't propagate this event since the HTTPStatusEvent
|
214
|
+
* event handler dispatches an IOErrorEvent.
|
215
|
+
*/
|
216
|
+
if(!_httpStatusErrorReceived) {
|
217
|
+
this.dispatchEvent(event);
|
218
|
+
}
|
219
|
+
}
|
220
|
+
private function onSecurityError(event:SecurityErrorEvent):void {
|
221
|
+
this.dispatchEvent(event);
|
222
|
+
}
|
223
|
+
private function onProgress(event:ProgressEvent):void {
|
224
|
+
this.dispatchEvent(event);
|
225
|
+
}
|
226
|
+
private function onUploadCompleteData(event:DataEvent):void {
|
227
|
+
var data:String = event.data;
|
228
|
+
if(isError(data)) {
|
229
|
+
this.dispatchEvent(
|
230
|
+
new IOErrorEvent(IOErrorEvent.IO_ERROR, event.bubbles, event.cancelable, "Amazon S3 returned an error: " + data + ".")
|
231
|
+
);
|
232
|
+
} else {
|
233
|
+
this.dispatchEvent(new DataEvent(DataEvent.UPLOAD_COMPLETE_DATA, event.bubbles, event.cancelable, data));
|
234
|
+
}
|
235
|
+
}
|
236
|
+
private function onHttpStatus(event:HTTPStatusEvent):void {
|
237
|
+
_httpStatusErrorReceived = true;
|
238
|
+
if(Math.floor(event.status/100) == 2) {
|
239
|
+
this.dispatchEvent(new DataEvent(DataEvent.UPLOAD_COMPLETE_DATA, event.bubbles, event.cancelable, "Amazon S3 returned HTTP status " + event.status.toString() + "."));
|
240
|
+
} else {
|
241
|
+
this.dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR, event.bubbles, event.cancelable, "Amazon S3 returned an error: HTTP status " + event.status.toString() + "."));
|
242
|
+
}
|
243
|
+
}
|
244
|
+
|
245
|
+
private function isError(responseText:String):Boolean {
|
246
|
+
var xml:XMLDocument = new XMLDocument();
|
247
|
+
xml.ignoreWhite = true;
|
248
|
+
xml.parseXML(responseText);
|
249
|
+
var root:XMLNode = xml.firstChild;
|
250
|
+
if( root == null || root.nodeName != "Error" )
|
251
|
+
{
|
252
|
+
return false;
|
253
|
+
}
|
254
|
+
return true;
|
255
|
+
}
|
256
|
+
|
257
|
+
}
|
258
|
+
|
259
|
+
}
|
@@ -0,0 +1,55 @@
|
|
1
|
+
package com.nathancolgate.s3_swf_upload {
|
2
|
+
|
3
|
+
import flash.display.*;
|
4
|
+
import flash.events.MouseEvent;
|
5
|
+
import flash.events.Event;
|
6
|
+
import flash.net.*;
|
7
|
+
|
8
|
+
public dynamic class BrowseButton extends Sprite {
|
9
|
+
|
10
|
+
private var _playButton:flash.display.SimpleButton;
|
11
|
+
|
12
|
+
public function BrowseButton(width:Number,
|
13
|
+
height:Number,
|
14
|
+
buttonUpUrl:String,
|
15
|
+
buttonDownUrl:String,
|
16
|
+
buttonOverUrl:String)
|
17
|
+
{
|
18
|
+
super();
|
19
|
+
|
20
|
+
_playButton = new flash.display.SimpleButton();
|
21
|
+
_playButton.useHandCursor = true;
|
22
|
+
addChild(_playButton);
|
23
|
+
|
24
|
+
// Hit Test
|
25
|
+
var hit_test:Shape = new flash.display.Shape();
|
26
|
+
hit_test.graphics.beginFill(0xFFCC00);
|
27
|
+
hit_test.graphics.drawRect(0, 0, width, height);
|
28
|
+
hit_test.graphics.endFill();
|
29
|
+
_playButton.hitTestState = hit_test;
|
30
|
+
|
31
|
+
// Up
|
32
|
+
var upLoader:Loader = new Loader();
|
33
|
+
upLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,function(e:Event):void{
|
34
|
+
_playButton.upState = new Bitmap(e.target.content.bitmapData);
|
35
|
+
});
|
36
|
+
upLoader.load(new URLRequest(buttonUpUrl));
|
37
|
+
|
38
|
+
// Down
|
39
|
+
var downLoader:Loader = new Loader();
|
40
|
+
downLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,function(e:Event):void{
|
41
|
+
_playButton.downState = new Bitmap(e.target.content.bitmapData);
|
42
|
+
});
|
43
|
+
downLoader.load(new URLRequest(buttonDownUrl));
|
44
|
+
|
45
|
+
// Over
|
46
|
+
var overLoader:Loader = new Loader();
|
47
|
+
overLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,function(e:Event):void{
|
48
|
+
_playButton.overState = new Bitmap(e.target.content.bitmapData);
|
49
|
+
});
|
50
|
+
overLoader.load(new URLRequest(buttonOverUrl));
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
}
|
55
|
+
}
|
@@ -0,0 +1,117 @@
|
|
1
|
+
package com.nathancolgate.s3_swf_upload {
|
2
|
+
|
3
|
+
import mx.collections.ArrayCollection;
|
4
|
+
import mx.events.CollectionEvent;
|
5
|
+
import flash.external.ExternalInterface;
|
6
|
+
import flash.net.FileReference;
|
7
|
+
import com.nathancolgate.s3_swf_upload.*;
|
8
|
+
|
9
|
+
public class S3Queue extends ArrayCollection {
|
10
|
+
|
11
|
+
// S3 Interaction Vars
|
12
|
+
private var _signatureUrl:String;
|
13
|
+
private var _prefixPath:String;
|
14
|
+
|
15
|
+
public var currentSignature:S3Signature;
|
16
|
+
|
17
|
+
public function S3Queue(signatureUrl:String,
|
18
|
+
prefixPath:String,
|
19
|
+
source:Array = null) {
|
20
|
+
|
21
|
+
_signatureUrl = signatureUrl;
|
22
|
+
_prefixPath = prefixPath;
|
23
|
+
super(source);
|
24
|
+
|
25
|
+
// Outgoing calls
|
26
|
+
this.addEventListener(CollectionEvent.COLLECTION_CHANGE, changeHandler);
|
27
|
+
// Incoming calls
|
28
|
+
ExternalInterface.addCallback("startUploading", startUploadingHandler);
|
29
|
+
ExternalInterface.addCallback("clearQueue", clearHandler);
|
30
|
+
ExternalInterface.addCallback("stopUploading", stopUploadingHandler);
|
31
|
+
}
|
32
|
+
|
33
|
+
public function uploadNextFile():void{
|
34
|
+
// ExternalInterface.call('s3_swf.jsLog','uploadNextFile');
|
35
|
+
// ExternalInterface.call('s3_swf.jsLog','Start uploadNextFile...');
|
36
|
+
var next_file:FileReference = FileReference(this.getItemAt(0));
|
37
|
+
currentSignature = new S3Signature(next_file,_signatureUrl,_prefixPath);
|
38
|
+
// ExternalInterface.call('s3_swf.jsLog','End uploadNextFile');
|
39
|
+
}
|
40
|
+
|
41
|
+
// whenever the queue changes this function is called
|
42
|
+
private function changeHandler(event:CollectionEvent):void{
|
43
|
+
// ExternalInterface.call('s3_swf.jsLog','changeHandler');
|
44
|
+
// ExternalInterface.call('s3_swf.jsLog','Calling onQueueChange...');
|
45
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onQueueChange',this.toJavascript());
|
46
|
+
// ExternalInterface.call('s3_swf.jsLog','onQueueChange called');
|
47
|
+
}
|
48
|
+
|
49
|
+
// Remove all files from the upload queue;
|
50
|
+
private function clearHandler():void{
|
51
|
+
// ExternalInterface.call('s3_swf.jsLog','clearHandler');
|
52
|
+
// ExternalInterface.call('s3_swf.jsLog','Removing All...');
|
53
|
+
this.removeAll();
|
54
|
+
// ExternalInterface.call('s3_swf.jsLog','All removed');
|
55
|
+
// ExternalInterface.call('s3_swf.jsLog','Calling onQueueClear...');
|
56
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onQueueClear',this.toJavascript());
|
57
|
+
// ExternalInterface.call('s3_swf.jsLog','onQueueClear called');
|
58
|
+
}
|
59
|
+
|
60
|
+
// Start uploading the files from the queue
|
61
|
+
private function startUploadingHandler():void{
|
62
|
+
// ExternalInterface.call('s3_swf.jsLog','startUploadingHandler');
|
63
|
+
if (this.length > 0){
|
64
|
+
// ExternalInterface.call('s3_swf.jsLog','Calling onUploadingStart...');
|
65
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onUploadingStart');
|
66
|
+
// ExternalInterface.call('s3_swf.jsLog','onUploadingStart called');
|
67
|
+
// ExternalInterface.call('s3_swf.jsLog','Uploading next file...');
|
68
|
+
uploadNextFile();
|
69
|
+
// ExternalInterface.call('s3_swf.jsLog','Next file uploaded');
|
70
|
+
} else {
|
71
|
+
// ExternalInterface.call('s3_swf.jsLog','Calling onQueueEmpty...');
|
72
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onQueueEmpty',this);
|
73
|
+
// ExternalInterface.call('s3_swf.jsLog','onQueueEmpty called');
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
// Cancel Current File Upload
|
78
|
+
// Which stops all future uploads as well
|
79
|
+
private function stopUploadingHandler():void{
|
80
|
+
// ExternalInterface.call('s3_swf.jsLog','stopUploadingHandler');
|
81
|
+
if (this.length > 0){
|
82
|
+
var current_file:FileReference = FileReference(this.getItemAt(0));
|
83
|
+
// ExternalInterface.call('s3_swf.jsLog','Cancelling current file...');
|
84
|
+
current_file.cancel();
|
85
|
+
|
86
|
+
currentSignature.s3upload.removeListeners();
|
87
|
+
|
88
|
+
// ExternalInterface.call('s3_swf.jsLog','Current file cancelled');
|
89
|
+
// ExternalInterface.call('s3_swf.jsLog','Calling onUploadingStop...');
|
90
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onUploadingStop');
|
91
|
+
// ExternalInterface.call('s3_swf.jsLog','onUploadingStop called');
|
92
|
+
} else {
|
93
|
+
// ExternalInterface.call('s3_swf.jsLog','Calling onQueueEmpty...');
|
94
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onQueueEmpty',this.toJavascript());
|
95
|
+
// ExternalInterface.call('s3_swf.jsLog','onQueueEmpty called');
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
// This is a rather silly function to need, especially since it worked at one point
|
100
|
+
// In flash player 10.1, you could no longer send files over external reference
|
101
|
+
// This is the hack to get around the problem. Essentially: turn all those
|
102
|
+
// Files into objects
|
103
|
+
// August 27, 2010 - NCC@BNB
|
104
|
+
public function toJavascript():Object {
|
105
|
+
var faux_queue:Object = new Object();
|
106
|
+
faux_queue.files = new Array();
|
107
|
+
for (var i:int = 0;i < source.length; i++) {
|
108
|
+
faux_queue.files[i] = new Object();
|
109
|
+
faux_queue.files[i].name = source[i].name;
|
110
|
+
faux_queue.files[i].size = source[i].size;
|
111
|
+
faux_queue.files[i].type = source[i].type;
|
112
|
+
}
|
113
|
+
return faux_queue;
|
114
|
+
}
|
115
|
+
|
116
|
+
}
|
117
|
+
}
|