Initial commit
This commit is contained in:
89
node_modules/xhr2/src/000-xml_http_request_event_target.coffee
generated
vendored
Normal file
89
node_modules/xhr2/src/000-xml_http_request_event_target.coffee
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
# This file's name is set up in such a way that it will always show up first in
|
||||
# the list of files given to coffee --join, so that the other files can assume
|
||||
# that XMLHttpRequestEventTarget was already defined.
|
||||
|
||||
|
||||
# The DOM EventTarget subclass used by XMLHttpRequest.
|
||||
#
|
||||
# @see http://xhr.spec.whatwg.org/#interface-xmlhttprequest
|
||||
class XMLHttpRequestEventTarget
|
||||
# @private
|
||||
# This is an abstract class and should not be instantiated directly.
|
||||
constructor: ->
|
||||
@onloadstart = null
|
||||
@onprogress = null
|
||||
@onabort = null
|
||||
@onerror = null
|
||||
@onload = null
|
||||
@ontimeout = null
|
||||
@onloadend = null
|
||||
@_listeners = {}
|
||||
|
||||
# @property {function(ProgressEvent)} DOM level 0-style handler
|
||||
# for the 'loadstart' event
|
||||
onloadstart: null
|
||||
|
||||
# @property {function(ProgressEvent)} DOM level 0-style handler
|
||||
# for the 'progress' event
|
||||
onprogress: null
|
||||
|
||||
# @property {function(ProgressEvent)} DOM level 0-style handler
|
||||
# for the 'abort' event
|
||||
onabort: null
|
||||
|
||||
# @property {function(ProgressEvent)} DOM level 0-style handler
|
||||
# for the 'error' event
|
||||
onerror: null
|
||||
|
||||
# @property {function(ProgressEvent)} DOM level 0-style handler
|
||||
# for the 'load' event
|
||||
onload: null
|
||||
|
||||
# @property {function(ProgressEvent)} DOM level 0-style handler
|
||||
# for the 'timeout' event
|
||||
ontimeout: null
|
||||
|
||||
# @property {function(ProgressEvent)} DOM level 0-style handler
|
||||
# for the 'loadend' event
|
||||
onloadend: null
|
||||
|
||||
# Adds a new-style listener for one of the XHR events.
|
||||
#
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#events
|
||||
#
|
||||
# @param {String} eventType an XHR event type, such as 'readystatechange'
|
||||
# @param {function(ProgressEvent)} listener function that will be called when
|
||||
# the event fires
|
||||
# @return {undefined} undefined
|
||||
addEventListener: (eventType, listener) ->
|
||||
eventType = eventType.toLowerCase()
|
||||
@_listeners[eventType] ||= []
|
||||
@_listeners[eventType].push listener
|
||||
undefined
|
||||
|
||||
# Removes an event listener added by calling addEventListener.
|
||||
#
|
||||
# @param {String} eventType an XHR event type, such as 'readystatechange'
|
||||
# @param {function(ProgressEvent)} listener the value passed in a previous
|
||||
# call to addEventListener.
|
||||
# @return {undefined} undefined
|
||||
removeEventListener: (eventType, listener) ->
|
||||
eventType = eventType.toLowerCase()
|
||||
if @_listeners[eventType]
|
||||
index = @_listeners[eventType].indexOf listener
|
||||
@_listeners[eventType].splice index, 1 if index isnt -1
|
||||
undefined
|
||||
|
||||
# Calls all the listeners for an event.
|
||||
#
|
||||
# @param {ProgressEvent} event the event to be dispatched
|
||||
# @return {undefined} undefined
|
||||
dispatchEvent: (event) ->
|
||||
event.currentTarget = event.target = @
|
||||
eventType = event.type
|
||||
if listeners = @_listeners[eventType]
|
||||
for listener in listeners
|
||||
listener.call @, event
|
||||
if listener = @["on#{eventType}"]
|
||||
listener.call @, event
|
||||
undefined
|
||||
782
node_modules/xhr2/src/001-xml_http_request.coffee
generated
vendored
Normal file
782
node_modules/xhr2/src/001-xml_http_request.coffee
generated
vendored
Normal file
@@ -0,0 +1,782 @@
|
||||
# This file's name is set up in such a way that it will always show up second
|
||||
# in the list of files given to coffee --join, so it can use the
|
||||
# XMLHttpRequestEventTarget definition and so that the other files can assume
|
||||
# that XMLHttpRequest was already defined.
|
||||
|
||||
http = require 'http'
|
||||
https = require 'https'
|
||||
os = require 'os'
|
||||
url = require 'url'
|
||||
|
||||
# The ECMAScript HTTP API.
|
||||
#
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#introduction
|
||||
class XMLHttpRequest extends XMLHttpRequestEventTarget
|
||||
# Creates a new request.
|
||||
#
|
||||
# @param {Object} options one or more of the options below
|
||||
# @option options {Boolean} anon if true, the request's anonymous flag
|
||||
# will be set
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#constructors
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#anonymous-flag
|
||||
constructor: (options) ->
|
||||
super()
|
||||
@onreadystatechange = null
|
||||
|
||||
@_anonymous = options and options.anon
|
||||
|
||||
@readyState = XMLHttpRequest.UNSENT
|
||||
@response = null
|
||||
@responseText = ''
|
||||
@responseType = ''
|
||||
@responseURL = ''
|
||||
@status = 0
|
||||
@statusText = ''
|
||||
@timeout = 0
|
||||
@upload = new XMLHttpRequestUpload @
|
||||
|
||||
@_method = null # String
|
||||
@_url = null # Return value of url.parse()
|
||||
@_sync = false
|
||||
@_headers = null # Object<String, String>
|
||||
@_loweredHeaders = null # Object<lowercase String, String>
|
||||
@_mimeOverride = null
|
||||
@_request = null # http.ClientRequest
|
||||
@_response = null # http.ClientResponse
|
||||
@_responseParts = null # Array<Buffer, String>
|
||||
@_responseHeaders = null # Object<lowercase String, String>
|
||||
@_aborting = null
|
||||
@_error = null
|
||||
@_loadedBytes = 0
|
||||
@_totalBytes = 0
|
||||
@_lengthComputable = false
|
||||
|
||||
# @property {function(ProgressEvent)} DOM level 0-style handler for the
|
||||
# 'readystatechange' event
|
||||
onreadystatechange: null
|
||||
|
||||
# @property {Number} the current state of the XHR object
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#states
|
||||
readyState: null
|
||||
|
||||
# @property {String, ArrayBuffer, Buffer, Object} processed XHR response
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-response-attribute
|
||||
response: null
|
||||
|
||||
# @property {String} response string, if responseType is '' or 'text'
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-responsetext-attribute
|
||||
responseText: null
|
||||
|
||||
# @property {String} sets the parsing method for the XHR response
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-responsetype-attribute
|
||||
responseType: null
|
||||
|
||||
# @property {Number} the HTTP
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-status-attribute
|
||||
status: null
|
||||
|
||||
# @property {Number} milliseconds to wait for the request to complete
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-timeout-attribute
|
||||
timeout: null
|
||||
|
||||
# @property {XMLHttpRequestUpload} the associated upload information
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-upload-attribute
|
||||
upload: null
|
||||
|
||||
# Sets the XHR's method, URL, synchronous flag, and authentication params.
|
||||
#
|
||||
# @param {String} method the HTTP method to be used
|
||||
# @param {String} url the URL that the request will be made to
|
||||
# @param {?Boolean} async if false, the XHR should be processed
|
||||
# synchronously; true by default
|
||||
# @param {?String} user the user credential to be used in HTTP basic
|
||||
# authentication
|
||||
# @param {?String} password the password credential to be used in HTTP basic
|
||||
# authentication
|
||||
# @return {undefined} undefined
|
||||
# @throw {SecurityError} method is not one of the allowed methods
|
||||
# @throw {SyntaxError} urlString is not a valid URL
|
||||
# @throw {Error} the URL contains an unsupported protocol; the supported
|
||||
# protocols are file, http and https
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-open()-method
|
||||
open: (method, url, async, user, password) ->
|
||||
method = method.toUpperCase()
|
||||
if method of @_restrictedMethods
|
||||
throw new SecurityError "HTTP method #{method} is not allowed in XHR"
|
||||
|
||||
xhrUrl = @_parseUrl url
|
||||
async = true if async is undefined
|
||||
|
||||
switch @readyState
|
||||
when XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED, XMLHttpRequest.DONE
|
||||
# Nothing to do here.
|
||||
null
|
||||
when XMLHttpRequest.HEADERS_RECEIVED, XMLHttpRequest.LOADING
|
||||
# TODO(pwnall): terminate abort(), terminate send()
|
||||
null
|
||||
|
||||
@_method = method
|
||||
@_url = xhrUrl
|
||||
@_sync = !async
|
||||
@_headers = {}
|
||||
@_loweredHeaders = {}
|
||||
@_mimeOverride = null
|
||||
@_setReadyState XMLHttpRequest.OPENED
|
||||
@_request = null
|
||||
@_response = null
|
||||
@status = 0
|
||||
@statusText = ''
|
||||
@_responseParts = []
|
||||
@_responseHeaders = null
|
||||
@_loadedBytes = 0
|
||||
@_totalBytes = 0
|
||||
@_lengthComputable = false
|
||||
undefined
|
||||
|
||||
# Appends a header to the list of author request headers.
|
||||
#
|
||||
# @param {String} name the HTTP header name
|
||||
# @param {String} value the HTTP header value
|
||||
# @return {undefined} undefined
|
||||
# @throw {InvalidStateError} readyState is not OPENED
|
||||
# @throw {SyntaxError} name is not a valid HTTP header name or value is not
|
||||
# a valid HTTP header value
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader()-method
|
||||
setRequestHeader: (name, value) ->
|
||||
unless @readyState is XMLHttpRequest.OPENED
|
||||
throw new InvalidStateError "XHR readyState must be OPENED"
|
||||
|
||||
loweredName = name.toLowerCase()
|
||||
if @_restrictedHeaders[loweredName] or /^sec\-/.test(loweredName) or
|
||||
/^proxy-/.test(loweredName)
|
||||
console.warn "Refused to set unsafe header \"#{name}\""
|
||||
return undefined
|
||||
|
||||
value = value.toString()
|
||||
if loweredName of @_loweredHeaders
|
||||
# Combine value with the existing header value.
|
||||
name = @_loweredHeaders[loweredName]
|
||||
@_headers[name] = @_headers[name] + ', ' + value
|
||||
else
|
||||
# New header.
|
||||
@_loweredHeaders[loweredName] = name
|
||||
@_headers[name] = value
|
||||
|
||||
undefined
|
||||
|
||||
# Initiates the request.
|
||||
#
|
||||
# @param {?String, ?ArrayBufferView} data the data to be sent; ignored for
|
||||
# GET and HEAD requests
|
||||
# @return {undefined} undefined
|
||||
# @throw {InvalidStateError} readyState is not OPENED
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-send()-method
|
||||
send: (data) ->
|
||||
unless @readyState is XMLHttpRequest.OPENED
|
||||
throw new InvalidStateError "XHR readyState must be OPENED"
|
||||
|
||||
if @_request
|
||||
throw new InvalidStateError "send() already called"
|
||||
|
||||
switch @_url.protocol
|
||||
when 'file:'
|
||||
@_sendFile data
|
||||
when 'http:', 'https:'
|
||||
@_sendHttp data
|
||||
else
|
||||
throw new NetworkError "Unsupported protocol #{@_url.protocol}"
|
||||
|
||||
undefined
|
||||
|
||||
# Cancels the network activity performed by this request.
|
||||
#
|
||||
# @return {undefined} undefined
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-abort()-method
|
||||
abort: ->
|
||||
return unless @_request
|
||||
|
||||
@_request.abort()
|
||||
@_setError()
|
||||
@_dispatchProgress 'abort'
|
||||
@_dispatchProgress 'loadend'
|
||||
undefined
|
||||
|
||||
# Returns a header value in the HTTP response for this XHR.
|
||||
#
|
||||
# @param {String} name case-insensitive HTTP header name
|
||||
# @return {?String} value the value of the header whose name matches the
|
||||
# given name, or null if there is no such header
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-getresponseheader()-method
|
||||
getResponseHeader: (name) ->
|
||||
return null unless @_responseHeaders
|
||||
|
||||
loweredName = name.toLowerCase()
|
||||
if loweredName of @_responseHeaders
|
||||
@_responseHeaders[loweredName]
|
||||
else
|
||||
null
|
||||
|
||||
# Returns all the HTTP headers in this XHR's response.
|
||||
#
|
||||
# @return {String} header lines separated by CR LF, where each header line
|
||||
# has the name and value separated by a ": " (colon, space); the empty
|
||||
# string is returned if the headers are not available
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-getallresponseheaders()-method
|
||||
getAllResponseHeaders: ->
|
||||
return '' unless @_responseHeaders
|
||||
|
||||
lines = ("#{name}: #{value}" for name, value of @_responseHeaders)
|
||||
lines.join "\r\n"
|
||||
|
||||
# Overrides the Content-Type
|
||||
#
|
||||
# @return {undefined} undefined
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-overridemimetype()-method
|
||||
overrideMimeType: (newMimeType) ->
|
||||
if @readyState is XMLHttpRequest.LOADING or
|
||||
@readyState is XMLHttpRequest.DONE
|
||||
throw new InvalidStateError(
|
||||
"overrideMimeType() not allowed in LOADING or DONE")
|
||||
|
||||
@_mimeOverride = newMimeType.toLowerCase()
|
||||
undefined
|
||||
|
||||
# Network configuration not exposed in the XHR API.
|
||||
#
|
||||
# Although the XMLHttpRequest specification calls itself "ECMAScript HTTP",
|
||||
# it assumes that requests are always performed in the context of a browser
|
||||
# application, where some network parameters are set by the browser user and
|
||||
# should not be modified by Web applications. This API provides access to
|
||||
# these network parameters.
|
||||
#
|
||||
# NOTE: this is not in the XMLHttpRequest API, and will not work in
|
||||
# browsers. It is a stable node-xhr2 API.
|
||||
#
|
||||
# @param {Object} options one or more of the options below
|
||||
# @option options {?http.Agent} httpAgent the value for the nodejsHttpAgent
|
||||
# property (the agent used for HTTP requests)
|
||||
# @option options {?https.Agent} httpsAgent the value for the
|
||||
# nodejsHttpsAgent property (the agent used for HTTPS requests)
|
||||
# @return {undefined} undefined
|
||||
nodejsSet: (options) ->
|
||||
if 'httpAgent' of options
|
||||
@nodejsHttpAgent = options.httpAgent
|
||||
if 'httpsAgent' of options
|
||||
@nodejsHttpsAgent = options.httpsAgent
|
||||
if 'baseUrl' of options
|
||||
baseUrl = options.baseUrl
|
||||
unless baseUrl is null
|
||||
parsedUrl = url.parse baseUrl, false, true
|
||||
unless parsedUrl.protocol
|
||||
throw new SyntaxError("baseUrl must be an absolute URL")
|
||||
@nodejsBaseUrl = baseUrl
|
||||
|
||||
undefined
|
||||
|
||||
# Default settings for the network configuration not exposed in the XHR API.
|
||||
#
|
||||
# NOTE: this is not in the XMLHttpRequest API, and will not work in
|
||||
# browsers. It is a stable node-xhr2 API.
|
||||
#
|
||||
# @param {Object} options one or more of the options below
|
||||
# @option options {?http.Agent} httpAgent the default value for the
|
||||
# nodejsHttpAgent property (the agent used for HTTP requests)
|
||||
# @option options {https.Agent} httpsAgent the default value for the
|
||||
# nodejsHttpsAgent property (the agent used for HTTPS requests)
|
||||
# @return {undefined} undefined
|
||||
# @see XMLHttpRequest.nodejsSet
|
||||
@nodejsSet: (options) ->
|
||||
# "this" will be set to XMLHttpRequest.prototype, so the instance nodejsSet
|
||||
# operates on default property values.
|
||||
XMLHttpRequest::nodejsSet options
|
||||
|
||||
undefined
|
||||
|
||||
# readyState value before XMLHttpRequest#open() is called
|
||||
UNSENT: 0
|
||||
# readyState value before XMLHttpRequest#open() is called
|
||||
@UNSENT: 0
|
||||
|
||||
# readyState value after XMLHttpRequest#open() is called, and before
|
||||
# XMLHttpRequest#send() is called; XMLHttpRequest#setRequestHeader() can be
|
||||
# called in this state
|
||||
OPENED: 1
|
||||
# readyState value after XMLHttpRequest#open() is called, and before
|
||||
# XMLHttpRequest#send() is called; XMLHttpRequest#setRequestHeader() can be
|
||||
# called in this state
|
||||
@OPENED: 1
|
||||
|
||||
# readyState value after redirects have been followed and the HTTP headers of
|
||||
# the final response have been received
|
||||
HEADERS_RECEIVED: 2
|
||||
# readyState value after redirects have been followed and the HTTP headers of
|
||||
# the final response have been received
|
||||
@HEADERS_RECEIVED: 2
|
||||
|
||||
# readyState value when the response entity body is being received
|
||||
LOADING: 3
|
||||
# readyState value when the response entity body is being received
|
||||
@LOADING: 3
|
||||
|
||||
# readyState value after the request has been completely processed
|
||||
DONE: 4
|
||||
# readyState value after the request has been completely processed
|
||||
@DONE: 4
|
||||
|
||||
# @property {http.Agent} the agent option passed to HTTP requests
|
||||
#
|
||||
# NOTE: this is not in the XMLHttpRequest API, and will not work in browsers.
|
||||
# It is a stable node-xhr2 API that is useful for testing & going through
|
||||
# web-proxies.
|
||||
nodejsHttpAgent: http.globalAgent
|
||||
|
||||
# @property {https.Agent} the agent option passed to HTTPS requests
|
||||
#
|
||||
# NOTE: this is not in the XMLHttpRequest API, and will not work in browsers.
|
||||
# It is a stable node-xhr2 API that is useful for testing & going through
|
||||
# web-proxies.
|
||||
nodejsHttpsAgent: https.globalAgent
|
||||
|
||||
# @property {String} the base URL that relative URLs get resolved to
|
||||
#
|
||||
# NOTE: this is not in the XMLHttpRequest API, and will not work in browsers.
|
||||
# Its browser equivalent is the base URL of the document associated with the
|
||||
# Window object. It is a stable node-xhr2 API provided for libraries such as
|
||||
# Angular Universal.
|
||||
nodejsBaseUrl: null
|
||||
|
||||
# HTTP methods that are disallowed in the XHR spec.
|
||||
#
|
||||
# @private
|
||||
# @see Step 6 in http://www.w3.org/TR/XMLHttpRequest/#the-open()-method
|
||||
_restrictedMethods:
|
||||
CONNECT: true
|
||||
TRACE: true
|
||||
TRACK: true
|
||||
|
||||
# HTTP request headers that are disallowed in the XHR spec.
|
||||
#
|
||||
# @private
|
||||
# @see Step 5 in
|
||||
# http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader()-method
|
||||
_restrictedHeaders:
|
||||
'accept-charset': true
|
||||
'accept-encoding': true
|
||||
'access-control-request-headers': true
|
||||
'access-control-request-method': true
|
||||
connection: true
|
||||
'content-length': true
|
||||
cookie: true
|
||||
cookie2: true
|
||||
date: true
|
||||
dnt: true
|
||||
expect: true
|
||||
host: true
|
||||
'keep-alive': true
|
||||
origin: true
|
||||
referer: true
|
||||
te: true
|
||||
trailer: true
|
||||
'transfer-encoding': true
|
||||
upgrade: true
|
||||
'user-agent': true
|
||||
via: true
|
||||
|
||||
# HTTP response headers that should not be exposed according to the XHR spec.
|
||||
#
|
||||
# @private
|
||||
# @see Step 3 in
|
||||
# http://www.w3.org/TR/XMLHttpRequest/#the-getresponseheader()-method
|
||||
_privateHeaders:
|
||||
'set-cookie': true
|
||||
'set-cookie2': true
|
||||
|
||||
# The value of the User-Agent header.
|
||||
_userAgent: "Mozilla/5.0 (#{os.type()} #{os.arch()}) " +
|
||||
"node.js/#{process.versions.node} v8/#{process.versions.v8}"
|
||||
|
||||
# Sets the readyState property and fires the readystatechange event.
|
||||
#
|
||||
# @private
|
||||
# @param {Number} newReadyState the new value of readyState
|
||||
# @return {undefined} undefined
|
||||
_setReadyState: (newReadyState) ->
|
||||
@readyState = newReadyState
|
||||
event = new ProgressEvent 'readystatechange'
|
||||
@dispatchEvent event
|
||||
undefined
|
||||
|
||||
# XMLHttpRequest#send() implementation for the file: protocol.
|
||||
#
|
||||
# @private
|
||||
_sendFile: ->
|
||||
unless @_url.method is 'GET'
|
||||
throw new NetworkError 'The file protocol only supports GET'
|
||||
|
||||
throw new Error "Protocol file: not implemented"
|
||||
|
||||
# XMLHttpRequest#send() implementation for the http: and https: protocols.
|
||||
#
|
||||
# @private
|
||||
# This method sets the instance variables and calls _sendHxxpRequest(), which
|
||||
# is responsible for building a node.js request and firing it off. The code
|
||||
# in _sendHxxpRequest() is separated off so it can be reused when handling
|
||||
# redirects.
|
||||
#
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#infrastructure-for-the-send()-method
|
||||
_sendHttp: (data) ->
|
||||
if @_sync
|
||||
throw new Error "Synchronous XHR processing not implemented"
|
||||
|
||||
if data? and (@_method is 'GET' or @_method is 'HEAD')
|
||||
console.warn "Discarding entity body for #{@_method} requests"
|
||||
data = null
|
||||
else
|
||||
# Send Content-Length: 0
|
||||
data or= ''
|
||||
|
||||
# NOTE: this is called before finalizeHeaders so that the uploader can
|
||||
# figure out Content-Length and Content-Type.
|
||||
@upload._setData data
|
||||
@_finalizeHeaders()
|
||||
|
||||
@_sendHxxpRequest()
|
||||
undefined
|
||||
|
||||
# Sets up and fires off a HTTP/HTTPS request using the node.js API.
|
||||
#
|
||||
# @private
|
||||
# This method contains the bulk of the XMLHttpRequest#send() implementation,
|
||||
# and is also used to issue new HTTP requests when handling HTTP redirects.
|
||||
#
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#infrastructure-for-the-send()-method
|
||||
_sendHxxpRequest: ->
|
||||
if @_url.protocol is 'http:'
|
||||
hxxp = http
|
||||
agent = @nodejsHttpAgent
|
||||
else
|
||||
hxxp = https
|
||||
agent = @nodejsHttpsAgent
|
||||
|
||||
request = hxxp.request
|
||||
hostname: @_url.hostname, port: @_url.port, path: @_url.path,
|
||||
auth: @_url.auth, method: @_method, headers: @_headers, agent: agent
|
||||
@_request = request
|
||||
if @timeout
|
||||
request.setTimeout @timeout, => @_onHttpTimeout request
|
||||
request.on 'response', (response) => @_onHttpResponse request, response
|
||||
request.on 'error', (error) => @_onHttpRequestError request, error
|
||||
@upload._startUpload request
|
||||
if @_request is request # An http error might have already fired.
|
||||
@_dispatchProgress 'loadstart'
|
||||
|
||||
undefined
|
||||
|
||||
# Fills in the restricted HTTP headers with default values.
|
||||
#
|
||||
# This is called right before the HTTP request is sent off.
|
||||
#
|
||||
# @private
|
||||
# @return {undefined} undefined
|
||||
_finalizeHeaders: ->
|
||||
@_headers['Connection'] = 'keep-alive'
|
||||
@_headers['Host'] = @_url.host
|
||||
if @_anonymous
|
||||
@_headers['Referer'] = 'about:blank'
|
||||
@_headers['User-Agent'] = @_userAgent
|
||||
@upload._finalizeHeaders @_headers, @_loweredHeaders
|
||||
undefined
|
||||
|
||||
|
||||
# Called when the headers of an HTTP response have been received.
|
||||
#
|
||||
# @private
|
||||
# @param {http.ClientRequest} request the node.js ClientRequest instance that
|
||||
# produced this response
|
||||
# @param {http.ClientResponse} response the node.js ClientResponse instance
|
||||
# passed to
|
||||
_onHttpResponse: (request, response) ->
|
||||
return unless @_request is request
|
||||
|
||||
# Transparent redirection handling.
|
||||
switch response.statusCode
|
||||
when 301, 302, 303, 307, 308
|
||||
@_url = @_parseUrl response.headers['location']
|
||||
@_method = 'GET'
|
||||
if 'content-type' of @_loweredHeaders
|
||||
delete @_headers[@_loweredHeaders['content-type']]
|
||||
delete @_loweredHeaders['content-type']
|
||||
# XMLHttpRequestUpload#_finalizeHeaders() sets Content-Type directly.
|
||||
if 'Content-Type' of @_headers
|
||||
delete @_headers['Content-Type']
|
||||
# Restricted headers can't be set by the user, no need to check
|
||||
# loweredHeaders.
|
||||
delete @_headers['Content-Length']
|
||||
|
||||
@upload._reset()
|
||||
@_finalizeHeaders()
|
||||
@_sendHxxpRequest()
|
||||
return
|
||||
|
||||
@_response = response
|
||||
@_response.on 'data', (data) => @_onHttpResponseData response, data
|
||||
@_response.on 'end', => @_onHttpResponseEnd response
|
||||
@_response.on 'close', => @_onHttpResponseClose response
|
||||
|
||||
@responseURL = @_url.href.split('#')[0]
|
||||
@status = @_response.statusCode
|
||||
@statusText = http.STATUS_CODES[@status]
|
||||
@_parseResponseHeaders response
|
||||
|
||||
if lengthString = @_responseHeaders['content-length']
|
||||
@_totalBytes = parseInt(lengthString)
|
||||
@_lengthComputable = true
|
||||
else
|
||||
@_lengthComputable = false
|
||||
|
||||
@_setReadyState XMLHttpRequest.HEADERS_RECEIVED
|
||||
|
||||
# Called when some data has been received on a HTTP connection.
|
||||
#
|
||||
# @private
|
||||
# @param {http.ClientResponse} response the node.js ClientResponse instance
|
||||
# that fired this event
|
||||
# @param {String, Buffer} data the data that has been received
|
||||
_onHttpResponseData: (response, data) ->
|
||||
return unless @_response is response
|
||||
|
||||
@_responseParts.push data
|
||||
@_loadedBytes += data.length
|
||||
|
||||
if @readyState isnt XMLHttpRequest.LOADING
|
||||
@_setReadyState XMLHttpRequest.LOADING
|
||||
@_dispatchProgress 'progress'
|
||||
|
||||
# Called when the HTTP request finished processing.
|
||||
#
|
||||
# @private
|
||||
# @param {http.ClientResponse} response the node.js ClientResponse instance
|
||||
# that fired this event
|
||||
_onHttpResponseEnd: (response) ->
|
||||
return unless @_response is response
|
||||
|
||||
@_parseResponse()
|
||||
|
||||
@_request = null
|
||||
@_response = null
|
||||
@_setReadyState XMLHttpRequest.DONE
|
||||
@_dispatchProgress 'load'
|
||||
@_dispatchProgress 'loadend'
|
||||
|
||||
# Called when the underlying HTTP connection was closed prematurely.
|
||||
#
|
||||
# If this method is called, it will be called after or instead of
|
||||
# onHttpResponseEnd.
|
||||
#
|
||||
# @private
|
||||
# @param {http.ClientResponse} response the node.js ClientResponse instance
|
||||
# that fired this event
|
||||
_onHttpResponseClose: (response) ->
|
||||
return unless @_response is response
|
||||
|
||||
request = @_request
|
||||
@_setError()
|
||||
request.abort()
|
||||
@_setReadyState XMLHttpRequest.DONE
|
||||
@_dispatchProgress 'error'
|
||||
@_dispatchProgress 'loadend'
|
||||
|
||||
# Called when the timeout set on the HTTP socket expires.
|
||||
#
|
||||
# @private
|
||||
# @param {http.ClientRequest} request the node.js ClientRequest instance that
|
||||
# fired this event
|
||||
_onHttpTimeout: (request) ->
|
||||
return unless @_request is request
|
||||
|
||||
@_setError()
|
||||
request.abort()
|
||||
@_setReadyState XMLHttpRequest.DONE
|
||||
@_dispatchProgress 'timeout'
|
||||
@_dispatchProgress 'loadend'
|
||||
|
||||
# Called when something wrong happens on the HTTP socket
|
||||
#
|
||||
# @private
|
||||
# @param {http.ClientRequest} request the node.js ClientRequest instance that
|
||||
# fired this event
|
||||
# @param {Error} error emitted exception
|
||||
_onHttpRequestError: (request, error) ->
|
||||
return unless @_request is request
|
||||
|
||||
@_setError()
|
||||
request.abort()
|
||||
@_setReadyState XMLHttpRequest.DONE
|
||||
@_dispatchProgress 'error'
|
||||
@_dispatchProgress 'loadend'
|
||||
|
||||
# Fires an XHR progress event.
|
||||
#
|
||||
# @private
|
||||
# @param {String} eventType one of the XHR progress event types, such as
|
||||
# 'load' and 'progress'
|
||||
_dispatchProgress: (eventType) ->
|
||||
event = new ProgressEvent eventType
|
||||
event.lengthComputable = @_lengthComputable
|
||||
event.loaded = @_loadedBytes
|
||||
event.total = @_totalBytes
|
||||
@dispatchEvent event
|
||||
undefined
|
||||
|
||||
# Sets up the XHR to reflect the fact that an error has occurred.
|
||||
#
|
||||
# The possible errors are a network error, a timeout, or an abort.
|
||||
#
|
||||
# @private
|
||||
_setError: ->
|
||||
@_request = null
|
||||
@_response = null
|
||||
@_responseHeaders = null
|
||||
@_responseParts = null
|
||||
undefined
|
||||
|
||||
# Parses a request URL string.
|
||||
#
|
||||
# @private
|
||||
# This method is a thin wrapper around url.parse() that normalizes HTTP
|
||||
# user/password credentials. It is used to parse the URL string passed to
|
||||
# XMLHttpRequest#open() and the URLs in the Location headers of HTTP redirect
|
||||
# responses.
|
||||
#
|
||||
# @param {String} urlString the URL to be parsed
|
||||
# @return {Object} parsed URL
|
||||
_parseUrl: (urlString) ->
|
||||
if @nodejsBaseUrl is null
|
||||
absoluteUrlString = urlString
|
||||
else
|
||||
absoluteUrlString = url.resolve @nodejsBaseUrl, urlString
|
||||
|
||||
xhrUrl = url.parse absoluteUrlString, false, true
|
||||
xhrUrl.hash = null
|
||||
if xhrUrl.auth and (user? or password?)
|
||||
index = xhrUrl.auth.indexOf ':'
|
||||
if index is -1
|
||||
user = xhrUrl.auth unless user
|
||||
else
|
||||
user = xhrUrl.substring(0, index) unless user
|
||||
password = xhrUrl.substring(index + 1) unless password
|
||||
if user or password
|
||||
xhrUrl.auth = "#{user}:#{password}"
|
||||
xhrUrl
|
||||
|
||||
# Reads the headers from a node.js ClientResponse instance.
|
||||
#
|
||||
# @private
|
||||
# @param {http.ClientResponse} response the response whose headers will be
|
||||
# imported into this XMLHttpRequest's state
|
||||
# @return {undefined} undefined
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-getresponseheader()-method
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-getallresponseheaders()-method
|
||||
_parseResponseHeaders: (response) ->
|
||||
@_responseHeaders = {}
|
||||
for name, value of response.headers
|
||||
loweredName = name.toLowerCase()
|
||||
continue if @_privateHeaders[loweredName]
|
||||
if @_mimeOverride isnt null and loweredName is 'content-type'
|
||||
value = @_mimeOverride
|
||||
@_responseHeaders[loweredName] = value
|
||||
|
||||
if @_mimeOverride isnt null and !('content-type' of @_responseHeaders)
|
||||
@_responseHeaders['content-type'] = @_mimeOverride
|
||||
undefined
|
||||
|
||||
# Sets the response and responseText properties when an XHR completes.
|
||||
#
|
||||
# @private
|
||||
# @return {undefined} undefined
|
||||
_parseResponse: ->
|
||||
if Buffer.concat
|
||||
buffer = Buffer.concat @_responseParts
|
||||
else
|
||||
# node 0.6
|
||||
buffer = @_concatBuffers @_responseParts
|
||||
@_responseParts = null
|
||||
|
||||
switch @responseType
|
||||
when 'text'
|
||||
@_parseTextResponse buffer
|
||||
when 'json'
|
||||
@responseText = null
|
||||
try
|
||||
@response = JSON.parse buffer.toString('utf-8')
|
||||
catch jsonError
|
||||
@response = null
|
||||
when 'buffer'
|
||||
@responseText = null
|
||||
@response = buffer
|
||||
when 'arraybuffer'
|
||||
@responseText = null
|
||||
arrayBuffer = new ArrayBuffer buffer.length
|
||||
view = new Uint8Array arrayBuffer
|
||||
view[i] = buffer[i] for i in [0...buffer.length]
|
||||
@response = arrayBuffer
|
||||
else
|
||||
# TODO(pwnall): content-base detection
|
||||
@_parseTextResponse buffer
|
||||
undefined
|
||||
|
||||
# Sets response and responseText for a 'text' response type.
|
||||
#
|
||||
# @private
|
||||
# @param {Buffer} buffer the node.js Buffer containing the binary response
|
||||
# @return {undefined} undefined
|
||||
_parseTextResponse: (buffer) ->
|
||||
try
|
||||
@responseText = buffer.toString @_parseResponseEncoding()
|
||||
catch e
|
||||
# Unknown encoding.
|
||||
@responseText = buffer.toString 'binary'
|
||||
|
||||
@response = @responseText
|
||||
undefined
|
||||
|
||||
# Figures out the string encoding of the XHR's response.
|
||||
#
|
||||
# This is called to determine the encoding when responseText is set.
|
||||
#
|
||||
# @private
|
||||
# @return {String} a string encoding, e.g. 'utf-8'
|
||||
_parseResponseEncoding: ->
|
||||
encoding = null
|
||||
if contentType = @_responseHeaders['content-type']
|
||||
if match = /\;\s*charset\=(.*)$/.exec contentType
|
||||
return match[1]
|
||||
'utf-8'
|
||||
|
||||
# Buffer.concat implementation for node 0.6.
|
||||
#
|
||||
# @private
|
||||
# @param {Array<Buffer>} buffers the buffers whose contents will be merged
|
||||
# @return {Buffer} same as Buffer.concat(buffers) in node 0.8 and above
|
||||
_concatBuffers: (buffers) ->
|
||||
if buffers.length is 0
|
||||
return new Buffer 0
|
||||
if buffers.length is 1
|
||||
return buffers[0]
|
||||
|
||||
length = 0
|
||||
length += buffer.length for buffer in buffers
|
||||
target = new Buffer length
|
||||
length = 0
|
||||
for buffer in buffers
|
||||
buffer.copy target, length
|
||||
length += buffer.length
|
||||
target
|
||||
|
||||
# XMLHttpRequest is the result of require('node-xhr2').
|
||||
module.exports = XMLHttpRequest
|
||||
|
||||
# Make node-xhr2 work as a drop-in replacement for libraries that promote the
|
||||
# following usage pattern:
|
||||
# var XMLHttpRequest = require('xhr-library-name').XMLHttpRequest
|
||||
XMLHttpRequest.XMLHttpRequest = XMLHttpRequest
|
||||
31
node_modules/xhr2/src/errors.coffee
generated
vendored
Normal file
31
node_modules/xhr2/src/errors.coffee
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
# This file defines the custom errors used in the XMLHttpRequest specification.
|
||||
|
||||
# Thrown if the XHR security policy is violated.
|
||||
class SecurityError extends Error
|
||||
# @private
|
||||
constructor: -> super
|
||||
|
||||
# Thrown if the XHR security policy is violated.
|
||||
XMLHttpRequest.SecurityError = SecurityError
|
||||
|
||||
|
||||
# Usually thrown if the XHR is in the wrong readyState for an operation.
|
||||
class InvalidStateError extends Error
|
||||
# @private
|
||||
constructor: -> super
|
||||
|
||||
# Usually thrown if the XHR is in the wrong readyState for an operation.
|
||||
class InvalidStateError extends Error
|
||||
XMLHttpRequest.InvalidStateError = InvalidStateError
|
||||
|
||||
# Thrown if there is a problem with the URL passed to the XHR.
|
||||
class NetworkError extends Error
|
||||
# @private
|
||||
constructor: -> super
|
||||
|
||||
# Thrown if parsing URLs errors out.
|
||||
XMLHttpRequest.SyntaxError = SyntaxError
|
||||
|
||||
class SyntaxError extends Error
|
||||
# @private:
|
||||
constructor: -> super
|
||||
39
node_modules/xhr2/src/progress_event.coffee
generated
vendored
Normal file
39
node_modules/xhr2/src/progress_event.coffee
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
# http://xhr.spec.whatwg.org/#interface-progressevent
|
||||
class ProgressEvent
|
||||
# Creates a new event.
|
||||
#
|
||||
# @param {String} type the event type, e.g. 'readystatechange'; must be
|
||||
# lowercased
|
||||
constructor: (@type) ->
|
||||
@target = null
|
||||
@currentTarget = null
|
||||
@lengthComputable = false
|
||||
@loaded = 0
|
||||
@total = 0
|
||||
# Getting the time from the OS is expensive, skip on that for now.
|
||||
# @timeStamp = Date.now()
|
||||
|
||||
# @property {Boolean} for compatibility with DOM events
|
||||
bubbles: false
|
||||
|
||||
# @property {Boolean} for fompatibility with DOM events
|
||||
cancelable: false
|
||||
|
||||
# @property {XMLHttpRequest} the request that caused this event
|
||||
target: null
|
||||
|
||||
# @property {Number} number of bytes that have already been downloaded or
|
||||
# uploaded
|
||||
loaded: null
|
||||
|
||||
# @property {Boolean} true if the Content-Length response header is available
|
||||
# and the value of the event's total property is meaningful
|
||||
lengthComputable: null
|
||||
|
||||
# @property {Number} number of bytes that will be downloaded or uploaded by
|
||||
# the request that fired the event
|
||||
total: null
|
||||
|
||||
|
||||
# The XHR spec exports the ProgressEvent constructor.
|
||||
XMLHttpRequest.ProgressEvent = ProgressEvent
|
||||
95
node_modules/xhr2/src/xml_http_request_upload.coffee
generated
vendored
Normal file
95
node_modules/xhr2/src/xml_http_request_upload.coffee
generated
vendored
Normal file
@@ -0,0 +1,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
|
||||
Reference in New Issue
Block a user