@e-mc/request 0.8.1 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +2 -0
  2. package/index.js +96 -39
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  ### @e-mc/request
2
2
 
3
+ https://e-mc.readthedocs.io
4
+
3
5
  ### LICENSE
4
6
 
5
7
  BSD 3-Clause
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
2
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const path = require("path");
5
5
  const fs = require("fs");
@@ -33,6 +33,7 @@ const kHostInfo = Symbol('hostInfo');
33
33
  const kConnectDns = Symbol('connectDns');
34
34
  const kPendingDns = Symbol('pendingDns');
35
35
  const kConnectHttp = Symbol('connectHttp');
36
+ const kStatusOn = Symbol('statusOn');
36
37
  const kHeadersOn = Symbol('headersOn');
37
38
  const PLATFORM_WIN32 = process.platform === 'win32';
38
39
  const SUPPORT_NODEJS20 = module_1.default.supported(20);
@@ -104,17 +105,18 @@ function getBaseHeaders(uri, headers) {
104
105
  return result[0][1];
105
106
  }
106
107
  }
107
- function setDnsCache(hostname, value) {
108
- if (DNS.EXPIRES > 0 && !DNS.CACHE[hostname]) {
108
+ function setDnsCache(hostname, value, expires) {
109
+ expires ?? (expires = DNS.EXPIRES);
110
+ if (expires > 0 && !DNS.CACHE[hostname]) {
109
111
  DNS.CACHE[hostname] = value;
110
- if (DNS.EXPIRES !== Infinity) {
112
+ if (expires !== Infinity) {
111
113
  const timeout = setTimeout(() => {
112
114
  const index = DNS.TIMEOUT.findIndex(item => item === timeout);
113
115
  if (index !== -1) {
114
116
  DNS.TIMEOUT.splice(index, 1);
115
117
  }
116
118
  DNS.CACHE[hostname] = undefined;
117
- }, DNS.EXPIRES);
119
+ }, expires);
118
120
  DNS.TIMEOUT.push(timeout);
119
121
  }
120
122
  }
@@ -259,6 +261,15 @@ function validateCerts(certs) {
259
261
  }
260
262
  return [text, file];
261
263
  }
264
+ function abortHeaders(href, request, options) {
265
+ const reason = (0, types_1.errorValue)("Aborted by client" /* ERR_MESSAGE.ABORTED_CLIENT */, href);
266
+ const outAbort = options.outAbort;
267
+ if (outAbort) {
268
+ outAbort.abort(reason);
269
+ this[kDownloading].delete(outAbort);
270
+ }
271
+ request.destroy(reason);
272
+ }
262
273
  class Request extends module_1.default {
263
274
  static async purgeMemory(percent = 1, limit = 0, parent) {
264
275
  if (percent >= 1) {
@@ -522,6 +533,8 @@ class Request extends module_1.default {
522
533
  return 'Locked';
523
534
  case 424 /* HTTP_STATUS.FAILED_DEPENDENCY */:
524
535
  return 'Failed Dependency';
536
+ case 425 /* HTTP_STATUS.TOO_EARLY */:
537
+ return 'Too Early';
525
538
  case 426 /* HTTP_STATUS.UPGRADE_REQUIRED */:
526
539
  return 'Upgrade Required';
527
540
  case 428 /* HTTP_STATUS.PRECONDITION_REQUIRED */:
@@ -554,6 +567,8 @@ class Request extends module_1.default {
554
567
  return 'Insufficient Storage';
555
568
  case 508 /* HTTP_STATUS.LOOP_DETECTED */:
556
569
  return 'Loop Detected';
570
+ case 509 /* HTTP_STATUS.BANDWIDTH_LIMIT_EXCEEDED */:
571
+ return 'Bandwidth Limit Exceeded';
557
572
  case 510 /* HTTP_STATUS.NOT_EXTENDED */:
558
573
  return 'Not Extended';
559
574
  case 511 /* HTTP_STATUS.NETWORK_AUTHENTICATION_REQUIRED */:
@@ -634,10 +649,11 @@ class Request extends module_1.default {
634
649
  this[_e] = Object.create(null);
635
650
  this[_f] = Object.create(null);
636
651
  this[_g] = [{}, {}];
637
- this[_h] = new Set();
638
- this[_j] = {};
639
- this[_k] = [Object.create(null)];
640
- this[_l] = new Map();
652
+ this[_h] = null;
653
+ this[_j] = null;
654
+ this[_k] = new Set();
655
+ this[_l] = {};
656
+ this[_m] = [Object.create(null)];
641
657
  if ((0, types_1.isPlainObject)(data)) {
642
658
  const { headers, read_timeout, agent, use, connect, certs } = data;
643
659
  const timeout = (0, util_1.fromSeconds)(data.timeout);
@@ -826,8 +842,11 @@ class Request extends module_1.default {
826
842
  }
827
843
  return this;
828
844
  }
829
- addDns(hostname, address, family) {
845
+ addDns(hostname, address, family, timeout) {
830
846
  switch (family) {
847
+ case 4:
848
+ case 6:
849
+ break;
831
850
  case 'IPv4':
832
851
  family = 4;
833
852
  break;
@@ -835,6 +854,9 @@ class Request extends module_1.default {
835
854
  family = 6;
836
855
  break;
837
856
  default:
857
+ if (typeof family === 'number' && timeout === undefined) {
858
+ timeout = family;
859
+ }
838
860
  if (net.isIPv4(address)) {
839
861
  family = 4;
840
862
  }
@@ -846,17 +868,17 @@ class Request extends module_1.default {
846
868
  }
847
869
  break;
848
870
  }
849
- setDnsCache(hostname, this[kConnectDns][hostname] = [{ address, family }]);
871
+ setDnsCache(hostname, this[kConnectDns][hostname] = [{ address, family }], timeout);
850
872
  }
851
873
  lookupDns(hostname) {
852
- var _m;
874
+ var _o;
853
875
  const resolved = this[kConnectDns][hostname] || DNS.CACHE[hostname];
854
876
  if (resolved) {
855
877
  return (...args) => {
856
878
  return SUPPORT_NODEJS20 ? args[2](null, resolved) : args[2](null, resolved[0].address, resolved[0].family);
857
879
  };
858
880
  }
859
- const pending = (_m = this[kPendingDns])[hostname] || (_m[hostname] = []);
881
+ const pending = (_o = this[kPendingDns])[hostname] || (_o[hostname] = []);
860
882
  return (value, options, callback) => {
861
883
  if (pending.push(callback) === 1) {
862
884
  const configure = (family) => family === 0 ? options : { family, hints: family === 6 ? dns.V4MAPPED : 0 };
@@ -928,13 +950,29 @@ class Request extends module_1.default {
928
950
  }
929
951
  }
930
952
  }
953
+ statusOn(code, patternUrl = '*', callback) {
954
+ if (typeof patternUrl === 'function') {
955
+ callback = patternUrl;
956
+ patternUrl = '*';
957
+ }
958
+ if ((0, types_1.isString)(patternUrl) && typeof callback === 'function') {
959
+ const on = this[kStatusOn] || (this[kStatusOn] = new Map());
960
+ for (const item of !Array.isArray(code) ? [code] : code) {
961
+ let status = on.get(item);
962
+ if (!status) {
963
+ on.set(item, status = []);
964
+ }
965
+ status.push([patternUrl, callback]);
966
+ }
967
+ }
968
+ }
931
969
  headersOn(name, patternUrl = '*', callback) {
932
970
  if (typeof patternUrl === 'function') {
933
971
  callback = patternUrl;
934
972
  patternUrl = '*';
935
973
  }
936
974
  if ((0, types_1.isString)(patternUrl) && typeof callback === 'function') {
937
- const on = this[kHeadersOn];
975
+ const on = this[kHeadersOn] || (this[kHeadersOn] = new Map());
938
976
  for (const item of !Array.isArray(name) ? [name] : name) {
939
977
  let headers = on.get(item);
940
978
  if (!headers) {
@@ -1311,21 +1349,21 @@ class Request extends module_1.default {
1311
1349
  return this.get(uri, options);
1312
1350
  }
1313
1351
  opts(url, options) {
1314
- var _m, _o, _p, _q;
1352
+ var _o, _p, _q, _r;
1315
1353
  if (typeof url === 'string') {
1316
1354
  url = new URL(url);
1317
1355
  }
1318
1356
  let host;
1319
1357
  if (this.host) {
1320
- host = (_m = HTTP.HOST)[_o = url.origin] || (_m[_o] = new host_1.default(url, HTTP.VERSION));
1358
+ host = (_o = HTTP.HOST)[_p = url.origin] || (_o[_p] = new host_1.default(url, HTTP.VERSION));
1321
1359
  }
1322
1360
  else {
1323
- host = (_p = this[kHostInfo])[_q = url.origin] || (_p[_q] = new host_1.default(url, this.httpVersion || 1));
1361
+ host = (_q = this[kHostInfo])[_r = url.origin] || (_q[_r] = new host_1.default(url, this.httpVersion || 1));
1324
1362
  }
1325
1363
  return { ...options, host, url };
1326
1364
  }
1327
1365
  open(uri, options) {
1328
- var _m, _o;
1366
+ var _o, _p;
1329
1367
  let { host, url, httpVersion, method = 'GET', encoding, format, headers, postData, keepAlive, agentTimeout, socketPath, timeout = this._config.connectTimeout, outStream } = options;
1330
1368
  const getting = method === 'GET';
1331
1369
  const posting = method === 'POST';
@@ -1417,7 +1455,7 @@ class Request extends module_1.default {
1417
1455
  const version = this.httpVersion;
1418
1456
  let request, ca, cert, key, minVersion, baseHeaders = this.headersOf(uri);
1419
1457
  if (getting && this.acceptEncoding && !localhost && !baseHeaders?.['accept-encoding']) {
1420
- (_m = (headers || (headers = {})))['accept-encoding'] || (_m['accept-encoding'] = 'gzip, deflate, br' + (LIB_ZSTD ? ', zstd' : ''));
1458
+ (_o = (headers || (headers = {})))['accept-encoding'] || (_o['accept-encoding'] = 'gzip, deflate, br' + (LIB_ZSTD ? ', zstd' : ''));
1421
1459
  }
1422
1460
  if (secure) {
1423
1461
  const certs = this[kCerts]?.[0][origin] || (this.host ? TLS.TEXT[origin] : null);
@@ -1426,7 +1464,7 @@ class Request extends module_1.default {
1426
1464
  }
1427
1465
  }
1428
1466
  if (!proxy && httpVersion !== 1 && ((httpVersion || host.version) === 2 && version !== 1 || secure && version === 2 && host.failed(2, true) === 0)) {
1429
- request = ((_o = this[kSession][0])[origin] || (_o[origin] = http2.connect(origin, { lookup: this.lookupDns(hostname), ca, cert, key, minVersion, settings: localhost ? { initialWindowSize: 4294967295 /* CONSTANTS.INITIAL_WINDOW_SIZE */, maxFrameSize: 16777215 /* CONSTANTS.MAX_FRAME_SIZE */, enablePush: false } : { enablePush: false } }))).request({ ...baseHeaders, ...host_1.default.getBasicAuth(url), ...headers, ':path': pathname, ':method': method });
1467
+ request = ((_p = this[kSession][0])[origin] || (_p[origin] = http2.connect(origin, { lookup: this.lookupDns(hostname), ca, cert, key, minVersion, settings: localhost ? { initialWindowSize: 4294967295 /* CONSTANTS.INITIAL_WINDOW_SIZE */, maxFrameSize: 16777215 /* CONSTANTS.MAX_FRAME_SIZE */, enablePush: false } : { enablePush: false } }))).request({ ...baseHeaders, ...host_1.default.getBasicAuth(url), ...headers, ':path': pathname, ':method': method });
1430
1468
  if (getting) {
1431
1469
  const listenerMap = {};
1432
1470
  const onEvent = request.on.bind(request);
@@ -1435,7 +1473,7 @@ class Request extends module_1.default {
1435
1473
  request.on('response', response => {
1436
1474
  connected = true;
1437
1475
  const statusCode = response[':status'];
1438
- if (statusCode >= 200 /* HTTP_STATUS.OK */ && statusCode < 300 /* HTTP_STATUS.MULTIPLE_CHOICES */) {
1476
+ if (this.matchStatus(statusCode, url, response, request, options) && statusCode >= 200 /* HTTP_STATUS.OK */ && statusCode < 300 /* HTTP_STATUS.MULTIPLE_CHOICES */) {
1439
1477
  if (emitter = checkEncoding(request, statusCode, response['content-encoding'])) {
1440
1478
  for (const event in listenerMap) {
1441
1479
  listenerMap[event].forEach(listener => {
@@ -1463,7 +1501,7 @@ class Request extends module_1.default {
1463
1501
  this.matchHeaders(url, response, request, options);
1464
1502
  });
1465
1503
  request.on = function (event, listener) {
1466
- var _m;
1504
+ var _o;
1467
1505
  switch (event) {
1468
1506
  case 'data':
1469
1507
  case 'error':
@@ -1473,7 +1511,7 @@ class Request extends module_1.default {
1473
1511
  break;
1474
1512
  }
1475
1513
  if (!connected) {
1476
- (listenerMap[_m = event + '-on'] || (listenerMap[_m] = [])).push(listener);
1514
+ (listenerMap[_o = event + '-on'] || (listenerMap[_o] = [])).push(listener);
1477
1515
  }
1478
1516
  default:
1479
1517
  onEvent(event, listener);
@@ -1482,7 +1520,7 @@ class Request extends module_1.default {
1482
1520
  return this;
1483
1521
  };
1484
1522
  request.once = function (event, listener) {
1485
- var _m;
1523
+ var _o;
1486
1524
  switch (event) {
1487
1525
  case 'data':
1488
1526
  case 'error':
@@ -1492,7 +1530,7 @@ class Request extends module_1.default {
1492
1530
  break;
1493
1531
  }
1494
1532
  if (!connected) {
1495
- (listenerMap[_m = event + '-once'] || (listenerMap[_m] = [])).push(listener);
1533
+ (listenerMap[_o = event + '-once'] || (listenerMap[_o] = [])).push(listener);
1496
1534
  }
1497
1535
  default:
1498
1536
  onceEvent(event, listener);
@@ -1556,7 +1594,7 @@ class Request extends module_1.default {
1556
1594
  }, response => {
1557
1595
  const statusCode = response.statusCode;
1558
1596
  const incoming = response.headers;
1559
- if ((getting || posting) && statusCode >= 200 /* HTTP_STATUS.OK */ && statusCode < 300 /* HTTP_STATUS.MULTIPLE_CHOICES */) {
1597
+ if (this.matchStatus(statusCode, url, incoming, request, options) && (getting || posting) && statusCode >= 200 /* HTTP_STATUS.OK */ && statusCode < 300 /* HTTP_STATUS.MULTIPLE_CHOICES */) {
1560
1598
  let source = checkEncoding(response, statusCode, incoming['content-encoding']);
1561
1599
  if (source) {
1562
1600
  source.once('finish', () => request.emit('end'));
@@ -2217,9 +2255,33 @@ class Request extends module_1.default {
2217
2255
  });
2218
2256
  this[kDownloading].clear();
2219
2257
  }
2258
+ matchStatus(code, url, headers, request, options) {
2259
+ const status = this[kStatusOn]?.get(code);
2260
+ if (status) {
2261
+ const href = url.href;
2262
+ const called = new Set();
2263
+ for (const [pattern, callback] of status) {
2264
+ if (pattern === '*' || pm.isMatch(href, pattern)) {
2265
+ called.add(callback);
2266
+ }
2267
+ }
2268
+ for (const callback of called) {
2269
+ try {
2270
+ if (callback(code, headers, url) === true) {
2271
+ abortHeaders.call(this, href, request, options);
2272
+ return false;
2273
+ }
2274
+ }
2275
+ catch (err) {
2276
+ this.writeFail(["Unable to process headers" /* ERR_HTTP.HEADERS */, url.origin], err, { type: 1024 /* LOG_TYPE.HTTP */, abortable: this.abortable, fatal: false });
2277
+ }
2278
+ }
2279
+ }
2280
+ return true;
2281
+ }
2220
2282
  matchHeaders(url, headers, request, options) {
2221
2283
  const on = this[kHeadersOn];
2222
- if (on.size) {
2284
+ if (on?.size) {
2223
2285
  const href = url.href;
2224
2286
  const called = new Map();
2225
2287
  for (const [name, item] of on) {
@@ -2238,21 +2300,16 @@ class Request extends module_1.default {
2238
2300
  for (const [callback, data] of called) {
2239
2301
  try {
2240
2302
  if (callback(data, url) === true) {
2241
- const reason = (0, types_1.errorValue)("Aborted by client" /* ERR_MESSAGE.ABORTED_CLIENT */, href);
2242
- const outAbort = options.outAbort;
2243
- if (outAbort) {
2244
- outAbort.abort(reason);
2245
- this[kDownloading].delete(outAbort);
2246
- }
2247
- request.destroy(reason);
2248
- return;
2303
+ abortHeaders.call(this, href, request, options);
2304
+ return false;
2249
2305
  }
2250
2306
  }
2251
2307
  catch (err) {
2252
- this.writeFail(['Unable to process headers', url.origin], err, { type: 1024 /* LOG_TYPE.HTTP */, abortable: this.abortable, fatal: false });
2308
+ this.writeFail(["Unable to process headers" /* ERR_HTTP.HEADERS */, url.origin], err, { type: 1024 /* LOG_TYPE.HTTP */, abortable: this.abortable, fatal: false });
2253
2309
  }
2254
2310
  }
2255
2311
  }
2312
+ return true;
2256
2313
  }
2257
2314
  set agentTimeout(value) {
2258
2315
  if (value > 0) {
@@ -2291,11 +2348,11 @@ class Request extends module_1.default {
2291
2348
  return this[kIpVersion];
2292
2349
  }
2293
2350
  get settings() {
2294
- var _m;
2295
- return (_m = this.module).settings || (_m.settings = {});
2351
+ var _o;
2352
+ return (_o = this.module).settings || (_o.settings = {});
2296
2353
  }
2297
2354
  }
2298
- _a = kSingleton, _b = kHttpVersion, _c = kHeaders, _d = kCerts, _e = kConnectDns, _f = kPendingDns, _g = kConnectHttp, _h = kDownloading, _j = kHostInfo, _k = kSession, _l = kHeadersOn;
2355
+ _a = kSingleton, _b = kHttpVersion, _c = kHeaders, _d = kCerts, _e = kConnectDns, _f = kPendingDns, _g = kConnectHttp, _h = kStatusOn, _j = kHeadersOn, _k = kDownloading, _l = kHostInfo, _m = kSession;
2299
2356
  exports.default = Request;
2300
2357
 
2301
2358
  if (exports.default) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e-mc/request",
3
- "version": "0.8.1",
3
+ "version": "0.8.2",
4
4
  "description": "Request constructor for E-mc.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -20,8 +20,8 @@
20
20
  "license": "BSD 3-Clause",
21
21
  "homepage": "https://github.com/anpham6/e-mc#readme",
22
22
  "dependencies": {
23
- "@e-mc/module": "0.8.1",
24
- "@e-mc/types": "0.8.1",
23
+ "@e-mc/module": "0.8.2",
24
+ "@e-mc/types": "0.8.2",
25
25
  "combined-stream": "^1.0.8",
26
26
  "js-yaml": "^4.1.0",
27
27
  "picomatch": "^3.0.1",