-
Notifications
You must be signed in to change notification settings - Fork 69
/
Copy paths3upload.coffee
105 lines (83 loc) · 3.25 KB
/
s3upload.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# S3 CORS upload
# http://docs.amazonwebservices.com/AmazonS3/latest/dev/cors.html#how-do-i-enable-cors
# http://www.ioncannon.net/programming/1539/direct-browser-uploading-amazon-s3-cors-fileapi-xhr2-and-signed-puts/
# https://github.com/carsonmcdonald/direct-browser-s3-upload-example
class window.S3Upload
s3_object_name: 'default_name' # setting an object name is not recommended on the client side, override or namespace on server side
s3_sign_put_url: '/signS3put'
file_dom_selector: 'file_upload'
with_credentials: false
onFinishS3Put: (public_url) ->
console.log 'base.onFinishS3Put()', public_url
onProgress: (percent, status) ->
console.log 'base.onProgress()', percent, status
onError: (status) ->
console.log 'base.onError()', status
# Don't override these
constructor: (options = {}) ->
@[option] = options[option] for option of options
if @files && @files.length > 0
handleFiles(@files)
else
@handleFileSelect document.getElementById(@file_dom_selector)
handleFiles: (files) ->
@onProgress 0, 'Upload started.'
for f in files
@uploadFile(f)
handleFileSelect: (file_element) ->
@handleFiles(file_element.files)
createCORSRequest: (method, url) ->
xhr = new XMLHttpRequest()
if xhr.withCredentials?
xhr.open method, url, true
else if typeof XDomainRequest != "undefined"
xhr = new XDomainRequest()
xhr.open method, url
else
xhr = null
xhr
executeOnSignedUrl: (file, callback) ->
this_s3upload = this
xhr = new XMLHttpRequest()
xhr.withCredentials = @with_credentials
xhr.open 'GET', @s3_sign_put_url + '?s3_object_type=' + file.type + '&s3_object_name=' + @s3_object_name, true
# Hack to pass bytes through unprocessed.
xhr.overrideMimeType 'text/plain; charset=x-user-defined'
xhr.onreadystatechange = (e) ->
if this.readyState == 4 and this.status == 200
try
result = JSON.parse this.responseText
catch error
this_s3upload.onError 'Signing server returned some ugly/empty JSON: "' + this.responseText + '"'
return false
callback decodeURIComponent(result.signed_request), result.url
else if this.readyState == 4 and this.status != 200
this_s3upload.onError 'Could not contact request signing server. Status = ' + this.status
xhr.send()
# Use a CORS call to upload the given file to S3. Assumes the url
# parameter has been signed and is accessible for upload.
uploadToS3: (file, url, public_url) ->
this_s3upload = this
xhr = @createCORSRequest 'PUT', url
if !xhr
@onError 'CORS not supported'
else
xhr.onload = ->
if xhr.status == 200
this_s3upload.onProgress 100, 'Upload completed.'
this_s3upload.onFinishS3Put public_url
else
this_s3upload.onError 'Upload error: ' + xhr.status
xhr.onerror = ->
this_s3upload.onError 'XHR error.'
xhr.upload.onprogress = (e) ->
if e.lengthComputable
percentLoaded = Math.round (e.loaded / e.total) * 100
this_s3upload.onProgress percentLoaded, if percentLoaded == 100 then 'Finalizing.' else 'Uploading.'
xhr.setRequestHeader 'Content-Type', file.type
xhr.setRequestHeader 'x-amz-acl', 'public-read'
xhr.send file
uploadFile: (file) ->
this_s3upload = this
@executeOnSignedUrl file, (signedURL, publicURL) ->
this_s3upload.uploadToS3 file, signedURL, publicURL