Updated the files.
This commit is contained in:
parent
1553e6b971
commit
753967d4f5
23418 changed files with 3784666 additions and 0 deletions
33
my-app/node_modules/xhr2/CONTRIBUTING.md
generated
vendored
Executable file
33
my-app/node_modules/xhr2/CONTRIBUTING.md
generated
vendored
Executable file
|
|
@ -0,0 +1,33 @@
|
|||
# xhr2 Contribution Policy
|
||||
|
||||
This is an open-source library and welcomes outside contributions.
|
||||
|
||||
Please file bugs on
|
||||
[the GitHub issue page](https://github.com/pwnall/xhr2/issues).
|
||||
|
||||
Please submit patches as
|
||||
[GitHub pull requests](https://help.github.com/articles/using-pull-requests).
|
||||
Please check the
|
||||
[existing pull requests](https://github.com/pwnall/xhr2/issues) to avoid
|
||||
duplicating effort.
|
||||
|
||||
|
||||
## Pull Request Checklist
|
||||
|
||||
* Do not modify the version in `package.json` or the commit history. Feel free
|
||||
to rebase your commits while the pull request is in progress.
|
||||
* If your patch adds new functionality, please make sure to include link to the
|
||||
relevant parts of the
|
||||
[W3C XMLHttpRequest specification](http://www.w3.org/TR/XMLHttpRequest/). Use
|
||||
the same style as existing source code.
|
||||
* Include tests whenever possible, so the functionality won't be broken by
|
||||
accident in future releases.
|
||||
|
||||
|
||||
## Obligatory Legalese
|
||||
|
||||
By submitting a contribution to the library, you grant Victor Costan
|
||||
(the library's author) a non-exclusive, irrevocable, perpetual, transferable,
|
||||
license to use, reproduce, modify, adapt, publish, translate, create derivative
|
||||
works from, distribute, perform and display your contribution (in whole or
|
||||
part) worldwide under the MIT license.
|
||||
131
my-app/node_modules/xhr2/Cakefile
generated
vendored
Executable file
131
my-app/node_modules/xhr2/Cakefile
generated
vendored
Executable file
|
|
@ -0,0 +1,131 @@
|
|||
async = require 'async'
|
||||
{spawn, exec} = require 'child_process'
|
||||
fs = require 'fs'
|
||||
glob = require 'glob'
|
||||
log = console.log
|
||||
path = require 'path'
|
||||
remove = require 'remove'
|
||||
|
||||
# Node 0.6 compatibility hack.
|
||||
unless fs.existsSync
|
||||
fs.existsSync = (filePath) -> path.existsSync filePath
|
||||
|
||||
|
||||
task 'build', ->
|
||||
build()
|
||||
|
||||
task 'test', ->
|
||||
vendor ->
|
||||
build ->
|
||||
ssl_cert ->
|
||||
test_cases = glob.sync 'test/js/**/*_test.js'
|
||||
test_cases.sort() # Consistent test case order.
|
||||
run 'node_modules/.bin/mocha --colors --slow 200 --timeout 1000 --exit ' +
|
||||
"--require test/js/helpers/setup.js #{test_cases.join(' ')}"
|
||||
|
||||
task 'webtest', ->
|
||||
vendor ->
|
||||
build ->
|
||||
ssl_cert ->
|
||||
webtest()
|
||||
|
||||
task 'cert', ->
|
||||
remove.removeSync 'test/ssl', ignoreMissing: true
|
||||
ssl_cert()
|
||||
|
||||
task 'vendor', ->
|
||||
remove.removeSync './test/vendor', ignoreMissing: true
|
||||
vendor()
|
||||
|
||||
task 'doc', ->
|
||||
run 'node_modules/.bin/codo --title "node-xhr API Documentation" src'
|
||||
|
||||
build = (callback) ->
|
||||
commands = []
|
||||
|
||||
# Ignoring ".coffee" when sorting.
|
||||
# We want "driver.coffee" to sort before "driver-browser.coffee"
|
||||
source_files = glob.sync 'src/**/*.coffee'
|
||||
source_files.sort (a, b) ->
|
||||
a.replace(/\.coffee$/, '').localeCompare b.replace(/\.coffee$/, '')
|
||||
|
||||
# Compile without --join for decent error messages.
|
||||
commands.push 'node_modules/.bin/coffee --output tmp --compile ' +
|
||||
source_files.join(' ')
|
||||
commands.push 'node_modules/.bin/coffee --output lib --compile ' +
|
||||
"--join xhr2.js #{source_files.join(' ')}"
|
||||
|
||||
# Tests are supposed to be independent, so the build order doesn't matter.
|
||||
test_dirs = glob.sync 'test/src/**/'
|
||||
for test_dir in test_dirs
|
||||
out_dir = test_dir.replace(/^test\/src\//, 'test/js/')
|
||||
test_files = glob.sync path.join(test_dir, '*.coffee')
|
||||
commands.push "node_modules/.bin/coffee --output #{out_dir} " +
|
||||
"--compile #{test_files.join(' ')}"
|
||||
|
||||
async.forEachSeries commands, run, ->
|
||||
# Build the binary test image.
|
||||
buffer = fs.readFileSync 'test/fixtures/xhr2.png'
|
||||
bytes = (buffer.readUInt8(i) for i in [0...buffer.length])
|
||||
globalJs = '((function(){ return this.global || this; })())'
|
||||
js = "#{globalJs}.xhr2PngBytes = #{JSON.stringify(bytes)};"
|
||||
fs.writeFile 'test/js/helpers/xhr2.png.js', js, ->
|
||||
callback() if callback
|
||||
|
||||
webtest = (callback) ->
|
||||
xhrServer = require './test/js/helpers/xhr_server.js'
|
||||
if 'BROWSER' of process.env
|
||||
if process.env['BROWSER'] is 'false'
|
||||
url = xhrServer.https.testUrl()
|
||||
console.log "Please open the URL below in your browser:\n #{url}"
|
||||
else
|
||||
xhrServer.https.openBrowser process.env['BROWSER']
|
||||
else
|
||||
xhrServer.https.openBrowser()
|
||||
callback() if callback?
|
||||
|
||||
ssl_cert = (callback) ->
|
||||
if fs.existsSync 'test/ssl/cert.pem'
|
||||
callback() if callback?
|
||||
return
|
||||
|
||||
fs.mkdirSync 'test/ssl' unless fs.existsSync 'test/ssl'
|
||||
run 'openssl req -new -x509 -days 365 -nodes -sha256 -newkey rsa:2048 ' +
|
||||
'-batch -out test/ssl/cert.pem -keyout test/ssl/cert.pem ' +
|
||||
'-subj /O=xhr2.js/OU=Testing/CN=localhost ', callback
|
||||
|
||||
vendor = (callback) ->
|
||||
# All the files will be dumped here.
|
||||
fs.mkdirSync 'test/vendor' unless fs.existsSync 'test/vendor'
|
||||
|
||||
downloads = [
|
||||
# chai.js ships different builds for browsers vs node.js
|
||||
['https://www.chaijs.com/chai.js', 'test/vendor/chai.js'],
|
||||
# sinon.js also ships special builds for browsers
|
||||
['https://sinonjs.org/releases/sinon.js', 'test/vendor/sinon.js'],
|
||||
]
|
||||
async.forEachSeries downloads, download, ->
|
||||
callback() if callback
|
||||
|
||||
run = (args...) ->
|
||||
for a in args
|
||||
switch typeof a
|
||||
when 'string' then command = a
|
||||
when 'object'
|
||||
if a instanceof Array then params = a
|
||||
else options = a
|
||||
when 'function' then callback = a
|
||||
|
||||
command += ' ' + params.join ' ' if params?
|
||||
cmd = spawn '/bin/sh', ['-c', command], options
|
||||
cmd.stdout.on 'data', (data) -> process.stdout.write data
|
||||
cmd.stderr.on 'data', (data) -> process.stderr.write data
|
||||
process.on 'SIGHUP', -> cmd.kill()
|
||||
cmd.on 'exit', (code) -> callback() if callback? and code is 0
|
||||
|
||||
download = ([url, file], callback) ->
|
||||
if fs.existsSync file
|
||||
callback() if callback?
|
||||
return
|
||||
|
||||
run "curl -o #{file} #{url}", callback
|
||||
19
my-app/node_modules/xhr2/LICENSE.txt
generated
vendored
Executable file
19
my-app/node_modules/xhr2/LICENSE.txt
generated
vendored
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2013 Victor Costan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
142
my-app/node_modules/xhr2/README.md
generated
vendored
Executable file
142
my-app/node_modules/xhr2/README.md
generated
vendored
Executable file
|
|
@ -0,0 +1,142 @@
|
|||
# XMLHttpRequest Emulation for node.js
|
||||
|
||||
This is an [npm](https://npmjs.org/) package that implements the
|
||||
[W3C XMLHttpRequest](http://www.w3.org/TR/XMLHttpRequest/) specification on top
|
||||
of the [node.js](http://nodejs.org/) APIs.
|
||||
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
This library is tested against the following platforms.
|
||||
|
||||
* [node.js](http://nodejs.org/) 10
|
||||
* [node.js](http://nodejs.org/) 12
|
||||
|
||||
Keep in mind that the versions above are not hard requirements.
|
||||
|
||||
|
||||
## Installation and Usage
|
||||
|
||||
The preferred installation method is to add the library to the `dependencies`
|
||||
section in your `package.json`.
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"xhr2": "*"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, `npm` can be used to install the library directly.
|
||||
|
||||
```bash
|
||||
npm install xhr2
|
||||
```
|
||||
|
||||
Once the library is installed, `require`-ing it returns the `XMLHttpRequest`
|
||||
constructor.
|
||||
|
||||
```javascript
|
||||
var XMLHttpRequest = require('xhr2');
|
||||
```
|
||||
|
||||
The other objects that are usually defined in an XHR environment are hanging
|
||||
off of `XMLHttpRequest`.
|
||||
|
||||
```javascript
|
||||
var XMLHttpRequestUpload = XMLHttpRequest.XMLHttpRequestUpload;
|
||||
```
|
||||
|
||||
MDN (the Mozilla Developer Network) has a
|
||||
[great intro to XMLHttpRequest](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest).
|
||||
|
||||
This library's [CoffeeDocs](http://coffeedoc.info/github/pwnall/node-xhr2/) can
|
||||
be used as quick reference to the XMLHttpRequest specification parts that were
|
||||
implemented.
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
The following standard features are implemented.
|
||||
|
||||
* `http` and `https` URI protocols
|
||||
* Basic authentication according to the XMLHttpRequest specification
|
||||
* request and response header management
|
||||
* `send()` accepts the following data types: String, ArrayBufferView,
|
||||
ArrayBuffer (deprecated in the standard)
|
||||
* `responseType` values: `text`, `json`, `arraybuffer`
|
||||
* `readystatechange` and download progress events
|
||||
* `overrideMimeType()`
|
||||
* `abort()`
|
||||
* `timeout`
|
||||
* automated redirection following
|
||||
|
||||
The following node.js extensions are implemented.
|
||||
|
||||
* `send()` accepts a node.js Buffer
|
||||
* Setting `responseType` to `buffer` produces a node.js Buffer
|
||||
* `nodejsSet` does XHR network configuration that is not exposed in browsers,
|
||||
for security reasons
|
||||
|
||||
The following standard features are not implemented.
|
||||
|
||||
* FormData
|
||||
* Blob
|
||||
* `file://` URIs
|
||||
* `data:` URIs
|
||||
* upload progress events
|
||||
* synchronous operation
|
||||
* Same-origin policy checks and CORS
|
||||
* cookie processing
|
||||
|
||||
|
||||
## Versioning
|
||||
|
||||
The library aims to implement the
|
||||
[W3C XMLHttpRequest](http://www.w3.org/TR/XMLHttpRequest/) specification, so
|
||||
the library's API will always be a (hopefully growing) subset of the API in the
|
||||
specification.
|
||||
|
||||
|
||||
## Development
|
||||
|
||||
The following commands will get the source tree in a `node-xhr2/` directory and
|
||||
build the library.
|
||||
|
||||
```bash
|
||||
git clone git://github.com/pwnall/node-xhr2.git
|
||||
cd node-xhr2
|
||||
npm install
|
||||
npm pack
|
||||
```
|
||||
|
||||
Installing CoffeeScript globally will let you type `cake` instead of
|
||||
`node_modules/.bin/cake`
|
||||
|
||||
```bash
|
||||
npm install -g coffeescript
|
||||
```
|
||||
|
||||
The library comes with unit tests that exercise the XMLHttpRequest API.
|
||||
|
||||
```bash
|
||||
cake test
|
||||
```
|
||||
|
||||
The tests themselves can be tested by running them in a browser environment,
|
||||
where a different XMLHttpRequest implementation is available. Both Google
|
||||
Chrome and Firefox deviate from the specification in small ways, so it's best
|
||||
to run the tests in both browsers and mentally compute an intersection of the
|
||||
failing tests.
|
||||
|
||||
```bash
|
||||
cake webtest
|
||||
BROWSER=firefox cake webtest
|
||||
```
|
||||
|
||||
|
||||
## Copyright and License
|
||||
|
||||
The library is Copyright (c) 2013 Victor Costan, and distributed under the MIT
|
||||
License.
|
||||
1
my-app/node_modules/xhr2/lib/browser.js
generated
vendored
Executable file
1
my-app/node_modules/xhr2/lib/browser.js
generated
vendored
Executable file
|
|
@ -0,0 +1 @@
|
|||
module.exports = XMLHttpRequest;
|
||||
1244
my-app/node_modules/xhr2/lib/xhr2.js
generated
vendored
Executable file
1244
my-app/node_modules/xhr2/lib/xhr2.js
generated
vendored
Executable file
File diff suppressed because it is too large
Load diff
57
my-app/node_modules/xhr2/package.json
generated
vendored
Executable file
57
my-app/node_modules/xhr2/package.json
generated
vendored
Executable file
|
|
@ -0,0 +1,57 @@
|
|||
{
|
||||
"name": "xhr2",
|
||||
"version": "0.2.1",
|
||||
"description": "XMLHttpRequest emulation for node.js",
|
||||
"keywords": [
|
||||
"xhr",
|
||||
"xmlhttprequest",
|
||||
"ajax",
|
||||
"browser"
|
||||
],
|
||||
"homepage": "https://github.com/pwnall/node-xhr2",
|
||||
"author": "Victor Costan <victor@costan.us> (http://www.costan.us)",
|
||||
"contributors": [
|
||||
"Alexander Black <aeonrush@live.ru>",
|
||||
"Daniel Friedman <dfriedman58@gmail.com>",
|
||||
"Eugen Mayer <eugen.mayer@kontextwork.de>",
|
||||
"Francois-Xavier Kowalski <francois-xavier.kowalski@hp.com>",
|
||||
"Sébastien Nicouleaud"
|
||||
],
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pwnall/node-xhr2.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/pwnall/node-xhr2/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"async": ">=3.0.1",
|
||||
"chai": ">=4.2.0",
|
||||
"codo": ">=2.1.2",
|
||||
"coffeescript": ">=2.4.1",
|
||||
"express": ">=4.17.1",
|
||||
"glob": ">=7.1.4",
|
||||
"mocha": ">=6.1.4",
|
||||
"open": ">=6.3.0",
|
||||
"remove": ">= 0.1.5",
|
||||
"sinon": ">=7.3.2",
|
||||
"sinon-chai": ">=3.3.0"
|
||||
},
|
||||
"main": "lib/xhr2.js",
|
||||
"browser": "lib/browser.js",
|
||||
"directories": {
|
||||
"doc": "doc",
|
||||
"lib": "lib",
|
||||
"src": "src",
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublish": "cake build",
|
||||
"test": "cake test"
|
||||
}
|
||||
}
|
||||
89
my-app/node_modules/xhr2/src/000-xml_http_request_event_target.coffee
generated
vendored
Executable file
89
my-app/node_modules/xhr2/src/000-xml_http_request_event_target.coffee
generated
vendored
Executable 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
|
||||
781
my-app/node_modules/xhr2/src/001-xml_http_request.coffee
generated
vendored
Executable file
781
my-app/node_modules/xhr2/src/001-xml_http_request.coffee
generated
vendored
Executable file
|
|
@ -0,0 +1,781 @@
|
|||
# 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
|
||||
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 default 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 Buffer.alloc 0
|
||||
if buffers.length is 1
|
||||
return buffers[0]
|
||||
|
||||
length = 0
|
||||
length += buffer.length for buffer in buffers
|
||||
target = Buffer.alloc 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
my-app/node_modules/xhr2/src/errors.coffee
generated
vendored
Executable file
31
my-app/node_modules/xhr2/src/errors.coffee
generated
vendored
Executable 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
my-app/node_modules/xhr2/src/progress_event.coffee
generated
vendored
Executable file
39
my-app/node_modules/xhr2/src/progress_event.coffee
generated
vendored
Executable 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
my-app/node_modules/xhr2/src/xml_http_request_upload.coffee
generated
vendored
Executable file
95
my-app/node_modules/xhr2/src/xml_http_request_upload.coffee
generated
vendored
Executable 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 = Buffer.from 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 = Buffer.alloc 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 = Buffer.alloc 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
|
||||
1
my-app/node_modules/xhr2/test/fixtures/hello.json
generated
vendored
Executable file
1
my-app/node_modules/xhr2/test/fixtures/hello.json
generated
vendored
Executable file
|
|
@ -0,0 +1 @@
|
|||
{"hello": "world", "answer": 42}
|
||||
1
my-app/node_modules/xhr2/test/fixtures/hello.txt
generated
vendored
Executable file
1
my-app/node_modules/xhr2/test/fixtures/hello.txt
generated
vendored
Executable file
|
|
@ -0,0 +1 @@
|
|||
Hello world!
|
||||
BIN
my-app/node_modules/xhr2/test/fixtures/xhr2.png
generated
vendored
Executable file
BIN
my-app/node_modules/xhr2/test/fixtures/xhr2.png
generated
vendored
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 563 B |
30
my-app/node_modules/xhr2/test/html/browser_test.html
generated
vendored
Executable file
30
my-app/node_modules/xhr2/test/html/browser_test.html
generated
vendored
Executable file
|
|
@ -0,0 +1,30 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>node-xhr2 browser tests</title>
|
||||
<link rel="stylesheet" href="/node_modules/mocha/mocha.css" />
|
||||
<script src="/test/vendor/sinon.js"></script>
|
||||
<script src="/test/vendor/chai.js"></script>
|
||||
<script src="/node_modules/sinon-chai/lib/sinon-chai.js"></script>
|
||||
<script src="/node_modules/mocha/mocha.js"></script>
|
||||
<script src="/test/js/helpers/browser_mocha_setup.js"></script>
|
||||
<script src="/test/js/helpers/xhr2.png.js"></script>
|
||||
<script src="/test/js/helpers/setup.js"></script>
|
||||
|
||||
<script src="/test/js/event_target_test.js"></script>
|
||||
<script src="/test/js/events_test.js"></script>
|
||||
<script src="/test/js/headers_test.js"></script>
|
||||
<script src="/test/js/redirect_test.js"></script>
|
||||
<script src="/test/js/response_type_test.js"></script>
|
||||
<script src="/test/js/send_test.js"></script>
|
||||
<script src="/test/js/status_test.js"></script>
|
||||
<script src="/test/js/xhr_test.js"></script>
|
||||
|
||||
<script src="/test/js/helpers/browser_mocha_runner.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="mocha"></div>
|
||||
</body>
|
||||
</html>
|
||||
85
my-app/node_modules/xhr2/test/src/event_target_test.coffee
generated
vendored
Executable file
85
my-app/node_modules/xhr2/test/src/event_target_test.coffee
generated
vendored
Executable file
|
|
@ -0,0 +1,85 @@
|
|||
describe 'XMLHttpRequestEventTarget', ->
|
||||
describe 'dispatchEvent', ->
|
||||
beforeEach ->
|
||||
@xhr = new XMLHttpRequest
|
||||
@loadEvent = new ProgressEvent 'load'
|
||||
|
||||
it 'works with a DOM0 listener', ->
|
||||
count = 0
|
||||
@xhr.onload = (event) ->
|
||||
count += 1
|
||||
@xhr.dispatchEvent @loadEvent
|
||||
expect(count).to.equal 1
|
||||
|
||||
it 'works with a DOM2 listener', ->
|
||||
count = 0
|
||||
@xhr.addEventListener 'load', (event) ->
|
||||
count += 1
|
||||
@xhr.dispatchEvent @loadEvent
|
||||
expect(count).to.equal 1
|
||||
|
||||
it 'removes a DOM2 listener correctly', ->
|
||||
count = 0
|
||||
listener = (event) ->
|
||||
count += 1
|
||||
@xhr.addEventListener 'load', listener
|
||||
@xhr.dispatchEvent @loadEvent
|
||||
expect(count).to.equal 1
|
||||
|
||||
count = 0
|
||||
@xhr.removeEventListener 'load', listener
|
||||
@xhr.dispatchEvent @loadEvent
|
||||
expect(count).to.equal 0
|
||||
|
||||
it 'binds this correctly in a DOM0 listener', ->
|
||||
eventThis = null
|
||||
@xhr.onload = (event) ->
|
||||
eventThis = @
|
||||
@xhr.dispatchEvent @loadEvent
|
||||
expect(eventThis).to.equal @xhr
|
||||
|
||||
it 'binds this correctly in a DOM2 listener', ->
|
||||
eventThis = null
|
||||
@xhr.addEventListener 'load', (event) ->
|
||||
eventThis = @
|
||||
@xhr.dispatchEvent @loadEvent
|
||||
expect(eventThis).to.equal @xhr
|
||||
|
||||
it 'sets target correctly in a DOM0 listener', ->
|
||||
eventTarget = null
|
||||
@xhr.onload = (event) ->
|
||||
eventTarget = event.target
|
||||
@xhr.dispatchEvent @loadEvent
|
||||
expect(eventTarget).to.equal @xhr
|
||||
|
||||
it 'sets target correctly in a DOM2 listener', ->
|
||||
eventTarget = null
|
||||
@xhr.addEventListener 'load', (event) ->
|
||||
eventTarget = event.target
|
||||
@xhr.dispatchEvent @loadEvent
|
||||
expect(eventTarget).to.equal @xhr
|
||||
|
||||
it 'works with a DOM0 and two DOM2 listeners', ->
|
||||
count = [0, 0, 0]
|
||||
@xhr.addEventListener 'load', (event) ->
|
||||
count[1] += 1
|
||||
@xhr.onload = (event) ->
|
||||
count[0] += 1
|
||||
@xhr.addEventListener 'load', (event) ->
|
||||
count[2] += 1
|
||||
@xhr.dispatchEvent @loadEvent
|
||||
expect(count).to.deep.equal [1, 1, 1]
|
||||
|
||||
it 'does not invoke a DOM0 listener for a different event', ->
|
||||
count = 0
|
||||
@xhr.onerror = (event) ->
|
||||
count += 1
|
||||
@xhr.dispatchEvent @loadEvent
|
||||
expect(count).to.equal 0
|
||||
|
||||
it 'does not invoke a DOM2 listener for a different event', ->
|
||||
count = 0
|
||||
@xhr.addEventListener 'error', (event) ->
|
||||
count += 1
|
||||
@xhr.dispatchEvent @loadEvent
|
||||
expect(count).to.equal 0
|
||||
204
my-app/node_modules/xhr2/test/src/events_test.coffee
generated
vendored
Executable file
204
my-app/node_modules/xhr2/test/src/events_test.coffee
generated
vendored
Executable file
|
|
@ -0,0 +1,204 @@
|
|||
describe 'XMLHttpRequest', ->
|
||||
beforeEach ->
|
||||
@xhr = new XMLHttpRequest
|
||||
@dripUrl = 'http://localhost:8912/_/drip'
|
||||
@dripJson = drips: 3, size: 1000, ms: 50, length: true
|
||||
|
||||
describe 'level 2 events', ->
|
||||
beforeEach ->
|
||||
@events = []
|
||||
@endFired = false
|
||||
@events.check = -> null # replaced by tests
|
||||
@xhr.addEventListener 'loadstart', (event) =>
|
||||
expect(event.type).to.equal 'loadstart'
|
||||
expect(@endFired).to.equal false
|
||||
@events.push event
|
||||
@xhr.addEventListener 'progress', (event) =>
|
||||
expect(event.type).to.equal 'progress'
|
||||
expect(@endFired).to.equal false
|
||||
@events.push event
|
||||
@xhr.addEventListener 'load', (event) =>
|
||||
expect(event.type).to.equal 'load'
|
||||
expect(@endFired).to.equal false
|
||||
@events.push event
|
||||
@xhr.addEventListener 'loadend', (event) =>
|
||||
expect(event.type).to.equal 'loadend'
|
||||
expect(@endFired).to.equal false
|
||||
@endFired = 'loadend already fired'
|
||||
@events.push event
|
||||
@events.check()
|
||||
@xhr.addEventListener 'error', (event) =>
|
||||
expect(event.type).to.equal 'error'
|
||||
expect(@endFired).to.equal false
|
||||
@events.push event
|
||||
@xhr.addEventListener 'abort', (event) =>
|
||||
expect(event.type).to.equal 'abort'
|
||||
expect(@endFired).to.equal false
|
||||
@events.push event
|
||||
|
||||
describe 'for a successful fetch with Content-Length set', ->
|
||||
beforeEach ->
|
||||
@xhr.open 'POST', @dripUrl
|
||||
@xhr.send JSON.stringify(@dripJson)
|
||||
|
||||
it 'events have the correct target', (done) ->
|
||||
@events.check = =>
|
||||
for event in @events
|
||||
expect(event.target).to.equal @xhr
|
||||
done()
|
||||
|
||||
it 'events have the correct bubbling setup', (done) ->
|
||||
@events.check = =>
|
||||
for event in @events
|
||||
expect(event.bubbles).to.equal false
|
||||
expect(event.cancelable).to.equal false
|
||||
done()
|
||||
|
||||
it 'events have the correct progress info', (done) ->
|
||||
@events.check = =>
|
||||
for event in @events
|
||||
switch event.type
|
||||
when 'loadstart'
|
||||
expect(event.loaded).to.equal 0
|
||||
expect(event.lengthComputable).to.equal false
|
||||
expect(event.total).to.equal 0
|
||||
when 'load', 'loadend'
|
||||
expect(event.loaded).to.equal 3000
|
||||
expect(event.lengthComputable).to.equal true
|
||||
expect(event.total).to.equal 3000
|
||||
when 'progress'
|
||||
if event.lengthComputable
|
||||
expect(event.loaded).to.be.gte 0
|
||||
expect(event.loaded).to.be.lte 3000
|
||||
expect(event.total).to.equal 3000
|
||||
else
|
||||
expect(event.loaded).to.be.gte 0
|
||||
expect(event.total).to.equal 0
|
||||
done()
|
||||
|
||||
it 'events include at least one intermediate progress event', (done) ->
|
||||
@events.check = =>
|
||||
found = 'no suitable progress event emitted'
|
||||
for event in @events
|
||||
continue unless event.type is 'progress'
|
||||
continue unless event.loaded > 0
|
||||
continue unless event.loaded < event.total
|
||||
found = true
|
||||
expect(found).to.equal true
|
||||
done()
|
||||
|
||||
describe 'for a successful fetch without Content-Length set', ->
|
||||
beforeEach ->
|
||||
@xhr.open 'POST', @dripUrl
|
||||
@dripJson.length = false
|
||||
@xhr.send JSON.stringify(@dripJson)
|
||||
|
||||
it 'events have the correct progress info', (done) ->
|
||||
@events.check = =>
|
||||
for event in @events
|
||||
expect(event.lengthComputable).to.equal false
|
||||
expect(event.total).to.equal 0
|
||||
switch event.type
|
||||
when 'loadstart'
|
||||
expect(event.loaded).to.equal 0
|
||||
when 'load', 'loadend'
|
||||
expect(event.loaded).to.equal 3000
|
||||
when 'progress'
|
||||
expect(event.loaded).to.be.gte 0
|
||||
done()
|
||||
|
||||
it 'events include at least one intermediate progress event', (done) ->
|
||||
@events.check = =>
|
||||
found = 'no suitable progress event emitted'
|
||||
for event in @events
|
||||
continue unless event.type is 'progress'
|
||||
continue if event.loaded is 0
|
||||
continue if event.loaded is 3000
|
||||
found = true
|
||||
expect(found).to.equal true
|
||||
done()
|
||||
|
||||
describe 'for a network error due to bad DNS', (done) ->
|
||||
beforeEach ->
|
||||
@xhr.open 'GET', 'https://broken.to.cause.an.xhrnetworkerror.com'
|
||||
@xhr.send()
|
||||
|
||||
it 'no progress or load is emitted', (done) ->
|
||||
@events.check = =>
|
||||
for event in @events
|
||||
expect(event.type).not.to.equal 'load'
|
||||
expect(event.type).not.to.equal 'progress'
|
||||
done()
|
||||
|
||||
it 'events include an error event', (done) ->
|
||||
@events.check = =>
|
||||
found = 'no suitable error emitted'
|
||||
for event in @events
|
||||
continue unless event.type is 'error'
|
||||
found = true
|
||||
expect(found).to.equal true
|
||||
done()
|
||||
|
||||
describe 'readystatechange', ->
|
||||
beforeEach ->
|
||||
@events = []
|
||||
@states = []
|
||||
@doneFired = false
|
||||
@events.check = -> null # replaced by tests
|
||||
@xhr.addEventListener 'readystatechange', (event) =>
|
||||
expect(event.type).to.equal 'readystatechange'
|
||||
expect(@doneFired).to.equal false
|
||||
@events.push event
|
||||
@states.push event.target.readyState
|
||||
if event.target.readyState is XMLHttpRequest.DONE
|
||||
@doneFired = 'DONE already fired'
|
||||
@events.check()
|
||||
|
||||
describe 'for a successful fetch with Content-Length set', ->
|
||||
beforeEach ->
|
||||
@xhr.open 'POST', @dripUrl
|
||||
@xhr.send JSON.stringify(@dripJson)
|
||||
|
||||
it 'events have the correct target', (done) ->
|
||||
@events.check = =>
|
||||
for event in @events
|
||||
expect(event.target).to.equal @xhr
|
||||
done()
|
||||
|
||||
it 'events have the correct bubbling setup', (done) ->
|
||||
@events.check = =>
|
||||
for event in @events
|
||||
expect(event.bubbles).to.equal false
|
||||
expect(event.cancelable).to.equal false
|
||||
done()
|
||||
|
||||
it 'events states are in the correct order', (done) ->
|
||||
@events.check = =>
|
||||
expect(@states).to.deep.equal [XMLHttpRequest.OPENED,
|
||||
XMLHttpRequest.HEADERS_RECEIVED,
|
||||
XMLHttpRequest.LOADING, XMLHttpRequest.DONE]
|
||||
done()
|
||||
|
||||
describe 'for a successful fetch without Content-Length set', ->
|
||||
beforeEach ->
|
||||
@xhr.open 'POST', @dripUrl
|
||||
@dripJson.length = false
|
||||
@xhr.send JSON.stringify(@dripJson)
|
||||
|
||||
it 'events states are in the correct order', (done) ->
|
||||
@events.check = =>
|
||||
expect(@states).to.deep.equal [XMLHttpRequest.OPENED,
|
||||
XMLHttpRequest.HEADERS_RECEIVED, XMLHttpRequest.LOADING,
|
||||
XMLHttpRequest.DONE]
|
||||
done()
|
||||
|
||||
describe 'for a network error due to bad DNS', (done) ->
|
||||
beforeEach ->
|
||||
@xhr.open 'GET', 'https://broken.to.cause.an.xhrnetworkerror.com'
|
||||
@xhr.send()
|
||||
|
||||
it 'events states are in the correct order', (done) ->
|
||||
@events.check = =>
|
||||
expect(@states).to.deep.equal [XMLHttpRequest.OPENED,
|
||||
XMLHttpRequest.DONE]
|
||||
done()
|
||||
168
my-app/node_modules/xhr2/test/src/headers_test.coffee
generated
vendored
Executable file
168
my-app/node_modules/xhr2/test/src/headers_test.coffee
generated
vendored
Executable file
|
|
@ -0,0 +1,168 @@
|
|||
describe 'XMLHttpRequest', ->
|
||||
beforeEach ->
|
||||
@xhr = new XMLHttpRequest
|
||||
|
||||
describe '#setRequestHeader', ->
|
||||
beforeEach ->
|
||||
@xhr.open 'POST', 'http://localhost:8912/_/headers'
|
||||
@xhr.responseType = 'text'
|
||||
|
||||
describe 'with allowed headers', ->
|
||||
beforeEach ->
|
||||
@xhr.setRequestHeader 'Authorization', 'lol'
|
||||
@xhr.setRequestHeader 'User-Agent', 'toaster'
|
||||
@xhr.setRequestHeader 'X-Answer', '42'
|
||||
@xhr.setRequestHeader 'X-Header-Name', 'value'
|
||||
|
||||
it 'should send the headers', (done) ->
|
||||
@xhr.onload = =>
|
||||
expect(@xhr.responseText).to.match(/^\{.*\}$/)
|
||||
headers = JSON.parse @xhr.responseText
|
||||
expect(headers).to.have.property 'authorization'
|
||||
expect(headers['authorization']).to.equal 'lol'
|
||||
expect(headers).to.have.property 'user-agent'
|
||||
expect(headers['user-agent']).to.equal 'toaster'
|
||||
expect(headers).to.have.property 'x-answer'
|
||||
expect(headers['x-answer']).to.equal '42'
|
||||
expect(headers).to.have.property 'x-header-name'
|
||||
expect(headers['x-header-name']).to.equal 'value'
|
||||
done()
|
||||
@xhr.send ''
|
||||
|
||||
describe 'with a mix of allowed and forbidden headers', ->
|
||||
beforeEach ->
|
||||
@xhr.setRequestHeader 'Authorization', 'lol'
|
||||
@xhr.setRequestHeader 'Proxy-Authorization', 'evil:kitten'
|
||||
@xhr.setRequestHeader 'Sec-Breach', 'yes please'
|
||||
@xhr.setRequestHeader 'Host', 'www.google.com'
|
||||
@xhr.setRequestHeader 'Origin', 'https://www.google.com'
|
||||
@xhr.setRequestHeader 'X-Answer', '42'
|
||||
|
||||
it 'should only send the allowed headers', (done) ->
|
||||
@xhr.onloadend = =>
|
||||
expect(@xhr.responseText).to.match(/^\{.*\}$/)
|
||||
headers = JSON.parse @xhr.responseText
|
||||
expect(headers).to.have.property 'authorization'
|
||||
expect(headers['authorization']).to.equal 'lol'
|
||||
expect(headers).not.to.have.property 'proxy-authorization'
|
||||
expect(headers).not.to.have.property 'sec-breach'
|
||||
expect(headers['origin']).not.to.match /www\.google\.com/
|
||||
expect(headers['host']).not.to.match /www\.google\.com/
|
||||
expect(headers).to.have.property 'x-answer'
|
||||
expect(headers['x-answer']).to.equal '42'
|
||||
done()
|
||||
@xhr.send ''
|
||||
|
||||
describe 'with repeated headers', ->
|
||||
beforeEach ->
|
||||
@xhr.setRequestHeader 'Authorization', 'trol'
|
||||
@xhr.setRequestHeader 'Authorization', 'lol'
|
||||
@xhr.setRequestHeader 'Authorization', 'lol'
|
||||
@xhr.setRequestHeader 'X-Answer', '42'
|
||||
|
||||
it 'should only send the allowed headers', (done) ->
|
||||
_done = false
|
||||
@xhr.onreadystatechange = =>
|
||||
return if _done or @xhr.readyState isnt XMLHttpRequest.DONE
|
||||
_done = true
|
||||
expect(@xhr.responseText).to.match(/^\{.*\}$/)
|
||||
headers = JSON.parse @xhr.responseText
|
||||
expect(headers).to.have.property 'authorization'
|
||||
expect(headers['authorization']).to.equal 'trol, lol, lol'
|
||||
expect(headers).to.have.property 'x-answer'
|
||||
expect(headers['x-answer']).to.equal '42'
|
||||
done()
|
||||
@xhr.send ''
|
||||
|
||||
describe 'with no headers', ->
|
||||
beforeEach ->
|
||||
@xhr.open 'POST', 'http://localhost:8912/_/headers'
|
||||
@xhr.responseType = 'text'
|
||||
|
||||
it 'should set the protected headers correctly', (done) ->
|
||||
@xhr.onload = =>
|
||||
expect(@xhr.responseText).to.match(/^\{.*\}$/)
|
||||
headers = JSON.parse @xhr.responseText
|
||||
expect(headers).to.have.property 'connection'
|
||||
expect(headers['connection']).to.equal 'keep-alive'
|
||||
expect(headers).to.have.property 'host'
|
||||
expect(headers['host']).to.equal 'localhost:8912'
|
||||
expect(headers).to.have.property 'user-agent'
|
||||
expect(headers['user-agent']).to.match(/^Mozilla\//)
|
||||
done()
|
||||
@xhr.send ''
|
||||
|
||||
describe '#getResponseHeader', ->
|
||||
beforeEach ->
|
||||
@xhr.open 'POST', 'http://localhost:8912/_/get_headers'
|
||||
@headerJson =
|
||||
'''
|
||||
{"Accept-Ranges": "bytes",
|
||||
"Content-Type": "application/xhr2; charset=utf-1337",
|
||||
"Set-Cookie": "UserID=JohnDoe; Max-Age=3600; Version=1",
|
||||
"X-Header": "one, more, value"}
|
||||
'''
|
||||
|
||||
it 'returns accessible headers', (done) ->
|
||||
@xhr.onloadend = =>
|
||||
expect(@xhr.getResponseHeader('AccEPt-RANgeS')).to.equal 'bytes'
|
||||
expect(@xhr.getResponseHeader('content-Type')).to.
|
||||
equal 'application/xhr2; charset=utf-1337'
|
||||
expect(@xhr.getResponseHeader('X-Header')).to.equal "one, more, value"
|
||||
done()
|
||||
@xhr.send @headerJson
|
||||
|
||||
it 'returns null for private headers', (done) ->
|
||||
@xhr.onloadend = =>
|
||||
expect(@xhr.getResponseHeader('set-cookie')).to.equal null
|
||||
done()
|
||||
@xhr.send @headerJson
|
||||
|
||||
it 'returns headers when the XHR enters HEADERS_RECEIVED', (done) ->
|
||||
_done = false
|
||||
@xhr.onreadystatechange = =>
|
||||
return if _done or @xhr.readyState isnt XMLHttpRequest.HEADERS_RECEIVED
|
||||
_done = true
|
||||
expect(@xhr.getResponseHeader('AccEPt-RANgeS')).to.equal 'bytes'
|
||||
done()
|
||||
@xhr.send @headerJson
|
||||
|
||||
describe '#getAllResponseHeaders', ->
|
||||
beforeEach ->
|
||||
@xhr.open 'POST', 'http://localhost:8912/_/get_headers'
|
||||
@headerJson =
|
||||
'''
|
||||
{"Accept-Ranges": "bytes",
|
||||
"Content-Type": "application/xhr2; charset=utf-1337",
|
||||
"Set-Cookie": "UserID=JohnDoe; Max-Age=3600; Version=1",
|
||||
"X-Header": "one, more, value"}
|
||||
'''
|
||||
|
||||
it 'contains accessible headers', (done) ->
|
||||
@xhr.onloadend = =>
|
||||
headers = @xhr.getAllResponseHeaders()
|
||||
expect(headers).to.match(/(\A|\r\n)accept-ranges: bytes(\r\n|\Z)/mi)
|
||||
expect(headers).to.match(
|
||||
/(\A|\r\n)content-type: application\/xhr2; charset=utf-1337(\r\n|\Z)/mi)
|
||||
expect(headers).to.match(/(\A|\r\n)X-Header: one, more, value(\r\n|\Z)/mi)
|
||||
done()
|
||||
@xhr.send @headerJson
|
||||
|
||||
it 'does not contain private headers', (done) ->
|
||||
@xhr.onloadend = =>
|
||||
headers = @xhr.getAllResponseHeaders()
|
||||
expect(headers).not.to.match(/(\A|\r\n)set-cookie:/mi)
|
||||
done()
|
||||
@xhr.send @headerJson
|
||||
|
||||
it 'returns headers when the XHR enters HEADERS_RECEIVED', (done) ->
|
||||
_done = false
|
||||
@xhr.onreadystatechange = =>
|
||||
return if _done or @xhr.readyState isnt XMLHttpRequest.HEADERS_RECEIVED
|
||||
_done = true
|
||||
headers = @xhr.getAllResponseHeaders()
|
||||
expect(headers).to.match(/(\A|\r\n)accept-ranges: bytes(\r\n|\Z)/mi)
|
||||
done()
|
||||
@xhr.send @headerJson
|
||||
|
||||
|
||||
10
my-app/node_modules/xhr2/test/src/helpers/browser_mocha_runner.coffee
generated
vendored
Executable file
10
my-app/node_modules/xhr2/test/src/helpers/browser_mocha_runner.coffee
generated
vendored
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
window.addEventListener 'load', ->
|
||||
runner = null
|
||||
runner = mocha.run ->
|
||||
return if runner is null # Synchronous tests may call this spuriously.
|
||||
failures = runner.failures || 0
|
||||
total = runner.total || 0
|
||||
image = new Image()
|
||||
image.src = "/diediedie?failed=#{failures}&total=#{total}";
|
||||
image.onload = ->
|
||||
null
|
||||
1
my-app/node_modules/xhr2/test/src/helpers/browser_mocha_setup.coffee
generated
vendored
Executable file
1
my-app/node_modules/xhr2/test/src/helpers/browser_mocha_setup.coffee
generated
vendored
Executable file
|
|
@ -0,0 +1 @@
|
|||
mocha.setup ui: 'bdd', slow: 150, timeout: 1000, bail: false
|
||||
38
my-app/node_modules/xhr2/test/src/helpers/setup.coffee
generated
vendored
Executable file
38
my-app/node_modules/xhr2/test/src/helpers/setup.coffee
generated
vendored
Executable file
|
|
@ -0,0 +1,38 @@
|
|||
if typeof window is 'undefined'
|
||||
# node.js
|
||||
global.XMLHttpRequest = require '../../../lib/xhr2'
|
||||
global.ProgressEvent = XMLHttpRequest.ProgressEvent
|
||||
global.NetworkError = XMLHttpRequest.NetworkError
|
||||
global.SecurityError = XMLHttpRequest.SecurityError
|
||||
global.InvalidStateError = XMLHttpRequest.InvalidStateError
|
||||
|
||||
global.chai = require 'chai'
|
||||
global.assert = global.chai.assert
|
||||
global.expect = global.chai.expect
|
||||
global.sinon = require 'sinon'
|
||||
global.sinonChai = require 'sinon-chai'
|
||||
|
||||
xhrServer = require './xhr_server'
|
||||
require './xhr2.png.js'
|
||||
|
||||
https = require 'https'
|
||||
agent = new https.Agent
|
||||
agent.options.rejectUnauthorized = true
|
||||
agent.options.ca = xhrServer.https.sslCertificate()
|
||||
global.XMLHttpRequest.nodejsSet httpsAgent: agent
|
||||
global.XMLHttpRequest.nodejsSet(
|
||||
baseUrl: xhrServer.http.testUrl().replace('https://', 'http://'))
|
||||
else
|
||||
# browser
|
||||
|
||||
# HACK(pwnall): the test is first loaded on https so the developer can bypass
|
||||
# the SSL interstitial; however, we need to run the test on http, because
|
||||
# Chrome blocks https -> http XHRs
|
||||
if window.location.href.indexOf('https://') is 0
|
||||
window.location.href = window.location.href.replace('https://', 'http://').
|
||||
replace(':8911', ':8912')
|
||||
|
||||
window.NetworkError = window.Error
|
||||
window.SecurityError = window.Error
|
||||
window.assert = window.chai.assert
|
||||
window.expect = window.chai.expect
|
||||
156
my-app/node_modules/xhr2/test/src/helpers/xhr_server.coffee
generated
vendored
Executable file
156
my-app/node_modules/xhr2/test/src/helpers/xhr_server.coffee
generated
vendored
Executable file
|
|
@ -0,0 +1,156 @@
|
|||
express = require 'express'
|
||||
fs = require 'fs'
|
||||
http = require 'http'
|
||||
https = require 'https'
|
||||
open = require 'open'
|
||||
|
||||
# express.js server for testing the Web application.
|
||||
class XhrServer
|
||||
# Starts up a HTTP server.
|
||||
constructor: (@port, @useHttps) ->
|
||||
@createApp()
|
||||
|
||||
# Opens the test URL in a browser.
|
||||
openBrowser: (appName) ->
|
||||
open @testUrl(), appName
|
||||
|
||||
# The URL that should be used to start the tests.
|
||||
testUrl: ->
|
||||
"https://localhost:#{@port}/test/html/browser_test.html"
|
||||
|
||||
# The self-signed certificate used by this server.
|
||||
sslCertificate: ->
|
||||
return null unless @useHttps
|
||||
keyMaterial = fs.readFileSync 'test/ssl/cert.pem', 'utf8'
|
||||
certIndex = keyMaterial.indexOf '-----BEGIN CERTIFICATE-----'
|
||||
keyMaterial.substring certIndex
|
||||
|
||||
# The key for the self-signed certificate used by this server.
|
||||
sslKey: ->
|
||||
return null unless @useHttps
|
||||
keyMaterial = fs.readFileSync 'test/ssl/cert.pem', 'utf8'
|
||||
certIndex = keyMaterial.indexOf '-----BEGIN CERTIFICATE-----'
|
||||
keyMaterial.substring 0, certIndex
|
||||
|
||||
# The server code.
|
||||
createApp: ->
|
||||
@app = express()
|
||||
|
||||
## Middleware.
|
||||
|
||||
# CORS headers on everything, in case that ever gets implemented.
|
||||
@app.use (request, response, next) ->
|
||||
response.header 'Access-Control-Allow-Origin', '*'
|
||||
response.header 'Access-Control-Allow-Methods', 'DELETE,GET,POST,PUT'
|
||||
response.header 'Access-Control-Allow-Headers',
|
||||
'Content-Type, Authorization'
|
||||
next()
|
||||
|
||||
@app.use express.static(fs.realpathSync(__dirname + '/../../../'),
|
||||
{ dotfiles: 'allow' })
|
||||
|
||||
## Routes
|
||||
|
||||
@app.all '/_/method', (request, response) ->
|
||||
body = request.method
|
||||
response.header 'Content-Type', 'text/plain; charset=utf-8'
|
||||
response.header 'Content-Length', body.length.toString()
|
||||
response.end body
|
||||
|
||||
# Echoes the request body. Used to test send(data).
|
||||
@app.post '/_/echo', (request, response) ->
|
||||
if request.headers['content-type']
|
||||
response.header 'Content-Type', request.headers['content-type']
|
||||
if request.headers['content-length']
|
||||
response.header 'Content-Length', request.headers['content-length']
|
||||
|
||||
request.on 'data', (chunk) -> response.write chunk
|
||||
request.on 'end', -> response.end()
|
||||
|
||||
# Lists the request headers. Used to test setRequestHeader().
|
||||
@app.all '/_/headers', (request, response) ->
|
||||
body = JSON.stringify request.headers
|
||||
response.header 'Content-Type', 'application/json'
|
||||
response.header 'Content-Length', body.length.toString()
|
||||
response.end body
|
||||
|
||||
# Sets the response headers in the request. Used to test getResponse*().
|
||||
@app.post '/_/get_headers', (request, response) ->
|
||||
jsonString = ''
|
||||
request.on 'data', (chunk) -> jsonString += chunk
|
||||
request.on 'end', ->
|
||||
headers = JSON.parse jsonString
|
||||
for name, value of headers
|
||||
response.header name, value
|
||||
response.header 'Content-Length', '0'
|
||||
response.end ''
|
||||
|
||||
# Sets every response detail. Used for error testing.
|
||||
@app.post '/_/response', (request, response) ->
|
||||
jsonString = ''
|
||||
request.on 'data', (chunk) -> jsonString += chunk
|
||||
request.on 'end', ->
|
||||
json = JSON.parse jsonString
|
||||
response.writeHead json.code, json.status, json.headers
|
||||
response.write json.body if json.body
|
||||
response.end()
|
||||
|
||||
# Sends data in small chunks. Used for event testing.
|
||||
@app.post '/_/drip', (request, response) ->
|
||||
request.connection.setNoDelay()
|
||||
jsonString = ''
|
||||
request.on 'data', (chunk) -> jsonString += chunk
|
||||
request.on 'end', ->
|
||||
json = JSON.parse jsonString
|
||||
sentDrips = 0
|
||||
drip = new Array(json.size + 1).join '.'
|
||||
response.header 'Content-Type', 'text/plain'
|
||||
if json.length
|
||||
response.header 'Content-Length', (json.drips * json.size).toString()
|
||||
sendDrip = =>
|
||||
response.write drip
|
||||
sentDrips += 1
|
||||
if sentDrips >= json.drips
|
||||
response.end()
|
||||
else
|
||||
setTimeout sendDrip, json.ms
|
||||
sendDrip()
|
||||
|
||||
# Returns a HTTP redirect. Used to test the redirection handling code.
|
||||
@app.all '/_/redirect/:status/:next_page', (request, response) =>
|
||||
response.statusCode = parseInt(request.params.status)
|
||||
response.header 'Location',
|
||||
"http://#{request.get('host')}/_/#{request.params.next_page}"
|
||||
body = "<p>This is supposed to have a redirect link</p>"
|
||||
response.header 'Content-Type', 'text/html'
|
||||
response.header 'Content-Length', body.length.toString()
|
||||
response.header 'X-Redirect-Header', 'should not show up'
|
||||
response.end body
|
||||
|
||||
# Requested when the browser test suite completes.
|
||||
@app.get '/diediedie', (request, response) =>
|
||||
if 'failed' of request.query
|
||||
failed = parseInt request.query['failed']
|
||||
else
|
||||
failed = 1
|
||||
total = parseInt request.query['total'] || 0
|
||||
passed = total - failed
|
||||
exitCode = if failed == 0 then 0 else 1
|
||||
console.log "#{passed} passed, #{failed} failed"
|
||||
|
||||
response.header 'Content-Type', 'image/png'
|
||||
response.header 'Content-Length', '0'
|
||||
response.end ''
|
||||
unless 'NO_EXIT' of process.env
|
||||
@server.close()
|
||||
process.exit exitCode
|
||||
|
||||
if @useHttps
|
||||
options = key: @sslKey(), cert: @sslCertificate()
|
||||
@server = https.createServer options, @app
|
||||
else
|
||||
@server = http.createServer @app
|
||||
@server.listen @port
|
||||
|
||||
module.exports.https = new XhrServer 8911, true
|
||||
module.exports.http = new XhrServer 8912, false
|
||||
162
my-app/node_modules/xhr2/test/src/nodejs_set_test.coffee
generated
vendored
Executable file
162
my-app/node_modules/xhr2/test/src/nodejs_set_test.coffee
generated
vendored
Executable file
|
|
@ -0,0 +1,162 @@
|
|||
describe 'XMLHttpRequest', ->
|
||||
describe '.nodejsSet', ->
|
||||
beforeEach ->
|
||||
@xhr = new XMLHttpRequest
|
||||
@customXhr = new XMLHttpRequest
|
||||
|
||||
describe 'with a httpAgent option', ->
|
||||
beforeEach ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
|
||||
@customAgent = { custom: 'httpAgent' }
|
||||
@customXhr.nodejsHttpAgent = @customAgent
|
||||
|
||||
@default = XMLHttpRequest::nodejsHttpAgent
|
||||
@agent = { mocking: 'httpAgent' }
|
||||
XMLHttpRequest.nodejsSet httpAgent: @agent
|
||||
|
||||
it 'sets the default nodejsHttpAgent', ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
expect(@xhr.nodejsHttpAgent).to.equal @agent
|
||||
|
||||
it 'does not interfere with custom nodejsHttpAgent settings', ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
expect(@customXhr.nodejsHttpAgent).to.equal @customAgent
|
||||
|
||||
afterEach ->
|
||||
XMLHttpRequest.nodejsSet httpAgent: @default
|
||||
|
||||
describe 'with a httpsAgent option', ->
|
||||
beforeEach ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
|
||||
@customAgent = { custom: 'httpsAgent' }
|
||||
@customXhr.nodejsHttpsAgent = @customAgent
|
||||
|
||||
@default = XMLHttpRequest::nodejsHttpsAgent
|
||||
@agent = { mocking: 'httpsAgent' }
|
||||
XMLHttpRequest.nodejsSet httpsAgent: @agent
|
||||
|
||||
it 'sets the default nodejsHttpsAgent', ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
expect(@xhr.nodejsHttpsAgent).to.equal @agent
|
||||
|
||||
it 'does not interfere with custom nodejsHttpsAgent settings', ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
expect(@customXhr.nodejsHttpsAgent).to.equal @customAgent
|
||||
|
||||
afterEach ->
|
||||
XMLHttpRequest.nodejsSet httpsAgent: @default
|
||||
|
||||
describe 'with a baseUrl option', ->
|
||||
beforeEach ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
|
||||
@customBaseUrl = 'http://custom.url/base'
|
||||
@customXhr.nodejsBaseUrl = @customBaseUrl
|
||||
|
||||
@default = XMLHttpRequest::nodejsBaseUrl
|
||||
@baseUrl = 'http://localhost/base'
|
||||
XMLHttpRequest.nodejsSet baseUrl: @baseUrl
|
||||
|
||||
it 'sets the default nodejsBaseUrl', ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
expect(@xhr.nodejsBaseUrl).to.equal @baseUrl
|
||||
|
||||
it 'does not interfere with custom nodejsBaseUrl settings', ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
expect(@customXhr.nodejsBaseUrl).to.equal @customBaseUrl
|
||||
|
||||
afterEach ->
|
||||
XMLHttpRequest.nodejsSet baseUrl: @default
|
||||
|
||||
describe '#nodejsSet', ->
|
||||
beforeEach ->
|
||||
@xhr = new XMLHttpRequest
|
||||
@customXhr = new XMLHttpRequest
|
||||
|
||||
describe 'with a httpAgent option', ->
|
||||
beforeEach ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
|
||||
@customAgent = { custom: 'httpAgent' }
|
||||
@customXhr.nodejsSet httpAgent: @customAgent
|
||||
|
||||
it 'sets nodejsHttpAgent on the XHR instance', ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
expect(@customXhr.nodejsHttpAgent).to.equal @customAgent
|
||||
|
||||
it 'does not interfere with default nodejsHttpAgent settings', ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
expect(@xhr.nodejsHttpAgent).not.to.equal @customAgent
|
||||
|
||||
describe 'with a httpsAgent option', ->
|
||||
beforeEach ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
|
||||
@customAgent = { custom: 'httpsAgent' }
|
||||
@customXhr.nodejsSet httpsAgent: @customAgent
|
||||
|
||||
it 'sets nodejsHttpsAgent on the XHR instance', ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
expect(@customXhr.nodejsHttpsAgent).to.equal @customAgent
|
||||
|
||||
it 'does not interfere with default nodejsHttpsAgent settings', ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
expect(@xhr.nodejsHttpsAgent).not.to.equal @customAgent
|
||||
|
||||
describe 'base URL parsing', ->
|
||||
beforeEach ->
|
||||
@xhr = new XMLHttpRequest
|
||||
|
||||
describe 'with null baseUrl', ->
|
||||
beforeEach ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
@xhr.nodejsSet baseUrl: null
|
||||
|
||||
it 'parses an absolute URL', ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
parsedUrl = @xhr._parseUrl('http://www.domain.com/path')
|
||||
expect(parsedUrl).to.be.ok
|
||||
expect(parsedUrl).to.have.property 'href'
|
||||
expect(parsedUrl.href).to.equal 'http://www.domain.com/path'
|
||||
|
||||
describe 'with a (protocol, domain, filePath) baseUrl', ->
|
||||
beforeEach ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
@xhr.nodejsSet baseUrl: 'https://base.url/dir/file.html'
|
||||
|
||||
it 'parses an absolute URL', ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
parsedUrl = @xhr._parseUrl('http://www.domain.com/path')
|
||||
expect(parsedUrl).to.be.ok
|
||||
expect(parsedUrl).to.have.property 'href'
|
||||
expect(parsedUrl.href).to.equal 'http://www.domain.com/path'
|
||||
|
||||
it 'parses a path-relative URL', ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
parsedUrl = @xhr._parseUrl('path/to.js')
|
||||
expect(parsedUrl).to.be.ok
|
||||
expect(parsedUrl).to.have.property 'href'
|
||||
expect(parsedUrl.href).to.equal 'https://base.url/dir/path/to.js'
|
||||
|
||||
it 'parses a path-relative URL with ..', ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
parsedUrl = @xhr._parseUrl('../path/to.js')
|
||||
expect(parsedUrl).to.be.ok
|
||||
expect(parsedUrl).to.have.property 'href'
|
||||
expect(parsedUrl.href).to.equal 'https://base.url/path/to.js'
|
||||
|
||||
it 'parses a host-relative URL', ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
parsedUrl = @xhr._parseUrl('/path/to.js')
|
||||
expect(parsedUrl).to.be.ok
|
||||
expect(parsedUrl).to.have.property 'href'
|
||||
expect(parsedUrl.href).to.equal 'https://base.url/path/to.js'
|
||||
|
||||
it 'parses a protocol-relative URL', ->
|
||||
return unless XMLHttpRequest.nodejsSet # Skip in browsers.
|
||||
parsedUrl = @xhr._parseUrl('//domain.com/path/to.js')
|
||||
expect(parsedUrl).to.be.ok
|
||||
expect(parsedUrl).to.have.property 'href'
|
||||
expect(parsedUrl.href).to.equal 'https://domain.com/path/to.js'
|
||||
57
my-app/node_modules/xhr2/test/src/redirect_test.coffee
generated
vendored
Executable file
57
my-app/node_modules/xhr2/test/src/redirect_test.coffee
generated
vendored
Executable file
|
|
@ -0,0 +1,57 @@
|
|||
describe 'XMLHttpRequest', ->
|
||||
describe 'when redirected', ->
|
||||
beforeEach ->
|
||||
@xhr = new XMLHttpRequest
|
||||
|
||||
it 'issues a GET for the next location', (done) ->
|
||||
@xhr.open 'POST', 'http://localhost:8912/_/redirect/302/method'
|
||||
@xhr.onload = =>
|
||||
expect(@xhr.responseText).to.match(/GET/i)
|
||||
done()
|
||||
@xhr.send 'This should be dropped during the redirect'
|
||||
|
||||
it 'does not return the redirect headers', (done) ->
|
||||
@xhr.open 'GET', 'http://localhost:8912/_/redirect/302/method'
|
||||
@xhr.onload = =>
|
||||
expect(@xhr.getResponseHeader('Content-Type')).to.equal(
|
||||
'text/plain; charset=utf-8')
|
||||
expect(@xhr.getResponseHeader('X-Redirect-Header')).not.to.be.ok
|
||||
done()
|
||||
@xhr.send()
|
||||
|
||||
it 'persists custom request headers across redirects', (done) ->
|
||||
@xhr.open 'GET', 'http://localhost:8912/_/redirect/302/headers'
|
||||
@xhr.setRequestHeader 'X-Redirect-Test', 'should be preserved'
|
||||
@xhr.onload = =>
|
||||
expect(@xhr.responseText).to.match(/^\{.*\}$/)
|
||||
headers = JSON.parse @xhr.responseText
|
||||
expect(headers['connection']).to.equal 'keep-alive'
|
||||
expect(headers).to.have.property 'host'
|
||||
expect(headers['host']).to.equal 'localhost:8912'
|
||||
expect(headers).to.have.property 'x-redirect-test'
|
||||
expect(headers['x-redirect-test']).to.equal 'should be preserved'
|
||||
done()
|
||||
@xhr.send()
|
||||
|
||||
it 'drops content-related headers across redirects', (done) ->
|
||||
@xhr.open 'POST', 'http://localhost:8912/_/redirect/302/headers'
|
||||
@xhr.setRequestHeader 'X-Redirect-Test', 'should be preserved'
|
||||
@xhr.onload = =>
|
||||
expect(@xhr.responseText).to.match(/^\{.*\}$/)
|
||||
headers = JSON.parse @xhr.responseText
|
||||
expect(headers['connection']).to.equal 'keep-alive'
|
||||
expect(headers).to.have.property 'host'
|
||||
expect(headers['host']).to.equal 'localhost:8912'
|
||||
expect(headers).to.have.property 'x-redirect-test'
|
||||
expect(headers['x-redirect-test']).to.equal 'should be preserved'
|
||||
expect(headers).not.to.have.property 'content-type'
|
||||
expect(headers).not.to.have.property 'content-length'
|
||||
done()
|
||||
@xhr.send 'This should be dropped during the redirect'
|
||||
|
||||
it 'provides the final responseURL', (done) ->
|
||||
@xhr.open 'GET', 'http://localhost:8912/_/redirect/302/method'
|
||||
@xhr.onload = =>
|
||||
expect(@xhr.responseURL).to.equal("http://localhost:8912/_/method")
|
||||
done()
|
||||
@xhr.send()
|
||||
88
my-app/node_modules/xhr2/test/src/response_type_test.coffee
generated
vendored
Executable file
88
my-app/node_modules/xhr2/test/src/response_type_test.coffee
generated
vendored
Executable file
|
|
@ -0,0 +1,88 @@
|
|||
describe 'XMLHttpRequest', ->
|
||||
describe '#responseType', ->
|
||||
beforeEach ->
|
||||
@xhr = new XMLHttpRequest
|
||||
@jsonUrl = 'http://localhost:8912/test/fixtures/hello.json'
|
||||
@jsonString = '{"hello": "world", "answer": 42}\n'
|
||||
@imageUrl = 'http://localhost:8912/test/fixtures/xhr2.png'
|
||||
|
||||
describe 'text', ->
|
||||
it 'reads a JSON file into a String', (done) ->
|
||||
@xhr.addEventListener 'load', =>
|
||||
expect(@xhr.response).to.equal @jsonString
|
||||
expect(@xhr.responseText).to.equal @jsonString
|
||||
done()
|
||||
@xhr.open 'GET', @jsonUrl
|
||||
@xhr.responseType = 'text'
|
||||
@xhr.send()
|
||||
|
||||
describe 'json', ->
|
||||
it 'reads a JSON file into a parsed JSON object', (done) ->
|
||||
_done = false
|
||||
@xhr.addEventListener 'readystatechange', =>
|
||||
return if _done or @xhr.readyState isnt XMLHttpRequest.DONE
|
||||
_done = true
|
||||
expect(@xhr.response).to.deep.equal hello: 'world', answer: 42
|
||||
done()
|
||||
@xhr.open 'GET', @jsonUrl
|
||||
@xhr.responseType = 'json'
|
||||
@xhr.send()
|
||||
|
||||
it 'produces null when reading a non-JSON file ', (done) ->
|
||||
@xhr.addEventListener 'loadend', =>
|
||||
expect(@xhr.response).to.equal null
|
||||
done()
|
||||
@xhr.open 'GET', 'http://localhost:8912/test/fixtures/hello.txt'
|
||||
@xhr.responseType = 'json'
|
||||
@xhr.send()
|
||||
|
||||
describe 'arraybuffer', ->
|
||||
it 'reads a JSON file into an ArrayBuffer', (done) ->
|
||||
@xhr.addEventListener 'loadend', =>
|
||||
expect(@xhr.response).to.be.instanceOf ArrayBuffer
|
||||
view = new Uint8Array @xhr.response
|
||||
string = (String.fromCharCode(view[i]) for i in [0...view.length]).
|
||||
join ''
|
||||
expect(string).to.equal @jsonString
|
||||
done()
|
||||
@xhr.open 'GET', @jsonUrl
|
||||
@xhr.responseType = 'arraybuffer'
|
||||
@xhr.send()
|
||||
|
||||
it 'reads a binary file into an ArrayBuffer', (done) ->
|
||||
@xhr.addEventListener 'loadend', =>
|
||||
expect(@xhr.response).to.be.instanceOf ArrayBuffer
|
||||
view = new Uint8Array @xhr.response
|
||||
bytes = (view[i] for i in [0...view.length])
|
||||
expect(bytes).to.deep.equal xhr2PngBytes
|
||||
done()
|
||||
@xhr.open 'GET', @imageUrl
|
||||
@xhr.responseType = 'arraybuffer'
|
||||
@xhr.send()
|
||||
|
||||
|
||||
describe 'buffer', ->
|
||||
it 'reads a JSON file into a node.js Buffer', (done) ->
|
||||
return done() if typeof Buffer is 'undefined'
|
||||
@xhr.addEventListener 'loadend', =>
|
||||
buffer = @xhr.response
|
||||
expect(buffer).to.be.instanceOf Buffer
|
||||
stringChars = for i in [0...buffer.length]
|
||||
String.fromCharCode buffer.readUInt8(i)
|
||||
expect(stringChars.join('')).to.equal @jsonString
|
||||
done()
|
||||
@xhr.open 'GET', @jsonUrl
|
||||
@xhr.responseType = 'buffer'
|
||||
@xhr.send()
|
||||
|
||||
it 'reads a binary file into a node.js Buffer', (done) ->
|
||||
return done() if typeof Buffer is 'undefined'
|
||||
@xhr.addEventListener 'loadend', =>
|
||||
buffer = @xhr.response
|
||||
expect(buffer).to.be.instanceOf Buffer
|
||||
bytes = (buffer.readUInt8(i) for i in [0...buffer.length])
|
||||
expect(bytes).to.deep.equal xhr2PngBytes
|
||||
done()
|
||||
@xhr.open 'GET', @imageUrl
|
||||
@xhr.responseType = 'buffer'
|
||||
@xhr.send()
|
||||
18
my-app/node_modules/xhr2/test/src/responseurl_test.coffee
generated
vendored
Executable file
18
my-app/node_modules/xhr2/test/src/responseurl_test.coffee
generated
vendored
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
describe 'XMLHttpRequest', ->
|
||||
describe '#responseURL', ->
|
||||
beforeEach ->
|
||||
@xhr = new XMLHttpRequest
|
||||
|
||||
it 'provies the URL of the response', (done) ->
|
||||
@xhr.open 'GET', 'http://localhost:8912/_/method'
|
||||
@xhr.onload = =>
|
||||
expect(@xhr.responseURL).to.equal("http://localhost:8912/_/method")
|
||||
done()
|
||||
@xhr.send()
|
||||
|
||||
it 'ignores the hash fragment', (done) ->
|
||||
@xhr.open 'GET', 'http://localhost:8912/_/method#foo'
|
||||
@xhr.onload = =>
|
||||
expect(@xhr.responseURL).to.equal("http://localhost:8912/_/method")
|
||||
done()
|
||||
@xhr.send()
|
||||
89
my-app/node_modules/xhr2/test/src/send_test.coffee
generated
vendored
Executable file
89
my-app/node_modules/xhr2/test/src/send_test.coffee
generated
vendored
Executable file
|
|
@ -0,0 +1,89 @@
|
|||
describe 'XMLHttpRequest', ->
|
||||
describe '#send', ->
|
||||
beforeEach ->
|
||||
@xhr = new XMLHttpRequest
|
||||
@xhr.open 'POST', 'http://localhost:8912/_/echo'
|
||||
|
||||
@arrayBuffer = new ArrayBuffer xhr2PngBytes.length
|
||||
@arrayBufferView = new Uint8Array @arrayBuffer
|
||||
if typeof Buffer is 'undefined'
|
||||
@buffer = null
|
||||
else
|
||||
@buffer = Buffer.alloc xhr2PngBytes.length
|
||||
|
||||
for i in [0...xhr2PngBytes.length]
|
||||
@arrayBufferView[i] = xhr2PngBytes[i]
|
||||
@buffer.writeUInt8 xhr2PngBytes[i], i if @buffer
|
||||
|
||||
it 'works with ASCII DOMStrings', (done) ->
|
||||
@xhr.onload = =>
|
||||
expect(@xhr.getResponseHeader('content-type')).to.
|
||||
match(/^text\/plain(;\s?charset=UTF-8)?$/)
|
||||
expect(@xhr.responseText).to.equal 'Hello world!'
|
||||
done()
|
||||
@xhr.send "Hello world!"
|
||||
|
||||
it 'works with UTF-8 DOMStrings', (done) ->
|
||||
@xhr.onloadend = =>
|
||||
expect(@xhr.getResponseHeader('content-type')).to.
|
||||
match(/^text\/plain(;\s?charset=UTF-8)?$/)
|
||||
expect(@xhr.responseText).to.equal '世界你好!'
|
||||
done()
|
||||
@xhr.send '世界你好!'
|
||||
|
||||
it 'works with ArrayBufferViews', (done) ->
|
||||
@xhr.responseType = 'arraybuffer'
|
||||
@xhr.onload = =>
|
||||
expect(@xhr.getResponseHeader('content-type')).to.equal null
|
||||
responseView = new Uint8Array @xhr.response
|
||||
responseBytes = (responseView[i] for i in [0...responseView.length])
|
||||
expect(responseBytes).to.deep.equal xhr2PngBytes
|
||||
done()
|
||||
@xhr.send @arrayBufferView
|
||||
|
||||
it 'works with ArrayBufferViews with set index and length', (done) ->
|
||||
@xhr.responseType = 'arraybuffer'
|
||||
@xhr.onload = =>
|
||||
expect(@xhr.getResponseHeader('content-type')).to.equal null
|
||||
responseView = new Uint8Array @xhr.response
|
||||
responseBytes = (responseView[i] for i in [0...responseView.length])
|
||||
expect(responseBytes).to.deep.equal xhr2PngBytes[10...52]
|
||||
done()
|
||||
arrayBufferView10 = new Uint8Array @arrayBuffer, 10, 42
|
||||
@xhr.send arrayBufferView10
|
||||
|
||||
it 'works with ArrayBuffers', (done) ->
|
||||
@xhr.responseType = 'arraybuffer'
|
||||
@xhr.onload = =>
|
||||
expect(@xhr.getResponseHeader('content-type')).to.equal null
|
||||
responseView = new Uint8Array @xhr.response
|
||||
responseBytes = (responseView[i] for i in [0...responseView.length])
|
||||
expect(responseBytes).to.deep.equal xhr2PngBytes
|
||||
done()
|
||||
@xhr.send @arrayBuffer
|
||||
|
||||
it 'works with node.js Buffers', (done) ->
|
||||
return done() unless @buffer
|
||||
# NOTE: using the same exact code as above, which is tested in a browser
|
||||
@xhr.responseType = 'arraybuffer'
|
||||
@xhr.onload = =>
|
||||
expect(@xhr.getResponseHeader('content-type')).to.equal null
|
||||
responseView = new Uint8Array @xhr.response
|
||||
responseBytes = (responseView[i] for i in [0...responseView.length])
|
||||
expect(responseBytes).to.deep.equal xhr2PngBytes
|
||||
done()
|
||||
@xhr.send @buffer
|
||||
|
||||
it 'sets POST headers correctly when given null data', (done) ->
|
||||
@xhr.open 'POST', 'http://localhost:8912/_/headers'
|
||||
@xhr.responseType = 'text'
|
||||
@xhr.onload = =>
|
||||
expect(@xhr.responseText).to.match(/^\{.*\}$/)
|
||||
headers = JSON.parse @xhr.responseText
|
||||
expect(headers).to.have.property 'content-length'
|
||||
expect(headers['content-length']).to.equal '0'
|
||||
expect(headers).not.to.have.property 'content-type'
|
||||
done()
|
||||
@xhr.send()
|
||||
|
||||
|
||||
47
my-app/node_modules/xhr2/test/src/status_test.coffee
generated
vendored
Executable file
47
my-app/node_modules/xhr2/test/src/status_test.coffee
generated
vendored
Executable file
|
|
@ -0,0 +1,47 @@
|
|||
describe 'XMLHttpRequest', ->
|
||||
beforeEach ->
|
||||
@xhr = new XMLHttpRequest
|
||||
@okUrl = 'http://localhost:8912/test/fixtures/hello.txt'
|
||||
|
||||
@errorUrl = 'http://localhost:8912/_/response'
|
||||
@errorJson = JSON.stringify
|
||||
code: 401, status: 'Unauthorized',
|
||||
body: JSON.stringify(error: 'Credential error'),
|
||||
headers:
|
||||
'Content-Type': 'application/json', 'Content-Length': '28'
|
||||
|
||||
describe '#status', ->
|
||||
it 'is 200 for a normal request', (done) ->
|
||||
@xhr.open 'GET', @okUrl
|
||||
_done = false
|
||||
@xhr.addEventListener 'readystatechange', =>
|
||||
return if _done
|
||||
if @xhr.readyState < XMLHttpRequest.HEADERS_RECEIVED
|
||||
expect(@xhr.status).to.equal 0
|
||||
expect(@xhr.statusText).to.equal ''
|
||||
else
|
||||
expect(@xhr.status).to.equal 200
|
||||
expect(@xhr.statusText).to.be.ok
|
||||
expect(@xhr.statusText).to.not.equal ''
|
||||
if @xhr.readyState is XMLHttpRequest.DONE
|
||||
_done = true
|
||||
done()
|
||||
@xhr.send()
|
||||
|
||||
it 'returns the server-reported status', (done) ->
|
||||
@xhr.open 'POST', @errorUrl
|
||||
_done = false
|
||||
@xhr.addEventListener 'readystatechange', =>
|
||||
return if _done
|
||||
if @xhr.readyState < XMLHttpRequest.HEADERS_RECEIVED
|
||||
expect(@xhr.status).to.equal 0
|
||||
expect(@xhr.statusText).to.equal ''
|
||||
else
|
||||
expect(@xhr.status).to.equal 401
|
||||
expect(@xhr.statusText).to.be.ok
|
||||
expect(@xhr.statusText).to.not.equal ''
|
||||
if @xhr.readyState is XMLHttpRequest.DONE
|
||||
_done = true
|
||||
done()
|
||||
@xhr.send @errorJson
|
||||
|
||||
102
my-app/node_modules/xhr2/test/src/xhr_test.coffee
generated
vendored
Executable file
102
my-app/node_modules/xhr2/test/src/xhr_test.coffee
generated
vendored
Executable file
|
|
@ -0,0 +1,102 @@
|
|||
describe 'XMLHttpRequest', ->
|
||||
beforeEach ->
|
||||
@xhr = new XMLHttpRequest
|
||||
|
||||
describe 'constructor', ->
|
||||
it 'sets readyState to UNSENT', ->
|
||||
expect(@xhr.readyState).to.equal XMLHttpRequest.UNSENT
|
||||
|
||||
it 'sets timeout to 0', ->
|
||||
expect(@xhr.timeout).to.equal 0
|
||||
|
||||
it 'sets responseType to ""', ->
|
||||
expect(@xhr.responseType).to.equal ''
|
||||
|
||||
it 'sets status to 0', ->
|
||||
expect(@xhr.status).to.equal 0
|
||||
|
||||
it 'sets statusText to ""', ->
|
||||
expect(@xhr.statusText).to.equal ''
|
||||
|
||||
describe '#open', ->
|
||||
it 'throws SecurityError on CONNECT', ->
|
||||
expect(=> @xhr.open 'CONNECT', 'http://localhost:8912/test').to.
|
||||
throw(SecurityError)
|
||||
|
||||
describe 'with a GET for a local https request', ->
|
||||
beforeEach ->
|
||||
@xhr.open 'GET', 'https://localhost:8911/test/fixtures/hello.txt'
|
||||
|
||||
it 'sets readyState to OPENED', ->
|
||||
expect(@xhr.readyState).to.equal XMLHttpRequest.OPENED
|
||||
|
||||
it 'keeps status 0', ->
|
||||
expect(@xhr.status).to.equal 0
|
||||
|
||||
it 'keeps statusText ""', ->
|
||||
expect(@xhr.statusText).to.equal ''
|
||||
|
||||
describe '#send', ->
|
||||
describe 'on a local http GET', ->
|
||||
beforeEach ->
|
||||
@xhr.open 'GET', 'http://localhost:8912/test/fixtures/hello.txt'
|
||||
|
||||
it 'kicks off the request', (done) ->
|
||||
@xhr.onload = (event) =>
|
||||
expect(@xhr.status).to.equal 200
|
||||
expect(@xhr.responseText).to.equal 'Hello world!\n'
|
||||
done()
|
||||
@xhr.send()
|
||||
|
||||
describe 'on a local https GET', ->
|
||||
beforeEach ->
|
||||
@xhr.open 'GET', 'https://localhost:8911/test/fixtures/hello.txt'
|
||||
|
||||
it 'kicks off the request', (done) ->
|
||||
@xhr.onload = (event) =>
|
||||
expect(@xhr.status).to.equal 200
|
||||
expect(@xhr.responseText).to.equal 'Hello world!\n'
|
||||
done()
|
||||
@xhr.send()
|
||||
|
||||
describe 'on a local relative GET', ->
|
||||
beforeEach ->
|
||||
@xhr.open 'GET', '../fixtures/hello.txt'
|
||||
|
||||
it 'kicks off the request', (done) ->
|
||||
@xhr.onload = (event) =>
|
||||
expect(@xhr.status).to.equal 200
|
||||
expect(@xhr.responseText).to.equal 'Hello world!\n'
|
||||
done()
|
||||
@xhr.send()
|
||||
|
||||
describe 'on a local gopher GET', ->
|
||||
describe '#open + #send', ->
|
||||
it 'throw a NetworkError', ->
|
||||
expect(=>
|
||||
@xhr.open 'GET', 'gopher:localhost:8911'
|
||||
@xhr.send()
|
||||
).to.throw(NetworkError)
|
||||
|
||||
describe 'readyState constants', ->
|
||||
it 'UNSENT < OPENED', ->
|
||||
expect(XMLHttpRequest.UNSENT).to.be.below(XMLHttpRequest.OPENED)
|
||||
|
||||
it 'OPENED < HEADERS_RECEIVED', ->
|
||||
expect(XMLHttpRequest.OPENED).to.be.
|
||||
below(XMLHttpRequest.HEADERS_RECEIVED)
|
||||
|
||||
it 'HEADERS_RECEIVED < LOADING', ->
|
||||
expect(XMLHttpRequest.HEADERS_RECEIVED).to.be.
|
||||
below(XMLHttpRequest.LOADING)
|
||||
|
||||
it 'LOADING < DONE', ->
|
||||
expect(XMLHttpRequest.LOADING).to.be.below(XMLHttpRequest.DONE)
|
||||
|
||||
it 'XMLHttpRequest constants match the instance costants', ->
|
||||
expect(XMLHttpRequest.UNSENT).to.equal @xhr.UNSENT
|
||||
expect(XMLHttpRequest.OPENED).to.equal @xhr.OPENED
|
||||
expect(XMLHttpRequest.HEADERS_RECEIVED).to.equal @xhr.HEADERS_RECEIVED
|
||||
expect(XMLHttpRequest.LOADING).to.equal @xhr.LOADING
|
||||
expect(XMLHttpRequest.DONE).to.equal @xhr.DONE
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue