s3_swf_upload 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
}
|