forked from tornado-packages/archive-monorepo
448 lines
19 KiB
JavaScript
448 lines
19 KiB
JavaScript
|
"use strict";
|
||
|
var __extends = (this && this.__extends) || (function () {
|
||
|
var extendStatics = Object.setPrototypeOf ||
|
||
|
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
||
|
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
||
|
return function (d, b) {
|
||
|
extendStatics(d, b);
|
||
|
function __() { this.constructor = d; }
|
||
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||
|
};
|
||
|
})();
|
||
|
var __assign = (this && this.__assign) || Object.assign || function(t) {
|
||
|
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||
|
s = arguments[i];
|
||
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
||
|
t[p] = s[p];
|
||
|
}
|
||
|
return t;
|
||
|
};
|
||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||
|
var http = require("http");
|
||
|
var https = require("https");
|
||
|
var url = require("url");
|
||
|
var progress_event_1 = require("./progress-event");
|
||
|
var errors_1 = require("./errors");
|
||
|
var xml_http_request_event_target_1 = require("./xml-http-request-event-target");
|
||
|
var xml_http_request_upload_1 = require("./xml-http-request-upload");
|
||
|
var Cookie = require("cookiejar");
|
||
|
var XMLHttpRequest = /** @class */ (function (_super) {
|
||
|
__extends(XMLHttpRequest, _super);
|
||
|
function XMLHttpRequest(options) {
|
||
|
if (options === void 0) { options = {}; }
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this.UNSENT = XMLHttpRequest.UNSENT;
|
||
|
_this.OPENED = XMLHttpRequest.OPENED;
|
||
|
_this.HEADERS_RECEIVED = XMLHttpRequest.HEADERS_RECEIVED;
|
||
|
_this.LOADING = XMLHttpRequest.LOADING;
|
||
|
_this.DONE = XMLHttpRequest.DONE;
|
||
|
_this.onreadystatechange = null;
|
||
|
_this.readyState = XMLHttpRequest.UNSENT;
|
||
|
_this.response = null;
|
||
|
_this.responseText = '';
|
||
|
_this.responseType = '';
|
||
|
_this.status = 0; // TODO: UNSENT?
|
||
|
_this.statusText = '';
|
||
|
_this.timeout = 0;
|
||
|
_this.upload = new xml_http_request_upload_1.XMLHttpRequestUpload();
|
||
|
_this.responseUrl = '';
|
||
|
_this.withCredentials = false;
|
||
|
_this._method = null;
|
||
|
_this._url = null;
|
||
|
_this._sync = false;
|
||
|
_this._headers = {};
|
||
|
_this._loweredHeaders = {};
|
||
|
_this._mimeOverride = null; // TODO: is type right?
|
||
|
_this._request = null;
|
||
|
_this._response = null;
|
||
|
_this._responseParts = null;
|
||
|
_this._responseHeaders = null;
|
||
|
_this._aborting = null; // TODO: type?
|
||
|
_this._error = null; // TODO: type?
|
||
|
_this._loadedBytes = 0;
|
||
|
_this._totalBytes = 0;
|
||
|
_this._lengthComputable = false;
|
||
|
_this._restrictedMethods = { CONNECT: true, TRACE: true, TRACK: true };
|
||
|
_this._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
|
||
|
};
|
||
|
_this._privateHeaders = { 'set-cookie': true, 'set-cookie2': true };
|
||
|
//Redacted private information (${os.type()} ${os.arch()}) node.js/${process.versions.node} v8/${process.versions.v8} from the original version @ github
|
||
|
//Pretend to be tor-browser https://blog.torproject.org/browser-fingerprinting-introduction-and-challenges-ahead/
|
||
|
_this._userAgent = "Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0";
|
||
|
_this._anonymous = options.anon || false;
|
||
|
return _this;
|
||
|
}
|
||
|
XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
|
||
|
if (async === void 0) { async = true; }
|
||
|
method = method.toUpperCase();
|
||
|
if (this._restrictedMethods[method]) {
|
||
|
throw new XMLHttpRequest.SecurityError("HTTP method " + method + " is not allowed in XHR");
|
||
|
}
|
||
|
;
|
||
|
var xhrUrl = this._parseUrl(url, user, password);
|
||
|
if (this.readyState === XMLHttpRequest.HEADERS_RECEIVED || this.readyState === XMLHttpRequest.LOADING) {
|
||
|
// TODO(pwnall): terminate abort(), terminate send()
|
||
|
}
|
||
|
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;
|
||
|
};
|
||
|
XMLHttpRequest.prototype.setRequestHeader = function (name, value) {
|
||
|
if (this.readyState !== XMLHttpRequest.OPENED) {
|
||
|
throw new XMLHttpRequest.InvalidStateError('XHR readyState must be OPENED');
|
||
|
}
|
||
|
var loweredName = name.toLowerCase();
|
||
|
if (this._restrictedHeaders[loweredName] || /^sec-/.test(loweredName) || /^proxy-/.test(loweredName)) {
|
||
|
console.warn("Refused to set unsafe header \"" + name + "\"");
|
||
|
return;
|
||
|
}
|
||
|
value = value.toString();
|
||
|
if (this._loweredHeaders[loweredName] != null) {
|
||
|
name = this._loweredHeaders[loweredName];
|
||
|
this._headers[name] = this._headers[name] + ", " + value;
|
||
|
}
|
||
|
else {
|
||
|
this._loweredHeaders[loweredName] = name;
|
||
|
this._headers[name] = value;
|
||
|
}
|
||
|
};
|
||
|
XMLHttpRequest.prototype.send = function (data) {
|
||
|
if (this.readyState !== XMLHttpRequest.OPENED) {
|
||
|
throw new XMLHttpRequest.InvalidStateError('XHR readyState must be OPENED');
|
||
|
}
|
||
|
if (this._request) {
|
||
|
throw new XMLHttpRequest.InvalidStateError('send() already called');
|
||
|
}
|
||
|
switch (this._url.protocol) {
|
||
|
case 'file:':
|
||
|
return this._sendFile(data);
|
||
|
case 'http:':
|
||
|
case 'https:':
|
||
|
return this._sendHttp(data);
|
||
|
default:
|
||
|
throw new XMLHttpRequest.NetworkError("Unsupported protocol " + this._url.protocol);
|
||
|
}
|
||
|
};
|
||
|
XMLHttpRequest.prototype.abort = function () {
|
||
|
if (this._request == null) {
|
||
|
return;
|
||
|
}
|
||
|
this._request.abort();
|
||
|
this._setError();
|
||
|
this._dispatchProgress('abort');
|
||
|
this._dispatchProgress('loadend');
|
||
|
};
|
||
|
XMLHttpRequest.prototype.getResponseHeader = function (name) {
|
||
|
if (this._responseHeaders == null || name == null) {
|
||
|
return null;
|
||
|
}
|
||
|
var loweredName = name.toLowerCase();
|
||
|
return this._responseHeaders.hasOwnProperty(loweredName)
|
||
|
? this._responseHeaders[name.toLowerCase()]
|
||
|
: null;
|
||
|
};
|
||
|
XMLHttpRequest.prototype.getAllResponseHeaders = function () {
|
||
|
var _this = this;
|
||
|
if (this._responseHeaders == null) {
|
||
|
return '';
|
||
|
}
|
||
|
return Object.keys(this._responseHeaders).map(function (key) { return key + ": " + _this._responseHeaders[key]; }).join('\r\n');
|
||
|
};
|
||
|
XMLHttpRequest.prototype.overrideMimeType = function (mimeType) {
|
||
|
if (this.readyState === XMLHttpRequest.LOADING || this.readyState === XMLHttpRequest.DONE) {
|
||
|
throw new XMLHttpRequest.InvalidStateError('overrideMimeType() not allowed in LOADING or DONE');
|
||
|
}
|
||
|
this._mimeOverride = mimeType.toLowerCase();
|
||
|
};
|
||
|
XMLHttpRequest.prototype.nodejsSet = function (options) {
|
||
|
this.nodejsHttpAgent = options.httpAgent || this.nodejsHttpAgent;
|
||
|
this.nodejsHttpsAgent = options.httpsAgent || this.nodejsHttpsAgent;
|
||
|
if (options.hasOwnProperty('baseUrl')) {
|
||
|
if (options.baseUrl != null) {
|
||
|
var parsedUrl = url.parse(options.baseUrl, false, true);
|
||
|
if (!parsedUrl.protocol) {
|
||
|
throw new XMLHttpRequest.SyntaxError("baseUrl must be an absolute URL");
|
||
|
}
|
||
|
}
|
||
|
this.nodejsBaseUrl = options.baseUrl;
|
||
|
}
|
||
|
};
|
||
|
XMLHttpRequest.nodejsSet = function (options) {
|
||
|
XMLHttpRequest.prototype.nodejsSet(options);
|
||
|
};
|
||
|
XMLHttpRequest.prototype._setReadyState = function (readyState) {
|
||
|
this.readyState = readyState;
|
||
|
this.dispatchEvent(new progress_event_1.ProgressEvent('readystatechange'));
|
||
|
};
|
||
|
XMLHttpRequest.prototype._sendFile = function (data) {
|
||
|
// TODO
|
||
|
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 && (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();
|
||
|
};
|
||
|
XMLHttpRequest.prototype._sendHxxpRequest = function () {
|
||
|
var _this = this;
|
||
|
if (this.withCredentials) {
|
||
|
var cookie = XMLHttpRequest.cookieJar
|
||
|
.getCookies(Cookie.CookieAccessInfo(this._url.hostname, this._url.pathname, this._url.protocol === 'https:')).toValueString();
|
||
|
this._headers.cookie = this._headers.cookie2 = cookie;
|
||
|
}
|
||
|
var _a = this._url.protocol === 'http:' ? [http, this.nodejsHttpAgent] : [https, this.nodejsHttpsAgent], hxxp = _a[0], agent = _a[1];
|
||
|
var requestMethod = hxxp.request.bind(hxxp);
|
||
|
var request = requestMethod({
|
||
|
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 () { return _this._onHttpTimeout(request); });
|
||
|
}
|
||
|
request.on('response', function (response) { return _this._onHttpResponse(request, response); });
|
||
|
request.on('error', function (error) { return _this._onHttpRequestError(request, error); });
|
||
|
this.upload._startUpload(request);
|
||
|
if (this._request === request) {
|
||
|
this._dispatchProgress('loadstart');
|
||
|
}
|
||
|
};
|
||
|
XMLHttpRequest.prototype._finalizeHeaders = function () {
|
||
|
this._headers = __assign({}, this._headers, { Connection: 'keep-alive', Host: this._url.host, 'User-Agent': this._userAgent }, this._anonymous ? { Referer: 'about:blank' } : {});
|
||
|
this.upload._finalizeHeaders(this._headers, this._loweredHeaders);
|
||
|
};
|
||
|
XMLHttpRequest.prototype._onHttpResponse = function (request, response) {
|
||
|
var _this = this;
|
||
|
if (this._request !== request) {
|
||
|
return;
|
||
|
}
|
||
|
if (this.withCredentials && (response.headers['set-cookie'] || response.headers['set-cookie2'])) {
|
||
|
XMLHttpRequest.cookieJar
|
||
|
.setCookies(response.headers['set-cookie'] || response.headers['set-cookie2']);
|
||
|
}
|
||
|
if ([301, 302, 303, 307, 308].indexOf(response.statusCode) >= 0) {
|
||
|
this._url = this._parseUrl(response.headers.location);
|
||
|
this._method = 'GET';
|
||
|
if (this._loweredHeaders['content-type']) {
|
||
|
delete this._headers[this._loweredHeaders['content-type']];
|
||
|
delete this._loweredHeaders['content-type'];
|
||
|
}
|
||
|
if (this._headers['Content-Type'] != null) {
|
||
|
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 (data) { return _this._onHttpResponseData(response, data); });
|
||
|
this._response.on('end', function () { return _this._onHttpResponseEnd(response); });
|
||
|
this._response.on('close', function () { return _this._onHttpResponseClose(response); });
|
||
|
this.responseUrl = this._url.href.split('#')[0];
|
||
|
this.status = response.statusCode;
|
||
|
this.statusText = http.STATUS_CODES[this.status];
|
||
|
this._parseResponseHeaders(response);
|
||
|
var lengthString = this._responseHeaders['content-length'] || '';
|
||
|
this._totalBytes = +lengthString;
|
||
|
this._lengthComputable = !!lengthString;
|
||
|
this._setReadyState(XMLHttpRequest.HEADERS_RECEIVED);
|
||
|
};
|
||
|
XMLHttpRequest.prototype._onHttpResponseData = function (response, data) {
|
||
|
if (this._response !== response) {
|
||
|
return;
|
||
|
}
|
||
|
this._responseParts.push(Buffer.from(data));
|
||
|
this._loadedBytes += data.length;
|
||
|
if (this.readyState !== XMLHttpRequest.LOADING) {
|
||
|
this._setReadyState(XMLHttpRequest.LOADING);
|
||
|
}
|
||
|
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');
|
||
|
this._dispatchProgress('loadend');
|
||
|
};
|
||
|
XMLHttpRequest.prototype._onHttpResponseClose = function (response) {
|
||
|
if (this._response !== response) {
|
||
|
return;
|
||
|
}
|
||
|
var request = this._request;
|
||
|
this._setError();
|
||
|
request.abort();
|
||
|
this._setReadyState(XMLHttpRequest.DONE);
|
||
|
this._dispatchProgress('error');
|
||
|
this._dispatchProgress('loadend');
|
||
|
};
|
||
|
XMLHttpRequest.prototype._onHttpTimeout = function (request) {
|
||
|
if (this._request !== request) {
|
||
|
return;
|
||
|
}
|
||
|
this._setError();
|
||
|
request.abort();
|
||
|
this._setReadyState(XMLHttpRequest.DONE);
|
||
|
this._dispatchProgress('timeout');
|
||
|
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');
|
||
|
this._dispatchProgress('loadend');
|
||
|
};
|
||
|
XMLHttpRequest.prototype._dispatchProgress = function (eventType) {
|
||
|
var event = new XMLHttpRequest.ProgressEvent(eventType);
|
||
|
event.lengthComputable = this._lengthComputable;
|
||
|
event.loaded = this._loadedBytes;
|
||
|
event.total = this._totalBytes;
|
||
|
this.dispatchEvent(event);
|
||
|
};
|
||
|
XMLHttpRequest.prototype._setError = function () {
|
||
|
this._request = null;
|
||
|
this._response = null;
|
||
|
this._responseHeaders = null;
|
||
|
this._responseParts = null;
|
||
|
};
|
||
|
XMLHttpRequest.prototype._parseUrl = function (urlString, user, password) {
|
||
|
var absoluteUrl = this.nodejsBaseUrl == null ? urlString : url.resolve(this.nodejsBaseUrl, urlString);
|
||
|
var xhrUrl = url.parse(absoluteUrl, false, true);
|
||
|
xhrUrl.hash = null;
|
||
|
var _a = (xhrUrl.auth || '').split(':'), xhrUser = _a[0], xhrPassword = _a[1];
|
||
|
if (xhrUser || xhrPassword || user || password) {
|
||
|
xhrUrl.auth = (user || xhrUser || '') + ":" + (password || xhrPassword || '');
|
||
|
}
|
||
|
return xhrUrl;
|
||
|
};
|
||
|
XMLHttpRequest.prototype._parseResponseHeaders = function (response) {
|
||
|
this._responseHeaders = {};
|
||
|
for (var name_1 in response.headers) {
|
||
|
var loweredName = name_1.toLowerCase();
|
||
|
if (this._privateHeaders[loweredName]) {
|
||
|
continue;
|
||
|
}
|
||
|
this._responseHeaders[loweredName] = response.headers[name_1];
|
||
|
}
|
||
|
if (this._mimeOverride != null) {
|
||
|
this._responseHeaders['content-type'] = this._mimeOverride;
|
||
|
}
|
||
|
};
|
||
|
XMLHttpRequest.prototype._parseResponse = function () {
|
||
|
var buffer = Buffer.concat(this._responseParts);
|
||
|
this._responseParts = null;
|
||
|
switch (this.responseType) {
|
||
|
case 'json':
|
||
|
this.responseText = null;
|
||
|
try {
|
||
|
this.response = JSON.parse(buffer.toString('utf-8'));
|
||
|
}
|
||
|
catch (_a) {
|
||
|
this.response = null;
|
||
|
}
|
||
|
return;
|
||
|
case 'buffer':
|
||
|
this.responseText = null;
|
||
|
this.response = buffer;
|
||
|
return;
|
||
|
case 'arraybuffer':
|
||
|
this.responseText = null;
|
||
|
var arrayBuffer = new ArrayBuffer(buffer.length);
|
||
|
var view = new Uint8Array(arrayBuffer);
|
||
|
for (var i = 0; i < buffer.length; i++) {
|
||
|
view[i] = buffer[i];
|
||
|
}
|
||
|
this.response = arrayBuffer;
|
||
|
return;
|
||
|
case 'text':
|
||
|
default:
|
||
|
try {
|
||
|
this.responseText = buffer.toString(this._parseResponseEncoding());
|
||
|
}
|
||
|
catch (_b) {
|
||
|
this.responseText = buffer.toString('binary');
|
||
|
}
|
||
|
this.response = this.responseText;
|
||
|
}
|
||
|
};
|
||
|
XMLHttpRequest.prototype._parseResponseEncoding = function () {
|
||
|
return /;\s*charset=(.*)$/.exec(this._responseHeaders['content-type'] || '')[1] || 'utf-8';
|
||
|
};
|
||
|
XMLHttpRequest.ProgressEvent = progress_event_1.ProgressEvent;
|
||
|
XMLHttpRequest.InvalidStateError = errors_1.InvalidStateError;
|
||
|
XMLHttpRequest.NetworkError = errors_1.NetworkError;
|
||
|
XMLHttpRequest.SecurityError = errors_1.SecurityError;
|
||
|
XMLHttpRequest.SyntaxError = errors_1.SyntaxError;
|
||
|
XMLHttpRequest.XMLHttpRequestUpload = xml_http_request_upload_1.XMLHttpRequestUpload;
|
||
|
XMLHttpRequest.UNSENT = 0;
|
||
|
XMLHttpRequest.OPENED = 1;
|
||
|
XMLHttpRequest.HEADERS_RECEIVED = 2;
|
||
|
XMLHttpRequest.LOADING = 3;
|
||
|
XMLHttpRequest.DONE = 4;
|
||
|
XMLHttpRequest.cookieJar = Cookie.CookieJar();
|
||
|
return XMLHttpRequest;
|
||
|
}(xml_http_request_event_target_1.XMLHttpRequestEventTarget));
|
||
|
exports.XMLHttpRequest = XMLHttpRequest;
|
||
|
XMLHttpRequest.prototype.nodejsHttpAgent = http.globalAgent;
|
||
|
XMLHttpRequest.prototype.nodejsHttpsAgent = https.globalAgent;
|
||
|
XMLHttpRequest.prototype.nodejsBaseUrl = null;
|
||
|
//# sourceMappingURL=xml-http-request.js.map
|