You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
4.8 KiB
JavaScript
190 lines
4.8 KiB
JavaScript
7 years ago
|
var Stream = require('stream');
|
||
|
var Response = require('./response');
|
||
|
var Base64 = require('Base64');
|
||
|
var inherits = require('inherits');
|
||
|
|
||
|
var Request = module.exports = function (xhr, params) {
|
||
|
var self = this;
|
||
|
self.writable = true;
|
||
|
self.xhr = xhr;
|
||
|
self.body = [];
|
||
|
|
||
|
self.uri = (params.scheme || 'http') + '://'
|
||
|
+ params.host
|
||
|
+ (params.port ? ':' + params.port : '')
|
||
|
+ (params.path || '/')
|
||
|
;
|
||
|
|
||
|
if (typeof params.withCredentials === 'undefined') {
|
||
|
params.withCredentials = true;
|
||
|
}
|
||
|
|
||
|
try { xhr.withCredentials = params.withCredentials }
|
||
|
catch (e) {}
|
||
|
|
||
|
xhr.open(
|
||
|
params.method || 'GET',
|
||
|
self.uri,
|
||
|
true
|
||
|
);
|
||
|
|
||
|
self._headers = {};
|
||
|
|
||
|
if (params.headers) {
|
||
|
var keys = objectKeys(params.headers);
|
||
|
for (var i = 0; i < keys.length; i++) {
|
||
|
var key = keys[i];
|
||
|
if (!self.isSafeRequestHeader(key)) continue;
|
||
|
var value = params.headers[key];
|
||
|
self.setHeader(key, value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (params.auth) {
|
||
|
//basic auth
|
||
|
this.setHeader('Authorization', 'Basic ' + Base64.btoa(params.auth));
|
||
|
}
|
||
|
|
||
|
var res = new Response;
|
||
|
res.on('close', function () {
|
||
|
self.emit('close');
|
||
|
});
|
||
|
|
||
|
res.on('ready', function () {
|
||
|
self.emit('response', res);
|
||
|
});
|
||
|
|
||
|
xhr.onreadystatechange = function () {
|
||
|
// Fix for IE9 bug
|
||
|
// SCRIPT575: Could not complete the operation due to error c00c023f
|
||
|
// It happens when a request is aborted, calling the success callback anyway with readyState === 4
|
||
|
if (xhr.__aborted) return;
|
||
|
res.handle(xhr);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
inherits(Request, Stream);
|
||
|
|
||
|
Request.prototype.setHeader = function (key, value) {
|
||
|
this._headers[key.toLowerCase()] = value
|
||
|
};
|
||
|
|
||
|
Request.prototype.getHeader = function (key) {
|
||
|
return this._headers[key.toLowerCase()]
|
||
|
};
|
||
|
|
||
|
Request.prototype.removeHeader = function (key) {
|
||
|
delete this._headers[key.toLowerCase()]
|
||
|
};
|
||
|
|
||
|
Request.prototype.write = function (s) {
|
||
|
this.body.push(s);
|
||
|
};
|
||
|
|
||
|
Request.prototype.destroy = function (s) {
|
||
|
this.xhr.__aborted = true;
|
||
|
this.xhr.abort();
|
||
|
this.emit('close');
|
||
|
};
|
||
|
|
||
|
Request.prototype.end = function (s) {
|
||
|
if (s !== undefined) this.body.push(s);
|
||
|
|
||
|
var keys = objectKeys(this._headers);
|
||
|
for (var i = 0; i < keys.length; i++) {
|
||
|
var key = keys[i];
|
||
|
var value = this._headers[key];
|
||
|
if (isArray(value)) {
|
||
|
for (var j = 0; j < value.length; j++) {
|
||
|
this.xhr.setRequestHeader(key, value[j]);
|
||
|
}
|
||
|
}
|
||
|
else this.xhr.setRequestHeader(key, value)
|
||
|
}
|
||
|
|
||
|
if (this.body.length === 0) {
|
||
|
this.xhr.send('');
|
||
|
}
|
||
|
else if (typeof this.body[0] === 'string') {
|
||
|
this.xhr.send(this.body.join(''));
|
||
|
}
|
||
|
else if (isArray(this.body[0])) {
|
||
|
var body = [];
|
||
|
for (var i = 0; i < this.body.length; i++) {
|
||
|
body.push.apply(body, this.body[i]);
|
||
|
}
|
||
|
this.xhr.send(body);
|
||
|
}
|
||
|
else if (/Array/.test(Object.prototype.toString.call(this.body[0]))) {
|
||
|
var len = 0;
|
||
|
for (var i = 0; i < this.body.length; i++) {
|
||
|
len += this.body[i].length;
|
||
|
}
|
||
|
var body = new(this.body[0].constructor)(len);
|
||
|
var k = 0;
|
||
|
|
||
|
for (var i = 0; i < this.body.length; i++) {
|
||
|
var b = this.body[i];
|
||
|
for (var j = 0; j < b.length; j++) {
|
||
|
body[k++] = b[j];
|
||
|
}
|
||
|
}
|
||
|
this.xhr.send(body);
|
||
|
}
|
||
|
else {
|
||
|
var body = '';
|
||
|
for (var i = 0; i < this.body.length; i++) {
|
||
|
body += this.body[i].toString();
|
||
|
}
|
||
|
this.xhr.send(body);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// Taken from http://dxr.mozilla.org/mozilla/mozilla-central/content/base/src/nsXMLHttpRequest.cpp.html
|
||
|
Request.unsafeHeaders = [
|
||
|
"accept-charset",
|
||
|
"accept-encoding",
|
||
|
"access-control-request-headers",
|
||
|
"access-control-request-method",
|
||
|
"connection",
|
||
|
"content-length",
|
||
|
"cookie",
|
||
|
"cookie2",
|
||
|
"content-transfer-encoding",
|
||
|
"date",
|
||
|
"expect",
|
||
|
"host",
|
||
|
"keep-alive",
|
||
|
"origin",
|
||
|
"referer",
|
||
|
"te",
|
||
|
"trailer",
|
||
|
"transfer-encoding",
|
||
|
"upgrade",
|
||
|
"user-agent",
|
||
|
"via"
|
||
|
];
|
||
|
|
||
|
Request.prototype.isSafeRequestHeader = function (headerName) {
|
||
|
if (!headerName) return false;
|
||
|
return indexOf(Request.unsafeHeaders, headerName.toLowerCase()) === -1;
|
||
|
};
|
||
|
|
||
|
var objectKeys = Object.keys || function (obj) {
|
||
|
var keys = [];
|
||
|
for (var key in obj) keys.push(key);
|
||
|
return keys;
|
||
|
};
|
||
|
|
||
|
var isArray = Array.isArray || function (xs) {
|
||
|
return Object.prototype.toString.call(xs) === '[object Array]';
|
||
|
};
|
||
|
|
||
|
var indexOf = function (xs, x) {
|
||
|
if (xs.indexOf) return xs.indexOf(x);
|
||
|
for (var i = 0; i < xs.length; i++) {
|
||
|
if (xs[i] === x) return i;
|
||
|
}
|
||
|
return -1;
|
||
|
};
|