@mswjs/interceptors 0.39.8 → 0.41.0
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/ClientRequest/package.json +7 -2
- package/RemoteHttpInterceptor/package.json +7 -2
- package/WebSocket/package.json +9 -2
- package/XMLHttpRequest/package.json +9 -3
- package/fetch/package.json +9 -3
- package/lib/browser/Interceptor-2mUoKZL1.d.mts +65 -0
- package/lib/browser/Interceptor-Deczogc8.d.cts +65 -0
- package/lib/browser/XMLHttpRequest-BUfglQD1.cjs +761 -0
- package/lib/browser/XMLHttpRequest-BUfglQD1.cjs.map +1 -0
- package/lib/browser/XMLHttpRequest-DS5fc8Qs.mjs +756 -0
- package/lib/browser/XMLHttpRequest-DS5fc8Qs.mjs.map +1 -0
- package/lib/browser/bufferUtils-BiiO6HZv.mjs +20 -0
- package/lib/browser/bufferUtils-BiiO6HZv.mjs.map +1 -0
- package/lib/browser/bufferUtils-Uc0eRItL.cjs +38 -0
- package/lib/browser/bufferUtils-Uc0eRItL.cjs.map +1 -0
- package/lib/browser/createRequestId-Cs4oXfa1.cjs +205 -0
- package/lib/browser/createRequestId-Cs4oXfa1.cjs.map +1 -0
- package/lib/browser/createRequestId-DQcIlohW.mjs +170 -0
- package/lib/browser/createRequestId-DQcIlohW.mjs.map +1 -0
- package/lib/browser/fetch-BHcqM3z7.cjs +253 -0
- package/lib/browser/fetch-BHcqM3z7.cjs.map +1 -0
- package/lib/browser/fetch-DSJoynSF.mjs +248 -0
- package/lib/browser/fetch-DSJoynSF.mjs.map +1 -0
- package/lib/browser/getRawRequest-BTaNLFr0.mjs +218 -0
- package/lib/browser/getRawRequest-BTaNLFr0.mjs.map +1 -0
- package/lib/browser/getRawRequest-zx8rUJL2.cjs +259 -0
- package/lib/browser/getRawRequest-zx8rUJL2.cjs.map +1 -0
- package/lib/browser/glossary-BdLS4k1H.d.cts +70 -0
- package/lib/browser/glossary-gEEJhK4S.d.mts +70 -0
- package/lib/browser/handleRequest-DI6a7Dty.cjs +189 -0
- package/lib/browser/handleRequest-DI6a7Dty.cjs.map +1 -0
- package/lib/browser/handleRequest-DxGbCTbb.mjs +178 -0
- package/lib/browser/handleRequest-DxGbCTbb.mjs.map +1 -0
- package/lib/browser/hasConfigurableGlobal-C8kXFDic.mjs +33 -0
- package/lib/browser/hasConfigurableGlobal-C8kXFDic.mjs.map +1 -0
- package/lib/browser/hasConfigurableGlobal-D7S3l5h6.cjs +45 -0
- package/lib/browser/hasConfigurableGlobal-D7S3l5h6.cjs.map +1 -0
- package/lib/browser/index.cjs +68 -0
- package/lib/browser/index.cjs.map +1 -0
- package/lib/browser/index.d.cts +87 -0
- package/lib/browser/index.d.mts +87 -0
- package/lib/browser/index.mjs +49 -75
- package/lib/browser/index.mjs.map +1 -1
- package/lib/browser/interceptors/WebSocket/index.cjs +621 -0
- package/lib/browser/interceptors/WebSocket/index.cjs.map +1 -0
- package/lib/browser/interceptors/WebSocket/index.d.cts +277 -0
- package/lib/browser/interceptors/WebSocket/index.d.mts +277 -0
- package/lib/browser/interceptors/WebSocket/index.mjs +587 -694
- package/lib/browser/interceptors/WebSocket/index.mjs.map +1 -1
- package/lib/browser/interceptors/XMLHttpRequest/index.cjs +7 -0
- package/lib/browser/interceptors/XMLHttpRequest/index.d.cts +15 -0
- package/lib/browser/interceptors/XMLHttpRequest/index.d.mts +15 -0
- package/lib/browser/interceptors/XMLHttpRequest/index.mjs +7 -12
- package/lib/browser/interceptors/fetch/index.cjs +6 -0
- package/lib/browser/interceptors/fetch/index.d.cts +13 -0
- package/lib/browser/interceptors/fetch/index.d.mts +13 -0
- package/lib/browser/interceptors/fetch/index.mjs +6 -11
- package/lib/browser/presets/browser.cjs +17 -0
- package/lib/browser/presets/browser.cjs.map +1 -0
- package/lib/browser/presets/browser.d.cts +12 -0
- package/lib/browser/presets/browser.d.mts +14 -0
- package/lib/browser/presets/browser.mjs +15 -19
- package/lib/browser/presets/browser.mjs.map +1 -1
- package/lib/node/BatchInterceptor-3LnAnLTx.cjs +49 -0
- package/lib/node/BatchInterceptor-3LnAnLTx.cjs.map +1 -0
- package/lib/node/BatchInterceptor-D7mXzHcQ.d.mts +26 -0
- package/lib/node/BatchInterceptor-DFaBPilf.mjs +44 -0
- package/lib/node/BatchInterceptor-DFaBPilf.mjs.map +1 -0
- package/lib/node/BatchInterceptor-D_YqR8qU.d.cts +26 -0
- package/lib/node/ClientRequest-2rDe54Ui.cjs +1043 -0
- package/lib/node/ClientRequest-2rDe54Ui.cjs.map +1 -0
- package/lib/node/ClientRequest-Ca8Qykuv.mjs +1034 -0
- package/lib/node/ClientRequest-Ca8Qykuv.mjs.map +1 -0
- package/lib/node/Interceptor-DEazpLJd.d.mts +133 -0
- package/lib/node/Interceptor-DJ2akVWI.d.cts +133 -0
- package/lib/node/RemoteHttpInterceptor.cjs +154 -0
- package/lib/node/RemoteHttpInterceptor.cjs.map +1 -0
- package/lib/node/RemoteHttpInterceptor.d.cts +39 -0
- package/lib/node/RemoteHttpInterceptor.d.mts +39 -0
- package/lib/node/RemoteHttpInterceptor.mjs +145 -186
- package/lib/node/RemoteHttpInterceptor.mjs.map +1 -1
- package/lib/node/XMLHttpRequest-B7kJdYYI.cjs +763 -0
- package/lib/node/XMLHttpRequest-B7kJdYYI.cjs.map +1 -0
- package/lib/node/XMLHttpRequest-C8dIZpds.mjs +757 -0
- package/lib/node/XMLHttpRequest-C8dIZpds.mjs.map +1 -0
- package/lib/node/bufferUtils-DiCTqG-7.cjs +38 -0
- package/lib/node/bufferUtils-DiCTqG-7.cjs.map +1 -0
- package/lib/node/bufferUtils-_8XfKIfX.mjs +20 -0
- package/lib/node/bufferUtils-_8XfKIfX.mjs.map +1 -0
- package/lib/node/chunk-CbDLau6x.cjs +34 -0
- package/lib/node/fetch-BmXpK10r.cjs +272 -0
- package/lib/node/fetch-BmXpK10r.cjs.map +1 -0
- package/lib/node/fetch-G1DVwDKG.mjs +265 -0
- package/lib/node/fetch-G1DVwDKG.mjs.map +1 -0
- package/lib/node/fetchUtils-BaY5iWXw.cjs +419 -0
- package/lib/node/fetchUtils-BaY5iWXw.cjs.map +1 -0
- package/lib/node/fetchUtils-CoU35g3M.mjs +359 -0
- package/lib/node/fetchUtils-CoU35g3M.mjs.map +1 -0
- package/lib/node/getRawRequest-BavnMWh_.cjs +36 -0
- package/lib/node/getRawRequest-BavnMWh_.cjs.map +1 -0
- package/lib/node/getRawRequest-DnwmXyOW.mjs +24 -0
- package/lib/node/getRawRequest-DnwmXyOW.mjs.map +1 -0
- package/lib/node/glossary-BLKRyLBd.cjs +12 -0
- package/lib/node/glossary-BLKRyLBd.cjs.map +1 -0
- package/lib/node/glossary-glQBRnVD.mjs +6 -0
- package/lib/node/glossary-glQBRnVD.mjs.map +1 -0
- package/lib/node/handleRequest-Bb7Y-XLw.cjs +220 -0
- package/lib/node/handleRequest-Bb7Y-XLw.cjs.map +1 -0
- package/lib/node/handleRequest-Y97UwBbF.mjs +190 -0
- package/lib/node/handleRequest-Y97UwBbF.mjs.map +1 -0
- package/lib/node/hasConfigurableGlobal-C97fWuaA.cjs +26 -0
- package/lib/node/hasConfigurableGlobal-C97fWuaA.cjs.map +1 -0
- package/lib/node/hasConfigurableGlobal-DBJA0vjm.mjs +20 -0
- package/lib/node/hasConfigurableGlobal-DBJA0vjm.mjs.map +1 -0
- package/lib/node/index-BMbJ8FXL.d.cts +113 -0
- package/lib/node/index-C0YAQ36w.d.mts +113 -0
- package/lib/node/index.cjs +30 -0
- package/lib/node/index.cjs.map +1 -0
- package/lib/node/index.d.cts +66 -0
- package/lib/node/index.d.mts +66 -0
- package/lib/node/index.mjs +13 -39
- package/lib/node/index.mjs.map +1 -1
- package/lib/node/interceptors/ClientRequest/index.cjs +6 -0
- package/lib/node/interceptors/ClientRequest/index.d.cts +2 -0
- package/lib/node/interceptors/ClientRequest/index.d.mts +3 -0
- package/lib/node/interceptors/ClientRequest/index.mjs +6 -11
- package/lib/node/interceptors/XMLHttpRequest/index.cjs +6 -0
- package/lib/node/interceptors/XMLHttpRequest/index.d.cts +14 -0
- package/lib/node/interceptors/XMLHttpRequest/index.d.mts +14 -0
- package/lib/node/interceptors/XMLHttpRequest/index.mjs +6 -13
- package/lib/node/interceptors/fetch/index.cjs +5 -0
- package/lib/node/interceptors/fetch/index.d.cts +12 -0
- package/lib/node/interceptors/fetch/index.d.mts +12 -0
- package/lib/node/interceptors/fetch/index.mjs +5 -12
- package/lib/node/node-DwCc6iuP.mjs +27 -0
- package/lib/node/node-DwCc6iuP.mjs.map +1 -0
- package/lib/node/node-dKdAf3tC.cjs +39 -0
- package/lib/node/node-dKdAf3tC.cjs.map +1 -0
- package/lib/node/presets/node.cjs +22 -0
- package/lib/node/presets/node.cjs.map +1 -0
- package/lib/node/presets/node.d.cts +13 -0
- package/lib/node/presets/node.d.mts +15 -0
- package/lib/node/presets/node.mjs +18 -23
- package/lib/node/presets/node.mjs.map +1 -1
- package/lib/node/utils/node/index.cjs +4 -0
- package/lib/node/utils/node/{index.d.ts → index.d.cts} +5 -2
- package/lib/node/utils/node/index.d.mts +16 -0
- package/lib/node/utils/node/index.mjs +3 -10
- package/package.json +34 -59
- package/presets/browser/package.json +2 -3
- package/presets/node/package.json +7 -2
- package/src/RemoteHttpInterceptor.ts +18 -13
- package/src/RequestController.test.ts +78 -31
- package/src/RequestController.ts +63 -39
- package/src/index.ts +4 -0
- package/src/interceptors/ClientRequest/MockHttpSocket.ts +43 -9
- package/src/interceptors/ClientRequest/index.ts +14 -18
- package/src/interceptors/ClientRequest/utils/parserUtils.ts +48 -0
- package/src/interceptors/WebSocket/index.ts +4 -1
- package/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts +45 -35
- package/src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts +24 -21
- package/src/interceptors/XMLHttpRequest/utils/getBodyByteLength.test.ts +2 -2
- package/src/interceptors/fetch/index.ts +61 -50
- package/src/utils/handleRequest.ts +65 -95
- package/lib/browser/Interceptor-af98b768.d.ts +0 -63
- package/lib/browser/chunk-2HUMWGRD.js +0 -37
- package/lib/browser/chunk-2HUMWGRD.js.map +0 -1
- package/lib/browser/chunk-2QICSCCS.js +0 -238
- package/lib/browser/chunk-2QICSCCS.js.map +0 -1
- package/lib/browser/chunk-3RXCRGL2.mjs +0 -117
- package/lib/browser/chunk-3RXCRGL2.mjs.map +0 -1
- package/lib/browser/chunk-6HYIRFX2.mjs +0 -22
- package/lib/browser/chunk-6HYIRFX2.mjs.map +0 -1
- package/lib/browser/chunk-E3CCOBRX.js +0 -846
- package/lib/browser/chunk-E3CCOBRX.js.map +0 -1
- package/lib/browser/chunk-E7UVBHVO.mjs +0 -846
- package/lib/browser/chunk-E7UVBHVO.mjs.map +0 -1
- package/lib/browser/chunk-H74PGQ4Y.js +0 -296
- package/lib/browser/chunk-H74PGQ4Y.js.map +0 -1
- package/lib/browser/chunk-LK6DILFK.js +0 -22
- package/lib/browser/chunk-LK6DILFK.js.map +0 -1
- package/lib/browser/chunk-PTTUYYVR.mjs +0 -238
- package/lib/browser/chunk-PTTUYYVR.mjs.map +0 -1
- package/lib/browser/chunk-Q7K2XAEP.mjs +0 -296
- package/lib/browser/chunk-Q7K2XAEP.mjs.map +0 -1
- package/lib/browser/chunk-QED3Q6Z2.mjs +0 -169
- package/lib/browser/chunk-QED3Q6Z2.mjs.map +0 -1
- package/lib/browser/chunk-T7TBRNJZ.js +0 -117
- package/lib/browser/chunk-T7TBRNJZ.js.map +0 -1
- package/lib/browser/chunk-TIPR373R.js +0 -169
- package/lib/browser/chunk-TIPR373R.js.map +0 -1
- package/lib/browser/chunk-VYSDLBSS.mjs +0 -37
- package/lib/browser/chunk-VYSDLBSS.mjs.map +0 -1
- package/lib/browser/glossary-7152281e.d.ts +0 -69
- package/lib/browser/index.d.ts +0 -83
- package/lib/browser/index.js +0 -81
- package/lib/browser/index.js.map +0 -1
- package/lib/browser/interceptors/WebSocket/index.d.ts +0 -271
- package/lib/browser/interceptors/WebSocket/index.js +0 -721
- package/lib/browser/interceptors/WebSocket/index.js.map +0 -1
- package/lib/browser/interceptors/XMLHttpRequest/index.d.ts +0 -15
- package/lib/browser/interceptors/XMLHttpRequest/index.js +0 -12
- package/lib/browser/interceptors/XMLHttpRequest/index.js.map +0 -1
- package/lib/browser/interceptors/XMLHttpRequest/index.mjs.map +0 -1
- package/lib/browser/interceptors/fetch/index.d.ts +0 -14
- package/lib/browser/interceptors/fetch/index.js +0 -11
- package/lib/browser/interceptors/fetch/index.js.map +0 -1
- package/lib/browser/interceptors/fetch/index.mjs.map +0 -1
- package/lib/browser/presets/browser.d.ts +0 -15
- package/lib/browser/presets/browser.js +0 -21
- package/lib/browser/presets/browser.js.map +0 -1
- package/lib/node/BatchInterceptor-5b72232f.d.ts +0 -24
- package/lib/node/Interceptor-bc5a9d8e.d.ts +0 -130
- package/lib/node/RemoteHttpInterceptor.d.ts +0 -45
- package/lib/node/RemoteHttpInterceptor.js +0 -193
- package/lib/node/RemoteHttpInterceptor.js.map +0 -1
- package/lib/node/chunk-3CNGDJFB.mjs +0 -313
- package/lib/node/chunk-3CNGDJFB.mjs.map +0 -1
- package/lib/node/chunk-3GJB4JDF.mjs +0 -14
- package/lib/node/chunk-3GJB4JDF.mjs.map +0 -1
- package/lib/node/chunk-4NEYTVWD.mjs +0 -848
- package/lib/node/chunk-4NEYTVWD.mjs.map +0 -1
- package/lib/node/chunk-4YBV77DG.js +0 -32
- package/lib/node/chunk-4YBV77DG.js.map +0 -1
- package/lib/node/chunk-6HYIRFX2.mjs +0 -22
- package/lib/node/chunk-6HYIRFX2.mjs.map +0 -1
- package/lib/node/chunk-6YM4PLBI.mjs +0 -7
- package/lib/node/chunk-6YM4PLBI.mjs.map +0 -1
- package/lib/node/chunk-72ZIHMEB.js +0 -249
- package/lib/node/chunk-72ZIHMEB.js.map +0 -1
- package/lib/node/chunk-73NOP3T5.js +0 -7
- package/lib/node/chunk-73NOP3T5.js.map +0 -1
- package/lib/node/chunk-A7Q4RTDJ.mjs +0 -249
- package/lib/node/chunk-A7Q4RTDJ.mjs.map +0 -1
- package/lib/node/chunk-A7U44ARP.js +0 -268
- package/lib/node/chunk-A7U44ARP.js.map +0 -1
- package/lib/node/chunk-EKNRB5ZS.mjs +0 -1115
- package/lib/node/chunk-EKNRB5ZS.mjs.map +0 -1
- package/lib/node/chunk-IHJSPMYM.mjs +0 -268
- package/lib/node/chunk-IHJSPMYM.mjs.map +0 -1
- package/lib/node/chunk-LK6DILFK.js +0 -22
- package/lib/node/chunk-LK6DILFK.js.map +0 -1
- package/lib/node/chunk-N4ZZFE24.js +0 -1115
- package/lib/node/chunk-N4ZZFE24.js.map +0 -1
- package/lib/node/chunk-PFGO5BSM.js +0 -25
- package/lib/node/chunk-PFGO5BSM.js.map +0 -1
- package/lib/node/chunk-R6JVCM7X.js +0 -51
- package/lib/node/chunk-R6JVCM7X.js.map +0 -1
- package/lib/node/chunk-RC2XPCC4.mjs +0 -51
- package/lib/node/chunk-RC2XPCC4.mjs.map +0 -1
- package/lib/node/chunk-SMXZPJEA.js +0 -14
- package/lib/node/chunk-SMXZPJEA.js.map +0 -1
- package/lib/node/chunk-TJDMZZXE.mjs +0 -32
- package/lib/node/chunk-TJDMZZXE.mjs.map +0 -1
- package/lib/node/chunk-TX5GBTFY.mjs +0 -25
- package/lib/node/chunk-TX5GBTFY.mjs.map +0 -1
- package/lib/node/chunk-VV2LUF5K.js +0 -848
- package/lib/node/chunk-VV2LUF5K.js.map +0 -1
- package/lib/node/chunk-Z5LWCBZS.js +0 -313
- package/lib/node/chunk-Z5LWCBZS.js.map +0 -1
- package/lib/node/index.d.ts +0 -62
- package/lib/node/index.js +0 -43
- package/lib/node/index.js.map +0 -1
- package/lib/node/interceptors/ClientRequest/index.d.ts +0 -111
- package/lib/node/interceptors/ClientRequest/index.js +0 -11
- package/lib/node/interceptors/ClientRequest/index.js.map +0 -1
- package/lib/node/interceptors/ClientRequest/index.mjs.map +0 -1
- package/lib/node/interceptors/XMLHttpRequest/index.d.ts +0 -14
- package/lib/node/interceptors/XMLHttpRequest/index.js +0 -13
- package/lib/node/interceptors/XMLHttpRequest/index.js.map +0 -1
- package/lib/node/interceptors/XMLHttpRequest/index.mjs.map +0 -1
- package/lib/node/interceptors/fetch/index.d.ts +0 -13
- package/lib/node/interceptors/fetch/index.js +0 -12
- package/lib/node/interceptors/fetch/index.js.map +0 -1
- package/lib/node/interceptors/fetch/index.mjs.map +0 -1
- package/lib/node/presets/node.d.ts +0 -16
- package/lib/node/presets/node.js +0 -27
- package/lib/node/presets/node.js.map +0 -1
- package/lib/node/utils/node/index.js +0 -10
- package/lib/node/utils/node/index.js.map +0 -1
- package/lib/node/utils/node/index.mjs.map +0 -1
- package/src/utils/RequestController.ts +0 -21
|
@@ -0,0 +1,1043 @@
|
|
|
1
|
+
const require_chunk = require('./chunk-CbDLau6x.cjs');
|
|
2
|
+
const require_fetchUtils = require('./fetchUtils-BaY5iWXw.cjs');
|
|
3
|
+
const require_getRawRequest = require('./getRawRequest-BavnMWh_.cjs');
|
|
4
|
+
const require_handleRequest = require('./handleRequest-Bb7Y-XLw.cjs');
|
|
5
|
+
const require_node = require('./node-dKdAf3tC.cjs');
|
|
6
|
+
let _open_draft_logger = require("@open-draft/logger");
|
|
7
|
+
let outvariant = require("outvariant");
|
|
8
|
+
let node_http = require("node:http");
|
|
9
|
+
node_http = require_chunk.__toESM(node_http);
|
|
10
|
+
let node_https = require("node:https");
|
|
11
|
+
node_https = require_chunk.__toESM(node_https);
|
|
12
|
+
let node_net = require("node:net");
|
|
13
|
+
node_net = require_chunk.__toESM(node_net);
|
|
14
|
+
let _http_common = require("_http_common");
|
|
15
|
+
let node_stream = require("node:stream");
|
|
16
|
+
let node_url = require("node:url");
|
|
17
|
+
let http = require("http");
|
|
18
|
+
|
|
19
|
+
//#region src/interceptors/Socket/utils/normalizeSocketWriteArgs.ts
|
|
20
|
+
/**
|
|
21
|
+
* Normalizes the arguments provided to the `Writable.prototype.write()`
|
|
22
|
+
* and `Writable.prototype.end()`.
|
|
23
|
+
*/
|
|
24
|
+
function normalizeSocketWriteArgs(args) {
|
|
25
|
+
const normalized = [
|
|
26
|
+
args[0],
|
|
27
|
+
void 0,
|
|
28
|
+
void 0
|
|
29
|
+
];
|
|
30
|
+
if (typeof args[1] === "string") normalized[1] = args[1];
|
|
31
|
+
else if (typeof args[1] === "function") normalized[2] = args[1];
|
|
32
|
+
if (typeof args[2] === "function") normalized[2] = args[2];
|
|
33
|
+
return normalized;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/interceptors/Socket/MockSocket.ts
|
|
38
|
+
var MockSocket = class extends node_net.default.Socket {
|
|
39
|
+
constructor(options) {
|
|
40
|
+
super();
|
|
41
|
+
this.options = options;
|
|
42
|
+
this.connecting = false;
|
|
43
|
+
this.connect();
|
|
44
|
+
this._final = (callback) => {
|
|
45
|
+
callback(null);
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
connect() {
|
|
49
|
+
this.connecting = true;
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
write(...args) {
|
|
53
|
+
const [chunk, encoding, callback] = normalizeSocketWriteArgs(args);
|
|
54
|
+
this.options.write(chunk, encoding, callback);
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
end(...args) {
|
|
58
|
+
const [chunk, encoding, callback] = normalizeSocketWriteArgs(args);
|
|
59
|
+
this.options.write(chunk, encoding, callback);
|
|
60
|
+
return super.end.apply(this, args);
|
|
61
|
+
}
|
|
62
|
+
push(chunk, encoding) {
|
|
63
|
+
this.options.read(chunk, encoding);
|
|
64
|
+
return super.push(chunk, encoding);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/interceptors/Socket/utils/baseUrlFromConnectionOptions.ts
|
|
70
|
+
function baseUrlFromConnectionOptions(options) {
|
|
71
|
+
if ("href" in options) return new URL(options.href);
|
|
72
|
+
const protocol = options.port === 443 ? "https:" : "http:";
|
|
73
|
+
const host = options.host;
|
|
74
|
+
const url = new URL(`${protocol}//${host}`);
|
|
75
|
+
if (options.port) url.port = options.port.toString();
|
|
76
|
+
if (options.path) url.pathname = options.path;
|
|
77
|
+
if (options.auth) {
|
|
78
|
+
const [username, password] = options.auth.split(":");
|
|
79
|
+
url.username = username;
|
|
80
|
+
url.password = password;
|
|
81
|
+
}
|
|
82
|
+
return url;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
//#endregion
|
|
86
|
+
//#region src/interceptors/ClientRequest/utils/recordRawHeaders.ts
|
|
87
|
+
const kRawHeaders = Symbol("kRawHeaders");
|
|
88
|
+
const kRestorePatches = Symbol("kRestorePatches");
|
|
89
|
+
function recordRawHeader(headers, args, behavior) {
|
|
90
|
+
ensureRawHeadersSymbol(headers, []);
|
|
91
|
+
const rawHeaders = Reflect.get(headers, kRawHeaders);
|
|
92
|
+
if (behavior === "set") {
|
|
93
|
+
for (let index = rawHeaders.length - 1; index >= 0; index--) if (rawHeaders[index][0].toLowerCase() === args[0].toLowerCase()) rawHeaders.splice(index, 1);
|
|
94
|
+
}
|
|
95
|
+
rawHeaders.push(args);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Define the raw headers symbol on the given `Headers` instance.
|
|
99
|
+
* If the symbol already exists, this function does nothing.
|
|
100
|
+
*/
|
|
101
|
+
function ensureRawHeadersSymbol(headers, rawHeaders) {
|
|
102
|
+
if (Reflect.has(headers, kRawHeaders)) return;
|
|
103
|
+
defineRawHeadersSymbol(headers, rawHeaders);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Define the raw headers symbol on the given `Headers` instance.
|
|
107
|
+
* If the symbol already exists, it gets overridden.
|
|
108
|
+
*/
|
|
109
|
+
function defineRawHeadersSymbol(headers, rawHeaders) {
|
|
110
|
+
Object.defineProperty(headers, kRawHeaders, {
|
|
111
|
+
value: rawHeaders,
|
|
112
|
+
enumerable: false,
|
|
113
|
+
configurable: true
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Patch the global `Headers` class to store raw headers.
|
|
118
|
+
* This is for compatibility with `IncomingMessage.prototype.rawHeaders`.
|
|
119
|
+
*
|
|
120
|
+
* @note Node.js has their own raw headers symbol but it
|
|
121
|
+
* only records the first header name in case of multi-value headers.
|
|
122
|
+
* Any other headers are normalized before comparing. This makes it
|
|
123
|
+
* incompatible with the `rawHeaders` format.
|
|
124
|
+
*
|
|
125
|
+
* let h = new Headers()
|
|
126
|
+
* h.append('X-Custom', 'one')
|
|
127
|
+
* h.append('x-custom', 'two')
|
|
128
|
+
* h[Symbol('headers map')] // Map { 'X-Custom' => 'one, two' }
|
|
129
|
+
*/
|
|
130
|
+
function recordRawFetchHeaders() {
|
|
131
|
+
if (Reflect.get(Headers, kRestorePatches)) return Reflect.get(Headers, kRestorePatches);
|
|
132
|
+
const { Headers: OriginalHeaders, Request: OriginalRequest, Response: OriginalResponse } = globalThis;
|
|
133
|
+
const { set, append, delete: headersDeleteMethod } = Headers.prototype;
|
|
134
|
+
Object.defineProperty(Headers, kRestorePatches, {
|
|
135
|
+
value: () => {
|
|
136
|
+
Headers.prototype.set = set;
|
|
137
|
+
Headers.prototype.append = append;
|
|
138
|
+
Headers.prototype.delete = headersDeleteMethod;
|
|
139
|
+
globalThis.Headers = OriginalHeaders;
|
|
140
|
+
globalThis.Request = OriginalRequest;
|
|
141
|
+
globalThis.Response = OriginalResponse;
|
|
142
|
+
Reflect.deleteProperty(Headers, kRestorePatches);
|
|
143
|
+
},
|
|
144
|
+
enumerable: false,
|
|
145
|
+
configurable: true
|
|
146
|
+
});
|
|
147
|
+
Object.defineProperty(globalThis, "Headers", {
|
|
148
|
+
enumerable: true,
|
|
149
|
+
writable: true,
|
|
150
|
+
value: new Proxy(Headers, { construct(target, args, newTarget) {
|
|
151
|
+
const headersInit = args[0] || [];
|
|
152
|
+
if (headersInit instanceof Headers && Reflect.has(headersInit, kRawHeaders)) {
|
|
153
|
+
const headers$1 = Reflect.construct(target, [Reflect.get(headersInit, kRawHeaders)], newTarget);
|
|
154
|
+
ensureRawHeadersSymbol(headers$1, [...Reflect.get(headersInit, kRawHeaders)]);
|
|
155
|
+
return headers$1;
|
|
156
|
+
}
|
|
157
|
+
const headers = Reflect.construct(target, args, newTarget);
|
|
158
|
+
if (!Reflect.has(headers, kRawHeaders)) ensureRawHeadersSymbol(headers, Array.isArray(headersInit) ? headersInit : Object.entries(headersInit));
|
|
159
|
+
return headers;
|
|
160
|
+
} })
|
|
161
|
+
});
|
|
162
|
+
Headers.prototype.set = new Proxy(Headers.prototype.set, { apply(target, thisArg, args) {
|
|
163
|
+
recordRawHeader(thisArg, args, "set");
|
|
164
|
+
return Reflect.apply(target, thisArg, args);
|
|
165
|
+
} });
|
|
166
|
+
Headers.prototype.append = new Proxy(Headers.prototype.append, { apply(target, thisArg, args) {
|
|
167
|
+
recordRawHeader(thisArg, args, "append");
|
|
168
|
+
return Reflect.apply(target, thisArg, args);
|
|
169
|
+
} });
|
|
170
|
+
Headers.prototype.delete = new Proxy(Headers.prototype.delete, { apply(target, thisArg, args) {
|
|
171
|
+
const rawHeaders = Reflect.get(thisArg, kRawHeaders);
|
|
172
|
+
if (rawHeaders) {
|
|
173
|
+
for (let index = rawHeaders.length - 1; index >= 0; index--) if (rawHeaders[index][0].toLowerCase() === args[0].toLowerCase()) rawHeaders.splice(index, 1);
|
|
174
|
+
}
|
|
175
|
+
return Reflect.apply(target, thisArg, args);
|
|
176
|
+
} });
|
|
177
|
+
Object.defineProperty(globalThis, "Request", {
|
|
178
|
+
enumerable: true,
|
|
179
|
+
writable: true,
|
|
180
|
+
value: new Proxy(Request, { construct(target, args, newTarget) {
|
|
181
|
+
const request = Reflect.construct(target, args, newTarget);
|
|
182
|
+
const inferredRawHeaders = [];
|
|
183
|
+
if (typeof args[0] === "object" && args[0].headers != null) inferredRawHeaders.push(...inferRawHeaders(args[0].headers));
|
|
184
|
+
if (typeof args[1] === "object" && args[1].headers != null) inferredRawHeaders.push(...inferRawHeaders(args[1].headers));
|
|
185
|
+
if (inferredRawHeaders.length > 0) ensureRawHeadersSymbol(request.headers, inferredRawHeaders);
|
|
186
|
+
return request;
|
|
187
|
+
} })
|
|
188
|
+
});
|
|
189
|
+
Object.defineProperty(globalThis, "Response", {
|
|
190
|
+
enumerable: true,
|
|
191
|
+
writable: true,
|
|
192
|
+
value: new Proxy(Response, { construct(target, args, newTarget) {
|
|
193
|
+
const response = Reflect.construct(target, args, newTarget);
|
|
194
|
+
if (typeof args[1] === "object" && args[1].headers != null) ensureRawHeadersSymbol(response.headers, inferRawHeaders(args[1].headers));
|
|
195
|
+
return response;
|
|
196
|
+
} })
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
function restoreHeadersPrototype() {
|
|
200
|
+
if (!Reflect.get(Headers, kRestorePatches)) return;
|
|
201
|
+
Reflect.get(Headers, kRestorePatches)();
|
|
202
|
+
}
|
|
203
|
+
function getRawFetchHeaders(headers) {
|
|
204
|
+
if (!Reflect.has(headers, kRawHeaders)) return Array.from(headers.entries());
|
|
205
|
+
const rawHeaders = Reflect.get(headers, kRawHeaders);
|
|
206
|
+
return rawHeaders.length > 0 ? rawHeaders : Array.from(headers.entries());
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Infers the raw headers from the given `HeadersInit` provided
|
|
210
|
+
* to the Request/Response constructor.
|
|
211
|
+
*
|
|
212
|
+
* If the `init.headers` is a Headers instance, use it directly.
|
|
213
|
+
* That means the headers were created standalone and already have
|
|
214
|
+
* the raw headers stored.
|
|
215
|
+
* If the `init.headers` is a HeadersInit, create a new Headers
|
|
216
|
+
* instance out of it.
|
|
217
|
+
*/
|
|
218
|
+
function inferRawHeaders(headers) {
|
|
219
|
+
if (headers instanceof Headers) return Reflect.get(headers, kRawHeaders) || [];
|
|
220
|
+
return Reflect.get(new Headers(headers), kRawHeaders);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
//#endregion
|
|
224
|
+
//#region src/interceptors/ClientRequest/utils/parserUtils.ts
|
|
225
|
+
/**
|
|
226
|
+
* @see https://github.com/nodejs/node/blob/f3adc11e37b8bfaaa026ea85c1cf22e3a0e29ae9/lib/_http_common.js#L180
|
|
227
|
+
*/
|
|
228
|
+
function freeParser(parser, socket) {
|
|
229
|
+
if (parser._consumed) parser.unconsume();
|
|
230
|
+
parser._headers = [];
|
|
231
|
+
parser._url = "";
|
|
232
|
+
parser.socket = null;
|
|
233
|
+
parser.incoming = null;
|
|
234
|
+
parser.outgoing = null;
|
|
235
|
+
parser.maxHeaderPairs = 2e3;
|
|
236
|
+
parser._consumed = false;
|
|
237
|
+
parser.onIncoming = null;
|
|
238
|
+
parser[_http_common.HTTPParser.kOnHeaders] = null;
|
|
239
|
+
parser[_http_common.HTTPParser.kOnHeadersComplete] = null;
|
|
240
|
+
parser[_http_common.HTTPParser.kOnMessageBegin] = null;
|
|
241
|
+
parser[_http_common.HTTPParser.kOnMessageComplete] = null;
|
|
242
|
+
parser[_http_common.HTTPParser.kOnBody] = null;
|
|
243
|
+
parser[_http_common.HTTPParser.kOnExecute] = null;
|
|
244
|
+
parser[_http_common.HTTPParser.kOnTimeout] = null;
|
|
245
|
+
parser.remove();
|
|
246
|
+
parser.free();
|
|
247
|
+
if (socket)
|
|
248
|
+
/**
|
|
249
|
+
* @note Unassigning the socket's parser will fail this assertion
|
|
250
|
+
* if there's still some data being processed on the socket:
|
|
251
|
+
* @see https://github.com/nodejs/node/blob/4e1f39b678b37017ac9baa0971e3aeecd3b67b51/lib/_http_client.js#L613
|
|
252
|
+
*/
|
|
253
|
+
if (socket.destroyed) socket.parser = null;
|
|
254
|
+
else socket.once("end", () => {
|
|
255
|
+
socket.parser = null;
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
//#endregion
|
|
260
|
+
//#region src/interceptors/ClientRequest/MockHttpSocket.ts
|
|
261
|
+
const kRequestId = Symbol("kRequestId");
|
|
262
|
+
var MockHttpSocket = class extends MockSocket {
|
|
263
|
+
constructor(options) {
|
|
264
|
+
super({
|
|
265
|
+
write: (chunk, encoding, callback) => {
|
|
266
|
+
if (this.socketState !== "passthrough") this.writeBuffer.push([
|
|
267
|
+
chunk,
|
|
268
|
+
encoding,
|
|
269
|
+
callback
|
|
270
|
+
]);
|
|
271
|
+
if (chunk) {
|
|
272
|
+
/**
|
|
273
|
+
* Forward any writes to the mock socket to the underlying original socket.
|
|
274
|
+
* This ensures functional duplex connections, like WebSocket.
|
|
275
|
+
* @see https://github.com/mswjs/interceptors/issues/682
|
|
276
|
+
*/
|
|
277
|
+
if (this.socketState === "passthrough") this.originalSocket?.write(chunk, encoding, callback);
|
|
278
|
+
this.requestParser.execute(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding));
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
read: (chunk) => {
|
|
282
|
+
if (chunk !== null)
|
|
283
|
+
/**
|
|
284
|
+
* @todo We need to free the parser if the connection has been
|
|
285
|
+
* upgraded to a non-HTTP protocol. It won't be able to parse data
|
|
286
|
+
* from that point onward anyway. No need to keep it in memory.
|
|
287
|
+
*/
|
|
288
|
+
this.responseParser.execute(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
this.requestRawHeadersBuffer = [];
|
|
292
|
+
this.responseRawHeadersBuffer = [];
|
|
293
|
+
this.writeBuffer = [];
|
|
294
|
+
this.socketState = "unknown";
|
|
295
|
+
this.onRequestHeaders = (rawHeaders) => {
|
|
296
|
+
this.requestRawHeadersBuffer.push(...rawHeaders);
|
|
297
|
+
};
|
|
298
|
+
this.onRequestStart = (versionMajor, versionMinor, rawHeaders, _, path, __, ___, ____, shouldKeepAlive) => {
|
|
299
|
+
this.shouldKeepAlive = shouldKeepAlive;
|
|
300
|
+
const url = new URL(path || "", this.baseUrl);
|
|
301
|
+
const method = this.connectionOptions.method?.toUpperCase() || "GET";
|
|
302
|
+
const headers = require_fetchUtils.FetchResponse.parseRawHeaders([...this.requestRawHeadersBuffer, ...rawHeaders || []]);
|
|
303
|
+
this.requestRawHeadersBuffer.length = 0;
|
|
304
|
+
const canHaveBody = method !== "GET" && method !== "HEAD";
|
|
305
|
+
if (url.username || url.password) {
|
|
306
|
+
if (!headers.has("authorization")) headers.set("authorization", `Basic ${url.username}:${url.password}`);
|
|
307
|
+
url.username = "";
|
|
308
|
+
url.password = "";
|
|
309
|
+
}
|
|
310
|
+
this.requestStream = new node_stream.Readable({ read: () => {
|
|
311
|
+
this.flushWriteBuffer();
|
|
312
|
+
} });
|
|
313
|
+
const requestId = require_fetchUtils.createRequestId();
|
|
314
|
+
this.request = new Request(url, {
|
|
315
|
+
method,
|
|
316
|
+
headers,
|
|
317
|
+
credentials: "same-origin",
|
|
318
|
+
duplex: canHaveBody ? "half" : void 0,
|
|
319
|
+
body: canHaveBody ? node_stream.Readable.toWeb(this.requestStream) : null
|
|
320
|
+
});
|
|
321
|
+
Reflect.set(this.request, kRequestId, requestId);
|
|
322
|
+
require_getRawRequest.setRawRequest(this.request, Reflect.get(this, "_httpMessage"));
|
|
323
|
+
require_node.setRawRequestBodyStream(this.request, this.requestStream);
|
|
324
|
+
/**
|
|
325
|
+
* @fixme Stop relying on the "X-Request-Id" request header
|
|
326
|
+
* to figure out if one interceptor has been invoked within another.
|
|
327
|
+
* @see https://github.com/mswjs/interceptors/issues/378
|
|
328
|
+
*/
|
|
329
|
+
if (this.request.headers.has(require_fetchUtils.INTERNAL_REQUEST_ID_HEADER_NAME)) {
|
|
330
|
+
this.passthrough();
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
this.onRequest({
|
|
334
|
+
requestId,
|
|
335
|
+
request: this.request,
|
|
336
|
+
socket: this
|
|
337
|
+
});
|
|
338
|
+
};
|
|
339
|
+
this.onResponseHeaders = (rawHeaders) => {
|
|
340
|
+
this.responseRawHeadersBuffer.push(...rawHeaders);
|
|
341
|
+
};
|
|
342
|
+
this.onResponseStart = (versionMajor, versionMinor, rawHeaders, method, url, status, statusText) => {
|
|
343
|
+
const headers = require_fetchUtils.FetchResponse.parseRawHeaders([...this.responseRawHeadersBuffer, ...rawHeaders || []]);
|
|
344
|
+
this.responseRawHeadersBuffer.length = 0;
|
|
345
|
+
const response = new require_fetchUtils.FetchResponse(
|
|
346
|
+
/**
|
|
347
|
+
* @note The Fetch API response instance exposed to the consumer
|
|
348
|
+
* is created over the response stream of the HTTP parser. It is NOT
|
|
349
|
+
* related to the Socket instance. This way, you can read response body
|
|
350
|
+
* in response listener while the Socket instance delays the emission
|
|
351
|
+
* of "end" and other events until those response listeners are finished.
|
|
352
|
+
*/
|
|
353
|
+
require_fetchUtils.FetchResponse.isResponseWithBody(status) ? node_stream.Readable.toWeb(this.responseStream = new node_stream.Readable({ read() {} })) : null,
|
|
354
|
+
{
|
|
355
|
+
url,
|
|
356
|
+
status,
|
|
357
|
+
statusText,
|
|
358
|
+
headers
|
|
359
|
+
}
|
|
360
|
+
);
|
|
361
|
+
(0, outvariant.invariant)(this.request, "Failed to handle a response: request does not exist");
|
|
362
|
+
require_fetchUtils.FetchResponse.setUrl(this.request.url, response);
|
|
363
|
+
/**
|
|
364
|
+
* @fixme Stop relying on the "X-Request-Id" request header
|
|
365
|
+
* to figure out if one interceptor has been invoked within another.
|
|
366
|
+
* @see https://github.com/mswjs/interceptors/issues/378
|
|
367
|
+
*/
|
|
368
|
+
if (this.request.headers.has(require_fetchUtils.INTERNAL_REQUEST_ID_HEADER_NAME)) return;
|
|
369
|
+
this.responseListenersPromise = this.onResponse({
|
|
370
|
+
response,
|
|
371
|
+
isMockedResponse: this.socketState === "mock",
|
|
372
|
+
requestId: Reflect.get(this.request, kRequestId),
|
|
373
|
+
request: this.request,
|
|
374
|
+
socket: this
|
|
375
|
+
});
|
|
376
|
+
};
|
|
377
|
+
this.connectionOptions = options.connectionOptions;
|
|
378
|
+
this.createConnection = options.createConnection;
|
|
379
|
+
this.onRequest = options.onRequest;
|
|
380
|
+
this.onResponse = options.onResponse;
|
|
381
|
+
this.baseUrl = baseUrlFromConnectionOptions(this.connectionOptions);
|
|
382
|
+
this.requestParser = new _http_common.HTTPParser();
|
|
383
|
+
this.requestParser.initialize(_http_common.HTTPParser.REQUEST, {});
|
|
384
|
+
this.requestParser[_http_common.HTTPParser.kOnHeaders] = this.onRequestHeaders.bind(this);
|
|
385
|
+
this.requestParser[_http_common.HTTPParser.kOnHeadersComplete] = this.onRequestStart.bind(this);
|
|
386
|
+
this.requestParser[_http_common.HTTPParser.kOnBody] = this.onRequestBody.bind(this);
|
|
387
|
+
this.requestParser[_http_common.HTTPParser.kOnMessageComplete] = this.onRequestEnd.bind(this);
|
|
388
|
+
this.responseParser = new _http_common.HTTPParser();
|
|
389
|
+
this.responseParser.initialize(_http_common.HTTPParser.RESPONSE, {});
|
|
390
|
+
this.responseParser[_http_common.HTTPParser.kOnHeaders] = this.onResponseHeaders.bind(this);
|
|
391
|
+
this.responseParser[_http_common.HTTPParser.kOnHeadersComplete] = this.onResponseStart.bind(this);
|
|
392
|
+
this.responseParser[_http_common.HTTPParser.kOnBody] = this.onResponseBody.bind(this);
|
|
393
|
+
this.responseParser[_http_common.HTTPParser.kOnMessageComplete] = this.onResponseEnd.bind(this);
|
|
394
|
+
this.once("finish", () => freeParser(this.requestParser, this));
|
|
395
|
+
if (this.baseUrl.protocol === "https:") {
|
|
396
|
+
Reflect.set(this, "encrypted", true);
|
|
397
|
+
Reflect.set(this, "authorized", false);
|
|
398
|
+
Reflect.set(this, "getProtocol", () => "TLSv1.3");
|
|
399
|
+
Reflect.set(this, "getSession", () => void 0);
|
|
400
|
+
Reflect.set(this, "isSessionReused", () => false);
|
|
401
|
+
Reflect.set(this, "getCipher", () => ({
|
|
402
|
+
name: "AES256-SHA",
|
|
403
|
+
standardName: "TLS_RSA_WITH_AES_256_CBC_SHA",
|
|
404
|
+
version: "TLSv1.3"
|
|
405
|
+
}));
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
emit(event, ...args) {
|
|
409
|
+
const emitEvent = super.emit.bind(this, event, ...args);
|
|
410
|
+
if (this.responseListenersPromise) {
|
|
411
|
+
this.responseListenersPromise.finally(emitEvent);
|
|
412
|
+
return this.listenerCount(event) > 0;
|
|
413
|
+
}
|
|
414
|
+
return emitEvent();
|
|
415
|
+
}
|
|
416
|
+
destroy(error) {
|
|
417
|
+
freeParser(this.responseParser, this);
|
|
418
|
+
if (error) this.emit("error", error);
|
|
419
|
+
return super.destroy(error);
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Establish this Socket connection as-is and pipe
|
|
423
|
+
* its data/events through this Socket.
|
|
424
|
+
*/
|
|
425
|
+
passthrough() {
|
|
426
|
+
this.socketState = "passthrough";
|
|
427
|
+
if (this.destroyed) return;
|
|
428
|
+
const socket = this.createConnection();
|
|
429
|
+
this.originalSocket = socket;
|
|
430
|
+
/**
|
|
431
|
+
* @note Inherit the original socket's connection handle.
|
|
432
|
+
* Without this, each push to the mock socket results in a
|
|
433
|
+
* new "connection" listener being added (i.e. buffering pushes).
|
|
434
|
+
* @see https://github.com/nodejs/node/blob/b18153598b25485ce4f54d0c5cb830a9457691ee/lib/net.js#L734
|
|
435
|
+
*/
|
|
436
|
+
if ("_handle" in socket) Object.defineProperty(this, "_handle", {
|
|
437
|
+
value: socket._handle,
|
|
438
|
+
enumerable: true,
|
|
439
|
+
writable: true
|
|
440
|
+
});
|
|
441
|
+
this.once("close", () => {
|
|
442
|
+
socket.removeAllListeners();
|
|
443
|
+
if (!socket.destroyed) socket.destroy();
|
|
444
|
+
this.originalSocket = void 0;
|
|
445
|
+
});
|
|
446
|
+
this.address = socket.address.bind(socket);
|
|
447
|
+
let writeArgs;
|
|
448
|
+
let headersWritten = false;
|
|
449
|
+
while (writeArgs = this.writeBuffer.shift()) if (writeArgs !== void 0) {
|
|
450
|
+
if (!headersWritten) {
|
|
451
|
+
const [chunk, encoding, callback] = writeArgs;
|
|
452
|
+
const chunkString = chunk.toString();
|
|
453
|
+
const chunkBeforeRequestHeaders = chunkString.slice(0, chunkString.indexOf("\r\n") + 2);
|
|
454
|
+
const chunkAfterRequestHeaders = chunkString.slice(chunk.indexOf("\r\n\r\n"));
|
|
455
|
+
const headersChunk = `${chunkBeforeRequestHeaders}${getRawFetchHeaders(this.request.headers).filter(([name]) => {
|
|
456
|
+
return name.toLowerCase() !== require_fetchUtils.INTERNAL_REQUEST_ID_HEADER_NAME;
|
|
457
|
+
}).map(([name, value]) => `${name}: ${value}`).join("\r\n")}${chunkAfterRequestHeaders}`;
|
|
458
|
+
socket.write(headersChunk, encoding, callback);
|
|
459
|
+
headersWritten = true;
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
socket.write(...writeArgs);
|
|
463
|
+
}
|
|
464
|
+
if (Reflect.get(socket, "encrypted")) [
|
|
465
|
+
"encrypted",
|
|
466
|
+
"authorized",
|
|
467
|
+
"getProtocol",
|
|
468
|
+
"getSession",
|
|
469
|
+
"isSessionReused",
|
|
470
|
+
"getCipher"
|
|
471
|
+
].forEach((propertyName) => {
|
|
472
|
+
Object.defineProperty(this, propertyName, {
|
|
473
|
+
enumerable: true,
|
|
474
|
+
get: () => {
|
|
475
|
+
const value = Reflect.get(socket, propertyName);
|
|
476
|
+
return typeof value === "function" ? value.bind(socket) : value;
|
|
477
|
+
}
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
socket.on("lookup", (...args) => this.emit("lookup", ...args)).on("connect", () => {
|
|
481
|
+
this.connecting = socket.connecting;
|
|
482
|
+
this.emit("connect");
|
|
483
|
+
}).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) => {
|
|
484
|
+
this.push(chunk);
|
|
485
|
+
}).on("error", (error) => {
|
|
486
|
+
Reflect.set(this, "_hadError", Reflect.get(socket, "_hadError"));
|
|
487
|
+
this.emit("error", error);
|
|
488
|
+
}).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"));
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Convert the given Fetch API `Response` instance to an
|
|
492
|
+
* HTTP message and push it to the socket.
|
|
493
|
+
*/
|
|
494
|
+
async respondWith(response) {
|
|
495
|
+
if (this.destroyed) return;
|
|
496
|
+
(0, outvariant.invariant)(this.socketState !== "mock", "[MockHttpSocket] Failed to respond to the \"%s %s\" request with \"%s %s\": the request has already been handled", this.request?.method, this.request?.url, response.status, response.statusText);
|
|
497
|
+
if (require_handleRequest.isPropertyAccessible(response, "type") && response.type === "error") {
|
|
498
|
+
this.errorWith(/* @__PURE__ */ new TypeError("Network error"));
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
this.mockConnect();
|
|
502
|
+
this.socketState = "mock";
|
|
503
|
+
this.flushWriteBuffer();
|
|
504
|
+
const serverResponse = new node_http.ServerResponse(new node_http.IncomingMessage(this));
|
|
505
|
+
/**
|
|
506
|
+
* Assign a mock socket instance to the server response to
|
|
507
|
+
* spy on the response chunk writes. Push the transformed response chunks
|
|
508
|
+
* to this `MockHttpSocket` instance to trigger the "data" event.
|
|
509
|
+
* @note Providing the same `MockSocket` instance when creating `ServerResponse`
|
|
510
|
+
* does not have the same effect.
|
|
511
|
+
* @see https://github.com/nodejs/node/blob/10099bb3f7fd97bb9dd9667188426866b3098e07/test/parallel/test-http-server-response-standalone.js#L32
|
|
512
|
+
*/
|
|
513
|
+
serverResponse.assignSocket(new MockSocket({
|
|
514
|
+
write: (chunk, encoding, callback) => {
|
|
515
|
+
this.push(chunk, encoding);
|
|
516
|
+
callback?.();
|
|
517
|
+
},
|
|
518
|
+
read() {}
|
|
519
|
+
}));
|
|
520
|
+
/**
|
|
521
|
+
* @note Remove the `Connection` and `Date` response headers
|
|
522
|
+
* injected by `ServerResponse` by default. Those are required
|
|
523
|
+
* from the server but the interceptor is NOT technically a server.
|
|
524
|
+
* It's confusing to add response headers that the developer didn't
|
|
525
|
+
* specify themselves. They can always add these if they wish.
|
|
526
|
+
* @see https://www.rfc-editor.org/rfc/rfc9110#field.date
|
|
527
|
+
* @see https://www.rfc-editor.org/rfc/rfc9110#field.connection
|
|
528
|
+
*/
|
|
529
|
+
serverResponse.removeHeader("connection");
|
|
530
|
+
serverResponse.removeHeader("date");
|
|
531
|
+
const rawResponseHeaders = getRawFetchHeaders(response.headers);
|
|
532
|
+
/**
|
|
533
|
+
* @note Call `.writeHead` in order to set the raw response headers
|
|
534
|
+
* in the same case as they were provided by the developer. Using
|
|
535
|
+
* `.setHeader()`/`.appendHeader()` normalizes header names.
|
|
536
|
+
*/
|
|
537
|
+
serverResponse.writeHead(response.status, response.statusText || node_http.STATUS_CODES[response.status], rawResponseHeaders);
|
|
538
|
+
this.once("error", () => {
|
|
539
|
+
serverResponse.destroy();
|
|
540
|
+
});
|
|
541
|
+
if (response.body) try {
|
|
542
|
+
const reader = response.body.getReader();
|
|
543
|
+
while (true) {
|
|
544
|
+
const { done, value } = await reader.read();
|
|
545
|
+
if (done) {
|
|
546
|
+
serverResponse.end();
|
|
547
|
+
break;
|
|
548
|
+
}
|
|
549
|
+
serverResponse.write(value);
|
|
550
|
+
}
|
|
551
|
+
} catch (error) {
|
|
552
|
+
if (error instanceof Error) {
|
|
553
|
+
serverResponse.destroy();
|
|
554
|
+
/**
|
|
555
|
+
* @note Destroy the request socket gracefully.
|
|
556
|
+
* Response stream errors do NOT produce request errors.
|
|
557
|
+
*/
|
|
558
|
+
this.destroy();
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
serverResponse.destroy();
|
|
562
|
+
throw error;
|
|
563
|
+
}
|
|
564
|
+
else serverResponse.end();
|
|
565
|
+
if (!this.shouldKeepAlive) {
|
|
566
|
+
this.emit("readable");
|
|
567
|
+
/**
|
|
568
|
+
* @todo @fixme This is likely a hack.
|
|
569
|
+
* Since we push null to the socket, it never propagates to the
|
|
570
|
+
* parser, and the parser never calls "onResponseEnd" to close
|
|
571
|
+
* the response stream. We are closing the stream here manually
|
|
572
|
+
* but that shouldn't be the case.
|
|
573
|
+
*/
|
|
574
|
+
this.responseStream?.push(null);
|
|
575
|
+
this.push(null);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Close this socket connection with the given error.
|
|
580
|
+
*/
|
|
581
|
+
errorWith(error) {
|
|
582
|
+
this.destroy(error);
|
|
583
|
+
}
|
|
584
|
+
mockConnect() {
|
|
585
|
+
this.connecting = false;
|
|
586
|
+
const isIPv6 = node_net.default.isIPv6(this.connectionOptions.hostname) || this.connectionOptions.family === 6;
|
|
587
|
+
const addressInfo = {
|
|
588
|
+
address: isIPv6 ? "::1" : "127.0.0.1",
|
|
589
|
+
family: isIPv6 ? "IPv6" : "IPv4",
|
|
590
|
+
port: this.connectionOptions.port
|
|
591
|
+
};
|
|
592
|
+
this.address = () => addressInfo;
|
|
593
|
+
this.emit("lookup", null, addressInfo.address, addressInfo.family === "IPv6" ? 6 : 4, this.connectionOptions.host);
|
|
594
|
+
this.emit("connect");
|
|
595
|
+
this.emit("ready");
|
|
596
|
+
if (this.baseUrl.protocol === "https:") {
|
|
597
|
+
this.emit("secure");
|
|
598
|
+
this.emit("secureConnect");
|
|
599
|
+
this.emit("session", this.connectionOptions.session || Buffer.from("mock-session-renegotiate"));
|
|
600
|
+
this.emit("session", Buffer.from("mock-session-resume"));
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
flushWriteBuffer() {
|
|
604
|
+
for (const writeCall of this.writeBuffer) if (typeof writeCall[2] === "function") {
|
|
605
|
+
writeCall[2]();
|
|
606
|
+
/**
|
|
607
|
+
* @note Remove the callback from the write call
|
|
608
|
+
* so it doesn't get called twice on passthrough
|
|
609
|
+
* if `request.end()` was called within `request.write()`.
|
|
610
|
+
* @see https://github.com/mswjs/interceptors/issues/684
|
|
611
|
+
*/
|
|
612
|
+
writeCall[2] = void 0;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
onRequestBody(chunk) {
|
|
616
|
+
(0, outvariant.invariant)(this.requestStream, "Failed to write to a request stream: stream does not exist");
|
|
617
|
+
this.requestStream.push(chunk);
|
|
618
|
+
}
|
|
619
|
+
onRequestEnd() {
|
|
620
|
+
if (this.requestStream) this.requestStream.push(null);
|
|
621
|
+
}
|
|
622
|
+
onResponseBody(chunk) {
|
|
623
|
+
(0, outvariant.invariant)(this.responseStream, "Failed to write to a response stream: stream does not exist");
|
|
624
|
+
this.responseStream.push(chunk);
|
|
625
|
+
}
|
|
626
|
+
onResponseEnd() {
|
|
627
|
+
if (this.responseStream) this.responseStream.push(null);
|
|
628
|
+
}
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
//#endregion
|
|
632
|
+
//#region src/interceptors/ClientRequest/agents.ts
|
|
633
|
+
var MockAgent = class extends node_http.default.Agent {
|
|
634
|
+
constructor(options) {
|
|
635
|
+
super();
|
|
636
|
+
this.customAgent = options.customAgent;
|
|
637
|
+
this.onRequest = options.onRequest;
|
|
638
|
+
this.onResponse = options.onResponse;
|
|
639
|
+
}
|
|
640
|
+
createConnection(options, callback) {
|
|
641
|
+
const createConnection = this.customAgent instanceof node_http.default.Agent ? this.customAgent.createConnection : super.createConnection;
|
|
642
|
+
const createConnectionOptions = this.customAgent instanceof node_http.default.Agent ? {
|
|
643
|
+
...options,
|
|
644
|
+
...this.customAgent.options
|
|
645
|
+
} : options;
|
|
646
|
+
return new MockHttpSocket({
|
|
647
|
+
connectionOptions: options,
|
|
648
|
+
createConnection: createConnection.bind(this.customAgent || this, createConnectionOptions, callback),
|
|
649
|
+
onRequest: this.onRequest.bind(this),
|
|
650
|
+
onResponse: this.onResponse.bind(this)
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
};
|
|
654
|
+
var MockHttpsAgent = class extends node_https.default.Agent {
|
|
655
|
+
constructor(options) {
|
|
656
|
+
super();
|
|
657
|
+
this.customAgent = options.customAgent;
|
|
658
|
+
this.onRequest = options.onRequest;
|
|
659
|
+
this.onResponse = options.onResponse;
|
|
660
|
+
}
|
|
661
|
+
createConnection(options, callback) {
|
|
662
|
+
const createConnection = this.customAgent instanceof node_http.default.Agent ? this.customAgent.createConnection : super.createConnection;
|
|
663
|
+
const createConnectionOptions = this.customAgent instanceof node_http.default.Agent ? {
|
|
664
|
+
...options,
|
|
665
|
+
...this.customAgent.options
|
|
666
|
+
} : options;
|
|
667
|
+
return new MockHttpSocket({
|
|
668
|
+
connectionOptions: options,
|
|
669
|
+
createConnection: createConnection.bind(this.customAgent || this, createConnectionOptions, callback),
|
|
670
|
+
onRequest: this.onRequest.bind(this),
|
|
671
|
+
onResponse: this.onResponse.bind(this)
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
|
|
676
|
+
//#endregion
|
|
677
|
+
//#region src/utils/getUrlByRequestOptions.ts
|
|
678
|
+
const logger$2 = new _open_draft_logger.Logger("utils getUrlByRequestOptions");
|
|
679
|
+
const DEFAULT_PATH = "/";
|
|
680
|
+
const DEFAULT_PROTOCOL = "http:";
|
|
681
|
+
const DEFAULT_HOSTNAME = "localhost";
|
|
682
|
+
const SSL_PORT = 443;
|
|
683
|
+
function getAgent(options) {
|
|
684
|
+
return options.agent instanceof http.Agent ? options.agent : void 0;
|
|
685
|
+
}
|
|
686
|
+
function getProtocolByRequestOptions(options) {
|
|
687
|
+
if (options.protocol) return options.protocol;
|
|
688
|
+
const agentProtocol = getAgent(options)?.protocol;
|
|
689
|
+
if (agentProtocol) return agentProtocol;
|
|
690
|
+
const port = getPortByRequestOptions(options);
|
|
691
|
+
return options.cert || port === SSL_PORT ? "https:" : options.uri?.protocol || DEFAULT_PROTOCOL;
|
|
692
|
+
}
|
|
693
|
+
function getPortByRequestOptions(options) {
|
|
694
|
+
if (options.port) return Number(options.port);
|
|
695
|
+
const agent = getAgent(options);
|
|
696
|
+
if (agent?.options.port) return Number(agent.options.port);
|
|
697
|
+
if (agent?.defaultPort) return Number(agent.defaultPort);
|
|
698
|
+
}
|
|
699
|
+
function getAuthByRequestOptions(options) {
|
|
700
|
+
if (options.auth) {
|
|
701
|
+
const [username, password] = options.auth.split(":");
|
|
702
|
+
return {
|
|
703
|
+
username,
|
|
704
|
+
password
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Returns true if host looks like an IPv6 address without surrounding brackets
|
|
710
|
+
* It assumes any host containing `:` is definitely not IPv4 and probably IPv6,
|
|
711
|
+
* but note that this could include invalid IPv6 addresses as well.
|
|
712
|
+
*/
|
|
713
|
+
function isRawIPv6Address(host) {
|
|
714
|
+
return host.includes(":") && !host.startsWith("[") && !host.endsWith("]");
|
|
715
|
+
}
|
|
716
|
+
function getHostname(options) {
|
|
717
|
+
let host = options.hostname || options.host;
|
|
718
|
+
if (host) {
|
|
719
|
+
if (isRawIPv6Address(host)) host = `[${host}]`;
|
|
720
|
+
return new URL(`http://${host}`).hostname;
|
|
721
|
+
}
|
|
722
|
+
return DEFAULT_HOSTNAME;
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Creates a `URL` instance from a given `RequestOptions` object.
|
|
726
|
+
*/
|
|
727
|
+
function getUrlByRequestOptions(options) {
|
|
728
|
+
logger$2.info("request options", options);
|
|
729
|
+
if (options.uri) {
|
|
730
|
+
logger$2.info("constructing url from explicitly provided \"options.uri\": %s", options.uri);
|
|
731
|
+
return new URL(options.uri.href);
|
|
732
|
+
}
|
|
733
|
+
logger$2.info("figuring out url from request options...");
|
|
734
|
+
const protocol = getProtocolByRequestOptions(options);
|
|
735
|
+
logger$2.info("protocol", protocol);
|
|
736
|
+
const port = getPortByRequestOptions(options);
|
|
737
|
+
logger$2.info("port", port);
|
|
738
|
+
const hostname = getHostname(options);
|
|
739
|
+
logger$2.info("hostname", hostname);
|
|
740
|
+
const path = options.path || DEFAULT_PATH;
|
|
741
|
+
logger$2.info("path", path);
|
|
742
|
+
const credentials = getAuthByRequestOptions(options);
|
|
743
|
+
logger$2.info("credentials", credentials);
|
|
744
|
+
const authString = credentials ? `${credentials.username}:${credentials.password}@` : "";
|
|
745
|
+
logger$2.info("auth string:", authString);
|
|
746
|
+
const portString = typeof port !== "undefined" ? `:${port}` : "";
|
|
747
|
+
const url = new URL(`${protocol}//${hostname}${portString}${path}`);
|
|
748
|
+
url.username = credentials?.username || "";
|
|
749
|
+
url.password = credentials?.password || "";
|
|
750
|
+
logger$2.info("created url:", url);
|
|
751
|
+
return url;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
//#endregion
|
|
755
|
+
//#region src/utils/cloneObject.ts
|
|
756
|
+
const logger$1 = new _open_draft_logger.Logger("cloneObject");
|
|
757
|
+
function isPlainObject(obj) {
|
|
758
|
+
logger$1.info("is plain object?", obj);
|
|
759
|
+
if (obj == null || !obj.constructor?.name) {
|
|
760
|
+
logger$1.info("given object is undefined, not a plain object...");
|
|
761
|
+
return false;
|
|
762
|
+
}
|
|
763
|
+
logger$1.info("checking the object constructor:", obj.constructor.name);
|
|
764
|
+
return obj.constructor.name === "Object";
|
|
765
|
+
}
|
|
766
|
+
function cloneObject(obj) {
|
|
767
|
+
logger$1.info("cloning object:", obj);
|
|
768
|
+
const enumerableProperties = Object.entries(obj).reduce((acc, [key, value]) => {
|
|
769
|
+
logger$1.info("analyzing key-value pair:", key, value);
|
|
770
|
+
acc[key] = isPlainObject(value) ? cloneObject(value) : value;
|
|
771
|
+
return acc;
|
|
772
|
+
}, {});
|
|
773
|
+
return isPlainObject(obj) ? enumerableProperties : Object.assign(Object.getPrototypeOf(obj), enumerableProperties);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
//#endregion
|
|
777
|
+
//#region src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts
|
|
778
|
+
const logger = new _open_draft_logger.Logger("http normalizeClientRequestArgs");
|
|
779
|
+
function resolveRequestOptions(args, url) {
|
|
780
|
+
if (typeof args[1] === "undefined" || typeof args[1] === "function") {
|
|
781
|
+
logger.info("request options not provided, deriving from the url", url);
|
|
782
|
+
return (0, node_url.urlToHttpOptions)(url);
|
|
783
|
+
}
|
|
784
|
+
if (args[1]) {
|
|
785
|
+
logger.info("has custom RequestOptions!", args[1]);
|
|
786
|
+
const requestOptionsFromUrl = (0, node_url.urlToHttpOptions)(url);
|
|
787
|
+
logger.info("derived RequestOptions from the URL:", requestOptionsFromUrl);
|
|
788
|
+
/**
|
|
789
|
+
* Clone the request options to lock their state
|
|
790
|
+
* at the moment they are provided to `ClientRequest`.
|
|
791
|
+
* @see https://github.com/mswjs/interceptors/issues/86
|
|
792
|
+
*/
|
|
793
|
+
logger.info("cloning RequestOptions...");
|
|
794
|
+
const clonedRequestOptions = cloneObject(args[1]);
|
|
795
|
+
logger.info("successfully cloned RequestOptions!", clonedRequestOptions);
|
|
796
|
+
return {
|
|
797
|
+
...requestOptionsFromUrl,
|
|
798
|
+
...clonedRequestOptions
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
logger.info("using an empty object as request options");
|
|
802
|
+
return {};
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Overrides the given `URL` instance with the explicit properties provided
|
|
806
|
+
* on the `RequestOptions` object. The options object takes precedence,
|
|
807
|
+
* and will replace URL properties like "host", "path", and "port", if specified.
|
|
808
|
+
*/
|
|
809
|
+
function overrideUrlByRequestOptions(url, options) {
|
|
810
|
+
url.host = options.host || url.host;
|
|
811
|
+
url.hostname = options.hostname || url.hostname;
|
|
812
|
+
url.port = options.port ? options.port.toString() : url.port;
|
|
813
|
+
if (options.path) {
|
|
814
|
+
const parsedOptionsPath = (0, node_url.parse)(options.path, false);
|
|
815
|
+
url.pathname = parsedOptionsPath.pathname || "";
|
|
816
|
+
url.search = parsedOptionsPath.search || "";
|
|
817
|
+
}
|
|
818
|
+
return url;
|
|
819
|
+
}
|
|
820
|
+
function resolveCallback(args) {
|
|
821
|
+
return typeof args[1] === "function" ? args[1] : args[2];
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Normalizes parameters given to a `http.request` call
|
|
825
|
+
* so it always has a `URL` and `RequestOptions`.
|
|
826
|
+
*/
|
|
827
|
+
function normalizeClientRequestArgs(defaultProtocol, args) {
|
|
828
|
+
let url;
|
|
829
|
+
let options;
|
|
830
|
+
let callback;
|
|
831
|
+
logger.info("arguments", args);
|
|
832
|
+
logger.info("using default protocol:", defaultProtocol);
|
|
833
|
+
if (args.length === 0) {
|
|
834
|
+
const url$1 = new node_url.URL("http://localhost");
|
|
835
|
+
return [url$1, resolveRequestOptions(args, url$1)];
|
|
836
|
+
}
|
|
837
|
+
if (typeof args[0] === "string") {
|
|
838
|
+
logger.info("first argument is a location string:", args[0]);
|
|
839
|
+
url = new node_url.URL(args[0]);
|
|
840
|
+
logger.info("created a url:", url);
|
|
841
|
+
const requestOptionsFromUrl = (0, node_url.urlToHttpOptions)(url);
|
|
842
|
+
logger.info("request options from url:", requestOptionsFromUrl);
|
|
843
|
+
options = resolveRequestOptions(args, url);
|
|
844
|
+
logger.info("resolved request options:", options);
|
|
845
|
+
callback = resolveCallback(args);
|
|
846
|
+
} else if (args[0] instanceof node_url.URL) {
|
|
847
|
+
url = args[0];
|
|
848
|
+
logger.info("first argument is a URL:", url);
|
|
849
|
+
if (typeof args[1] !== "undefined" && require_handleRequest.isObject(args[1])) url = overrideUrlByRequestOptions(url, args[1]);
|
|
850
|
+
options = resolveRequestOptions(args, url);
|
|
851
|
+
logger.info("derived request options:", options);
|
|
852
|
+
callback = resolveCallback(args);
|
|
853
|
+
} else if ("hash" in args[0] && !("method" in args[0])) {
|
|
854
|
+
const [legacyUrl] = args;
|
|
855
|
+
logger.info("first argument is a legacy URL:", legacyUrl);
|
|
856
|
+
if (legacyUrl.hostname === null) {
|
|
857
|
+
/**
|
|
858
|
+
* We are dealing with a relative url, so use the path as an "option" and
|
|
859
|
+
* merge in any existing options, giving priority to existing options -- i.e. a path in any
|
|
860
|
+
* existing options will take precedence over the one contained in the url. This is consistent
|
|
861
|
+
* with the behaviour in ClientRequest.
|
|
862
|
+
* @see https://github.com/nodejs/node/blob/d84f1312915fe45fe0febe888db692c74894c382/lib/_http_client.js#L122
|
|
863
|
+
*/
|
|
864
|
+
logger.info("given legacy URL is relative (no hostname)");
|
|
865
|
+
return require_handleRequest.isObject(args[1]) ? normalizeClientRequestArgs(defaultProtocol, [{
|
|
866
|
+
path: legacyUrl.path,
|
|
867
|
+
...args[1]
|
|
868
|
+
}, args[2]]) : normalizeClientRequestArgs(defaultProtocol, [{ path: legacyUrl.path }, args[1]]);
|
|
869
|
+
}
|
|
870
|
+
logger.info("given legacy url is absolute");
|
|
871
|
+
const resolvedUrl = new node_url.URL(legacyUrl.href);
|
|
872
|
+
return args[1] === void 0 ? normalizeClientRequestArgs(defaultProtocol, [resolvedUrl]) : typeof args[1] === "function" ? normalizeClientRequestArgs(defaultProtocol, [resolvedUrl, args[1]]) : normalizeClientRequestArgs(defaultProtocol, [
|
|
873
|
+
resolvedUrl,
|
|
874
|
+
args[1],
|
|
875
|
+
args[2]
|
|
876
|
+
]);
|
|
877
|
+
} else if (require_handleRequest.isObject(args[0])) {
|
|
878
|
+
options = { ...args[0] };
|
|
879
|
+
logger.info("first argument is RequestOptions:", options);
|
|
880
|
+
options.protocol = options.protocol || defaultProtocol;
|
|
881
|
+
logger.info("normalized request options:", options);
|
|
882
|
+
url = getUrlByRequestOptions(options);
|
|
883
|
+
logger.info("created a URL from RequestOptions:", url.href);
|
|
884
|
+
callback = resolveCallback(args);
|
|
885
|
+
} else throw new Error(`Failed to construct ClientRequest with these parameters: ${args}`);
|
|
886
|
+
options.protocol = options.protocol || url.protocol;
|
|
887
|
+
options.method = options.method || "GET";
|
|
888
|
+
/**
|
|
889
|
+
* Ensure that the default Agent is always set.
|
|
890
|
+
* This prevents the protocol mismatch for requests with { agent: false },
|
|
891
|
+
* where the global Agent is inferred.
|
|
892
|
+
* @see https://github.com/mswjs/msw/issues/1150
|
|
893
|
+
* @see https://github.com/nodejs/node/blob/418ff70b810f0e7112d48baaa72932a56cfa213b/lib/_http_client.js#L130
|
|
894
|
+
* @see https://github.com/nodejs/node/blob/418ff70b810f0e7112d48baaa72932a56cfa213b/lib/_http_client.js#L157-L159
|
|
895
|
+
*/
|
|
896
|
+
if (!options._defaultAgent) {
|
|
897
|
+
logger.info("has no default agent, setting the default agent for \"%s\"", options.protocol);
|
|
898
|
+
options._defaultAgent = options.protocol === "https:" ? node_https.globalAgent : node_http.globalAgent;
|
|
899
|
+
}
|
|
900
|
+
logger.info("successfully resolved url:", url.href);
|
|
901
|
+
logger.info("successfully resolved options:", options);
|
|
902
|
+
logger.info("successfully resolved callback:", callback);
|
|
903
|
+
/**
|
|
904
|
+
* @note If the user-provided URL is not a valid URL in Node.js,
|
|
905
|
+
* (e.g. the one provided by the JSDOM polyfills), case it to
|
|
906
|
+
* string. Otherwise, this throws on Node.js incompatibility
|
|
907
|
+
* (`ERR_INVALID_ARG_TYPE` on the connection listener)
|
|
908
|
+
* @see https://github.com/node-fetch/node-fetch/issues/1376#issuecomment-966435555
|
|
909
|
+
*/
|
|
910
|
+
if (!(url instanceof node_url.URL)) url = url.toString();
|
|
911
|
+
return [
|
|
912
|
+
url,
|
|
913
|
+
options,
|
|
914
|
+
callback
|
|
915
|
+
];
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
//#endregion
|
|
919
|
+
//#region src/interceptors/ClientRequest/index.ts
|
|
920
|
+
var ClientRequestInterceptor = class ClientRequestInterceptor extends require_fetchUtils.Interceptor {
|
|
921
|
+
static {
|
|
922
|
+
this.symbol = Symbol("client-request-interceptor");
|
|
923
|
+
}
|
|
924
|
+
constructor() {
|
|
925
|
+
super(ClientRequestInterceptor.symbol);
|
|
926
|
+
this.onRequest = async ({ request, socket }) => {
|
|
927
|
+
const controller = new require_fetchUtils.RequestController(request, {
|
|
928
|
+
passthrough() {
|
|
929
|
+
socket.passthrough();
|
|
930
|
+
},
|
|
931
|
+
async respondWith(response) {
|
|
932
|
+
await socket.respondWith(response);
|
|
933
|
+
},
|
|
934
|
+
errorWith(reason) {
|
|
935
|
+
if (reason instanceof Error) socket.errorWith(reason);
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
await require_handleRequest.handleRequest({
|
|
939
|
+
request,
|
|
940
|
+
requestId: Reflect.get(request, kRequestId),
|
|
941
|
+
controller,
|
|
942
|
+
emitter: this.emitter
|
|
943
|
+
});
|
|
944
|
+
};
|
|
945
|
+
this.onResponse = async ({ requestId, request, response, isMockedResponse }) => {
|
|
946
|
+
return require_handleRequest.emitAsync(this.emitter, "response", {
|
|
947
|
+
requestId,
|
|
948
|
+
request,
|
|
949
|
+
response,
|
|
950
|
+
isMockedResponse
|
|
951
|
+
});
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
setup() {
|
|
955
|
+
const { ClientRequest: OriginalClientRequest, get: originalGet, request: originalRequest } = node_http.default;
|
|
956
|
+
const { get: originalHttpsGet, request: originalHttpsRequest } = node_https.default;
|
|
957
|
+
const onRequest = this.onRequest.bind(this);
|
|
958
|
+
const onResponse = this.onResponse.bind(this);
|
|
959
|
+
node_http.default.ClientRequest = new Proxy(node_http.default.ClientRequest, { construct: (target, args) => {
|
|
960
|
+
const [url, options, callback] = normalizeClientRequestArgs("http:", args);
|
|
961
|
+
options.agent = new (options.protocol === "https:" ? MockHttpsAgent : MockAgent)({
|
|
962
|
+
customAgent: options.agent,
|
|
963
|
+
onRequest,
|
|
964
|
+
onResponse
|
|
965
|
+
});
|
|
966
|
+
return Reflect.construct(target, [
|
|
967
|
+
url,
|
|
968
|
+
options,
|
|
969
|
+
callback
|
|
970
|
+
]);
|
|
971
|
+
} });
|
|
972
|
+
node_http.default.request = new Proxy(node_http.default.request, { apply: (target, thisArg, args) => {
|
|
973
|
+
const [url, options, callback] = normalizeClientRequestArgs("http:", args);
|
|
974
|
+
options.agent = new MockAgent({
|
|
975
|
+
customAgent: options.agent,
|
|
976
|
+
onRequest,
|
|
977
|
+
onResponse
|
|
978
|
+
});
|
|
979
|
+
return Reflect.apply(target, thisArg, [
|
|
980
|
+
url,
|
|
981
|
+
options,
|
|
982
|
+
callback
|
|
983
|
+
]);
|
|
984
|
+
} });
|
|
985
|
+
node_http.default.get = new Proxy(node_http.default.get, { apply: (target, thisArg, args) => {
|
|
986
|
+
const [url, options, callback] = normalizeClientRequestArgs("http:", args);
|
|
987
|
+
options.agent = new MockAgent({
|
|
988
|
+
customAgent: options.agent,
|
|
989
|
+
onRequest,
|
|
990
|
+
onResponse
|
|
991
|
+
});
|
|
992
|
+
return Reflect.apply(target, thisArg, [
|
|
993
|
+
url,
|
|
994
|
+
options,
|
|
995
|
+
callback
|
|
996
|
+
]);
|
|
997
|
+
} });
|
|
998
|
+
node_https.default.request = new Proxy(node_https.default.request, { apply: (target, thisArg, args) => {
|
|
999
|
+
const [url, options, callback] = normalizeClientRequestArgs("https:", args);
|
|
1000
|
+
options.agent = new MockHttpsAgent({
|
|
1001
|
+
customAgent: options.agent,
|
|
1002
|
+
onRequest,
|
|
1003
|
+
onResponse
|
|
1004
|
+
});
|
|
1005
|
+
return Reflect.apply(target, thisArg, [
|
|
1006
|
+
url,
|
|
1007
|
+
options,
|
|
1008
|
+
callback
|
|
1009
|
+
]);
|
|
1010
|
+
} });
|
|
1011
|
+
node_https.default.get = new Proxy(node_https.default.get, { apply: (target, thisArg, args) => {
|
|
1012
|
+
const [url, options, callback] = normalizeClientRequestArgs("https:", args);
|
|
1013
|
+
options.agent = new MockHttpsAgent({
|
|
1014
|
+
customAgent: options.agent,
|
|
1015
|
+
onRequest,
|
|
1016
|
+
onResponse
|
|
1017
|
+
});
|
|
1018
|
+
return Reflect.apply(target, thisArg, [
|
|
1019
|
+
url,
|
|
1020
|
+
options,
|
|
1021
|
+
callback
|
|
1022
|
+
]);
|
|
1023
|
+
} });
|
|
1024
|
+
recordRawFetchHeaders();
|
|
1025
|
+
this.subscriptions.push(() => {
|
|
1026
|
+
node_http.default.ClientRequest = OriginalClientRequest;
|
|
1027
|
+
node_http.default.get = originalGet;
|
|
1028
|
+
node_http.default.request = originalRequest;
|
|
1029
|
+
node_https.default.get = originalHttpsGet;
|
|
1030
|
+
node_https.default.request = originalHttpsRequest;
|
|
1031
|
+
restoreHeadersPrototype();
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
};
|
|
1035
|
+
|
|
1036
|
+
//#endregion
|
|
1037
|
+
Object.defineProperty(exports, 'ClientRequestInterceptor', {
|
|
1038
|
+
enumerable: true,
|
|
1039
|
+
get: function () {
|
|
1040
|
+
return ClientRequestInterceptor;
|
|
1041
|
+
}
|
|
1042
|
+
});
|
|
1043
|
+
//# sourceMappingURL=ClientRequest-2rDe54Ui.cjs.map
|