index.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. "use strict";
  2. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
  3. if (k2 === undefined) k2 = k;
  4. var desc = Object.getOwnPropertyDescriptor(m, k);
  5. if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
  6. desc = { enumerable: true, get: function() { return m[k]; } };
  7. }
  8. Object.defineProperty(o, k2, desc);
  9. }) : (function(o, m, k, k2) {
  10. if (k2 === undefined) k2 = k;
  11. o[k2] = m[k];
  12. }));
  13. var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
  14. Object.defineProperty(o, "default", { enumerable: true, value: v });
  15. }) : function(o, v) {
  16. o["default"] = v;
  17. });
  18. var __importStar = (this && this.__importStar) || function (mod) {
  19. if (mod && mod.__esModule) return mod;
  20. var result = {};
  21. if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
  22. __setModuleDefault(result, mod);
  23. return result;
  24. };
  25. var __exportStar = (this && this.__exportStar) || function(m, exports) {
  26. for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
  27. };
  28. Object.defineProperty(exports, "__esModule", { value: true });
  29. exports.Agent = void 0;
  30. const net = __importStar(require("net"));
  31. const http = __importStar(require("http"));
  32. const https_1 = require("https");
  33. __exportStar(require("./helpers"), exports);
  34. const INTERNAL = Symbol('AgentBaseInternalState');
  35. class Agent extends http.Agent {
  36. constructor(opts) {
  37. super(opts);
  38. this[INTERNAL] = {};
  39. }
  40. /**
  41. * Determine whether this is an `http` or `https` request.
  42. */
  43. isSecureEndpoint(options) {
  44. if (options) {
  45. // First check the `secureEndpoint` property explicitly, since this
  46. // means that a parent `Agent` is "passing through" to this instance.
  47. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  48. if (typeof options.secureEndpoint === 'boolean') {
  49. return options.secureEndpoint;
  50. }
  51. // If no explicit `secure` endpoint, check if `protocol` property is
  52. // set. This will usually be the case since using a full string URL
  53. // or `URL` instance should be the most common usage.
  54. if (typeof options.protocol === 'string') {
  55. return options.protocol === 'https:';
  56. }
  57. }
  58. // Finally, if no `protocol` property was set, then fall back to
  59. // checking the stack trace of the current call stack, and try to
  60. // detect the "https" module.
  61. const { stack } = new Error();
  62. if (typeof stack !== 'string')
  63. return false;
  64. return stack
  65. .split('\n')
  66. .some((l) => l.indexOf('(https.js:') !== -1 ||
  67. l.indexOf('node:https:') !== -1);
  68. }
  69. // In order to support async signatures in `connect()` and Node's native
  70. // connection pooling in `http.Agent`, the array of sockets for each origin
  71. // has to be updated synchronously. This is so the length of the array is
  72. // accurate when `addRequest()` is next called. We achieve this by creating a
  73. // fake socket and adding it to `sockets[origin]` and incrementing
  74. // `totalSocketCount`.
  75. incrementSockets(name) {
  76. // If `maxSockets` and `maxTotalSockets` are both Infinity then there is no
  77. // need to create a fake socket because Node.js native connection pooling
  78. // will never be invoked.
  79. if (this.maxSockets === Infinity && this.maxTotalSockets === Infinity) {
  80. return null;
  81. }
  82. // All instances of `sockets` are expected TypeScript errors. The
  83. // alternative is to add it as a private property of this class but that
  84. // will break TypeScript subclassing.
  85. if (!this.sockets[name]) {
  86. // @ts-expect-error `sockets` is readonly in `@types/node`
  87. this.sockets[name] = [];
  88. }
  89. const fakeSocket = new net.Socket({ writable: false });
  90. this.sockets[name].push(fakeSocket);
  91. // @ts-expect-error `totalSocketCount` isn't defined in `@types/node`
  92. this.totalSocketCount++;
  93. return fakeSocket;
  94. }
  95. decrementSockets(name, socket) {
  96. if (!this.sockets[name] || socket === null) {
  97. return;
  98. }
  99. const sockets = this.sockets[name];
  100. const index = sockets.indexOf(socket);
  101. if (index !== -1) {
  102. sockets.splice(index, 1);
  103. // @ts-expect-error `totalSocketCount` isn't defined in `@types/node`
  104. this.totalSocketCount--;
  105. if (sockets.length === 0) {
  106. // @ts-expect-error `sockets` is readonly in `@types/node`
  107. delete this.sockets[name];
  108. }
  109. }
  110. }
  111. // In order to properly update the socket pool, we need to call `getName()` on
  112. // the core `https.Agent` if it is a secureEndpoint.
  113. getName(options) {
  114. const secureEndpoint = this.isSecureEndpoint(options);
  115. if (secureEndpoint) {
  116. // @ts-expect-error `getName()` isn't defined in `@types/node`
  117. return https_1.Agent.prototype.getName.call(this, options);
  118. }
  119. // @ts-expect-error `getName()` isn't defined in `@types/node`
  120. return super.getName(options);
  121. }
  122. createSocket(req, options, cb) {
  123. const connectOpts = {
  124. ...options,
  125. secureEndpoint: this.isSecureEndpoint(options),
  126. };
  127. const name = this.getName(connectOpts);
  128. const fakeSocket = this.incrementSockets(name);
  129. Promise.resolve()
  130. .then(() => this.connect(req, connectOpts))
  131. .then((socket) => {
  132. this.decrementSockets(name, fakeSocket);
  133. if (socket instanceof http.Agent) {
  134. try {
  135. // @ts-expect-error `addRequest()` isn't defined in `@types/node`
  136. return socket.addRequest(req, connectOpts);
  137. }
  138. catch (err) {
  139. return cb(err);
  140. }
  141. }
  142. this[INTERNAL].currentSocket = socket;
  143. // @ts-expect-error `createSocket()` isn't defined in `@types/node`
  144. super.createSocket(req, options, cb);
  145. }, (err) => {
  146. this.decrementSockets(name, fakeSocket);
  147. cb(err);
  148. });
  149. }
  150. createConnection() {
  151. const socket = this[INTERNAL].currentSocket;
  152. this[INTERNAL].currentSocket = undefined;
  153. if (!socket) {
  154. throw new Error('No socket was returned in the `connect()` function');
  155. }
  156. return socket;
  157. }
  158. get defaultPort() {
  159. return (this[INTERNAL].defaultPort ??
  160. (this.protocol === 'https:' ? 443 : 80));
  161. }
  162. set defaultPort(v) {
  163. if (this[INTERNAL]) {
  164. this[INTERNAL].defaultPort = v;
  165. }
  166. }
  167. get protocol() {
  168. return (this[INTERNAL].protocol ??
  169. (this.isSecureEndpoint() ? 'https:' : 'http:'));
  170. }
  171. set protocol(v) {
  172. if (this[INTERNAL]) {
  173. this[INTERNAL].protocol = v;
  174. }
  175. }
  176. }
  177. exports.Agent = Agent;
  178. //# sourceMappingURL=index.js.map