@mswjs/interceptors 0.31.1 → 0.32.1
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.
- package/README.md +56 -39
- package/lib/node/RemoteHttpInterceptor.d.ts +1 -2
- package/lib/node/RemoteHttpInterceptor.js +11 -11
- package/lib/node/RemoteHttpInterceptor.mjs +5 -5
- package/lib/node/{chunk-LTEXDYJ6.js → chunk-2COJKQQB.js} +3 -3
- package/lib/node/chunk-3OJLYEWA.mjs +963 -0
- package/lib/node/chunk-3OJLYEWA.mjs.map +1 -0
- package/lib/node/chunk-5JMJ55U7.js +963 -0
- package/lib/node/chunk-5JMJ55U7.js.map +1 -0
- package/lib/node/{chunk-E4AC7YAC.js → chunk-BFLYGQ6D.js} +4 -2
- package/lib/node/{chunk-KSHIDGUL.mjs → chunk-DV4PBH4D.mjs} +3 -3
- package/lib/node/{chunk-OUWBQF3Z.mjs → chunk-KWV3JXSI.mjs} +14 -14
- package/lib/node/chunk-KWV3JXSI.mjs.map +1 -0
- package/lib/node/{chunk-6FRASLM3.mjs → chunk-PNWPIDEL.mjs} +2 -2
- package/lib/node/{chunk-APT7KA3B.js → chunk-PYD4E2EJ.js} +13 -13
- package/lib/node/{chunk-Q7POAM5N.mjs → chunk-TGTPXCLF.mjs} +3 -1
- package/lib/node/{chunk-MQJ3JOOK.js → chunk-UXCYRE4F.js} +14 -14
- package/lib/node/chunk-UXCYRE4F.js.map +1 -0
- package/lib/node/index.js +3 -3
- package/lib/node/index.mjs +2 -2
- package/lib/node/interceptors/ClientRequest/index.d.ts +83 -14
- package/lib/node/interceptors/ClientRequest/index.js +4 -4
- package/lib/node/interceptors/ClientRequest/index.mjs +3 -3
- package/lib/node/interceptors/XMLHttpRequest/index.js +4 -4
- package/lib/node/interceptors/XMLHttpRequest/index.mjs +3 -3
- package/lib/node/interceptors/fetch/index.js +10 -10
- package/lib/node/interceptors/fetch/index.mjs +2 -2
- package/lib/node/presets/node.d.ts +2 -3
- package/lib/node/presets/node.js +6 -6
- package/lib/node/presets/node.mjs +4 -4
- package/package.json +2 -2
- package/src/interceptors/ClientRequest/MockHttpSocket.ts +595 -0
- package/src/interceptors/ClientRequest/agents.ts +78 -0
- package/src/interceptors/ClientRequest/index.test.ts +14 -12
- package/src/interceptors/ClientRequest/index.ts +200 -41
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.test.ts +78 -98
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts +40 -22
- package/src/interceptors/Socket/MockSocket.test.ts +264 -0
- package/src/interceptors/Socket/MockSocket.ts +59 -0
- package/src/interceptors/Socket/utils/baseUrlFromConnectionOptions.ts +26 -0
- package/src/interceptors/Socket/utils/normalizeSocketWriteArgs.test.ts +52 -0
- package/src/interceptors/Socket/utils/normalizeSocketWriteArgs.ts +33 -0
- package/src/interceptors/Socket/utils/parseRawHeaders.ts +10 -0
- package/lib/node/chunk-IS3CIGXU.js +0 -909
- package/lib/node/chunk-IS3CIGXU.js.map +0 -1
- package/lib/node/chunk-MQJ3JOOK.js.map +0 -1
- package/lib/node/chunk-OMOWHUE6.mjs +0 -909
- package/lib/node/chunk-OMOWHUE6.mjs.map +0 -1
- package/lib/node/chunk-OUWBQF3Z.mjs.map +0 -1
- package/src/interceptors/ClientRequest/NodeClientRequest.test.ts +0 -206
- package/src/interceptors/ClientRequest/NodeClientRequest.ts +0 -680
- package/src/interceptors/ClientRequest/http.get.ts +0 -30
- package/src/interceptors/ClientRequest/http.request.ts +0 -27
- package/src/interceptors/ClientRequest/utils/cloneIncomingMessage.test.ts +0 -26
- package/src/interceptors/ClientRequest/utils/cloneIncomingMessage.ts +0 -74
- package/src/interceptors/ClientRequest/utils/createRequest.test.ts +0 -144
- package/src/interceptors/ClientRequest/utils/createRequest.ts +0 -51
- package/src/interceptors/ClientRequest/utils/createResponse.test.ts +0 -53
- package/src/interceptors/ClientRequest/utils/createResponse.ts +0 -55
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestEndArgs.test.ts +0 -41
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestEndArgs.ts +0 -53
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestWriteArgs.test.ts +0 -36
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestWriteArgs.ts +0 -39
- /package/lib/node/{chunk-LTEXDYJ6.js.map → chunk-2COJKQQB.js.map} +0 -0
- /package/lib/node/{chunk-E4AC7YAC.js.map → chunk-BFLYGQ6D.js.map} +0 -0
- /package/lib/node/{chunk-KSHIDGUL.mjs.map → chunk-DV4PBH4D.mjs.map} +0 -0
- /package/lib/node/{chunk-6FRASLM3.mjs.map → chunk-PNWPIDEL.mjs.map} +0 -0
- /package/lib/node/{chunk-APT7KA3B.js.map → chunk-PYD4E2EJ.js.map} +0 -0
- /package/lib/node/{chunk-Q7POAM5N.mjs.map → chunk-TGTPXCLF.mjs.map} +0 -0
|
@@ -0,0 +1,963 @@
|
|
|
1
|
+
import {
|
|
2
|
+
emitAsync,
|
|
3
|
+
toInteractiveRequest
|
|
4
|
+
} from "./chunk-KWV3JXSI.mjs";
|
|
5
|
+
import {
|
|
6
|
+
INTERNAL_REQUEST_ID_HEADER_NAME,
|
|
7
|
+
Interceptor,
|
|
8
|
+
RESPONSE_STATUS_CODES_WITHOUT_BODY,
|
|
9
|
+
createRequestId,
|
|
10
|
+
createServerErrorResponse,
|
|
11
|
+
isPropertyAccessible
|
|
12
|
+
} from "./chunk-TGTPXCLF.mjs";
|
|
13
|
+
|
|
14
|
+
// src/interceptors/ClientRequest/index.ts
|
|
15
|
+
import http2 from "http";
|
|
16
|
+
import https2 from "https";
|
|
17
|
+
import { until } from "@open-draft/until";
|
|
18
|
+
|
|
19
|
+
// src/interceptors/ClientRequest/MockHttpSocket.ts
|
|
20
|
+
import net2 from "net";
|
|
21
|
+
import {
|
|
22
|
+
HTTPParser
|
|
23
|
+
} from "_http_common";
|
|
24
|
+
import { IncomingMessage, ServerResponse } from "http";
|
|
25
|
+
import { Readable } from "stream";
|
|
26
|
+
import { invariant } from "outvariant";
|
|
27
|
+
|
|
28
|
+
// src/interceptors/Socket/MockSocket.ts
|
|
29
|
+
import net from "net";
|
|
30
|
+
|
|
31
|
+
// src/interceptors/Socket/utils/normalizeSocketWriteArgs.ts
|
|
32
|
+
function normalizeSocketWriteArgs(args) {
|
|
33
|
+
const normalized = [args[0], void 0, void 0];
|
|
34
|
+
if (typeof args[1] === "string") {
|
|
35
|
+
normalized[1] = args[1];
|
|
36
|
+
} else if (typeof args[1] === "function") {
|
|
37
|
+
normalized[2] = args[1];
|
|
38
|
+
}
|
|
39
|
+
if (typeof args[2] === "function") {
|
|
40
|
+
normalized[2] = args[2];
|
|
41
|
+
}
|
|
42
|
+
return normalized;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/interceptors/Socket/MockSocket.ts
|
|
46
|
+
var MockSocket = class extends net.Socket {
|
|
47
|
+
constructor(options) {
|
|
48
|
+
super();
|
|
49
|
+
this.options = options;
|
|
50
|
+
this.connecting = false;
|
|
51
|
+
this.connect();
|
|
52
|
+
this._final = (callback) => {
|
|
53
|
+
callback(null);
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
connect() {
|
|
57
|
+
this.connecting = true;
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
write(...args) {
|
|
61
|
+
const [chunk, encoding, callback] = normalizeSocketWriteArgs(
|
|
62
|
+
args
|
|
63
|
+
);
|
|
64
|
+
this.options.write(chunk, encoding, callback);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
end(...args) {
|
|
68
|
+
const [chunk, encoding, callback] = normalizeSocketWriteArgs(
|
|
69
|
+
args
|
|
70
|
+
);
|
|
71
|
+
this.options.write(chunk, encoding, callback);
|
|
72
|
+
return super.end.apply(this, args);
|
|
73
|
+
}
|
|
74
|
+
push(chunk, encoding) {
|
|
75
|
+
this.options.read(chunk, encoding);
|
|
76
|
+
return super.push(chunk, encoding);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// src/interceptors/Socket/utils/baseUrlFromConnectionOptions.ts
|
|
81
|
+
function baseUrlFromConnectionOptions(options) {
|
|
82
|
+
if ("href" in options) {
|
|
83
|
+
return new URL(options.href);
|
|
84
|
+
}
|
|
85
|
+
const protocol = options.port === 443 ? "https:" : "http:";
|
|
86
|
+
const host = options.host;
|
|
87
|
+
const url = new URL(`${protocol}//${host}`);
|
|
88
|
+
if (options.port) {
|
|
89
|
+
url.port = options.port.toString();
|
|
90
|
+
}
|
|
91
|
+
if (options.path) {
|
|
92
|
+
url.pathname = options.path;
|
|
93
|
+
}
|
|
94
|
+
if (options.auth) {
|
|
95
|
+
const [username, password] = options.auth.split(":");
|
|
96
|
+
url.username = username;
|
|
97
|
+
url.password = password;
|
|
98
|
+
}
|
|
99
|
+
return url;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/interceptors/Socket/utils/parseRawHeaders.ts
|
|
103
|
+
function parseRawHeaders(rawHeaders) {
|
|
104
|
+
const headers = new Headers();
|
|
105
|
+
for (let line = 0; line < rawHeaders.length; line += 2) {
|
|
106
|
+
headers.append(rawHeaders[line], rawHeaders[line + 1]);
|
|
107
|
+
}
|
|
108
|
+
return headers;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// src/utils/getValueBySymbol.ts
|
|
112
|
+
function getValueBySymbol(symbolName, source) {
|
|
113
|
+
const ownSymbols = Object.getOwnPropertySymbols(source);
|
|
114
|
+
const symbol = ownSymbols.find((symbol2) => {
|
|
115
|
+
return symbol2.description === symbolName;
|
|
116
|
+
});
|
|
117
|
+
if (symbol) {
|
|
118
|
+
return Reflect.get(source, symbol);
|
|
119
|
+
}
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// src/utils/isObject.ts
|
|
124
|
+
function isObject(value, loose = false) {
|
|
125
|
+
return loose ? Object.prototype.toString.call(value).startsWith("[object ") : Object.prototype.toString.call(value) === "[object Object]";
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// src/utils/getRawFetchHeaders.ts
|
|
129
|
+
function getRawFetchHeaders(headers) {
|
|
130
|
+
const headersList = getValueBySymbol("headers list", headers);
|
|
131
|
+
if (!headersList) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const headersMap = getValueBySymbol("headers map", headersList);
|
|
135
|
+
if (!headersMap || !isHeadersMapWithRawHeaderNames(headersMap)) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const rawHeaders = /* @__PURE__ */ new Map();
|
|
139
|
+
headersMap.forEach(({ name, value }) => {
|
|
140
|
+
rawHeaders.set(name, value);
|
|
141
|
+
});
|
|
142
|
+
return rawHeaders;
|
|
143
|
+
}
|
|
144
|
+
function isHeadersMapWithRawHeaderNames(headersMap) {
|
|
145
|
+
return Array.from(
|
|
146
|
+
headersMap.values()
|
|
147
|
+
).every((value) => {
|
|
148
|
+
return isObject(value) && "name" in value;
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// src/interceptors/ClientRequest/MockHttpSocket.ts
|
|
153
|
+
var kRequestId = Symbol("kRequestId");
|
|
154
|
+
var MockHttpSocket = class extends MockSocket {
|
|
155
|
+
constructor(options) {
|
|
156
|
+
super({
|
|
157
|
+
write: (chunk, encoding, callback) => {
|
|
158
|
+
this.writeBuffer.push([chunk, encoding, callback]);
|
|
159
|
+
if (chunk) {
|
|
160
|
+
this.requestParser.execute(
|
|
161
|
+
Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding)
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
read: (chunk) => {
|
|
166
|
+
if (chunk !== null) {
|
|
167
|
+
this.responseParser.execute(
|
|
168
|
+
Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
this.writeBuffer = [];
|
|
174
|
+
this.responseType = "bypassed";
|
|
175
|
+
this.onRequestStart = (versionMajor, versionMinor, rawHeaders, _, path, __, ___, ____, shouldKeepAlive) => {
|
|
176
|
+
this.shouldKeepAlive = shouldKeepAlive;
|
|
177
|
+
const url = new URL(path, this.baseUrl);
|
|
178
|
+
const method = this.connectionOptions.method || "GET";
|
|
179
|
+
const headers = parseRawHeaders(rawHeaders);
|
|
180
|
+
const canHaveBody = method !== "GET" && method !== "HEAD";
|
|
181
|
+
if (url.username || url.password) {
|
|
182
|
+
if (!headers.has("authorization")) {
|
|
183
|
+
headers.set("authorization", `Basic ${url.username}:${url.password}`);
|
|
184
|
+
}
|
|
185
|
+
url.username = "";
|
|
186
|
+
url.password = "";
|
|
187
|
+
}
|
|
188
|
+
if (canHaveBody) {
|
|
189
|
+
this.requestStream = new Readable({
|
|
190
|
+
/**
|
|
191
|
+
* @note Provide the `read()` method so a `Readable` could be
|
|
192
|
+
* used as the actual request body (the stream calls "read()").
|
|
193
|
+
* We control the queue in the onRequestBody/End functions.
|
|
194
|
+
*/
|
|
195
|
+
read: () => {
|
|
196
|
+
this.flushWriteBuffer();
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
const requestId = createRequestId();
|
|
201
|
+
this.request = new Request(url, {
|
|
202
|
+
method,
|
|
203
|
+
headers,
|
|
204
|
+
credentials: "same-origin",
|
|
205
|
+
// @ts-expect-error Undocumented Fetch property.
|
|
206
|
+
duplex: canHaveBody ? "half" : void 0,
|
|
207
|
+
body: canHaveBody ? Readable.toWeb(this.requestStream) : null
|
|
208
|
+
});
|
|
209
|
+
Reflect.set(this.request, kRequestId, requestId);
|
|
210
|
+
if (this.request.headers.has(INTERNAL_REQUEST_ID_HEADER_NAME)) {
|
|
211
|
+
this.passthrough();
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
this.onRequest({
|
|
215
|
+
requestId,
|
|
216
|
+
request: this.request,
|
|
217
|
+
socket: this
|
|
218
|
+
});
|
|
219
|
+
};
|
|
220
|
+
this.onResponseStart = (versionMajor, versionMinor, rawHeaders, method, url, status, statusText) => {
|
|
221
|
+
const headers = parseRawHeaders(rawHeaders);
|
|
222
|
+
const canHaveBody = !RESPONSE_STATUS_CODES_WITHOUT_BODY.has(status);
|
|
223
|
+
if (canHaveBody) {
|
|
224
|
+
this.responseStream = new Readable();
|
|
225
|
+
}
|
|
226
|
+
const response = new Response(
|
|
227
|
+
/**
|
|
228
|
+
* @note The Fetch API response instance exposed to the consumer
|
|
229
|
+
* is created over the response stream of the HTTP parser. It is NOT
|
|
230
|
+
* related to the Socket instance. This way, you can read response body
|
|
231
|
+
* in response listener while the Socket instance delays the emission
|
|
232
|
+
* of "end" and other events until those response listeners are finished.
|
|
233
|
+
*/
|
|
234
|
+
canHaveBody ? Readable.toWeb(this.responseStream) : null,
|
|
235
|
+
{
|
|
236
|
+
status,
|
|
237
|
+
statusText,
|
|
238
|
+
headers
|
|
239
|
+
}
|
|
240
|
+
);
|
|
241
|
+
invariant(
|
|
242
|
+
this.request,
|
|
243
|
+
"Failed to handle a response: request does not exist"
|
|
244
|
+
);
|
|
245
|
+
if (this.request.headers.has(INTERNAL_REQUEST_ID_HEADER_NAME)) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
this.responseListenersPromise = this.onResponse({
|
|
249
|
+
response,
|
|
250
|
+
isMockedResponse: this.responseType === "mock",
|
|
251
|
+
requestId: Reflect.get(this.request, kRequestId),
|
|
252
|
+
request: this.request,
|
|
253
|
+
socket: this
|
|
254
|
+
});
|
|
255
|
+
};
|
|
256
|
+
this.connectionOptions = options.connectionOptions;
|
|
257
|
+
this.createConnection = options.createConnection;
|
|
258
|
+
this.onRequest = options.onRequest;
|
|
259
|
+
this.onResponse = options.onResponse;
|
|
260
|
+
this.baseUrl = baseUrlFromConnectionOptions(this.connectionOptions);
|
|
261
|
+
this.requestParser = new HTTPParser();
|
|
262
|
+
this.requestParser.initialize(HTTPParser.REQUEST, {});
|
|
263
|
+
this.requestParser[HTTPParser.kOnHeadersComplete] = this.onRequestStart.bind(this);
|
|
264
|
+
this.requestParser[HTTPParser.kOnBody] = this.onRequestBody.bind(this);
|
|
265
|
+
this.requestParser[HTTPParser.kOnMessageComplete] = this.onRequestEnd.bind(this);
|
|
266
|
+
this.responseParser = new HTTPParser();
|
|
267
|
+
this.responseParser.initialize(HTTPParser.RESPONSE, {});
|
|
268
|
+
this.responseParser[HTTPParser.kOnHeadersComplete] = this.onResponseStart.bind(this);
|
|
269
|
+
this.responseParser[HTTPParser.kOnBody] = this.onResponseBody.bind(this);
|
|
270
|
+
this.responseParser[HTTPParser.kOnMessageComplete] = this.onResponseEnd.bind(this);
|
|
271
|
+
this.once("finish", () => this.requestParser.free());
|
|
272
|
+
if (this.baseUrl.protocol === "https:") {
|
|
273
|
+
Reflect.set(this, "encrypted", true);
|
|
274
|
+
Reflect.set(this, "authorized", false);
|
|
275
|
+
Reflect.set(this, "getProtocol", () => "TLSv1.3");
|
|
276
|
+
Reflect.set(this, "getSession", () => void 0);
|
|
277
|
+
Reflect.set(this, "isSessionReused", () => false);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
emit(event, ...args) {
|
|
281
|
+
const emitEvent = super.emit.bind(this, event, ...args);
|
|
282
|
+
if (this.responseListenersPromise) {
|
|
283
|
+
this.responseListenersPromise.finally(emitEvent);
|
|
284
|
+
return this.listenerCount(event) > 0;
|
|
285
|
+
}
|
|
286
|
+
return emitEvent();
|
|
287
|
+
}
|
|
288
|
+
destroy(error) {
|
|
289
|
+
this.responseParser.free();
|
|
290
|
+
if (error) {
|
|
291
|
+
this.emit("error", error);
|
|
292
|
+
}
|
|
293
|
+
return super.destroy(error);
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Establish this Socket connection as-is and pipe
|
|
297
|
+
* its data/events through this Socket.
|
|
298
|
+
*/
|
|
299
|
+
passthrough() {
|
|
300
|
+
if (this.destroyed) {
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
const socket = this.createConnection();
|
|
304
|
+
this.once("error", (error) => {
|
|
305
|
+
socket.destroy(error);
|
|
306
|
+
});
|
|
307
|
+
this.address = socket.address.bind(socket);
|
|
308
|
+
let writeArgs;
|
|
309
|
+
let headersWritten = false;
|
|
310
|
+
while (writeArgs = this.writeBuffer.shift()) {
|
|
311
|
+
if (writeArgs !== void 0) {
|
|
312
|
+
if (!headersWritten) {
|
|
313
|
+
const [chunk, encoding, callback] = writeArgs;
|
|
314
|
+
const chunkString = chunk.toString();
|
|
315
|
+
const chunkBeforeRequestHeaders = chunkString.slice(
|
|
316
|
+
0,
|
|
317
|
+
chunkString.indexOf("\r\n") + 2
|
|
318
|
+
);
|
|
319
|
+
const chunkAfterRequestHeaders = chunkString.slice(
|
|
320
|
+
chunk.indexOf("\r\n\r\n")
|
|
321
|
+
);
|
|
322
|
+
const requestHeaders = getRawFetchHeaders(this.request.headers) || this.request.headers;
|
|
323
|
+
const requestHeadersString = Array.from(requestHeaders.entries()).filter(([name]) => name !== INTERNAL_REQUEST_ID_HEADER_NAME).map(([name, value]) => `${name}: ${value}`).join("\r\n");
|
|
324
|
+
const headersChunk = `${chunkBeforeRequestHeaders}${requestHeadersString}${chunkAfterRequestHeaders}`;
|
|
325
|
+
socket.write(headersChunk, encoding, callback);
|
|
326
|
+
headersWritten = true;
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
socket.write(...writeArgs);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
if (Reflect.get(socket, "encrypted")) {
|
|
333
|
+
const tlsProperties = [
|
|
334
|
+
"encrypted",
|
|
335
|
+
"authorized",
|
|
336
|
+
"getProtocol",
|
|
337
|
+
"getSession",
|
|
338
|
+
"isSessionReused"
|
|
339
|
+
];
|
|
340
|
+
tlsProperties.forEach((propertyName) => {
|
|
341
|
+
Object.defineProperty(this, propertyName, {
|
|
342
|
+
enumerable: true,
|
|
343
|
+
get: () => {
|
|
344
|
+
const value = Reflect.get(socket, propertyName);
|
|
345
|
+
return typeof value === "function" ? value.bind(socket) : value;
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
socket.on("lookup", (...args) => this.emit("lookup", ...args)).on("connect", () => {
|
|
351
|
+
this.connecting = socket.connecting;
|
|
352
|
+
this.emit("connect");
|
|
353
|
+
}).on("secureConnect", () => this.emit("secureConnect")).on("secure", () => this.emit("secure")).on("session", (session) => this.emit("session", session)).on("ready", () => this.emit("ready")).on("drain", () => this.emit("drain")).on("data", (chunk) => {
|
|
354
|
+
this.push(chunk);
|
|
355
|
+
}).on("error", (error) => {
|
|
356
|
+
Reflect.set(this, "_hadError", Reflect.get(socket, "_hadError"));
|
|
357
|
+
this.emit("error", error);
|
|
358
|
+
}).on("resume", () => this.emit("resume")).on("timeout", () => this.emit("timeout")).on("prefinish", () => this.emit("prefinish")).on("finish", () => this.emit("finish")).on("close", (hadError) => this.emit("close", hadError)).on("end", () => this.emit("end"));
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Convert the given Fetch API `Response` instance to an
|
|
362
|
+
* HTTP message and push it to the socket.
|
|
363
|
+
*/
|
|
364
|
+
async respondWith(response) {
|
|
365
|
+
var _a;
|
|
366
|
+
if (this.destroyed) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
if (isPropertyAccessible(response, "type") && response.type === "error") {
|
|
370
|
+
this.errorWith(new TypeError("Network error"));
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
this.mockConnect();
|
|
374
|
+
this.responseType = "mock";
|
|
375
|
+
this.flushWriteBuffer();
|
|
376
|
+
const serverResponse = new ServerResponse(new IncomingMessage(this));
|
|
377
|
+
serverResponse.assignSocket(
|
|
378
|
+
new MockSocket({
|
|
379
|
+
write: (chunk, encoding, callback) => {
|
|
380
|
+
this.push(chunk, encoding);
|
|
381
|
+
callback == null ? void 0 : callback();
|
|
382
|
+
},
|
|
383
|
+
read() {
|
|
384
|
+
}
|
|
385
|
+
})
|
|
386
|
+
);
|
|
387
|
+
serverResponse.statusCode = response.status;
|
|
388
|
+
serverResponse.statusMessage = response.statusText;
|
|
389
|
+
serverResponse.removeHeader("connection");
|
|
390
|
+
serverResponse.removeHeader("date");
|
|
391
|
+
this.once("error", () => {
|
|
392
|
+
serverResponse.destroy();
|
|
393
|
+
});
|
|
394
|
+
const headers = getRawFetchHeaders(response.headers) || response.headers;
|
|
395
|
+
for (const [name, value] of headers) {
|
|
396
|
+
serverResponse.setHeader(name, value);
|
|
397
|
+
}
|
|
398
|
+
if (response.body) {
|
|
399
|
+
try {
|
|
400
|
+
const reader = response.body.getReader();
|
|
401
|
+
while (true) {
|
|
402
|
+
const { done, value } = await reader.read();
|
|
403
|
+
if (done) {
|
|
404
|
+
serverResponse.end();
|
|
405
|
+
break;
|
|
406
|
+
}
|
|
407
|
+
serverResponse.write(value);
|
|
408
|
+
}
|
|
409
|
+
} catch (error) {
|
|
410
|
+
this.respondWith(createServerErrorResponse(error));
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
} else {
|
|
414
|
+
serverResponse.end();
|
|
415
|
+
}
|
|
416
|
+
if (!this.shouldKeepAlive) {
|
|
417
|
+
this.emit("readable");
|
|
418
|
+
(_a = this.responseStream) == null ? void 0 : _a.push(null);
|
|
419
|
+
this.push(null);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Close this socket connection with the given error.
|
|
424
|
+
*/
|
|
425
|
+
errorWith(error) {
|
|
426
|
+
this.destroy(error);
|
|
427
|
+
}
|
|
428
|
+
mockConnect() {
|
|
429
|
+
this.connecting = false;
|
|
430
|
+
const isIPv6 = net2.isIPv6(this.connectionOptions.hostname) || this.connectionOptions.family === 6;
|
|
431
|
+
const addressInfo = {
|
|
432
|
+
address: isIPv6 ? "::1" : "127.0.0.1",
|
|
433
|
+
family: isIPv6 ? "IPv6" : "IPv4",
|
|
434
|
+
port: this.connectionOptions.port
|
|
435
|
+
};
|
|
436
|
+
this.address = () => addressInfo;
|
|
437
|
+
this.emit(
|
|
438
|
+
"lookup",
|
|
439
|
+
null,
|
|
440
|
+
addressInfo.address,
|
|
441
|
+
addressInfo.family === "IPv6" ? 6 : 4,
|
|
442
|
+
this.connectionOptions.host
|
|
443
|
+
);
|
|
444
|
+
this.emit("connect");
|
|
445
|
+
this.emit("ready");
|
|
446
|
+
if (this.baseUrl.protocol === "https:") {
|
|
447
|
+
this.emit("secure");
|
|
448
|
+
this.emit("secureConnect");
|
|
449
|
+
this.emit(
|
|
450
|
+
"session",
|
|
451
|
+
this.connectionOptions.session || Buffer.from("mock-session-renegotiate")
|
|
452
|
+
);
|
|
453
|
+
this.emit("session", Buffer.from("mock-session-resume"));
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
flushWriteBuffer() {
|
|
457
|
+
var _a;
|
|
458
|
+
let args;
|
|
459
|
+
while (args = this.writeBuffer.shift()) {
|
|
460
|
+
(_a = args == null ? void 0 : args[2]) == null ? void 0 : _a.call(args);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
onRequestBody(chunk) {
|
|
464
|
+
invariant(
|
|
465
|
+
this.requestStream,
|
|
466
|
+
"Failed to write to a request stream: stream does not exist"
|
|
467
|
+
);
|
|
468
|
+
this.requestStream.push(chunk);
|
|
469
|
+
}
|
|
470
|
+
onRequestEnd() {
|
|
471
|
+
if (this.requestStream) {
|
|
472
|
+
this.requestStream.push(null);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
onResponseBody(chunk) {
|
|
476
|
+
invariant(
|
|
477
|
+
this.responseStream,
|
|
478
|
+
"Failed to write to a response stream: stream does not exist"
|
|
479
|
+
);
|
|
480
|
+
this.responseStream.push(chunk);
|
|
481
|
+
}
|
|
482
|
+
onResponseEnd() {
|
|
483
|
+
if (this.responseStream) {
|
|
484
|
+
this.responseStream.push(null);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
// src/interceptors/ClientRequest/agents.ts
|
|
490
|
+
import http from "http";
|
|
491
|
+
import https from "https";
|
|
492
|
+
var MockAgent = class extends http.Agent {
|
|
493
|
+
constructor(options) {
|
|
494
|
+
super();
|
|
495
|
+
this.customAgent = options.customAgent;
|
|
496
|
+
this.onRequest = options.onRequest;
|
|
497
|
+
this.onResponse = options.onResponse;
|
|
498
|
+
}
|
|
499
|
+
createConnection(options, callback) {
|
|
500
|
+
const createConnection = this.customAgent instanceof http.Agent && this.customAgent.createConnection || super.createConnection;
|
|
501
|
+
const socket = new MockHttpSocket({
|
|
502
|
+
connectionOptions: options,
|
|
503
|
+
createConnection: createConnection.bind(this, options, callback),
|
|
504
|
+
onRequest: this.onRequest.bind(this),
|
|
505
|
+
onResponse: this.onResponse.bind(this)
|
|
506
|
+
});
|
|
507
|
+
return socket;
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
var MockHttpsAgent = class extends https.Agent {
|
|
511
|
+
constructor(options) {
|
|
512
|
+
super();
|
|
513
|
+
this.customAgent = options.customAgent;
|
|
514
|
+
this.onRequest = options.onRequest;
|
|
515
|
+
this.onResponse = options.onResponse;
|
|
516
|
+
}
|
|
517
|
+
createConnection(options, callback) {
|
|
518
|
+
const createConnection = this.customAgent instanceof https.Agent && this.customAgent.createConnection || super.createConnection;
|
|
519
|
+
const socket = new MockHttpSocket({
|
|
520
|
+
connectionOptions: options,
|
|
521
|
+
createConnection: createConnection.bind(this, options, callback),
|
|
522
|
+
onRequest: this.onRequest.bind(this),
|
|
523
|
+
onResponse: this.onResponse.bind(this)
|
|
524
|
+
});
|
|
525
|
+
return socket;
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
// src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts
|
|
530
|
+
import {
|
|
531
|
+
Agent as HttpAgent,
|
|
532
|
+
globalAgent as httpGlobalAgent
|
|
533
|
+
} from "http";
|
|
534
|
+
import {
|
|
535
|
+
Agent as HttpsAgent,
|
|
536
|
+
globalAgent as httpsGlobalAgent
|
|
537
|
+
} from "https";
|
|
538
|
+
import {
|
|
539
|
+
URL as URL2,
|
|
540
|
+
parse as parseUrl
|
|
541
|
+
} from "url";
|
|
542
|
+
import { Logger as Logger3 } from "@open-draft/logger";
|
|
543
|
+
|
|
544
|
+
// src/utils/getRequestOptionsByUrl.ts
|
|
545
|
+
function getRequestOptionsByUrl(url) {
|
|
546
|
+
const options = {
|
|
547
|
+
method: "GET",
|
|
548
|
+
protocol: url.protocol,
|
|
549
|
+
hostname: typeof url.hostname === "string" && url.hostname.startsWith("[") ? url.hostname.slice(1, -1) : url.hostname,
|
|
550
|
+
host: url.host,
|
|
551
|
+
path: `${url.pathname}${url.search || ""}`
|
|
552
|
+
};
|
|
553
|
+
if (!!url.port) {
|
|
554
|
+
options.port = Number(url.port);
|
|
555
|
+
}
|
|
556
|
+
if (url.username || url.password) {
|
|
557
|
+
options.auth = `${url.username}:${url.password}`;
|
|
558
|
+
}
|
|
559
|
+
return options;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// src/utils/getUrlByRequestOptions.ts
|
|
563
|
+
import { Agent } from "http";
|
|
564
|
+
import { Logger } from "@open-draft/logger";
|
|
565
|
+
var logger = new Logger("utils getUrlByRequestOptions");
|
|
566
|
+
var DEFAULT_PATH = "/";
|
|
567
|
+
var DEFAULT_PROTOCOL = "http:";
|
|
568
|
+
var DEFAULT_HOSTNAME = "localhost";
|
|
569
|
+
var SSL_PORT = 443;
|
|
570
|
+
function getAgent(options) {
|
|
571
|
+
return options.agent instanceof Agent ? options.agent : void 0;
|
|
572
|
+
}
|
|
573
|
+
function getProtocolByRequestOptions(options) {
|
|
574
|
+
var _a;
|
|
575
|
+
if (options.protocol) {
|
|
576
|
+
return options.protocol;
|
|
577
|
+
}
|
|
578
|
+
const agent = getAgent(options);
|
|
579
|
+
const agentProtocol = agent == null ? void 0 : agent.protocol;
|
|
580
|
+
if (agentProtocol) {
|
|
581
|
+
return agentProtocol;
|
|
582
|
+
}
|
|
583
|
+
const port = getPortByRequestOptions(options);
|
|
584
|
+
const isSecureRequest = options.cert || port === SSL_PORT;
|
|
585
|
+
return isSecureRequest ? "https:" : ((_a = options.uri) == null ? void 0 : _a.protocol) || DEFAULT_PROTOCOL;
|
|
586
|
+
}
|
|
587
|
+
function getPortByRequestOptions(options) {
|
|
588
|
+
if (options.port) {
|
|
589
|
+
return Number(options.port);
|
|
590
|
+
}
|
|
591
|
+
const agent = getAgent(options);
|
|
592
|
+
if (agent == null ? void 0 : agent.options.port) {
|
|
593
|
+
return Number(agent.options.port);
|
|
594
|
+
}
|
|
595
|
+
if (agent == null ? void 0 : agent.defaultPort) {
|
|
596
|
+
return Number(agent.defaultPort);
|
|
597
|
+
}
|
|
598
|
+
return void 0;
|
|
599
|
+
}
|
|
600
|
+
function getAuthByRequestOptions(options) {
|
|
601
|
+
if (options.auth) {
|
|
602
|
+
const [username, password] = options.auth.split(":");
|
|
603
|
+
return { username, password };
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
function isRawIPv6Address(host) {
|
|
607
|
+
return host.includes(":") && !host.startsWith("[") && !host.endsWith("]");
|
|
608
|
+
}
|
|
609
|
+
function getHostname(options) {
|
|
610
|
+
let host = options.hostname || options.host;
|
|
611
|
+
if (host) {
|
|
612
|
+
if (isRawIPv6Address(host)) {
|
|
613
|
+
host = `[${host}]`;
|
|
614
|
+
}
|
|
615
|
+
return new URL(`http://${host}`).hostname;
|
|
616
|
+
}
|
|
617
|
+
return DEFAULT_HOSTNAME;
|
|
618
|
+
}
|
|
619
|
+
function getUrlByRequestOptions(options) {
|
|
620
|
+
logger.info("request options", options);
|
|
621
|
+
if (options.uri) {
|
|
622
|
+
logger.info(
|
|
623
|
+
'constructing url from explicitly provided "options.uri": %s',
|
|
624
|
+
options.uri
|
|
625
|
+
);
|
|
626
|
+
return new URL(options.uri.href);
|
|
627
|
+
}
|
|
628
|
+
logger.info("figuring out url from request options...");
|
|
629
|
+
const protocol = getProtocolByRequestOptions(options);
|
|
630
|
+
logger.info("protocol", protocol);
|
|
631
|
+
const port = getPortByRequestOptions(options);
|
|
632
|
+
logger.info("port", port);
|
|
633
|
+
const hostname = getHostname(options);
|
|
634
|
+
logger.info("hostname", hostname);
|
|
635
|
+
const path = options.path || DEFAULT_PATH;
|
|
636
|
+
logger.info("path", path);
|
|
637
|
+
const credentials = getAuthByRequestOptions(options);
|
|
638
|
+
logger.info("credentials", credentials);
|
|
639
|
+
const authString = credentials ? `${credentials.username}:${credentials.password}@` : "";
|
|
640
|
+
logger.info("auth string:", authString);
|
|
641
|
+
const portString = typeof port !== "undefined" ? `:${port}` : "";
|
|
642
|
+
const url = new URL(`${protocol}//${hostname}${portString}${path}`);
|
|
643
|
+
url.username = (credentials == null ? void 0 : credentials.username) || "";
|
|
644
|
+
url.password = (credentials == null ? void 0 : credentials.password) || "";
|
|
645
|
+
logger.info("created url:", url);
|
|
646
|
+
return url;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// src/utils/cloneObject.ts
|
|
650
|
+
import { Logger as Logger2 } from "@open-draft/logger";
|
|
651
|
+
var logger2 = new Logger2("cloneObject");
|
|
652
|
+
function isPlainObject(obj) {
|
|
653
|
+
var _a;
|
|
654
|
+
logger2.info("is plain object?", obj);
|
|
655
|
+
if (obj == null || !((_a = obj.constructor) == null ? void 0 : _a.name)) {
|
|
656
|
+
logger2.info("given object is undefined, not a plain object...");
|
|
657
|
+
return false;
|
|
658
|
+
}
|
|
659
|
+
logger2.info("checking the object constructor:", obj.constructor.name);
|
|
660
|
+
return obj.constructor.name === "Object";
|
|
661
|
+
}
|
|
662
|
+
function cloneObject(obj) {
|
|
663
|
+
logger2.info("cloning object:", obj);
|
|
664
|
+
const enumerableProperties = Object.entries(obj).reduce(
|
|
665
|
+
(acc, [key, value]) => {
|
|
666
|
+
logger2.info("analyzing key-value pair:", key, value);
|
|
667
|
+
acc[key] = isPlainObject(value) ? cloneObject(value) : value;
|
|
668
|
+
return acc;
|
|
669
|
+
},
|
|
670
|
+
{}
|
|
671
|
+
);
|
|
672
|
+
return isPlainObject(obj) ? enumerableProperties : Object.assign(Object.getPrototypeOf(obj), enumerableProperties);
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
// src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts
|
|
676
|
+
var logger3 = new Logger3("http normalizeClientRequestArgs");
|
|
677
|
+
function resolveRequestOptions(args, url) {
|
|
678
|
+
if (typeof args[1] === "undefined" || typeof args[1] === "function") {
|
|
679
|
+
logger3.info("request options not provided, deriving from the url", url);
|
|
680
|
+
return getRequestOptionsByUrl(url);
|
|
681
|
+
}
|
|
682
|
+
if (args[1]) {
|
|
683
|
+
logger3.info("has custom RequestOptions!", args[1]);
|
|
684
|
+
const requestOptionsFromUrl = getRequestOptionsByUrl(url);
|
|
685
|
+
logger3.info("derived RequestOptions from the URL:", requestOptionsFromUrl);
|
|
686
|
+
logger3.info("cloning RequestOptions...");
|
|
687
|
+
const clonedRequestOptions = cloneObject(args[1]);
|
|
688
|
+
logger3.info("successfully cloned RequestOptions!", clonedRequestOptions);
|
|
689
|
+
return {
|
|
690
|
+
...requestOptionsFromUrl,
|
|
691
|
+
...clonedRequestOptions
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
logger3.info("using an empty object as request options");
|
|
695
|
+
return {};
|
|
696
|
+
}
|
|
697
|
+
function overrideUrlByRequestOptions(url, options) {
|
|
698
|
+
url.host = options.host || url.host;
|
|
699
|
+
url.hostname = options.hostname || url.hostname;
|
|
700
|
+
url.port = options.port ? options.port.toString() : url.port;
|
|
701
|
+
if (options.path) {
|
|
702
|
+
const parsedOptionsPath = parseUrl(options.path, false);
|
|
703
|
+
url.pathname = parsedOptionsPath.pathname || "";
|
|
704
|
+
url.search = parsedOptionsPath.search || "";
|
|
705
|
+
}
|
|
706
|
+
return url;
|
|
707
|
+
}
|
|
708
|
+
function resolveCallback(args) {
|
|
709
|
+
return typeof args[1] === "function" ? args[1] : args[2];
|
|
710
|
+
}
|
|
711
|
+
function normalizeClientRequestArgs(defaultProtocol, args) {
|
|
712
|
+
let url;
|
|
713
|
+
let options;
|
|
714
|
+
let callback;
|
|
715
|
+
logger3.info("arguments", args);
|
|
716
|
+
logger3.info("using default protocol:", defaultProtocol);
|
|
717
|
+
if (args.length === 0) {
|
|
718
|
+
const url2 = new URL2("http://localhost");
|
|
719
|
+
const options2 = resolveRequestOptions(args, url2);
|
|
720
|
+
return [url2, options2];
|
|
721
|
+
}
|
|
722
|
+
if (typeof args[0] === "string") {
|
|
723
|
+
logger3.info("first argument is a location string:", args[0]);
|
|
724
|
+
url = new URL2(args[0]);
|
|
725
|
+
logger3.info("created a url:", url);
|
|
726
|
+
const requestOptionsFromUrl = getRequestOptionsByUrl(url);
|
|
727
|
+
logger3.info("request options from url:", requestOptionsFromUrl);
|
|
728
|
+
options = resolveRequestOptions(args, url);
|
|
729
|
+
logger3.info("resolved request options:", options);
|
|
730
|
+
callback = resolveCallback(args);
|
|
731
|
+
} else if (args[0] instanceof URL2) {
|
|
732
|
+
url = args[0];
|
|
733
|
+
logger3.info("first argument is a URL:", url);
|
|
734
|
+
if (typeof args[1] !== "undefined" && isObject(args[1])) {
|
|
735
|
+
url = overrideUrlByRequestOptions(url, args[1]);
|
|
736
|
+
}
|
|
737
|
+
options = resolveRequestOptions(args, url);
|
|
738
|
+
logger3.info("derived request options:", options);
|
|
739
|
+
callback = resolveCallback(args);
|
|
740
|
+
} else if ("hash" in args[0] && !("method" in args[0])) {
|
|
741
|
+
const [legacyUrl] = args;
|
|
742
|
+
logger3.info("first argument is a legacy URL:", legacyUrl);
|
|
743
|
+
if (legacyUrl.hostname === null) {
|
|
744
|
+
logger3.info("given legacy URL is relative (no hostname)");
|
|
745
|
+
return isObject(args[1]) ? normalizeClientRequestArgs(defaultProtocol, [
|
|
746
|
+
{ path: legacyUrl.path, ...args[1] },
|
|
747
|
+
args[2]
|
|
748
|
+
]) : normalizeClientRequestArgs(defaultProtocol, [
|
|
749
|
+
{ path: legacyUrl.path },
|
|
750
|
+
args[1]
|
|
751
|
+
]);
|
|
752
|
+
}
|
|
753
|
+
logger3.info("given legacy url is absolute");
|
|
754
|
+
const resolvedUrl = new URL2(legacyUrl.href);
|
|
755
|
+
return args[1] === void 0 ? normalizeClientRequestArgs(defaultProtocol, [resolvedUrl]) : typeof args[1] === "function" ? normalizeClientRequestArgs(defaultProtocol, [resolvedUrl, args[1]]) : normalizeClientRequestArgs(defaultProtocol, [
|
|
756
|
+
resolvedUrl,
|
|
757
|
+
args[1],
|
|
758
|
+
args[2]
|
|
759
|
+
]);
|
|
760
|
+
} else if (isObject(args[0])) {
|
|
761
|
+
options = { ...args[0] };
|
|
762
|
+
logger3.info("first argument is RequestOptions:", options);
|
|
763
|
+
options.protocol = options.protocol || defaultProtocol;
|
|
764
|
+
logger3.info("normalized request options:", options);
|
|
765
|
+
url = getUrlByRequestOptions(options);
|
|
766
|
+
logger3.info("created a URL from RequestOptions:", url.href);
|
|
767
|
+
callback = resolveCallback(args);
|
|
768
|
+
} else {
|
|
769
|
+
throw new Error(
|
|
770
|
+
`Failed to construct ClientRequest with these parameters: ${args}`
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
options.protocol = options.protocol || url.protocol;
|
|
774
|
+
options.method = options.method || "GET";
|
|
775
|
+
if (typeof options.agent === "undefined") {
|
|
776
|
+
const agent = options.protocol === "https:" ? new HttpsAgent({
|
|
777
|
+
rejectUnauthorized: options.rejectUnauthorized
|
|
778
|
+
}) : new HttpAgent();
|
|
779
|
+
options.agent = agent;
|
|
780
|
+
logger3.info("resolved fallback agent:", agent);
|
|
781
|
+
}
|
|
782
|
+
if (!options._defaultAgent) {
|
|
783
|
+
logger3.info(
|
|
784
|
+
'has no default agent, setting the default agent for "%s"',
|
|
785
|
+
options.protocol
|
|
786
|
+
);
|
|
787
|
+
options._defaultAgent = options.protocol === "https:" ? httpsGlobalAgent : httpGlobalAgent;
|
|
788
|
+
}
|
|
789
|
+
logger3.info("successfully resolved url:", url.href);
|
|
790
|
+
logger3.info("successfully resolved options:", options);
|
|
791
|
+
logger3.info("successfully resolved callback:", callback);
|
|
792
|
+
if (!(url instanceof URL2)) {
|
|
793
|
+
url = url.toString();
|
|
794
|
+
}
|
|
795
|
+
return [url, options, callback];
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
// src/utils/isNodeLikeError.ts
|
|
799
|
+
function isNodeLikeError(error) {
|
|
800
|
+
if (error == null) {
|
|
801
|
+
return false;
|
|
802
|
+
}
|
|
803
|
+
if (!(error instanceof Error)) {
|
|
804
|
+
return false;
|
|
805
|
+
}
|
|
806
|
+
return "code" in error && "errno" in error;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
// src/interceptors/ClientRequest/index.ts
|
|
810
|
+
var _ClientRequestInterceptor = class extends Interceptor {
|
|
811
|
+
constructor() {
|
|
812
|
+
super(_ClientRequestInterceptor.symbol);
|
|
813
|
+
this.onRequest = async ({
|
|
814
|
+
request,
|
|
815
|
+
socket
|
|
816
|
+
}) => {
|
|
817
|
+
const requestId = Reflect.get(request, kRequestId);
|
|
818
|
+
const { interactiveRequest, requestController } = toInteractiveRequest(request);
|
|
819
|
+
this.emitter.once("request", ({ requestId: pendingRequestId }) => {
|
|
820
|
+
if (pendingRequestId !== requestId) {
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
if (requestController.responsePromise.state === "pending") {
|
|
824
|
+
this.logger.info(
|
|
825
|
+
"request has not been handled in listeners, executing fail-safe listener..."
|
|
826
|
+
);
|
|
827
|
+
requestController.responsePromise.resolve(void 0);
|
|
828
|
+
}
|
|
829
|
+
});
|
|
830
|
+
const listenerResult = await until(async () => {
|
|
831
|
+
await emitAsync(this.emitter, "request", {
|
|
832
|
+
requestId,
|
|
833
|
+
request: interactiveRequest
|
|
834
|
+
});
|
|
835
|
+
return await requestController.responsePromise;
|
|
836
|
+
});
|
|
837
|
+
if (listenerResult.error) {
|
|
838
|
+
if (listenerResult.error instanceof Response) {
|
|
839
|
+
socket.respondWith(listenerResult.error);
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
if (isNodeLikeError(listenerResult.error)) {
|
|
843
|
+
socket.errorWith(listenerResult.error);
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
if (this.emitter.listenerCount("unhandledException") > 0) {
|
|
847
|
+
await emitAsync(this.emitter, "unhandledException", {
|
|
848
|
+
error: listenerResult.error,
|
|
849
|
+
request,
|
|
850
|
+
requestId,
|
|
851
|
+
controller: {
|
|
852
|
+
respondWith: socket.respondWith.bind(socket),
|
|
853
|
+
errorWith: socket.errorWith.bind(socket)
|
|
854
|
+
}
|
|
855
|
+
});
|
|
856
|
+
if (!socket.connecting || socket.destroyed) {
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
socket.respondWith(createServerErrorResponse(listenerResult.error));
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
const mockedResponse = listenerResult.data;
|
|
864
|
+
if (mockedResponse) {
|
|
865
|
+
socket.respondWith(mockedResponse);
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
socket.passthrough();
|
|
869
|
+
};
|
|
870
|
+
this.onResponse = async ({
|
|
871
|
+
requestId,
|
|
872
|
+
request,
|
|
873
|
+
response,
|
|
874
|
+
isMockedResponse
|
|
875
|
+
}) => {
|
|
876
|
+
return emitAsync(this.emitter, "response", {
|
|
877
|
+
requestId,
|
|
878
|
+
request,
|
|
879
|
+
response,
|
|
880
|
+
isMockedResponse
|
|
881
|
+
});
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
setup() {
|
|
885
|
+
const { get: originalGet, request: originalRequest } = http2;
|
|
886
|
+
const { get: originalHttpsGet, request: originalHttpsRequest } = https2;
|
|
887
|
+
const onRequest = this.onRequest.bind(this);
|
|
888
|
+
const onResponse = this.onResponse.bind(this);
|
|
889
|
+
http2.request = new Proxy(http2.request, {
|
|
890
|
+
apply: (target, thisArg, args) => {
|
|
891
|
+
const [url, options, callback] = normalizeClientRequestArgs(
|
|
892
|
+
"http:",
|
|
893
|
+
args
|
|
894
|
+
);
|
|
895
|
+
const mockAgent = new MockAgent({
|
|
896
|
+
customAgent: options.agent,
|
|
897
|
+
onRequest,
|
|
898
|
+
onResponse
|
|
899
|
+
});
|
|
900
|
+
options.agent = mockAgent;
|
|
901
|
+
return Reflect.apply(target, thisArg, [url, options, callback]);
|
|
902
|
+
}
|
|
903
|
+
});
|
|
904
|
+
http2.get = new Proxy(http2.get, {
|
|
905
|
+
apply: (target, thisArg, args) => {
|
|
906
|
+
const [url, options, callback] = normalizeClientRequestArgs(
|
|
907
|
+
"http:",
|
|
908
|
+
args
|
|
909
|
+
);
|
|
910
|
+
const mockAgent = new MockAgent({
|
|
911
|
+
customAgent: options.agent,
|
|
912
|
+
onRequest,
|
|
913
|
+
onResponse
|
|
914
|
+
});
|
|
915
|
+
options.agent = mockAgent;
|
|
916
|
+
return Reflect.apply(target, thisArg, [url, options, callback]);
|
|
917
|
+
}
|
|
918
|
+
});
|
|
919
|
+
https2.request = new Proxy(https2.request, {
|
|
920
|
+
apply: (target, thisArg, args) => {
|
|
921
|
+
const [url, options, callback] = normalizeClientRequestArgs(
|
|
922
|
+
"https:",
|
|
923
|
+
args
|
|
924
|
+
);
|
|
925
|
+
const mockAgent = new MockHttpsAgent({
|
|
926
|
+
customAgent: options.agent,
|
|
927
|
+
onRequest,
|
|
928
|
+
onResponse
|
|
929
|
+
});
|
|
930
|
+
options.agent = mockAgent;
|
|
931
|
+
return Reflect.apply(target, thisArg, [url, options, callback]);
|
|
932
|
+
}
|
|
933
|
+
});
|
|
934
|
+
https2.get = new Proxy(https2.get, {
|
|
935
|
+
apply: (target, thisArg, args) => {
|
|
936
|
+
const [url, options, callback] = normalizeClientRequestArgs(
|
|
937
|
+
"https:",
|
|
938
|
+
args
|
|
939
|
+
);
|
|
940
|
+
const mockAgent = new MockHttpsAgent({
|
|
941
|
+
customAgent: options.agent,
|
|
942
|
+
onRequest,
|
|
943
|
+
onResponse
|
|
944
|
+
});
|
|
945
|
+
options.agent = mockAgent;
|
|
946
|
+
return Reflect.apply(target, thisArg, [url, options, callback]);
|
|
947
|
+
}
|
|
948
|
+
});
|
|
949
|
+
this.subscriptions.push(() => {
|
|
950
|
+
http2.get = originalGet;
|
|
951
|
+
http2.request = originalRequest;
|
|
952
|
+
https2.get = originalHttpsGet;
|
|
953
|
+
https2.request = originalHttpsRequest;
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
};
|
|
957
|
+
var ClientRequestInterceptor = _ClientRequestInterceptor;
|
|
958
|
+
ClientRequestInterceptor.symbol = Symbol("client-request-interceptor");
|
|
959
|
+
|
|
960
|
+
export {
|
|
961
|
+
ClientRequestInterceptor
|
|
962
|
+
};
|
|
963
|
+
//# sourceMappingURL=chunk-3OJLYEWA.mjs.map
|