UNPKG

7.29 kBJavaScriptView Raw
1"use strict";
2var __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}));
13var __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});
18var __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};
25var __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};
28Object.defineProperty(exports, "__esModule", { value: true });
29exports.Agent = void 0;
30const net = __importStar(require("net"));
31const http = __importStar(require("http"));
32const https_1 = require("https");
33__exportStar(require("./helpers"), exports);
34const INTERNAL = Symbol('AgentBaseInternalState');
35class 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 = typeof options.secureEndpoint === 'boolean'
115 ? options.secureEndpoint
116 : this.isSecureEndpoint(options);
117 if (secureEndpoint) {
118 // @ts-expect-error `getName()` isn't defined in `@types/node`
119 return https_1.Agent.prototype.getName.call(this, options);
120 }
121 // @ts-expect-error `getName()` isn't defined in `@types/node`
122 return super.getName(options);
123 }
124 createSocket(req, options, cb) {
125 const connectOpts = {
126 ...options,
127 secureEndpoint: this.isSecureEndpoint(options),
128 };
129 const name = this.getName(connectOpts);
130 const fakeSocket = this.incrementSockets(name);
131 Promise.resolve()
132 .then(() => this.connect(req, connectOpts))
133 .then((socket) => {
134 this.decrementSockets(name, fakeSocket);
135 if (socket instanceof http.Agent) {
136 // @ts-expect-error `addRequest()` isn't defined in `@types/node`
137 return socket.addRequest(req, connectOpts);
138 }
139 this[INTERNAL].currentSocket = socket;
140 // @ts-expect-error `createSocket()` isn't defined in `@types/node`
141 super.createSocket(req, options, cb);
142 }, (err) => {
143 this.decrementSockets(name, fakeSocket);
144 cb(err);
145 });
146 }
147 createConnection() {
148 const socket = this[INTERNAL].currentSocket;
149 this[INTERNAL].currentSocket = undefined;
150 if (!socket) {
151 throw new Error('No socket was returned in the `connect()` function');
152 }
153 return socket;
154 }
155 get defaultPort() {
156 return (this[INTERNAL].defaultPort ??
157 (this.protocol === 'https:' ? 443 : 80));
158 }
159 set defaultPort(v) {
160 if (this[INTERNAL]) {
161 this[INTERNAL].defaultPort = v;
162 }
163 }
164 get protocol() {
165 return (this[INTERNAL].protocol ??
166 (this.isSecureEndpoint() ? 'https:' : 'http:'));
167 }
168 set protocol(v) {
169 if (this[INTERNAL]) {
170 this[INTERNAL].protocol = v;
171 }
172 }
173}
174exports.Agent = Agent;
175//# sourceMappingURL=index.js.map
\No newline at end of file