Initial commit
This commit is contained in:
31
node_modules/xhr2/.npmignore
generated
vendored
Normal file
31
node_modules/xhr2/.npmignore
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
# Vim.
|
||||
*.swp
|
||||
.vimrc
|
||||
|
||||
# OSX
|
||||
.DS_Store
|
||||
|
||||
# Git.
|
||||
.git
|
||||
|
||||
# Travis.
|
||||
.travis.yml
|
||||
|
||||
# Npm modules.
|
||||
node_modules
|
||||
|
||||
# Vendored javascript modules.
|
||||
test/vendor
|
||||
|
||||
# Test build output.
|
||||
test/js
|
||||
tmp/*.js
|
||||
|
||||
# Documentation output.
|
||||
doc/*.html
|
||||
doc/assets
|
||||
doc/classes
|
||||
doc/files
|
||||
|
||||
# Potentially sensitive credentials and keys used during testing.
|
||||
test/ssl
|
||||
33
node_modules/xhr2/CONTRIBUTING.md
generated
vendored
Normal file
33
node_modules/xhr2/CONTRIBUTING.md
generated
vendored
Normal 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.
|
||||
132
node_modules/xhr2/Cakefile
generated
vendored
Normal file
132
node_modules/xhr2/Cakefile
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
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 ' +
|
||||
"--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.writeFileSync '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
|
||||
['http://chaijs.com/chai.js', 'test/vendor/chai.js'],
|
||||
# sinon.js also ships special builds for browsers
|
||||
['http://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
node_modules/xhr2/LICENSE.txt
generated
vendored
Normal file
19
node_modules/xhr2/LICENSE.txt
generated
vendored
Normal 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.
|
||||
144
node_modules/xhr2/README.md
generated
vendored
Normal file
144
node_modules/xhr2/README.md
generated
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
# 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/) 0.6
|
||||
* [node.js](http://nodejs.org/) 0.8
|
||||
* [node.js](http://nodejs.org/) 0.10
|
||||
* [node.js](http://nodejs.org/) 0.11
|
||||
|
||||
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 coffee-script
|
||||
```
|
||||
|
||||
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
node_modules/xhr2/lib/browser.js
generated
vendored
Normal file
1
node_modules/xhr2/lib/browser.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = XMLHttpRequest;
|
||||
875
node_modules/xhr2/lib/xhr2.js
generated
vendored
Normal file
875
node_modules/xhr2/lib/xhr2.js
generated
vendored
Normal file
@@ -0,0 +1,875 @@
|
||||
// Generated by CoffeeScript 1.12.2
|
||||
(function() {
|
||||
var InvalidStateError, NetworkError, ProgressEvent, SecurityError, SyntaxError, XMLHttpRequest, XMLHttpRequestEventTarget, XMLHttpRequestUpload, http, https, os, url,
|
||||
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
hasProp = {}.hasOwnProperty;
|
||||
|
||||
XMLHttpRequestEventTarget = (function() {
|
||||
function XMLHttpRequestEventTarget() {
|
||||
this.onloadstart = null;
|
||||
this.onprogress = null;
|
||||
this.onabort = null;
|
||||
this.onerror = null;
|
||||
this.onload = null;
|
||||
this.ontimeout = null;
|
||||
this.onloadend = null;
|
||||
this._listeners = {};
|
||||
}
|
||||
|
||||
XMLHttpRequestEventTarget.prototype.onloadstart = null;
|
||||
|
||||
XMLHttpRequestEventTarget.prototype.onprogress = null;
|
||||
|
||||
XMLHttpRequestEventTarget.prototype.onabort = null;
|
||||
|
||||
XMLHttpRequestEventTarget.prototype.onerror = null;
|
||||
|
||||
XMLHttpRequestEventTarget.prototype.onload = null;
|
||||
|
||||
XMLHttpRequestEventTarget.prototype.ontimeout = null;
|
||||
|
||||
XMLHttpRequestEventTarget.prototype.onloadend = null;
|
||||
|
||||
XMLHttpRequestEventTarget.prototype.addEventListener = function(eventType, listener) {
|
||||
var base;
|
||||
eventType = eventType.toLowerCase();
|
||||
(base = this._listeners)[eventType] || (base[eventType] = []);
|
||||
this._listeners[eventType].push(listener);
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequestEventTarget.prototype.removeEventListener = function(eventType, listener) {
|
||||
var index;
|
||||
eventType = eventType.toLowerCase();
|
||||
if (this._listeners[eventType]) {
|
||||
index = this._listeners[eventType].indexOf(listener);
|
||||
if (index !== -1) {
|
||||
this._listeners[eventType].splice(index, 1);
|
||||
}
|
||||
}
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequestEventTarget.prototype.dispatchEvent = function(event) {
|
||||
var eventType, j, len, listener, listeners;
|
||||
event.currentTarget = event.target = this;
|
||||
eventType = event.type;
|
||||
if (listeners = this._listeners[eventType]) {
|
||||
for (j = 0, len = listeners.length; j < len; j++) {
|
||||
listener = listeners[j];
|
||||
listener.call(this, event);
|
||||
}
|
||||
}
|
||||
if (listener = this["on" + eventType]) {
|
||||
listener.call(this, event);
|
||||
}
|
||||
return void 0;
|
||||
};
|
||||
|
||||
return XMLHttpRequestEventTarget;
|
||||
|
||||
})();
|
||||
|
||||
http = require('http');
|
||||
|
||||
https = require('https');
|
||||
|
||||
os = require('os');
|
||||
|
||||
url = require('url');
|
||||
|
||||
XMLHttpRequest = (function(superClass) {
|
||||
extend(XMLHttpRequest, superClass);
|
||||
|
||||
function XMLHttpRequest(options) {
|
||||
XMLHttpRequest.__super__.constructor.call(this);
|
||||
this.onreadystatechange = null;
|
||||
this._anonymous = options && options.anon;
|
||||
this.readyState = XMLHttpRequest.UNSENT;
|
||||
this.response = null;
|
||||
this.responseText = '';
|
||||
this.responseType = '';
|
||||
this.responseURL = '';
|
||||
this.status = 0;
|
||||
this.statusText = '';
|
||||
this.timeout = 0;
|
||||
this.upload = new XMLHttpRequestUpload(this);
|
||||
this._method = null;
|
||||
this._url = null;
|
||||
this._sync = false;
|
||||
this._headers = null;
|
||||
this._loweredHeaders = null;
|
||||
this._mimeOverride = null;
|
||||
this._request = null;
|
||||
this._response = null;
|
||||
this._responseParts = null;
|
||||
this._responseHeaders = null;
|
||||
this._aborting = null;
|
||||
this._error = null;
|
||||
this._loadedBytes = 0;
|
||||
this._totalBytes = 0;
|
||||
this._lengthComputable = false;
|
||||
}
|
||||
|
||||
XMLHttpRequest.prototype.onreadystatechange = null;
|
||||
|
||||
XMLHttpRequest.prototype.readyState = null;
|
||||
|
||||
XMLHttpRequest.prototype.response = null;
|
||||
|
||||
XMLHttpRequest.prototype.responseText = null;
|
||||
|
||||
XMLHttpRequest.prototype.responseType = null;
|
||||
|
||||
XMLHttpRequest.prototype.status = null;
|
||||
|
||||
XMLHttpRequest.prototype.timeout = null;
|
||||
|
||||
XMLHttpRequest.prototype.upload = null;
|
||||
|
||||
XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
|
||||
var xhrUrl;
|
||||
method = method.toUpperCase();
|
||||
if (method in this._restrictedMethods) {
|
||||
throw new SecurityError("HTTP method " + method + " is not allowed in XHR");
|
||||
}
|
||||
xhrUrl = this._parseUrl(url);
|
||||
if (async === void 0) {
|
||||
async = true;
|
||||
}
|
||||
switch (this.readyState) {
|
||||
case XMLHttpRequest.UNSENT:
|
||||
case XMLHttpRequest.OPENED:
|
||||
case XMLHttpRequest.DONE:
|
||||
null;
|
||||
break;
|
||||
case XMLHttpRequest.HEADERS_RECEIVED:
|
||||
case XMLHttpRequest.LOADING:
|
||||
null;
|
||||
}
|
||||
this._method = method;
|
||||
this._url = xhrUrl;
|
||||
this._sync = !async;
|
||||
this._headers = {};
|
||||
this._loweredHeaders = {};
|
||||
this._mimeOverride = null;
|
||||
this._setReadyState(XMLHttpRequest.OPENED);
|
||||
this._request = null;
|
||||
this._response = null;
|
||||
this.status = 0;
|
||||
this.statusText = '';
|
||||
this._responseParts = [];
|
||||
this._responseHeaders = null;
|
||||
this._loadedBytes = 0;
|
||||
this._totalBytes = 0;
|
||||
this._lengthComputable = false;
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype.setRequestHeader = function(name, value) {
|
||||
var loweredName;
|
||||
if (this.readyState !== XMLHttpRequest.OPENED) {
|
||||
throw new InvalidStateError("XHR readyState must be OPENED");
|
||||
}
|
||||
loweredName = name.toLowerCase();
|
||||
if (this._restrictedHeaders[loweredName] || /^sec\-/.test(loweredName) || /^proxy-/.test(loweredName)) {
|
||||
console.warn("Refused to set unsafe header \"" + name + "\"");
|
||||
return void 0;
|
||||
}
|
||||
value = value.toString();
|
||||
if (loweredName in this._loweredHeaders) {
|
||||
name = this._loweredHeaders[loweredName];
|
||||
this._headers[name] = this._headers[name] + ', ' + value;
|
||||
} else {
|
||||
this._loweredHeaders[loweredName] = name;
|
||||
this._headers[name] = value;
|
||||
}
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype.send = function(data) {
|
||||
if (this.readyState !== XMLHttpRequest.OPENED) {
|
||||
throw new InvalidStateError("XHR readyState must be OPENED");
|
||||
}
|
||||
if (this._request) {
|
||||
throw new InvalidStateError("send() already called");
|
||||
}
|
||||
switch (this._url.protocol) {
|
||||
case 'file:':
|
||||
this._sendFile(data);
|
||||
break;
|
||||
case 'http:':
|
||||
case 'https:':
|
||||
this._sendHttp(data);
|
||||
break;
|
||||
default:
|
||||
throw new NetworkError("Unsupported protocol " + this._url.protocol);
|
||||
}
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype.abort = function() {
|
||||
if (!this._request) {
|
||||
return;
|
||||
}
|
||||
this._request.abort();
|
||||
this._setError();
|
||||
this._dispatchProgress('abort');
|
||||
this._dispatchProgress('loadend');
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype.getResponseHeader = function(name) {
|
||||
var loweredName;
|
||||
if (!this._responseHeaders) {
|
||||
return null;
|
||||
}
|
||||
loweredName = name.toLowerCase();
|
||||
if (loweredName in this._responseHeaders) {
|
||||
return this._responseHeaders[loweredName];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype.getAllResponseHeaders = function() {
|
||||
var lines, name, value;
|
||||
if (!this._responseHeaders) {
|
||||
return '';
|
||||
}
|
||||
lines = (function() {
|
||||
var ref, results;
|
||||
ref = this._responseHeaders;
|
||||
results = [];
|
||||
for (name in ref) {
|
||||
value = ref[name];
|
||||
results.push(name + ": " + value);
|
||||
}
|
||||
return results;
|
||||
}).call(this);
|
||||
return lines.join("\r\n");
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype.overrideMimeType = function(newMimeType) {
|
||||
if (this.readyState === XMLHttpRequest.LOADING || this.readyState === XMLHttpRequest.DONE) {
|
||||
throw new InvalidStateError("overrideMimeType() not allowed in LOADING or DONE");
|
||||
}
|
||||
this._mimeOverride = newMimeType.toLowerCase();
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype.nodejsSet = function(options) {
|
||||
var baseUrl, parsedUrl;
|
||||
if ('httpAgent' in options) {
|
||||
this.nodejsHttpAgent = options.httpAgent;
|
||||
}
|
||||
if ('httpsAgent' in options) {
|
||||
this.nodejsHttpsAgent = options.httpsAgent;
|
||||
}
|
||||
if ('baseUrl' in options) {
|
||||
baseUrl = options.baseUrl;
|
||||
if (baseUrl !== null) {
|
||||
parsedUrl = url.parse(baseUrl, false, true);
|
||||
if (!parsedUrl.protocol) {
|
||||
throw new SyntaxError("baseUrl must be an absolute URL");
|
||||
}
|
||||
}
|
||||
this.nodejsBaseUrl = baseUrl;
|
||||
}
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequest.nodejsSet = function(options) {
|
||||
XMLHttpRequest.prototype.nodejsSet(options);
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype.UNSENT = 0;
|
||||
|
||||
XMLHttpRequest.UNSENT = 0;
|
||||
|
||||
XMLHttpRequest.prototype.OPENED = 1;
|
||||
|
||||
XMLHttpRequest.OPENED = 1;
|
||||
|
||||
XMLHttpRequest.prototype.HEADERS_RECEIVED = 2;
|
||||
|
||||
XMLHttpRequest.HEADERS_RECEIVED = 2;
|
||||
|
||||
XMLHttpRequest.prototype.LOADING = 3;
|
||||
|
||||
XMLHttpRequest.LOADING = 3;
|
||||
|
||||
XMLHttpRequest.prototype.DONE = 4;
|
||||
|
||||
XMLHttpRequest.DONE = 4;
|
||||
|
||||
XMLHttpRequest.prototype.nodejsHttpAgent = http.globalAgent;
|
||||
|
||||
XMLHttpRequest.prototype.nodejsHttpsAgent = https.globalAgent;
|
||||
|
||||
XMLHttpRequest.prototype.nodejsBaseUrl = null;
|
||||
|
||||
XMLHttpRequest.prototype._restrictedMethods = {
|
||||
CONNECT: true,
|
||||
TRACE: true,
|
||||
TRACK: true
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._restrictedHeaders = {
|
||||
'accept-charset': true,
|
||||
'accept-encoding': true,
|
||||
'access-control-request-headers': true,
|
||||
'access-control-request-method': true,
|
||||
connection: true,
|
||||
'content-length': true,
|
||||
cookie: true,
|
||||
cookie2: true,
|
||||
date: true,
|
||||
dnt: true,
|
||||
expect: true,
|
||||
host: true,
|
||||
'keep-alive': true,
|
||||
origin: true,
|
||||
referer: true,
|
||||
te: true,
|
||||
trailer: true,
|
||||
'transfer-encoding': true,
|
||||
upgrade: true,
|
||||
'user-agent': true,
|
||||
via: true
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._privateHeaders = {
|
||||
'set-cookie': true,
|
||||
'set-cookie2': true
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._userAgent = ("Mozilla/5.0 (" + (os.type()) + " " + (os.arch()) + ") ") + ("node.js/" + process.versions.node + " v8/" + process.versions.v8);
|
||||
|
||||
XMLHttpRequest.prototype._setReadyState = function(newReadyState) {
|
||||
var event;
|
||||
this.readyState = newReadyState;
|
||||
event = new ProgressEvent('readystatechange');
|
||||
this.dispatchEvent(event);
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._sendFile = function() {
|
||||
if (this._url.method !== 'GET') {
|
||||
throw new NetworkError('The file protocol only supports GET');
|
||||
}
|
||||
throw new Error("Protocol file: not implemented");
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._sendHttp = function(data) {
|
||||
if (this._sync) {
|
||||
throw new Error("Synchronous XHR processing not implemented");
|
||||
}
|
||||
if ((data != null) && (this._method === 'GET' || this._method === 'HEAD')) {
|
||||
console.warn("Discarding entity body for " + this._method + " requests");
|
||||
data = null;
|
||||
} else {
|
||||
data || (data = '');
|
||||
}
|
||||
this.upload._setData(data);
|
||||
this._finalizeHeaders();
|
||||
this._sendHxxpRequest();
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._sendHxxpRequest = function() {
|
||||
var agent, hxxp, request;
|
||||
if (this._url.protocol === 'http:') {
|
||||
hxxp = http;
|
||||
agent = this.nodejsHttpAgent;
|
||||
} else {
|
||||
hxxp = https;
|
||||
agent = this.nodejsHttpsAgent;
|
||||
}
|
||||
request = hxxp.request({
|
||||
hostname: this._url.hostname,
|
||||
port: this._url.port,
|
||||
path: this._url.path,
|
||||
auth: this._url.auth,
|
||||
method: this._method,
|
||||
headers: this._headers,
|
||||
agent: agent
|
||||
});
|
||||
this._request = request;
|
||||
if (this.timeout) {
|
||||
request.setTimeout(this.timeout, (function(_this) {
|
||||
return function() {
|
||||
return _this._onHttpTimeout(request);
|
||||
};
|
||||
})(this));
|
||||
}
|
||||
request.on('response', (function(_this) {
|
||||
return function(response) {
|
||||
return _this._onHttpResponse(request, response);
|
||||
};
|
||||
})(this));
|
||||
request.on('error', (function(_this) {
|
||||
return function(error) {
|
||||
return _this._onHttpRequestError(request, error);
|
||||
};
|
||||
})(this));
|
||||
this.upload._startUpload(request);
|
||||
if (this._request === request) {
|
||||
this._dispatchProgress('loadstart');
|
||||
}
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._finalizeHeaders = function() {
|
||||
this._headers['Connection'] = 'keep-alive';
|
||||
this._headers['Host'] = this._url.host;
|
||||
if (this._anonymous) {
|
||||
this._headers['Referer'] = 'about:blank';
|
||||
}
|
||||
this._headers['User-Agent'] = this._userAgent;
|
||||
this.upload._finalizeHeaders(this._headers, this._loweredHeaders);
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._onHttpResponse = function(request, response) {
|
||||
var lengthString;
|
||||
if (this._request !== request) {
|
||||
return;
|
||||
}
|
||||
switch (response.statusCode) {
|
||||
case 301:
|
||||
case 302:
|
||||
case 303:
|
||||
case 307:
|
||||
case 308:
|
||||
this._url = this._parseUrl(response.headers['location']);
|
||||
this._method = 'GET';
|
||||
if ('content-type' in this._loweredHeaders) {
|
||||
delete this._headers[this._loweredHeaders['content-type']];
|
||||
delete this._loweredHeaders['content-type'];
|
||||
}
|
||||
if ('Content-Type' in this._headers) {
|
||||
delete this._headers['Content-Type'];
|
||||
}
|
||||
delete this._headers['Content-Length'];
|
||||
this.upload._reset();
|
||||
this._finalizeHeaders();
|
||||
this._sendHxxpRequest();
|
||||
return;
|
||||
}
|
||||
this._response = response;
|
||||
this._response.on('data', (function(_this) {
|
||||
return function(data) {
|
||||
return _this._onHttpResponseData(response, data);
|
||||
};
|
||||
})(this));
|
||||
this._response.on('end', (function(_this) {
|
||||
return function() {
|
||||
return _this._onHttpResponseEnd(response);
|
||||
};
|
||||
})(this));
|
||||
this._response.on('close', (function(_this) {
|
||||
return function() {
|
||||
return _this._onHttpResponseClose(response);
|
||||
};
|
||||
})(this));
|
||||
this.responseURL = this._url.href.split('#')[0];
|
||||
this.status = this._response.statusCode;
|
||||
this.statusText = http.STATUS_CODES[this.status];
|
||||
this._parseResponseHeaders(response);
|
||||
if (lengthString = this._responseHeaders['content-length']) {
|
||||
this._totalBytes = parseInt(lengthString);
|
||||
this._lengthComputable = true;
|
||||
} else {
|
||||
this._lengthComputable = false;
|
||||
}
|
||||
return this._setReadyState(XMLHttpRequest.HEADERS_RECEIVED);
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._onHttpResponseData = function(response, data) {
|
||||
if (this._response !== response) {
|
||||
return;
|
||||
}
|
||||
this._responseParts.push(data);
|
||||
this._loadedBytes += data.length;
|
||||
if (this.readyState !== XMLHttpRequest.LOADING) {
|
||||
this._setReadyState(XMLHttpRequest.LOADING);
|
||||
}
|
||||
return this._dispatchProgress('progress');
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._onHttpResponseEnd = function(response) {
|
||||
if (this._response !== response) {
|
||||
return;
|
||||
}
|
||||
this._parseResponse();
|
||||
this._request = null;
|
||||
this._response = null;
|
||||
this._setReadyState(XMLHttpRequest.DONE);
|
||||
this._dispatchProgress('load');
|
||||
return this._dispatchProgress('loadend');
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._onHttpResponseClose = function(response) {
|
||||
var request;
|
||||
if (this._response !== response) {
|
||||
return;
|
||||
}
|
||||
request = this._request;
|
||||
this._setError();
|
||||
request.abort();
|
||||
this._setReadyState(XMLHttpRequest.DONE);
|
||||
this._dispatchProgress('error');
|
||||
return this._dispatchProgress('loadend');
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._onHttpTimeout = function(request) {
|
||||
if (this._request !== request) {
|
||||
return;
|
||||
}
|
||||
this._setError();
|
||||
request.abort();
|
||||
this._setReadyState(XMLHttpRequest.DONE);
|
||||
this._dispatchProgress('timeout');
|
||||
return this._dispatchProgress('loadend');
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._onHttpRequestError = function(request, error) {
|
||||
if (this._request !== request) {
|
||||
return;
|
||||
}
|
||||
this._setError();
|
||||
request.abort();
|
||||
this._setReadyState(XMLHttpRequest.DONE);
|
||||
this._dispatchProgress('error');
|
||||
return this._dispatchProgress('loadend');
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._dispatchProgress = function(eventType) {
|
||||
var event;
|
||||
event = new ProgressEvent(eventType);
|
||||
event.lengthComputable = this._lengthComputable;
|
||||
event.loaded = this._loadedBytes;
|
||||
event.total = this._totalBytes;
|
||||
this.dispatchEvent(event);
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._setError = function() {
|
||||
this._request = null;
|
||||
this._response = null;
|
||||
this._responseHeaders = null;
|
||||
this._responseParts = null;
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._parseUrl = function(urlString) {
|
||||
var absoluteUrlString, index, password, user, xhrUrl;
|
||||
if (this.nodejsBaseUrl === null) {
|
||||
absoluteUrlString = urlString;
|
||||
} else {
|
||||
absoluteUrlString = url.resolve(this.nodejsBaseUrl, urlString);
|
||||
}
|
||||
xhrUrl = url.parse(absoluteUrlString, false, true);
|
||||
xhrUrl.hash = null;
|
||||
if (xhrUrl.auth && ((typeof user !== "undefined" && user !== null) || (typeof password !== "undefined" && password !== null))) {
|
||||
index = xhrUrl.auth.indexOf(':');
|
||||
if (index === -1) {
|
||||
if (!user) {
|
||||
user = xhrUrl.auth;
|
||||
}
|
||||
} else {
|
||||
if (!user) {
|
||||
user = xhrUrl.substring(0, index);
|
||||
}
|
||||
if (!password) {
|
||||
password = xhrUrl.substring(index + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (user || password) {
|
||||
xhrUrl.auth = user + ":" + password;
|
||||
}
|
||||
return xhrUrl;
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._parseResponseHeaders = function(response) {
|
||||
var loweredName, name, ref, value;
|
||||
this._responseHeaders = {};
|
||||
ref = response.headers;
|
||||
for (name in ref) {
|
||||
value = ref[name];
|
||||
loweredName = name.toLowerCase();
|
||||
if (this._privateHeaders[loweredName]) {
|
||||
continue;
|
||||
}
|
||||
if (this._mimeOverride !== null && loweredName === 'content-type') {
|
||||
value = this._mimeOverride;
|
||||
}
|
||||
this._responseHeaders[loweredName] = value;
|
||||
}
|
||||
if (this._mimeOverride !== null && !('content-type' in this._responseHeaders)) {
|
||||
this._responseHeaders['content-type'] = this._mimeOverride;
|
||||
}
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._parseResponse = function() {
|
||||
var arrayBuffer, buffer, i, j, jsonError, ref, view;
|
||||
if (Buffer.concat) {
|
||||
buffer = Buffer.concat(this._responseParts);
|
||||
} else {
|
||||
buffer = this._concatBuffers(this._responseParts);
|
||||
}
|
||||
this._responseParts = null;
|
||||
switch (this.responseType) {
|
||||
case 'text':
|
||||
this._parseTextResponse(buffer);
|
||||
break;
|
||||
case 'json':
|
||||
this.responseText = null;
|
||||
try {
|
||||
this.response = JSON.parse(buffer.toString('utf-8'));
|
||||
} catch (error1) {
|
||||
jsonError = error1;
|
||||
this.response = null;
|
||||
}
|
||||
break;
|
||||
case 'buffer':
|
||||
this.responseText = null;
|
||||
this.response = buffer;
|
||||
break;
|
||||
case 'arraybuffer':
|
||||
this.responseText = null;
|
||||
arrayBuffer = new ArrayBuffer(buffer.length);
|
||||
view = new Uint8Array(arrayBuffer);
|
||||
for (i = j = 0, ref = buffer.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||||
view[i] = buffer[i];
|
||||
}
|
||||
this.response = arrayBuffer;
|
||||
break;
|
||||
default:
|
||||
this._parseTextResponse(buffer);
|
||||
}
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._parseTextResponse = function(buffer) {
|
||||
var e;
|
||||
try {
|
||||
this.responseText = buffer.toString(this._parseResponseEncoding());
|
||||
} catch (error1) {
|
||||
e = error1;
|
||||
this.responseText = buffer.toString('binary');
|
||||
}
|
||||
this.response = this.responseText;
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._parseResponseEncoding = function() {
|
||||
var contentType, encoding, match;
|
||||
encoding = null;
|
||||
if (contentType = this._responseHeaders['content-type']) {
|
||||
if (match = /\;\s*charset\=(.*)$/.exec(contentType)) {
|
||||
return match[1];
|
||||
}
|
||||
}
|
||||
return 'utf-8';
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype._concatBuffers = function(buffers) {
|
||||
var buffer, j, k, len, len1, length, target;
|
||||
if (buffers.length === 0) {
|
||||
return new Buffer(0);
|
||||
}
|
||||
if (buffers.length === 1) {
|
||||
return buffers[0];
|
||||
}
|
||||
length = 0;
|
||||
for (j = 0, len = buffers.length; j < len; j++) {
|
||||
buffer = buffers[j];
|
||||
length += buffer.length;
|
||||
}
|
||||
target = new Buffer(length);
|
||||
length = 0;
|
||||
for (k = 0, len1 = buffers.length; k < len1; k++) {
|
||||
buffer = buffers[k];
|
||||
buffer.copy(target, length);
|
||||
length += buffer.length;
|
||||
}
|
||||
return target;
|
||||
};
|
||||
|
||||
return XMLHttpRequest;
|
||||
|
||||
})(XMLHttpRequestEventTarget);
|
||||
|
||||
module.exports = XMLHttpRequest;
|
||||
|
||||
XMLHttpRequest.XMLHttpRequest = XMLHttpRequest;
|
||||
|
||||
SecurityError = (function(superClass) {
|
||||
extend(SecurityError, superClass);
|
||||
|
||||
function SecurityError() {
|
||||
SecurityError.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
return SecurityError;
|
||||
|
||||
})(Error);
|
||||
|
||||
XMLHttpRequest.SecurityError = SecurityError;
|
||||
|
||||
InvalidStateError = (function(superClass) {
|
||||
extend(InvalidStateError, superClass);
|
||||
|
||||
function InvalidStateError() {
|
||||
InvalidStateError.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
return InvalidStateError;
|
||||
|
||||
})(Error);
|
||||
|
||||
InvalidStateError = (function(superClass) {
|
||||
extend(InvalidStateError, superClass);
|
||||
|
||||
function InvalidStateError() {
|
||||
return InvalidStateError.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
return InvalidStateError;
|
||||
|
||||
})(Error);
|
||||
|
||||
XMLHttpRequest.InvalidStateError = InvalidStateError;
|
||||
|
||||
NetworkError = (function(superClass) {
|
||||
extend(NetworkError, superClass);
|
||||
|
||||
function NetworkError() {
|
||||
NetworkError.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
return NetworkError;
|
||||
|
||||
})(Error);
|
||||
|
||||
XMLHttpRequest.SyntaxError = SyntaxError;
|
||||
|
||||
SyntaxError = (function(superClass) {
|
||||
extend(SyntaxError, superClass);
|
||||
|
||||
function SyntaxError() {
|
||||
SyntaxError.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
return SyntaxError;
|
||||
|
||||
})(Error);
|
||||
|
||||
ProgressEvent = (function() {
|
||||
function ProgressEvent(type) {
|
||||
this.type = type;
|
||||
this.target = null;
|
||||
this.currentTarget = null;
|
||||
this.lengthComputable = false;
|
||||
this.loaded = 0;
|
||||
this.total = 0;
|
||||
}
|
||||
|
||||
ProgressEvent.prototype.bubbles = false;
|
||||
|
||||
ProgressEvent.prototype.cancelable = false;
|
||||
|
||||
ProgressEvent.prototype.target = null;
|
||||
|
||||
ProgressEvent.prototype.loaded = null;
|
||||
|
||||
ProgressEvent.prototype.lengthComputable = null;
|
||||
|
||||
ProgressEvent.prototype.total = null;
|
||||
|
||||
return ProgressEvent;
|
||||
|
||||
})();
|
||||
|
||||
XMLHttpRequest.ProgressEvent = ProgressEvent;
|
||||
|
||||
XMLHttpRequestUpload = (function(superClass) {
|
||||
extend(XMLHttpRequestUpload, superClass);
|
||||
|
||||
function XMLHttpRequestUpload(request) {
|
||||
XMLHttpRequestUpload.__super__.constructor.call(this);
|
||||
this._request = request;
|
||||
this._reset();
|
||||
}
|
||||
|
||||
XMLHttpRequestUpload.prototype._reset = function() {
|
||||
this._contentType = null;
|
||||
this._body = null;
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequestUpload.prototype._setData = function(data) {
|
||||
var body, i, j, k, offset, ref, ref1, view;
|
||||
if (typeof data === 'undefined' || data === null) {
|
||||
return;
|
||||
}
|
||||
if (typeof data === 'string') {
|
||||
if (data.length !== 0) {
|
||||
this._contentType = 'text/plain;charset=UTF-8';
|
||||
}
|
||||
this._body = new Buffer(data, 'utf8');
|
||||
} else if (Buffer.isBuffer(data)) {
|
||||
this._body = data;
|
||||
} else if (data instanceof ArrayBuffer) {
|
||||
body = new Buffer(data.byteLength);
|
||||
view = new Uint8Array(data);
|
||||
for (i = j = 0, ref = data.byteLength; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||||
body[i] = view[i];
|
||||
}
|
||||
this._body = body;
|
||||
} else if (data.buffer && data.buffer instanceof ArrayBuffer) {
|
||||
body = new Buffer(data.byteLength);
|
||||
offset = data.byteOffset;
|
||||
view = new Uint8Array(data.buffer);
|
||||
for (i = k = 0, ref1 = data.byteLength; 0 <= ref1 ? k < ref1 : k > ref1; i = 0 <= ref1 ? ++k : --k) {
|
||||
body[i] = view[i + offset];
|
||||
}
|
||||
this._body = body;
|
||||
} else {
|
||||
throw new Error("Unsupported send() data " + data);
|
||||
}
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequestUpload.prototype._finalizeHeaders = function(headers, loweredHeaders) {
|
||||
if (this._contentType) {
|
||||
if (!('content-type' in loweredHeaders)) {
|
||||
headers['Content-Type'] = this._contentType;
|
||||
}
|
||||
}
|
||||
if (this._body) {
|
||||
headers['Content-Length'] = this._body.length.toString();
|
||||
}
|
||||
return void 0;
|
||||
};
|
||||
|
||||
XMLHttpRequestUpload.prototype._startUpload = function(request) {
|
||||
if (this._body) {
|
||||
request.write(this._body);
|
||||
}
|
||||
request.end();
|
||||
return void 0;
|
||||
};
|
||||
|
||||
return XMLHttpRequestUpload;
|
||||
|
||||
})(XMLHttpRequestEventTarget);
|
||||
|
||||
XMLHttpRequest.XMLHttpRequestUpload = XMLHttpRequestUpload;
|
||||
|
||||
}).call(this);
|
||||
50
node_modules/xhr2/package.json
generated
vendored
Normal file
50
node_modules/xhr2/package.json
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "xhr2",
|
||||
"version": "0.1.4",
|
||||
"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": [
|
||||
"Daniel Friedman <dfriedman58@gmail.com>",
|
||||
"Francois-Xavier Kowalski <francois-xavier.kowalski@hp.com>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pwnall/node-xhr2.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/pwnall/node-xhr2/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
},
|
||||
"dependencies": {
|
||||
},
|
||||
"devDependencies": {
|
||||
"async": ">= 1.4.2",
|
||||
"chai": ">= 3.2.0",
|
||||
"codo": ">= 2.0.11",
|
||||
"coffee-script": ">= 1.9.3",
|
||||
"express": ">= 4.13.3",
|
||||
"glob": ">= 5.0.14",
|
||||
"mocha": ">= 2.2.5",
|
||||
"open": ">= 0.0.5",
|
||||
"remove": ">= 0.1.5",
|
||||
"sinon": ">= 1.15.4",
|
||||
"sinon-chai": ">= 2.8.0"
|
||||
},
|
||||
"main": "lib/xhr2.js",
|
||||
"browser": "lib/browser.js",
|
||||
"directories": {
|
||||
"doc": "doc",
|
||||
"lib": "lib",
|
||||
"src": "src",
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublish": "node_modules/coffee-script/bin/cake build",
|
||||
"test": "node_modules/coffee-script/bin/cake test"
|
||||
}
|
||||
}
|
||||
89
node_modules/xhr2/src/000-xml_http_request_event_target.coffee
generated
vendored
Normal file
89
node_modules/xhr2/src/000-xml_http_request_event_target.coffee
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
# This file's name is set up in such a way that it will always show up first in
|
||||
# the list of files given to coffee --join, so that the other files can assume
|
||||
# that XMLHttpRequestEventTarget was already defined.
|
||||
|
||||
|
||||
# The DOM EventTarget subclass used by XMLHttpRequest.
|
||||
#
|
||||
# @see http://xhr.spec.whatwg.org/#interface-xmlhttprequest
|
||||
class XMLHttpRequestEventTarget
|
||||
# @private
|
||||
# This is an abstract class and should not be instantiated directly.
|
||||
constructor: ->
|
||||
@onloadstart = null
|
||||
@onprogress = null
|
||||
@onabort = null
|
||||
@onerror = null
|
||||
@onload = null
|
||||
@ontimeout = null
|
||||
@onloadend = null
|
||||
@_listeners = {}
|
||||
|
||||
# @property {function(ProgressEvent)} DOM level 0-style handler
|
||||
# for the 'loadstart' event
|
||||
onloadstart: null
|
||||
|
||||
# @property {function(ProgressEvent)} DOM level 0-style handler
|
||||
# for the 'progress' event
|
||||
onprogress: null
|
||||
|
||||
# @property {function(ProgressEvent)} DOM level 0-style handler
|
||||
# for the 'abort' event
|
||||
onabort: null
|
||||
|
||||
# @property {function(ProgressEvent)} DOM level 0-style handler
|
||||
# for the 'error' event
|
||||
onerror: null
|
||||
|
||||
# @property {function(ProgressEvent)} DOM level 0-style handler
|
||||
# for the 'load' event
|
||||
onload: null
|
||||
|
||||
# @property {function(ProgressEvent)} DOM level 0-style handler
|
||||
# for the 'timeout' event
|
||||
ontimeout: null
|
||||
|
||||
# @property {function(ProgressEvent)} DOM level 0-style handler
|
||||
# for the 'loadend' event
|
||||
onloadend: null
|
||||
|
||||
# Adds a new-style listener for one of the XHR events.
|
||||
#
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#events
|
||||
#
|
||||
# @param {String} eventType an XHR event type, such as 'readystatechange'
|
||||
# @param {function(ProgressEvent)} listener function that will be called when
|
||||
# the event fires
|
||||
# @return {undefined} undefined
|
||||
addEventListener: (eventType, listener) ->
|
||||
eventType = eventType.toLowerCase()
|
||||
@_listeners[eventType] ||= []
|
||||
@_listeners[eventType].push listener
|
||||
undefined
|
||||
|
||||
# Removes an event listener added by calling addEventListener.
|
||||
#
|
||||
# @param {String} eventType an XHR event type, such as 'readystatechange'
|
||||
# @param {function(ProgressEvent)} listener the value passed in a previous
|
||||
# call to addEventListener.
|
||||
# @return {undefined} undefined
|
||||
removeEventListener: (eventType, listener) ->
|
||||
eventType = eventType.toLowerCase()
|
||||
if @_listeners[eventType]
|
||||
index = @_listeners[eventType].indexOf listener
|
||||
@_listeners[eventType].splice index, 1 if index isnt -1
|
||||
undefined
|
||||
|
||||
# Calls all the listeners for an event.
|
||||
#
|
||||
# @param {ProgressEvent} event the event to be dispatched
|
||||
# @return {undefined} undefined
|
||||
dispatchEvent: (event) ->
|
||||
event.currentTarget = event.target = @
|
||||
eventType = event.type
|
||||
if listeners = @_listeners[eventType]
|
||||
for listener in listeners
|
||||
listener.call @, event
|
||||
if listener = @["on#{eventType}"]
|
||||
listener.call @, event
|
||||
undefined
|
||||
782
node_modules/xhr2/src/001-xml_http_request.coffee
generated
vendored
Normal file
782
node_modules/xhr2/src/001-xml_http_request.coffee
generated
vendored
Normal file
@@ -0,0 +1,782 @@
|
||||
# This file's name is set up in such a way that it will always show up second
|
||||
# in the list of files given to coffee --join, so it can use the
|
||||
# XMLHttpRequestEventTarget definition and so that the other files can assume
|
||||
# that XMLHttpRequest was already defined.
|
||||
|
||||
http = require 'http'
|
||||
https = require 'https'
|
||||
os = require 'os'
|
||||
url = require 'url'
|
||||
|
||||
# The ECMAScript HTTP API.
|
||||
#
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#introduction
|
||||
class XMLHttpRequest extends XMLHttpRequestEventTarget
|
||||
# Creates a new request.
|
||||
#
|
||||
# @param {Object} options one or more of the options below
|
||||
# @option options {Boolean} anon if true, the request's anonymous flag
|
||||
# will be set
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#constructors
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#anonymous-flag
|
||||
constructor: (options) ->
|
||||
super()
|
||||
@onreadystatechange = null
|
||||
|
||||
@_anonymous = options and options.anon
|
||||
|
||||
@readyState = XMLHttpRequest.UNSENT
|
||||
@response = null
|
||||
@responseText = ''
|
||||
@responseType = ''
|
||||
@responseURL = ''
|
||||
@status = 0
|
||||
@statusText = ''
|
||||
@timeout = 0
|
||||
@upload = new XMLHttpRequestUpload @
|
||||
|
||||
@_method = null # String
|
||||
@_url = null # Return value of url.parse()
|
||||
@_sync = false
|
||||
@_headers = null # Object<String, String>
|
||||
@_loweredHeaders = null # Object<lowercase String, String>
|
||||
@_mimeOverride = null
|
||||
@_request = null # http.ClientRequest
|
||||
@_response = null # http.ClientResponse
|
||||
@_responseParts = null # Array<Buffer, String>
|
||||
@_responseHeaders = null # Object<lowercase String, String>
|
||||
@_aborting = null
|
||||
@_error = null
|
||||
@_loadedBytes = 0
|
||||
@_totalBytes = 0
|
||||
@_lengthComputable = false
|
||||
|
||||
# @property {function(ProgressEvent)} DOM level 0-style handler for the
|
||||
# 'readystatechange' event
|
||||
onreadystatechange: null
|
||||
|
||||
# @property {Number} the current state of the XHR object
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#states
|
||||
readyState: null
|
||||
|
||||
# @property {String, ArrayBuffer, Buffer, Object} processed XHR response
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-response-attribute
|
||||
response: null
|
||||
|
||||
# @property {String} response string, if responseType is '' or 'text'
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-responsetext-attribute
|
||||
responseText: null
|
||||
|
||||
# @property {String} sets the parsing method for the XHR response
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-responsetype-attribute
|
||||
responseType: null
|
||||
|
||||
# @property {Number} the HTTP
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-status-attribute
|
||||
status: null
|
||||
|
||||
# @property {Number} milliseconds to wait for the request to complete
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-timeout-attribute
|
||||
timeout: null
|
||||
|
||||
# @property {XMLHttpRequestUpload} the associated upload information
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-upload-attribute
|
||||
upload: null
|
||||
|
||||
# Sets the XHR's method, URL, synchronous flag, and authentication params.
|
||||
#
|
||||
# @param {String} method the HTTP method to be used
|
||||
# @param {String} url the URL that the request will be made to
|
||||
# @param {?Boolean} async if false, the XHR should be processed
|
||||
# synchronously; true by default
|
||||
# @param {?String} user the user credential to be used in HTTP basic
|
||||
# authentication
|
||||
# @param {?String} password the password credential to be used in HTTP basic
|
||||
# authentication
|
||||
# @return {undefined} undefined
|
||||
# @throw {SecurityError} method is not one of the allowed methods
|
||||
# @throw {SyntaxError} urlString is not a valid URL
|
||||
# @throw {Error} the URL contains an unsupported protocol; the supported
|
||||
# protocols are file, http and https
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-open()-method
|
||||
open: (method, url, async, user, password) ->
|
||||
method = method.toUpperCase()
|
||||
if method of @_restrictedMethods
|
||||
throw new SecurityError "HTTP method #{method} is not allowed in XHR"
|
||||
|
||||
xhrUrl = @_parseUrl url
|
||||
async = true if async is undefined
|
||||
|
||||
switch @readyState
|
||||
when XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED, XMLHttpRequest.DONE
|
||||
# Nothing to do here.
|
||||
null
|
||||
when XMLHttpRequest.HEADERS_RECEIVED, XMLHttpRequest.LOADING
|
||||
# TODO(pwnall): terminate abort(), terminate send()
|
||||
null
|
||||
|
||||
@_method = method
|
||||
@_url = xhrUrl
|
||||
@_sync = !async
|
||||
@_headers = {}
|
||||
@_loweredHeaders = {}
|
||||
@_mimeOverride = null
|
||||
@_setReadyState XMLHttpRequest.OPENED
|
||||
@_request = null
|
||||
@_response = null
|
||||
@status = 0
|
||||
@statusText = ''
|
||||
@_responseParts = []
|
||||
@_responseHeaders = null
|
||||
@_loadedBytes = 0
|
||||
@_totalBytes = 0
|
||||
@_lengthComputable = false
|
||||
undefined
|
||||
|
||||
# Appends a header to the list of author request headers.
|
||||
#
|
||||
# @param {String} name the HTTP header name
|
||||
# @param {String} value the HTTP header value
|
||||
# @return {undefined} undefined
|
||||
# @throw {InvalidStateError} readyState is not OPENED
|
||||
# @throw {SyntaxError} name is not a valid HTTP header name or value is not
|
||||
# a valid HTTP header value
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader()-method
|
||||
setRequestHeader: (name, value) ->
|
||||
unless @readyState is XMLHttpRequest.OPENED
|
||||
throw new InvalidStateError "XHR readyState must be OPENED"
|
||||
|
||||
loweredName = name.toLowerCase()
|
||||
if @_restrictedHeaders[loweredName] or /^sec\-/.test(loweredName) or
|
||||
/^proxy-/.test(loweredName)
|
||||
console.warn "Refused to set unsafe header \"#{name}\""
|
||||
return undefined
|
||||
|
||||
value = value.toString()
|
||||
if loweredName of @_loweredHeaders
|
||||
# Combine value with the existing header value.
|
||||
name = @_loweredHeaders[loweredName]
|
||||
@_headers[name] = @_headers[name] + ', ' + value
|
||||
else
|
||||
# New header.
|
||||
@_loweredHeaders[loweredName] = name
|
||||
@_headers[name] = value
|
||||
|
||||
undefined
|
||||
|
||||
# Initiates the request.
|
||||
#
|
||||
# @param {?String, ?ArrayBufferView} data the data to be sent; ignored for
|
||||
# GET and HEAD requests
|
||||
# @return {undefined} undefined
|
||||
# @throw {InvalidStateError} readyState is not OPENED
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-send()-method
|
||||
send: (data) ->
|
||||
unless @readyState is XMLHttpRequest.OPENED
|
||||
throw new InvalidStateError "XHR readyState must be OPENED"
|
||||
|
||||
if @_request
|
||||
throw new InvalidStateError "send() already called"
|
||||
|
||||
switch @_url.protocol
|
||||
when 'file:'
|
||||
@_sendFile data
|
||||
when 'http:', 'https:'
|
||||
@_sendHttp data
|
||||
else
|
||||
throw new NetworkError "Unsupported protocol #{@_url.protocol}"
|
||||
|
||||
undefined
|
||||
|
||||
# Cancels the network activity performed by this request.
|
||||
#
|
||||
# @return {undefined} undefined
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-abort()-method
|
||||
abort: ->
|
||||
return unless @_request
|
||||
|
||||
@_request.abort()
|
||||
@_setError()
|
||||
@_dispatchProgress 'abort'
|
||||
@_dispatchProgress 'loadend'
|
||||
undefined
|
||||
|
||||
# Returns a header value in the HTTP response for this XHR.
|
||||
#
|
||||
# @param {String} name case-insensitive HTTP header name
|
||||
# @return {?String} value the value of the header whose name matches the
|
||||
# given name, or null if there is no such header
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-getresponseheader()-method
|
||||
getResponseHeader: (name) ->
|
||||
return null unless @_responseHeaders
|
||||
|
||||
loweredName = name.toLowerCase()
|
||||
if loweredName of @_responseHeaders
|
||||
@_responseHeaders[loweredName]
|
||||
else
|
||||
null
|
||||
|
||||
# Returns all the HTTP headers in this XHR's response.
|
||||
#
|
||||
# @return {String} header lines separated by CR LF, where each header line
|
||||
# has the name and value separated by a ": " (colon, space); the empty
|
||||
# string is returned if the headers are not available
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-getallresponseheaders()-method
|
||||
getAllResponseHeaders: ->
|
||||
return '' unless @_responseHeaders
|
||||
|
||||
lines = ("#{name}: #{value}" for name, value of @_responseHeaders)
|
||||
lines.join "\r\n"
|
||||
|
||||
# Overrides the Content-Type
|
||||
#
|
||||
# @return {undefined} undefined
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-overridemimetype()-method
|
||||
overrideMimeType: (newMimeType) ->
|
||||
if @readyState is XMLHttpRequest.LOADING or
|
||||
@readyState is XMLHttpRequest.DONE
|
||||
throw new InvalidStateError(
|
||||
"overrideMimeType() not allowed in LOADING or DONE")
|
||||
|
||||
@_mimeOverride = newMimeType.toLowerCase()
|
||||
undefined
|
||||
|
||||
# Network configuration not exposed in the XHR API.
|
||||
#
|
||||
# Although the XMLHttpRequest specification calls itself "ECMAScript HTTP",
|
||||
# it assumes that requests are always performed in the context of a browser
|
||||
# application, where some network parameters are set by the browser user and
|
||||
# should not be modified by Web applications. This API provides access to
|
||||
# these network parameters.
|
||||
#
|
||||
# NOTE: this is not in the XMLHttpRequest API, and will not work in
|
||||
# browsers. It is a stable node-xhr2 API.
|
||||
#
|
||||
# @param {Object} options one or more of the options below
|
||||
# @option options {?http.Agent} httpAgent the value for the nodejsHttpAgent
|
||||
# property (the agent used for HTTP requests)
|
||||
# @option options {?https.Agent} httpsAgent the value for the
|
||||
# nodejsHttpsAgent property (the agent used for HTTPS requests)
|
||||
# @return {undefined} undefined
|
||||
nodejsSet: (options) ->
|
||||
if 'httpAgent' of options
|
||||
@nodejsHttpAgent = options.httpAgent
|
||||
if 'httpsAgent' of options
|
||||
@nodejsHttpsAgent = options.httpsAgent
|
||||
if 'baseUrl' of options
|
||||
baseUrl = options.baseUrl
|
||||
unless baseUrl is null
|
||||
parsedUrl = url.parse baseUrl, false, true
|
||||
unless parsedUrl.protocol
|
||||
throw new SyntaxError("baseUrl must be an absolute URL")
|
||||
@nodejsBaseUrl = baseUrl
|
||||
|
||||
undefined
|
||||
|
||||
# Default settings for the network configuration not exposed in the XHR API.
|
||||
#
|
||||
# NOTE: this is not in the XMLHttpRequest API, and will not work in
|
||||
# browsers. It is a stable node-xhr2 API.
|
||||
#
|
||||
# @param {Object} options one or more of the options below
|
||||
# @option options {?http.Agent} httpAgent the default value for the
|
||||
# nodejsHttpAgent property (the agent used for HTTP requests)
|
||||
# @option options {https.Agent} httpsAgent the default value for the
|
||||
# nodejsHttpsAgent property (the agent used for HTTPS requests)
|
||||
# @return {undefined} undefined
|
||||
# @see XMLHttpRequest.nodejsSet
|
||||
@nodejsSet: (options) ->
|
||||
# "this" will be set to XMLHttpRequest.prototype, so the instance nodejsSet
|
||||
# operates on default property values.
|
||||
XMLHttpRequest::nodejsSet options
|
||||
|
||||
undefined
|
||||
|
||||
# readyState value before XMLHttpRequest#open() is called
|
||||
UNSENT: 0
|
||||
# readyState value before XMLHttpRequest#open() is called
|
||||
@UNSENT: 0
|
||||
|
||||
# readyState value after XMLHttpRequest#open() is called, and before
|
||||
# XMLHttpRequest#send() is called; XMLHttpRequest#setRequestHeader() can be
|
||||
# called in this state
|
||||
OPENED: 1
|
||||
# readyState value after XMLHttpRequest#open() is called, and before
|
||||
# XMLHttpRequest#send() is called; XMLHttpRequest#setRequestHeader() can be
|
||||
# called in this state
|
||||
@OPENED: 1
|
||||
|
||||
# readyState value after redirects have been followed and the HTTP headers of
|
||||
# the final response have been received
|
||||
HEADERS_RECEIVED: 2
|
||||
# readyState value after redirects have been followed and the HTTP headers of
|
||||
# the final response have been received
|
||||
@HEADERS_RECEIVED: 2
|
||||
|
||||
# readyState value when the response entity body is being received
|
||||
LOADING: 3
|
||||
# readyState value when the response entity body is being received
|
||||
@LOADING: 3
|
||||
|
||||
# readyState value after the request has been completely processed
|
||||
DONE: 4
|
||||
# readyState value after the request has been completely processed
|
||||
@DONE: 4
|
||||
|
||||
# @property {http.Agent} the agent option passed to HTTP requests
|
||||
#
|
||||
# NOTE: this is not in the XMLHttpRequest API, and will not work in browsers.
|
||||
# It is a stable node-xhr2 API that is useful for testing & going through
|
||||
# web-proxies.
|
||||
nodejsHttpAgent: http.globalAgent
|
||||
|
||||
# @property {https.Agent} the agent option passed to HTTPS requests
|
||||
#
|
||||
# NOTE: this is not in the XMLHttpRequest API, and will not work in browsers.
|
||||
# It is a stable node-xhr2 API that is useful for testing & going through
|
||||
# web-proxies.
|
||||
nodejsHttpsAgent: https.globalAgent
|
||||
|
||||
# @property {String} the base URL that relative URLs get resolved to
|
||||
#
|
||||
# NOTE: this is not in the XMLHttpRequest API, and will not work in browsers.
|
||||
# Its browser equivalent is the base URL of the document associated with the
|
||||
# Window object. It is a stable node-xhr2 API provided for libraries such as
|
||||
# Angular Universal.
|
||||
nodejsBaseUrl: null
|
||||
|
||||
# HTTP methods that are disallowed in the XHR spec.
|
||||
#
|
||||
# @private
|
||||
# @see Step 6 in http://www.w3.org/TR/XMLHttpRequest/#the-open()-method
|
||||
_restrictedMethods:
|
||||
CONNECT: true
|
||||
TRACE: true
|
||||
TRACK: true
|
||||
|
||||
# HTTP request headers that are disallowed in the XHR spec.
|
||||
#
|
||||
# @private
|
||||
# @see Step 5 in
|
||||
# http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader()-method
|
||||
_restrictedHeaders:
|
||||
'accept-charset': true
|
||||
'accept-encoding': true
|
||||
'access-control-request-headers': true
|
||||
'access-control-request-method': true
|
||||
connection: true
|
||||
'content-length': true
|
||||
cookie: true
|
||||
cookie2: true
|
||||
date: true
|
||||
dnt: true
|
||||
expect: true
|
||||
host: true
|
||||
'keep-alive': true
|
||||
origin: true
|
||||
referer: true
|
||||
te: true
|
||||
trailer: true
|
||||
'transfer-encoding': true
|
||||
upgrade: true
|
||||
'user-agent': true
|
||||
via: true
|
||||
|
||||
# HTTP response headers that should not be exposed according to the XHR spec.
|
||||
#
|
||||
# @private
|
||||
# @see Step 3 in
|
||||
# http://www.w3.org/TR/XMLHttpRequest/#the-getresponseheader()-method
|
||||
_privateHeaders:
|
||||
'set-cookie': true
|
||||
'set-cookie2': true
|
||||
|
||||
# The value of the User-Agent header.
|
||||
_userAgent: "Mozilla/5.0 (#{os.type()} #{os.arch()}) " +
|
||||
"node.js/#{process.versions.node} v8/#{process.versions.v8}"
|
||||
|
||||
# Sets the readyState property and fires the readystatechange event.
|
||||
#
|
||||
# @private
|
||||
# @param {Number} newReadyState the new value of readyState
|
||||
# @return {undefined} undefined
|
||||
_setReadyState: (newReadyState) ->
|
||||
@readyState = newReadyState
|
||||
event = new ProgressEvent 'readystatechange'
|
||||
@dispatchEvent event
|
||||
undefined
|
||||
|
||||
# XMLHttpRequest#send() implementation for the file: protocol.
|
||||
#
|
||||
# @private
|
||||
_sendFile: ->
|
||||
unless @_url.method is 'GET'
|
||||
throw new NetworkError 'The file protocol only supports GET'
|
||||
|
||||
throw new Error "Protocol file: not implemented"
|
||||
|
||||
# XMLHttpRequest#send() implementation for the http: and https: protocols.
|
||||
#
|
||||
# @private
|
||||
# This method sets the instance variables and calls _sendHxxpRequest(), which
|
||||
# is responsible for building a node.js request and firing it off. The code
|
||||
# in _sendHxxpRequest() is separated off so it can be reused when handling
|
||||
# redirects.
|
||||
#
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#infrastructure-for-the-send()-method
|
||||
_sendHttp: (data) ->
|
||||
if @_sync
|
||||
throw new Error "Synchronous XHR processing not implemented"
|
||||
|
||||
if data? and (@_method is 'GET' or @_method is 'HEAD')
|
||||
console.warn "Discarding entity body for #{@_method} requests"
|
||||
data = null
|
||||
else
|
||||
# Send Content-Length: 0
|
||||
data or= ''
|
||||
|
||||
# NOTE: this is called before finalizeHeaders so that the uploader can
|
||||
# figure out Content-Length and Content-Type.
|
||||
@upload._setData data
|
||||
@_finalizeHeaders()
|
||||
|
||||
@_sendHxxpRequest()
|
||||
undefined
|
||||
|
||||
# Sets up and fires off a HTTP/HTTPS request using the node.js API.
|
||||
#
|
||||
# @private
|
||||
# This method contains the bulk of the XMLHttpRequest#send() implementation,
|
||||
# and is also used to issue new HTTP requests when handling HTTP redirects.
|
||||
#
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#infrastructure-for-the-send()-method
|
||||
_sendHxxpRequest: ->
|
||||
if @_url.protocol is 'http:'
|
||||
hxxp = http
|
||||
agent = @nodejsHttpAgent
|
||||
else
|
||||
hxxp = https
|
||||
agent = @nodejsHttpsAgent
|
||||
|
||||
request = hxxp.request
|
||||
hostname: @_url.hostname, port: @_url.port, path: @_url.path,
|
||||
auth: @_url.auth, method: @_method, headers: @_headers, agent: agent
|
||||
@_request = request
|
||||
if @timeout
|
||||
request.setTimeout @timeout, => @_onHttpTimeout request
|
||||
request.on 'response', (response) => @_onHttpResponse request, response
|
||||
request.on 'error', (error) => @_onHttpRequestError request, error
|
||||
@upload._startUpload request
|
||||
if @_request is request # An http error might have already fired.
|
||||
@_dispatchProgress 'loadstart'
|
||||
|
||||
undefined
|
||||
|
||||
# Fills in the restricted HTTP headers with default values.
|
||||
#
|
||||
# This is called right before the HTTP request is sent off.
|
||||
#
|
||||
# @private
|
||||
# @return {undefined} undefined
|
||||
_finalizeHeaders: ->
|
||||
@_headers['Connection'] = 'keep-alive'
|
||||
@_headers['Host'] = @_url.host
|
||||
if @_anonymous
|
||||
@_headers['Referer'] = 'about:blank'
|
||||
@_headers['User-Agent'] = @_userAgent
|
||||
@upload._finalizeHeaders @_headers, @_loweredHeaders
|
||||
undefined
|
||||
|
||||
|
||||
# Called when the headers of an HTTP response have been received.
|
||||
#
|
||||
# @private
|
||||
# @param {http.ClientRequest} request the node.js ClientRequest instance that
|
||||
# produced this response
|
||||
# @param {http.ClientResponse} response the node.js ClientResponse instance
|
||||
# passed to
|
||||
_onHttpResponse: (request, response) ->
|
||||
return unless @_request is request
|
||||
|
||||
# Transparent redirection handling.
|
||||
switch response.statusCode
|
||||
when 301, 302, 303, 307, 308
|
||||
@_url = @_parseUrl response.headers['location']
|
||||
@_method = 'GET'
|
||||
if 'content-type' of @_loweredHeaders
|
||||
delete @_headers[@_loweredHeaders['content-type']]
|
||||
delete @_loweredHeaders['content-type']
|
||||
# XMLHttpRequestUpload#_finalizeHeaders() sets Content-Type directly.
|
||||
if 'Content-Type' of @_headers
|
||||
delete @_headers['Content-Type']
|
||||
# Restricted headers can't be set by the user, no need to check
|
||||
# loweredHeaders.
|
||||
delete @_headers['Content-Length']
|
||||
|
||||
@upload._reset()
|
||||
@_finalizeHeaders()
|
||||
@_sendHxxpRequest()
|
||||
return
|
||||
|
||||
@_response = response
|
||||
@_response.on 'data', (data) => @_onHttpResponseData response, data
|
||||
@_response.on 'end', => @_onHttpResponseEnd response
|
||||
@_response.on 'close', => @_onHttpResponseClose response
|
||||
|
||||
@responseURL = @_url.href.split('#')[0]
|
||||
@status = @_response.statusCode
|
||||
@statusText = http.STATUS_CODES[@status]
|
||||
@_parseResponseHeaders response
|
||||
|
||||
if lengthString = @_responseHeaders['content-length']
|
||||
@_totalBytes = parseInt(lengthString)
|
||||
@_lengthComputable = true
|
||||
else
|
||||
@_lengthComputable = false
|
||||
|
||||
@_setReadyState XMLHttpRequest.HEADERS_RECEIVED
|
||||
|
||||
# Called when some data has been received on a HTTP connection.
|
||||
#
|
||||
# @private
|
||||
# @param {http.ClientResponse} response the node.js ClientResponse instance
|
||||
# that fired this event
|
||||
# @param {String, Buffer} data the data that has been received
|
||||
_onHttpResponseData: (response, data) ->
|
||||
return unless @_response is response
|
||||
|
||||
@_responseParts.push data
|
||||
@_loadedBytes += data.length
|
||||
|
||||
if @readyState isnt XMLHttpRequest.LOADING
|
||||
@_setReadyState XMLHttpRequest.LOADING
|
||||
@_dispatchProgress 'progress'
|
||||
|
||||
# Called when the HTTP request finished processing.
|
||||
#
|
||||
# @private
|
||||
# @param {http.ClientResponse} response the node.js ClientResponse instance
|
||||
# that fired this event
|
||||
_onHttpResponseEnd: (response) ->
|
||||
return unless @_response is response
|
||||
|
||||
@_parseResponse()
|
||||
|
||||
@_request = null
|
||||
@_response = null
|
||||
@_setReadyState XMLHttpRequest.DONE
|
||||
@_dispatchProgress 'load'
|
||||
@_dispatchProgress 'loadend'
|
||||
|
||||
# Called when the underlying HTTP connection was closed prematurely.
|
||||
#
|
||||
# If this method is called, it will be called after or instead of
|
||||
# onHttpResponseEnd.
|
||||
#
|
||||
# @private
|
||||
# @param {http.ClientResponse} response the node.js ClientResponse instance
|
||||
# that fired this event
|
||||
_onHttpResponseClose: (response) ->
|
||||
return unless @_response is response
|
||||
|
||||
request = @_request
|
||||
@_setError()
|
||||
request.abort()
|
||||
@_setReadyState XMLHttpRequest.DONE
|
||||
@_dispatchProgress 'error'
|
||||
@_dispatchProgress 'loadend'
|
||||
|
||||
# Called when the timeout set on the HTTP socket expires.
|
||||
#
|
||||
# @private
|
||||
# @param {http.ClientRequest} request the node.js ClientRequest instance that
|
||||
# fired this event
|
||||
_onHttpTimeout: (request) ->
|
||||
return unless @_request is request
|
||||
|
||||
@_setError()
|
||||
request.abort()
|
||||
@_setReadyState XMLHttpRequest.DONE
|
||||
@_dispatchProgress 'timeout'
|
||||
@_dispatchProgress 'loadend'
|
||||
|
||||
# Called when something wrong happens on the HTTP socket
|
||||
#
|
||||
# @private
|
||||
# @param {http.ClientRequest} request the node.js ClientRequest instance that
|
||||
# fired this event
|
||||
# @param {Error} error emitted exception
|
||||
_onHttpRequestError: (request, error) ->
|
||||
return unless @_request is request
|
||||
|
||||
@_setError()
|
||||
request.abort()
|
||||
@_setReadyState XMLHttpRequest.DONE
|
||||
@_dispatchProgress 'error'
|
||||
@_dispatchProgress 'loadend'
|
||||
|
||||
# Fires an XHR progress event.
|
||||
#
|
||||
# @private
|
||||
# @param {String} eventType one of the XHR progress event types, such as
|
||||
# 'load' and 'progress'
|
||||
_dispatchProgress: (eventType) ->
|
||||
event = new ProgressEvent eventType
|
||||
event.lengthComputable = @_lengthComputable
|
||||
event.loaded = @_loadedBytes
|
||||
event.total = @_totalBytes
|
||||
@dispatchEvent event
|
||||
undefined
|
||||
|
||||
# Sets up the XHR to reflect the fact that an error has occurred.
|
||||
#
|
||||
# The possible errors are a network error, a timeout, or an abort.
|
||||
#
|
||||
# @private
|
||||
_setError: ->
|
||||
@_request = null
|
||||
@_response = null
|
||||
@_responseHeaders = null
|
||||
@_responseParts = null
|
||||
undefined
|
||||
|
||||
# Parses a request URL string.
|
||||
#
|
||||
# @private
|
||||
# This method is a thin wrapper around url.parse() that normalizes HTTP
|
||||
# user/password credentials. It is used to parse the URL string passed to
|
||||
# XMLHttpRequest#open() and the URLs in the Location headers of HTTP redirect
|
||||
# responses.
|
||||
#
|
||||
# @param {String} urlString the URL to be parsed
|
||||
# @return {Object} parsed URL
|
||||
_parseUrl: (urlString) ->
|
||||
if @nodejsBaseUrl is null
|
||||
absoluteUrlString = urlString
|
||||
else
|
||||
absoluteUrlString = url.resolve @nodejsBaseUrl, urlString
|
||||
|
||||
xhrUrl = url.parse absoluteUrlString, false, true
|
||||
xhrUrl.hash = null
|
||||
if xhrUrl.auth and (user? or password?)
|
||||
index = xhrUrl.auth.indexOf ':'
|
||||
if index is -1
|
||||
user = xhrUrl.auth unless user
|
||||
else
|
||||
user = xhrUrl.substring(0, index) unless user
|
||||
password = xhrUrl.substring(index + 1) unless password
|
||||
if user or password
|
||||
xhrUrl.auth = "#{user}:#{password}"
|
||||
xhrUrl
|
||||
|
||||
# Reads the headers from a node.js ClientResponse instance.
|
||||
#
|
||||
# @private
|
||||
# @param {http.ClientResponse} response the response whose headers will be
|
||||
# imported into this XMLHttpRequest's state
|
||||
# @return {undefined} undefined
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-getresponseheader()-method
|
||||
# @see http://www.w3.org/TR/XMLHttpRequest/#the-getallresponseheaders()-method
|
||||
_parseResponseHeaders: (response) ->
|
||||
@_responseHeaders = {}
|
||||
for name, value of response.headers
|
||||
loweredName = name.toLowerCase()
|
||||
continue if @_privateHeaders[loweredName]
|
||||
if @_mimeOverride isnt null and loweredName is 'content-type'
|
||||
value = @_mimeOverride
|
||||
@_responseHeaders[loweredName] = value
|
||||
|
||||
if @_mimeOverride isnt null and !('content-type' of @_responseHeaders)
|
||||
@_responseHeaders['content-type'] = @_mimeOverride
|
||||
undefined
|
||||
|
||||
# Sets the response and responseText properties when an XHR completes.
|
||||
#
|
||||
# @private
|
||||
# @return {undefined} undefined
|
||||
_parseResponse: ->
|
||||
if Buffer.concat
|
||||
buffer = Buffer.concat @_responseParts
|
||||
else
|
||||
# node 0.6
|
||||
buffer = @_concatBuffers @_responseParts
|
||||
@_responseParts = null
|
||||
|
||||
switch @responseType
|
||||
when 'text'
|
||||
@_parseTextResponse buffer
|
||||
when 'json'
|
||||
@responseText = null
|
||||
try
|
||||
@response = JSON.parse buffer.toString('utf-8')
|
||||
catch jsonError
|
||||
@response = null
|
||||
when 'buffer'
|
||||
@responseText = null
|
||||
@response = buffer
|
||||
when 'arraybuffer'
|
||||
@responseText = null
|
||||
arrayBuffer = new ArrayBuffer buffer.length
|
||||
view = new Uint8Array arrayBuffer
|
||||
view[i] = buffer[i] for i in [0...buffer.length]
|
||||
@response = arrayBuffer
|
||||
else
|
||||
# TODO(pwnall): content-base detection
|
||||
@_parseTextResponse buffer
|
||||
undefined
|
||||
|
||||
# Sets response and responseText for a 'text' response type.
|
||||
#
|
||||
# @private
|
||||
# @param {Buffer} buffer the node.js Buffer containing the binary response
|
||||
# @return {undefined} undefined
|
||||
_parseTextResponse: (buffer) ->
|
||||
try
|
||||
@responseText = buffer.toString @_parseResponseEncoding()
|
||||
catch e
|
||||
# Unknown encoding.
|
||||
@responseText = buffer.toString 'binary'
|
||||
|
||||
@response = @responseText
|
||||
undefined
|
||||
|
||||
# Figures out the string encoding of the XHR's response.
|
||||
#
|
||||
# This is called to determine the encoding when responseText is set.
|
||||
#
|
||||
# @private
|
||||
# @return {String} a string encoding, e.g. 'utf-8'
|
||||
_parseResponseEncoding: ->
|
||||
encoding = null
|
||||
if contentType = @_responseHeaders['content-type']
|
||||
if match = /\;\s*charset\=(.*)$/.exec contentType
|
||||
return match[1]
|
||||
'utf-8'
|
||||
|
||||
# Buffer.concat implementation for node 0.6.
|
||||
#
|
||||
# @private
|
||||
# @param {Array<Buffer>} buffers the buffers whose contents will be merged
|
||||
# @return {Buffer} same as Buffer.concat(buffers) in node 0.8 and above
|
||||
_concatBuffers: (buffers) ->
|
||||
if buffers.length is 0
|
||||
return new Buffer 0
|
||||
if buffers.length is 1
|
||||
return buffers[0]
|
||||
|
||||
length = 0
|
||||
length += buffer.length for buffer in buffers
|
||||
target = new Buffer length
|
||||
length = 0
|
||||
for buffer in buffers
|
||||
buffer.copy target, length
|
||||
length += buffer.length
|
||||
target
|
||||
|
||||
# XMLHttpRequest is the result of require('node-xhr2').
|
||||
module.exports = XMLHttpRequest
|
||||
|
||||
# Make node-xhr2 work as a drop-in replacement for libraries that promote the
|
||||
# following usage pattern:
|
||||
# var XMLHttpRequest = require('xhr-library-name').XMLHttpRequest
|
||||
XMLHttpRequest.XMLHttpRequest = XMLHttpRequest
|
||||
31
node_modules/xhr2/src/errors.coffee
generated
vendored
Normal file
31
node_modules/xhr2/src/errors.coffee
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
# This file defines the custom errors used in the XMLHttpRequest specification.
|
||||
|
||||
# Thrown if the XHR security policy is violated.
|
||||
class SecurityError extends Error
|
||||
# @private
|
||||
constructor: -> super
|
||||
|
||||
# Thrown if the XHR security policy is violated.
|
||||
XMLHttpRequest.SecurityError = SecurityError
|
||||
|
||||
|
||||
# Usually thrown if the XHR is in the wrong readyState for an operation.
|
||||
class InvalidStateError extends Error
|
||||
# @private
|
||||
constructor: -> super
|
||||
|
||||
# Usually thrown if the XHR is in the wrong readyState for an operation.
|
||||
class InvalidStateError extends Error
|
||||
XMLHttpRequest.InvalidStateError = InvalidStateError
|
||||
|
||||
# Thrown if there is a problem with the URL passed to the XHR.
|
||||
class NetworkError extends Error
|
||||
# @private
|
||||
constructor: -> super
|
||||
|
||||
# Thrown if parsing URLs errors out.
|
||||
XMLHttpRequest.SyntaxError = SyntaxError
|
||||
|
||||
class SyntaxError extends Error
|
||||
# @private:
|
||||
constructor: -> super
|
||||
39
node_modules/xhr2/src/progress_event.coffee
generated
vendored
Normal file
39
node_modules/xhr2/src/progress_event.coffee
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
# http://xhr.spec.whatwg.org/#interface-progressevent
|
||||
class ProgressEvent
|
||||
# Creates a new event.
|
||||
#
|
||||
# @param {String} type the event type, e.g. 'readystatechange'; must be
|
||||
# lowercased
|
||||
constructor: (@type) ->
|
||||
@target = null
|
||||
@currentTarget = null
|
||||
@lengthComputable = false
|
||||
@loaded = 0
|
||||
@total = 0
|
||||
# Getting the time from the OS is expensive, skip on that for now.
|
||||
# @timeStamp = Date.now()
|
||||
|
||||
# @property {Boolean} for compatibility with DOM events
|
||||
bubbles: false
|
||||
|
||||
# @property {Boolean} for fompatibility with DOM events
|
||||
cancelable: false
|
||||
|
||||
# @property {XMLHttpRequest} the request that caused this event
|
||||
target: null
|
||||
|
||||
# @property {Number} number of bytes that have already been downloaded or
|
||||
# uploaded
|
||||
loaded: null
|
||||
|
||||
# @property {Boolean} true if the Content-Length response header is available
|
||||
# and the value of the event's total property is meaningful
|
||||
lengthComputable: null
|
||||
|
||||
# @property {Number} number of bytes that will be downloaded or uploaded by
|
||||
# the request that fired the event
|
||||
total: null
|
||||
|
||||
|
||||
# The XHR spec exports the ProgressEvent constructor.
|
||||
XMLHttpRequest.ProgressEvent = ProgressEvent
|
||||
95
node_modules/xhr2/src/xml_http_request_upload.coffee
generated
vendored
Normal file
95
node_modules/xhr2/src/xml_http_request_upload.coffee
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
# @see http://xhr.spec.whatwg.org/#interface-xmlhttprequest
|
||||
class XMLHttpRequestUpload extends XMLHttpRequestEventTarget
|
||||
# @private
|
||||
# @param {XMLHttpRequest} the XMLHttpRequest that this upload object is
|
||||
# associated with
|
||||
constructor: (request) ->
|
||||
super()
|
||||
@_request = request
|
||||
@_reset()
|
||||
|
||||
# Sets up this Upload to handle a new request.
|
||||
#
|
||||
# @private
|
||||
# @return {undefined} undefined
|
||||
_reset: ->
|
||||
@_contentType = null
|
||||
@_body = null
|
||||
undefined
|
||||
|
||||
# Implements the upload-related part of the send() XHR specification.
|
||||
#
|
||||
# @private
|
||||
# @param {?String, ?Buffer, ?ArrayBufferView} data the argument passed to
|
||||
# XMLHttpRequest#send()
|
||||
# @return {undefined} undefined
|
||||
# @see step 4 of http://www.w3.org/TR/XMLHttpRequest/#the-send()-method
|
||||
_setData: (data) ->
|
||||
if typeof data is 'undefined' or data is null
|
||||
return
|
||||
|
||||
if typeof data is 'string'
|
||||
# DOMString
|
||||
if data.length isnt 0
|
||||
@_contentType = 'text/plain;charset=UTF-8'
|
||||
@_body = new Buffer data, 'utf8'
|
||||
else if Buffer.isBuffer data
|
||||
# node.js Buffer
|
||||
@_body = data
|
||||
else if data instanceof ArrayBuffer
|
||||
# ArrayBuffer arguments were supported in an old revision of the spec.
|
||||
body = new Buffer data.byteLength
|
||||
view = new Uint8Array data
|
||||
body[i] = view[i] for i in [0...data.byteLength]
|
||||
@_body = body
|
||||
else if data.buffer and data.buffer instanceof ArrayBuffer
|
||||
# ArrayBufferView
|
||||
body = new Buffer data.byteLength
|
||||
offset = data.byteOffset
|
||||
view = new Uint8Array data.buffer
|
||||
body[i] = view[i + offset] for i in [0...data.byteLength]
|
||||
@_body = body
|
||||
else
|
||||
# NOTE: diverging from the XHR specification of coercing everything else
|
||||
# to Strings via toString() because that behavior masks bugs and is
|
||||
# rarely useful
|
||||
throw new Error "Unsupported send() data #{data}"
|
||||
|
||||
undefined
|
||||
|
||||
# Updates the HTTP headers right before the request is sent.
|
||||
#
|
||||
# This is used to set data-dependent headers such as Content-Length and
|
||||
# Content-Type.
|
||||
#
|
||||
# @private
|
||||
# @param {Object<String, String>} headers the HTTP headers to be sent
|
||||
# @param {Object<String, String>} loweredHeaders maps lowercased HTTP header
|
||||
# names (e.g., 'content-type') to the actual names used in the headers
|
||||
# parameter (e.g., 'Content-Type')
|
||||
# @return {undefined} undefined
|
||||
_finalizeHeaders: (headers, loweredHeaders) ->
|
||||
if @_contentType
|
||||
unless 'content-type' of loweredHeaders
|
||||
headers['Content-Type'] = @_contentType
|
||||
|
||||
if @_body
|
||||
# Restricted headers can't be set by the user, no need to check
|
||||
# loweredHeaders.
|
||||
headers['Content-Length'] = @_body.length.toString()
|
||||
|
||||
undefined
|
||||
|
||||
# Starts sending the HTTP request data.
|
||||
#
|
||||
# @private
|
||||
# @param {http.ClientRequest} request the HTTP request
|
||||
# @return {undefined} undefined
|
||||
_startUpload: (request) ->
|
||||
request.write @_body if @_body
|
||||
request.end()
|
||||
|
||||
undefined
|
||||
|
||||
# Export the XMLHttpRequestUpload constructor.
|
||||
XMLHttpRequest.XMLHttpRequestUpload = XMLHttpRequestUpload
|
||||
1
node_modules/xhr2/test/fixtures/hello.json
generated
vendored
Normal file
1
node_modules/xhr2/test/fixtures/hello.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"hello": "world", "answer": 42}
|
||||
1
node_modules/xhr2/test/fixtures/hello.txt
generated
vendored
Normal file
1
node_modules/xhr2/test/fixtures/hello.txt
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
Hello world!
|
||||
BIN
node_modules/xhr2/test/fixtures/xhr2.png
generated
vendored
Normal file
BIN
node_modules/xhr2/test/fixtures/xhr2.png
generated
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 563 B |
30
node_modules/xhr2/test/html/browser_test.html
generated
vendored
Normal file
30
node_modules/xhr2/test/html/browser_test.html
generated
vendored
Normal 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
node_modules/xhr2/test/src/event_target_test.coffee
generated
vendored
Normal file
85
node_modules/xhr2/test/src/event_target_test.coffee
generated
vendored
Normal 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
node_modules/xhr2/test/src/events_test.coffee
generated
vendored
Normal file
204
node_modules/xhr2/test/src/events_test.coffee
generated
vendored
Normal 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()
|
||||
165
node_modules/xhr2/test/src/headers_test.coffee
generated
vendored
Normal file
165
node_modules/xhr2/test/src/headers_test.coffee
generated
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
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 '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 '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
node_modules/xhr2/test/src/helpers/browser_mocha_runner.coffee
generated
vendored
Normal file
10
node_modules/xhr2/test/src/helpers/browser_mocha_runner.coffee
generated
vendored
Normal 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
node_modules/xhr2/test/src/helpers/browser_mocha_setup.coffee
generated
vendored
Normal file
1
node_modules/xhr2/test/src/helpers/browser_mocha_setup.coffee
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
mocha.setup ui: 'bdd', slow: 150, timeout: 1000, bail: false
|
||||
39
node_modules/xhr2/test/src/helpers/setup.coffee
generated
vendored
Normal file
39
node_modules/xhr2/test/src/helpers/setup.coffee
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
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
|
||||
console.log xhrServer.http.testUrl()
|
||||
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
node_modules/xhr2/test/src/helpers/xhr_server.coffee
generated
vendored
Normal file
156
node_modules/xhr2/test/src/helpers/xhr_server.coffee
generated
vendored
Normal 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
node_modules/xhr2/test/src/nodejs_set_test.coffee
generated
vendored
Normal file
162
node_modules/xhr2/test/src/nodejs_set_test.coffee
generated
vendored
Normal 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
node_modules/xhr2/test/src/redirect_test.coffee
generated
vendored
Normal file
57
node_modules/xhr2/test/src/redirect_test.coffee
generated
vendored
Normal 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
node_modules/xhr2/test/src/response_type_test.coffee
generated
vendored
Normal file
88
node_modules/xhr2/test/src/response_type_test.coffee
generated
vendored
Normal 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
node_modules/xhr2/test/src/responseurl_test.coffee
generated
vendored
Normal file
18
node_modules/xhr2/test/src/responseurl_test.coffee
generated
vendored
Normal 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
node_modules/xhr2/test/src/send_test.coffee
generated
vendored
Normal file
89
node_modules/xhr2/test/src/send_test.coffee
generated
vendored
Normal 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 = new Buffer 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
node_modules/xhr2/test/src/status_test.coffee
generated
vendored
Normal file
47
node_modules/xhr2/test/src/status_test.coffee
generated
vendored
Normal 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
node_modules/xhr2/test/src/xhr_test.coffee
generated
vendored
Normal file
102
node_modules/xhr2/test/src/xhr_test.coffee
generated
vendored
Normal 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
|
||||
|
||||
Reference in New Issue
Block a user