UNPKG

18.8 kBJavaScriptView Raw
1"use strict";
2var __extends = (this && this.__extends) || (function () {
3 var extendStatics = Object.setPrototypeOf ||
4 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
5 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
6 return function (d, b) {
7 extendStatics(d, b);
8 function __() { this.constructor = d; }
9 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
10 };
11})();
12var __assign = (this && this.__assign) || Object.assign || function(t) {
13 for (var s, i = 1, n = arguments.length; i < n; i++) {
14 s = arguments[i];
15 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
16 t[p] = s[p];
17 }
18 return t;
19};
20Object.defineProperty(exports, "__esModule", { value: true });
21var http = require("http");
22var https = require("https");
23var os = require("os");
24var url = require("url");
25var progress_event_1 = require("./progress-event");
26var errors_1 = require("./errors");
27var xml_http_request_event_target_1 = require("./xml-http-request-event-target");
28var xml_http_request_upload_1 = require("./xml-http-request-upload");
29var Cookie = require("cookiejar");
30var XMLHttpRequest = /** @class */ (function (_super) {
31 __extends(XMLHttpRequest, _super);
32 function XMLHttpRequest(options) {
33 if (options === void 0) { options = {}; }
34 var _this = _super.call(this) || this;
35 _this.UNSENT = XMLHttpRequest.UNSENT;
36 _this.OPENED = XMLHttpRequest.OPENED;
37 _this.HEADERS_RECEIVED = XMLHttpRequest.HEADERS_RECEIVED;
38 _this.LOADING = XMLHttpRequest.LOADING;
39 _this.DONE = XMLHttpRequest.DONE;
40 _this.onreadystatechange = null;
41 _this.readyState = XMLHttpRequest.UNSENT;
42 _this.response = null;
43 _this.responseText = '';
44 _this.responseType = '';
45 _this.status = 0; // TODO: UNSENT?
46 _this.statusText = '';
47 _this.timeout = 0;
48 _this.upload = new xml_http_request_upload_1.XMLHttpRequestUpload();
49 _this.responseUrl = '';
50 _this.withCredentials = false;
51 _this._method = null;
52 _this._url = null;
53 _this._sync = false;
54 _this._headers = {};
55 _this._loweredHeaders = {};
56 _this._mimeOverride = null; // TODO: is type right?
57 _this._request = null;
58 _this._response = null;
59 _this._responseParts = null;
60 _this._responseHeaders = null;
61 _this._aborting = null; // TODO: type?
62 _this._error = null; // TODO: type?
63 _this._loadedBytes = 0;
64 _this._totalBytes = 0;
65 _this._lengthComputable = false;
66 _this._restrictedMethods = { CONNECT: true, TRACE: true, TRACK: true };
67 _this._restrictedHeaders = {
68 'accept-charset': true,
69 'accept-encoding': true,
70 'access-control-request-headers': true,
71 'access-control-request-method': true,
72 connection: true,
73 'content-length': true,
74 cookie: true,
75 cookie2: true,
76 date: true,
77 dnt: true,
78 expect: true,
79 host: true,
80 'keep-alive': true,
81 origin: true,
82 referer: true,
83 te: true,
84 trailer: true,
85 'transfer-encoding': true,
86 upgrade: true,
87 'user-agent': true,
88 via: true
89 };
90 _this._privateHeaders = { 'set-cookie': true, 'set-cookie2': true };
91 _this._userAgent = "Mozilla/5.0 (" + os.type() + " " + os.arch() + ") node.js/" + process.versions.node + " v8/" + process.versions.v8;
92 _this._anonymous = options.anon || false;
93 return _this;
94 }
95 XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
96 if (async === void 0) { async = true; }
97 method = method.toUpperCase();
98 if (this._restrictedMethods[method]) {
99 throw new XMLHttpRequest.SecurityError("HTTP method " + method + " is not allowed in XHR");
100 }
101 ;
102 var xhrUrl = this._parseUrl(url, user, password);
103 if (this.readyState === XMLHttpRequest.HEADERS_RECEIVED || this.readyState === XMLHttpRequest.LOADING) {
104 // TODO(pwnall): terminate abort(), terminate send()
105 }
106 this._method = method;
107 this._url = xhrUrl;
108 this._sync = !async;
109 this._headers = {};
110 this._loweredHeaders = {};
111 this._mimeOverride = null;
112 this._setReadyState(XMLHttpRequest.OPENED);
113 this._request = null;
114 this._response = null;
115 this.status = 0;
116 this.statusText = '';
117 this._responseParts = [];
118 this._responseHeaders = null;
119 this._loadedBytes = 0;
120 this._totalBytes = 0;
121 this._lengthComputable = false;
122 };
123 XMLHttpRequest.prototype.setRequestHeader = function (name, value) {
124 if (this.readyState !== XMLHttpRequest.OPENED) {
125 throw new XMLHttpRequest.InvalidStateError('XHR readyState must be OPENED');
126 }
127 var loweredName = name.toLowerCase();
128 if (this._restrictedHeaders[loweredName] || /^sec-/.test(loweredName) || /^proxy-/.test(loweredName)) {
129 console.warn("Refused to set unsafe header \"" + name + "\"");
130 return;
131 }
132 value = value.toString();
133 if (this._loweredHeaders[loweredName] != null) {
134 name = this._loweredHeaders[loweredName];
135 this._headers[name] = this._headers[name] + ", " + value;
136 }
137 else {
138 this._loweredHeaders[loweredName] = name;
139 this._headers[name] = value;
140 }
141 };
142 XMLHttpRequest.prototype.send = function (data) {
143 if (this.readyState !== XMLHttpRequest.OPENED) {
144 throw new XMLHttpRequest.InvalidStateError('XHR readyState must be OPENED');
145 }
146 if (this._request) {
147 throw new XMLHttpRequest.InvalidStateError('send() already called');
148 }
149 switch (this._url.protocol) {
150 case 'file:':
151 return this._sendFile(data);
152 case 'http:':
153 case 'https:':
154 return this._sendHttp(data);
155 default:
156 throw new XMLHttpRequest.NetworkError("Unsupported protocol " + this._url.protocol);
157 }
158 };
159 XMLHttpRequest.prototype.abort = function () {
160 if (this._request == null) {
161 return;
162 }
163 this._request.abort();
164 this._setError();
165 this._dispatchProgress('abort');
166 this._dispatchProgress('loadend');
167 };
168 XMLHttpRequest.prototype.getResponseHeader = function (name) {
169 if (this._responseHeaders == null || name == null) {
170 return null;
171 }
172 var loweredName = name.toLowerCase();
173 return this._responseHeaders.hasOwnProperty(loweredName)
174 ? this._responseHeaders[name.toLowerCase()]
175 : null;
176 };
177 XMLHttpRequest.prototype.getAllResponseHeaders = function () {
178 var _this = this;
179 if (this._responseHeaders == null) {
180 return '';
181 }
182 return Object.keys(this._responseHeaders).map(function (key) { return key + ": " + _this._responseHeaders[key]; }).join('\r\n');
183 };
184 XMLHttpRequest.prototype.overrideMimeType = function (mimeType) {
185 if (this.readyState === XMLHttpRequest.LOADING || this.readyState === XMLHttpRequest.DONE) {
186 throw new XMLHttpRequest.InvalidStateError('overrideMimeType() not allowed in LOADING or DONE');
187 }
188 this._mimeOverride = mimeType.toLowerCase();
189 };
190 XMLHttpRequest.prototype.nodejsSet = function (options) {
191 this.nodejsHttpAgent = options.httpAgent || this.nodejsHttpAgent;
192 this.nodejsHttpsAgent = options.httpsAgent || this.nodejsHttpsAgent;
193 if (options.hasOwnProperty('baseUrl')) {
194 if (options.baseUrl != null) {
195 var parsedUrl = url.parse(options.baseUrl, false, true);
196 if (!parsedUrl.protocol) {
197 throw new XMLHttpRequest.SyntaxError("baseUrl must be an absolute URL");
198 }
199 }
200 this.nodejsBaseUrl = options.baseUrl;
201 }
202 };
203 XMLHttpRequest.nodejsSet = function (options) {
204 XMLHttpRequest.prototype.nodejsSet(options);
205 };
206 XMLHttpRequest.prototype._setReadyState = function (readyState) {
207 this.readyState = readyState;
208 this.dispatchEvent(new progress_event_1.ProgressEvent('readystatechange'));
209 };
210 XMLHttpRequest.prototype._sendFile = function (data) {
211 // TODO
212 throw new Error('Protocol file: not implemented');
213 };
214 XMLHttpRequest.prototype._sendHttp = function (data) {
215 if (this._sync) {
216 throw new Error('Synchronous XHR processing not implemented');
217 }
218 if (data && (this._method === 'GET' || this._method === 'HEAD')) {
219 console.warn("Discarding entity body for " + this._method + " requests");
220 data = null;
221 }
222 else {
223 data = data || '';
224 }
225 this.upload._setData(data);
226 this._finalizeHeaders();
227 this._sendHxxpRequest();
228 };
229 XMLHttpRequest.prototype._sendHxxpRequest = function () {
230 var _this = this;
231 if (this.withCredentials) {
232 var cookie = XMLHttpRequest.cookieJar
233 .getCookies(Cookie.CookieAccessInfo(this._url.hostname, this._url.pathname, this._url.protocol === 'https:')).toValueString();
234 this._headers.cookie = this._headers.cookie2 = cookie;
235 }
236 var _a = this._url.protocol === 'http:' ? [http, this.nodejsHttpAgent] : [https, this.nodejsHttpsAgent], hxxp = _a[0], agent = _a[1];
237 var requestMethod = hxxp.request.bind(hxxp);
238 var request = requestMethod({
239 hostname: this._url.hostname,
240 port: +this._url.port,
241 path: this._url.path,
242 auth: this._url.auth,
243 method: this._method,
244 headers: this._headers,
245 agent: agent
246 });
247 this._request = request;
248 if (this.timeout) {
249 request.setTimeout(this.timeout, function () { return _this._onHttpTimeout(request); });
250 }
251 request.on('response', function (response) { return _this._onHttpResponse(request, response); });
252 request.on('error', function (error) { return _this._onHttpRequestError(request, error); });
253 this.upload._startUpload(request);
254 if (this._request === request) {
255 this._dispatchProgress('loadstart');
256 }
257 };
258 XMLHttpRequest.prototype._finalizeHeaders = function () {
259 this._headers = __assign({}, this._headers, { Connection: 'keep-alive', Host: this._url.host, 'User-Agent': this._userAgent }, this._anonymous ? { Referer: 'about:blank' } : {});
260 this.upload._finalizeHeaders(this._headers, this._loweredHeaders);
261 };
262 XMLHttpRequest.prototype._onHttpResponse = function (request, response) {
263 var _this = this;
264 if (this._request !== request) {
265 return;
266 }
267 if (this.withCredentials && (response.headers['set-cookie'] || response.headers['set-cookie2'])) {
268 XMLHttpRequest.cookieJar
269 .setCookies(response.headers['set-cookie'] || response.headers['set-cookie2']);
270 }
271 if ([301, 302, 303, 307, 308].indexOf(response.statusCode) >= 0) {
272 this._url = this._parseUrl(response.headers.location);
273 this._method = 'GET';
274 if (this._loweredHeaders['content-type']) {
275 delete this._headers[this._loweredHeaders['content-type']];
276 delete this._loweredHeaders['content-type'];
277 }
278 if (this._headers['Content-Type'] != null) {
279 delete this._headers['Content-Type'];
280 }
281 delete this._headers['Content-Length'];
282 this.upload._reset();
283 this._finalizeHeaders();
284 this._sendHxxpRequest();
285 return;
286 }
287 this._response = response;
288 this._response.on('data', function (data) { return _this._onHttpResponseData(response, data); });
289 this._response.on('end', function () { return _this._onHttpResponseEnd(response); });
290 this._response.on('close', function () { return _this._onHttpResponseClose(response); });
291 this.responseUrl = this._url.href.split('#')[0];
292 this.status = response.statusCode;
293 this.statusText = http.STATUS_CODES[this.status];
294 this._parseResponseHeaders(response);
295 var lengthString = this._responseHeaders['content-length'] || '';
296 this._totalBytes = +lengthString;
297 this._lengthComputable = !!lengthString;
298 this._setReadyState(XMLHttpRequest.HEADERS_RECEIVED);
299 };
300 XMLHttpRequest.prototype._onHttpResponseData = function (response, data) {
301 if (this._response !== response) {
302 return;
303 }
304 this._responseParts.push(new Buffer(data));
305 this._loadedBytes += data.length;
306 if (this.readyState !== XMLHttpRequest.LOADING) {
307 this._setReadyState(XMLHttpRequest.LOADING);
308 }
309 this._dispatchProgress('progress');
310 };
311 XMLHttpRequest.prototype._onHttpResponseEnd = function (response) {
312 if (this._response !== response) {
313 return;
314 }
315 this._parseResponse();
316 this._request = null;
317 this._response = null;
318 this._setReadyState(XMLHttpRequest.DONE);
319 this._dispatchProgress('load');
320 this._dispatchProgress('loadend');
321 };
322 XMLHttpRequest.prototype._onHttpResponseClose = function (response) {
323 if (this._response !== response) {
324 return;
325 }
326 var request = this._request;
327 this._setError();
328 request.abort();
329 this._setReadyState(XMLHttpRequest.DONE);
330 this._dispatchProgress('error');
331 this._dispatchProgress('loadend');
332 };
333 XMLHttpRequest.prototype._onHttpTimeout = function (request) {
334 if (this._request !== request) {
335 return;
336 }
337 this._setError();
338 request.abort();
339 this._setReadyState(XMLHttpRequest.DONE);
340 this._dispatchProgress('timeout');
341 this._dispatchProgress('loadend');
342 };
343 XMLHttpRequest.prototype._onHttpRequestError = function (request, error) {
344 if (this._request !== request) {
345 return;
346 }
347 this._setError();
348 request.abort();
349 this._setReadyState(XMLHttpRequest.DONE);
350 this._dispatchProgress('error');
351 this._dispatchProgress('loadend');
352 };
353 XMLHttpRequest.prototype._dispatchProgress = function (eventType) {
354 var event = new XMLHttpRequest.ProgressEvent(eventType);
355 event.lengthComputable = this._lengthComputable;
356 event.loaded = this._loadedBytes;
357 event.total = this._totalBytes;
358 this.dispatchEvent(event);
359 };
360 XMLHttpRequest.prototype._setError = function () {
361 this._request = null;
362 this._response = null;
363 this._responseHeaders = null;
364 this._responseParts = null;
365 };
366 XMLHttpRequest.prototype._parseUrl = function (urlString, user, password) {
367 var absoluteUrl = this.nodejsBaseUrl == null ? urlString : url.resolve(this.nodejsBaseUrl, urlString);
368 var xhrUrl = url.parse(absoluteUrl, false, true);
369 xhrUrl.hash = null;
370 var _a = (xhrUrl.auth || '').split(':'), xhrUser = _a[0], xhrPassword = _a[1];
371 if (xhrUser || xhrPassword || user || password) {
372 xhrUrl.auth = (user || xhrUser || '') + ":" + (password || xhrPassword || '');
373 }
374 return xhrUrl;
375 };
376 XMLHttpRequest.prototype._parseResponseHeaders = function (response) {
377 this._responseHeaders = {};
378 for (var name_1 in response.headers) {
379 var loweredName = name_1.toLowerCase();
380 if (this._privateHeaders[loweredName]) {
381 continue;
382 }
383 this._responseHeaders[loweredName] = response.headers[name_1];
384 }
385 if (this._mimeOverride != null) {
386 this._responseHeaders['content-type'] = this._mimeOverride;
387 }
388 };
389 XMLHttpRequest.prototype._parseResponse = function () {
390 var buffer = Buffer.concat(this._responseParts);
391 this._responseParts = null;
392 switch (this.responseType) {
393 case 'json':
394 this.responseText = null;
395 try {
396 this.response = JSON.parse(buffer.toString('utf-8'));
397 }
398 catch (_a) {
399 this.response = null;
400 }
401 return;
402 case 'buffer':
403 this.responseText = null;
404 this.response = buffer;
405 return;
406 case 'arraybuffer':
407 this.responseText = null;
408 var arrayBuffer = new ArrayBuffer(buffer.length);
409 var view = new Uint8Array(arrayBuffer);
410 for (var i = 0; i < buffer.length; i++) {
411 view[i] = buffer[i];
412 }
413 this.response = arrayBuffer;
414 return;
415 case 'text':
416 default:
417 try {
418 this.responseText = buffer.toString(this._parseResponseEncoding());
419 }
420 catch (_b) {
421 this.responseText = buffer.toString('binary');
422 }
423 this.response = this.responseText;
424 }
425 };
426 XMLHttpRequest.prototype._parseResponseEncoding = function () {
427 return /;\s*charset=(.*)$/.exec(this._responseHeaders['content-type'] || '')[1] || 'utf-8';
428 };
429 XMLHttpRequest.ProgressEvent = progress_event_1.ProgressEvent;
430 XMLHttpRequest.InvalidStateError = errors_1.InvalidStateError;
431 XMLHttpRequest.NetworkError = errors_1.NetworkError;
432 XMLHttpRequest.SecurityError = errors_1.SecurityError;
433 XMLHttpRequest.SyntaxError = errors_1.SyntaxError;
434 XMLHttpRequest.XMLHttpRequestUpload = xml_http_request_upload_1.XMLHttpRequestUpload;
435 XMLHttpRequest.UNSENT = 0;
436 XMLHttpRequest.OPENED = 1;
437 XMLHttpRequest.HEADERS_RECEIVED = 2;
438 XMLHttpRequest.LOADING = 3;
439 XMLHttpRequest.DONE = 4;
440 XMLHttpRequest.cookieJar = Cookie.CookieJar();
441 return XMLHttpRequest;
442}(xml_http_request_event_target_1.XMLHttpRequestEventTarget));
443exports.XMLHttpRequest = XMLHttpRequest;
444XMLHttpRequest.prototype.nodejsHttpAgent = http.globalAgent;
445XMLHttpRequest.prototype.nodejsHttpsAgent = https.globalAgent;
446XMLHttpRequest.prototype.nodejsBaseUrl = null;
447//# sourceMappingURL=xml-http-request.js.map
\No newline at end of file