xml_http_request_upload.coffee
3.03 KB
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
# @see http://xhr.spec.whatwg.org/#interface-xmlhttprequest
class XMLHttpRequestUpload extends XMLHttpRequestEventTarget
# @private
# @param {XMLHttpRequest} the XMLHttpRequest that this upload object is
# associated with
constructor: (request) ->
super()
@_request = request
@_reset()
# Sets up this Upload to handle a new request.
#
# @private
# @return {undefined} undefined
_reset: ->
@_contentType = null
@_body = null
undefined
# Implements the upload-related part of the send() XHR specification.
#
# @private
# @param {?String, ?Buffer, ?ArrayBufferView} data the argument passed to
# XMLHttpRequest#send()
# @return {undefined} undefined
# @see step 4 of http://www.w3.org/TR/XMLHttpRequest/#the-send()-method
_setData: (data) ->
if typeof data is 'undefined' or data is null
return
if typeof data is 'string'
# DOMString
if data.length isnt 0
@_contentType = 'text/plain;charset=UTF-8'
@_body = new Buffer data, 'utf8'
else if Buffer.isBuffer data
# node.js Buffer
@_body = data
else if data instanceof ArrayBuffer
# ArrayBuffer arguments were supported in an old revision of the spec.
body = new Buffer data.byteLength
view = new Uint8Array data
body[i] = view[i] for i in [0...data.byteLength]
@_body = body
else if data.buffer and data.buffer instanceof ArrayBuffer
# ArrayBufferView
body = new Buffer data.byteLength
offset = data.byteOffset
view = new Uint8Array data.buffer
body[i] = view[i + offset] for i in [0...data.byteLength]
@_body = body
else
# NOTE: diverging from the XHR specification of coercing everything else
# to Strings via toString() because that behavior masks bugs and is
# rarely useful
throw new Error "Unsupported send() data #{data}"
undefined
# Updates the HTTP headers right before the request is sent.
#
# This is used to set data-dependent headers such as Content-Length and
# Content-Type.
#
# @private
# @param {Object<String, String>} headers the HTTP headers to be sent
# @param {Object<String, String>} loweredHeaders maps lowercased HTTP header
# names (e.g., 'content-type') to the actual names used in the headers
# parameter (e.g., 'Content-Type')
# @return {undefined} undefined
_finalizeHeaders: (headers, loweredHeaders) ->
if @_contentType
unless 'content-type' of loweredHeaders
headers['Content-Type'] = @_contentType
if @_body
# Restricted headers can't be set by the user, no need to check
# loweredHeaders.
headers['Content-Length'] = @_body.length.toString()
undefined
# Starts sending the HTTP request data.
#
# @private
# @param {http.ClientRequest} request the HTTP request
# @return {undefined} undefined
_startUpload: (request) ->
request.write @_body if @_body
request.end()
undefined
# Export the XMLHttpRequestUpload constructor.
XMLHttpRequest.XMLHttpRequestUpload = XMLHttpRequestUpload