Initial commit

This commit is contained in:
2024-11-22 23:29:59 -07:00
commit f6379c144b
3594 changed files with 309643 additions and 0 deletions

31
node_modules/xhr2/.npmignore generated vendored Normal file
View 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
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1 @@
module.exports = XMLHttpRequest;

875
node_modules/xhr2/lib/xhr2.js generated vendored Normal file
View 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
View 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"
}
}

View 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
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1 @@
{"hello": "world", "answer": 42}

1
node_modules/xhr2/test/fixtures/hello.txt generated vendored Normal file
View File

@@ -0,0 +1 @@
Hello world!

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
View 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
View 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
View 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
View 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

View 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

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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