@depup/mswjs__interceptors 0.41.3-depup.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 +11 -0
- package/LICENSE.md +9 -0
- package/README.md +31 -0
- package/RemoteHttpInterceptor/package.json +11 -0
- package/WebSocket/package.json +12 -0
- package/XMLHttpRequest/package.json +12 -0
- package/changes.json +10 -0
- package/fetch/package.json +12 -0
- package/lib/browser/Interceptor-Deczogc8.d.cts +65 -0
- package/lib/browser/Interceptor-gqKgs-aF.d.mts +65 -0
- package/lib/browser/XMLHttpRequest-BACqefB-.cjs +761 -0
- package/lib/browser/XMLHttpRequest-BACqefB-.cjs.map +1 -0
- package/lib/browser/XMLHttpRequest-BvxZV0WU.mjs +756 -0
- package/lib/browser/XMLHttpRequest-BvxZV0WU.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-DdKEdDOR.mjs +248 -0
- package/lib/browser/fetch-DdKEdDOR.mjs.map +1 -0
- package/lib/browser/fetch-U3v3Y4ap.cjs +253 -0
- package/lib/browser/fetch-U3v3Y4ap.cjs.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-DYwOrogs.d.mts +70 -0
- package/lib/browser/handleRequest-CvX2G-Lz.cjs +189 -0
- package/lib/browser/handleRequest-CvX2G-Lz.cjs.map +1 -0
- package/lib/browser/handleRequest-D7kpTI5U.mjs +178 -0
- package/lib/browser/handleRequest-D7kpTI5U.mjs.map +1 -0
- package/lib/browser/hasConfigurableGlobal-BvCTG97d.cjs +45 -0
- package/lib/browser/hasConfigurableGlobal-BvCTG97d.cjs.map +1 -0
- package/lib/browser/hasConfigurableGlobal-npXitu1-.mjs +33 -0
- package/lib/browser/hasConfigurableGlobal-npXitu1-.mjs.map +1 -0
- package/lib/browser/index.cjs +70 -0
- package/lib/browser/index.cjs.map +1 -0
- package/lib/browser/index.d.cts +96 -0
- package/lib/browser/index.d.mts +96 -0
- package/lib/browser/index.mjs +56 -0
- package/lib/browser/index.mjs.map +1 -0
- package/lib/browser/interceptors/WebSocket/index.cjs +622 -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 +615 -0
- package/lib/browser/interceptors/WebSocket/index.mjs.map +1 -0
- 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 -0
- 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 -0
- 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 +17 -0
- package/lib/browser/presets/browser.mjs.map +1 -0
- package/lib/browser/resolveWebSocketUrl-6K6EgqsA.cjs +31 -0
- package/lib/browser/resolveWebSocketUrl-6K6EgqsA.cjs.map +1 -0
- package/lib/browser/resolveWebSocketUrl-C83-x9iE.mjs +25 -0
- package/lib/browser/resolveWebSocketUrl-C83-x9iE.mjs.map +1 -0
- 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 +152 -0
- package/lib/node/RemoteHttpInterceptor.mjs.map +1 -0
- 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 +54 -0
- package/lib/node/index.cjs.map +1 -0
- package/lib/node/index.d.cts +75 -0
- package/lib/node/index.d.mts +75 -0
- package/lib/node/index.mjs +40 -0
- package/lib/node/index.mjs.map +1 -0
- 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 -0
- 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 -0
- 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 -0
- 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 +22 -0
- package/lib/node/presets/node.mjs.map +1 -0
- package/lib/node/utils/node/index.cjs +4 -0
- package/lib/node/utils/node/index.d.cts +16 -0
- package/lib/node/utils/node/index.d.mts +16 -0
- package/lib/node/utils/node/index.mjs +3 -0
- package/package.json +204 -0
- package/presets/browser/package.json +5 -0
- package/presets/node/package.json +11 -0
- package/src/BatchInterceptor.test.ts +255 -0
- package/src/BatchInterceptor.ts +95 -0
- package/src/Interceptor.test.ts +205 -0
- package/src/Interceptor.ts +249 -0
- package/src/InterceptorError.ts +7 -0
- package/src/RemoteHttpInterceptor.ts +251 -0
- package/src/RequestController.test.ts +104 -0
- package/src/RequestController.ts +109 -0
- package/src/createRequestId.test.ts +7 -0
- package/src/createRequestId.ts +9 -0
- package/src/getRawRequest.ts +21 -0
- package/src/glossary.ts +37 -0
- package/src/index.ts +15 -0
- package/src/interceptors/ClientRequest/MockHttpSocket.ts +724 -0
- package/src/interceptors/ClientRequest/agents.ts +110 -0
- package/src/interceptors/ClientRequest/index.test.ts +75 -0
- package/src/interceptors/ClientRequest/index.ts +193 -0
- package/src/interceptors/ClientRequest/utils/getIncomingMessageBody.test.ts +54 -0
- package/src/interceptors/ClientRequest/utils/getIncomingMessageBody.ts +45 -0
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.test.ts +427 -0
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts +268 -0
- package/src/interceptors/ClientRequest/utils/parserUtils.ts +48 -0
- package/src/interceptors/ClientRequest/utils/recordRawHeaders.test.ts +258 -0
- package/src/interceptors/ClientRequest/utils/recordRawHeaders.ts +262 -0
- package/src/interceptors/Socket/MockSocket.test.ts +264 -0
- package/src/interceptors/Socket/MockSocket.ts +58 -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/WebSocket/WebSocketClassTransport.ts +116 -0
- package/src/interceptors/WebSocket/WebSocketClientConnection.ts +152 -0
- package/src/interceptors/WebSocket/WebSocketOverride.ts +252 -0
- package/src/interceptors/WebSocket/WebSocketServerConnection.ts +420 -0
- package/src/interceptors/WebSocket/WebSocketTransport.ts +39 -0
- package/src/interceptors/WebSocket/index.ts +191 -0
- package/src/interceptors/WebSocket/utils/bindEvent.test.ts +27 -0
- package/src/interceptors/WebSocket/utils/bindEvent.ts +21 -0
- package/src/interceptors/WebSocket/utils/events.test.ts +101 -0
- package/src/interceptors/WebSocket/utils/events.ts +94 -0
- package/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts +746 -0
- package/src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts +121 -0
- package/src/interceptors/XMLHttpRequest/index.ts +61 -0
- package/src/interceptors/XMLHttpRequest/polyfills/EventPolyfill.ts +51 -0
- package/src/interceptors/XMLHttpRequest/polyfills/ProgressEventPolyfill.ts +17 -0
- package/src/interceptors/XMLHttpRequest/utils/concatArrayBuffer.ts +12 -0
- package/src/interceptors/XMLHttpRequest/utils/concateArrayBuffer.test.ts +12 -0
- package/src/interceptors/XMLHttpRequest/utils/createEvent.test.ts +26 -0
- package/src/interceptors/XMLHttpRequest/utils/createEvent.ts +41 -0
- package/src/interceptors/XMLHttpRequest/utils/createResponse.ts +49 -0
- package/src/interceptors/XMLHttpRequest/utils/getBodyByteLength.test.ts +164 -0
- package/src/interceptors/XMLHttpRequest/utils/getBodyByteLength.ts +16 -0
- package/src/interceptors/XMLHttpRequest/utils/isDomParserSupportedType.ts +14 -0
- package/src/interceptors/fetch/index.ts +214 -0
- package/src/interceptors/fetch/utils/brotli-decompress.browser.ts +14 -0
- package/src/interceptors/fetch/utils/brotli-decompress.ts +31 -0
- package/src/interceptors/fetch/utils/createNetworkError.ts +5 -0
- package/src/interceptors/fetch/utils/decompression.ts +85 -0
- package/src/interceptors/fetch/utils/followRedirect.ts +114 -0
- package/src/presets/browser.ts +11 -0
- package/src/presets/node.ts +13 -0
- package/src/utils/bufferUtils.test.ts +21 -0
- package/src/utils/bufferUtils.ts +22 -0
- package/src/utils/canParseUrl.ts +13 -0
- package/src/utils/cloneObject.test.ts +94 -0
- package/src/utils/cloneObject.ts +36 -0
- package/src/utils/createProxy.test.ts +164 -0
- package/src/utils/createProxy.ts +104 -0
- package/src/utils/emitAsync.ts +25 -0
- package/src/utils/fetchUtils.ts +119 -0
- package/src/utils/findPropertySource.test.ts +27 -0
- package/src/utils/findPropertySource.ts +20 -0
- package/src/utils/getCleanUrl.test.ts +32 -0
- package/src/utils/getCleanUrl.ts +6 -0
- package/src/utils/getUrlByRequestOptions.test.ts +163 -0
- package/src/utils/getUrlByRequestOptions.ts +152 -0
- package/src/utils/getValueBySymbol.test.ts +14 -0
- package/src/utils/getValueBySymbol.ts +19 -0
- package/src/utils/handleRequest.ts +205 -0
- package/src/utils/hasConfigurableGlobal.test.ts +83 -0
- package/src/utils/hasConfigurableGlobal.ts +34 -0
- package/src/utils/isNodeLikeError.ts +13 -0
- package/src/utils/isObject.test.ts +21 -0
- package/src/utils/isObject.ts +8 -0
- package/src/utils/isPropertyAccessible.ts +19 -0
- package/src/utils/nextTick.ts +11 -0
- package/src/utils/node/index.ts +39 -0
- package/src/utils/parseJson.test.ts +10 -0
- package/src/utils/parseJson.ts +12 -0
- package/src/utils/resolveWebSocketUrl.ts +45 -0
- package/src/utils/responseUtils.ts +59 -0
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import { it, expect } from 'vitest'
|
|
2
|
+
import { parse } from 'url'
|
|
3
|
+
import { globalAgent as httpGlobalAgent, RequestOptions } from 'http'
|
|
4
|
+
import { Agent as HttpsAgent, globalAgent as httpsGlobalAgent } from 'https'
|
|
5
|
+
import { getUrlByRequestOptions } from '../../../utils/getUrlByRequestOptions'
|
|
6
|
+
import { normalizeClientRequestArgs } from './normalizeClientRequestArgs'
|
|
7
|
+
|
|
8
|
+
it('handles [string, callback] input', () => {
|
|
9
|
+
const [url, options, callback] = normalizeClientRequestArgs('https:', [
|
|
10
|
+
'https://mswjs.io/resource',
|
|
11
|
+
function cb() {},
|
|
12
|
+
])
|
|
13
|
+
|
|
14
|
+
// URL string must be converted to a URL instance.
|
|
15
|
+
expect(url.href).toEqual('https://mswjs.io/resource')
|
|
16
|
+
|
|
17
|
+
// Request options must be derived from the URL instance.
|
|
18
|
+
expect(options).toHaveProperty('method', 'GET')
|
|
19
|
+
expect(options).toHaveProperty('protocol', 'https:')
|
|
20
|
+
expect(options).toHaveProperty('hostname', 'mswjs.io')
|
|
21
|
+
expect(options).toHaveProperty('path', '/resource')
|
|
22
|
+
|
|
23
|
+
// Callback must be preserved.
|
|
24
|
+
expect(callback?.name).toEqual('cb')
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('handles [string, RequestOptions, callback] input', () => {
|
|
28
|
+
const initialOptions = {
|
|
29
|
+
headers: {
|
|
30
|
+
'Content-Type': 'text/plain',
|
|
31
|
+
},
|
|
32
|
+
}
|
|
33
|
+
const [url, options, callback] = normalizeClientRequestArgs('https:', [
|
|
34
|
+
'https://mswjs.io/resource',
|
|
35
|
+
initialOptions,
|
|
36
|
+
function cb() {},
|
|
37
|
+
])
|
|
38
|
+
|
|
39
|
+
// URL must be created from the string.
|
|
40
|
+
expect(url.href).toEqual('https://mswjs.io/resource')
|
|
41
|
+
|
|
42
|
+
// Request options must be preserved.
|
|
43
|
+
expect(options).toHaveProperty('headers', initialOptions.headers)
|
|
44
|
+
|
|
45
|
+
// Callback must be preserved.
|
|
46
|
+
expect(callback?.name).toEqual('cb')
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('handles [URL, callback] input', () => {
|
|
50
|
+
const [url, options, callback] = normalizeClientRequestArgs('https:', [
|
|
51
|
+
new URL('https://mswjs.io/resource'),
|
|
52
|
+
function cb() {},
|
|
53
|
+
])
|
|
54
|
+
|
|
55
|
+
// URL must be preserved.
|
|
56
|
+
expect(url.href).toEqual('https://mswjs.io/resource')
|
|
57
|
+
|
|
58
|
+
// Request options must be derived from the URL instance.
|
|
59
|
+
expect(options.method).toEqual('GET')
|
|
60
|
+
expect(options.protocol).toEqual('https:')
|
|
61
|
+
expect(options.hostname).toEqual('mswjs.io')
|
|
62
|
+
expect(options.path).toEqual('/resource')
|
|
63
|
+
|
|
64
|
+
// Callback must be preserved.
|
|
65
|
+
expect(callback?.name).toEqual('cb')
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('handles [Absolute Legacy URL, callback] input', () => {
|
|
69
|
+
const [url, options, callback] = normalizeClientRequestArgs('https:', [
|
|
70
|
+
parse('https://cherry:durian@mswjs.io:12345/resource?apple=banana'),
|
|
71
|
+
function cb() {},
|
|
72
|
+
])
|
|
73
|
+
|
|
74
|
+
// URL must be preserved.
|
|
75
|
+
expect(url.toJSON()).toEqual(
|
|
76
|
+
new URL(
|
|
77
|
+
'https://cherry:durian@mswjs.io:12345/resource?apple=banana'
|
|
78
|
+
).toJSON()
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
// Request options must be derived from the URL instance.
|
|
82
|
+
expect(options.method).toEqual('GET')
|
|
83
|
+
expect(options.protocol).toEqual('https:')
|
|
84
|
+
expect(options.hostname).toEqual('mswjs.io')
|
|
85
|
+
expect(options.path).toEqual('/resource?apple=banana')
|
|
86
|
+
expect(options.port).toEqual(12345)
|
|
87
|
+
expect(options.auth).toEqual('cherry:durian')
|
|
88
|
+
|
|
89
|
+
// Callback must be preserved.
|
|
90
|
+
expect(callback?.name).toEqual('cb')
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it('handles [Relative Legacy URL, RequestOptions without path set, callback] input', () => {
|
|
94
|
+
const [url, options, callback] = normalizeClientRequestArgs('http:', [
|
|
95
|
+
parse('/resource?apple=banana'),
|
|
96
|
+
{ host: 'mswjs.io' },
|
|
97
|
+
function cb() {},
|
|
98
|
+
])
|
|
99
|
+
|
|
100
|
+
// Correct WHATWG URL generated.
|
|
101
|
+
expect(url.toJSON()).toEqual(
|
|
102
|
+
new URL('http://mswjs.io/resource?apple=banana').toJSON()
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
// No path in request options, so legacy url path is copied-in.
|
|
106
|
+
expect(options.protocol).toEqual('http:')
|
|
107
|
+
expect(options.host).toEqual('mswjs.io')
|
|
108
|
+
expect(options.path).toEqual('/resource?apple=banana')
|
|
109
|
+
|
|
110
|
+
// Callback must be preserved.
|
|
111
|
+
expect(callback?.name).toEqual('cb')
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('handles [Relative Legacy URL, RequestOptions with path set, callback] input', () => {
|
|
115
|
+
const [url, options, callback] = normalizeClientRequestArgs('http:', [
|
|
116
|
+
parse('/resource?apple=banana'),
|
|
117
|
+
{ host: 'mswjs.io', path: '/other?cherry=durian' },
|
|
118
|
+
function cb() {},
|
|
119
|
+
])
|
|
120
|
+
|
|
121
|
+
// Correct WHATWG URL generated.
|
|
122
|
+
expect(url.toJSON()).toEqual(
|
|
123
|
+
new URL('http://mswjs.io/other?cherry=durian').toJSON()
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
// Path in request options, so that path is preferred.
|
|
127
|
+
expect(options.protocol).toEqual('http:')
|
|
128
|
+
expect(options.host).toEqual('mswjs.io')
|
|
129
|
+
expect(options.path).toEqual('/other?cherry=durian')
|
|
130
|
+
|
|
131
|
+
// Callback must be preserved.
|
|
132
|
+
expect(callback?.name).toEqual('cb')
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
it('handles [Relative Legacy URL, callback] input', () => {
|
|
136
|
+
const [url, options, callback] = normalizeClientRequestArgs('http:', [
|
|
137
|
+
parse('/resource?apple=banana'),
|
|
138
|
+
function cb() {},
|
|
139
|
+
])
|
|
140
|
+
|
|
141
|
+
// Correct WHATWG URL generated.
|
|
142
|
+
expect(url.toJSON()).toMatch(
|
|
143
|
+
getUrlByRequestOptions({ path: '/resource?apple=banana' }).toJSON()
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
// Check path is in options.
|
|
147
|
+
expect(options.protocol).toEqual('http:')
|
|
148
|
+
expect(options.path).toEqual('/resource?apple=banana')
|
|
149
|
+
|
|
150
|
+
// Callback must be preserved.
|
|
151
|
+
expect(callback).toBeTypeOf('function')
|
|
152
|
+
expect(callback?.name).toEqual('cb')
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it('handles [Relative Legacy URL] input', () => {
|
|
156
|
+
const [url, options, callback] = normalizeClientRequestArgs('http:', [
|
|
157
|
+
parse('/resource?apple=banana'),
|
|
158
|
+
])
|
|
159
|
+
|
|
160
|
+
// Correct WHATWG URL generated.
|
|
161
|
+
expect(url.toJSON()).toMatch(
|
|
162
|
+
getUrlByRequestOptions({ path: '/resource?apple=banana' }).toJSON()
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
// Check path is in options.
|
|
166
|
+
expect(options.protocol).toEqual('http:')
|
|
167
|
+
expect(options.path).toEqual('/resource?apple=banana')
|
|
168
|
+
|
|
169
|
+
// Callback must be preserved.
|
|
170
|
+
expect(callback).toBeUndefined()
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
it('handles [URL, RequestOptions, callback] input', () => {
|
|
174
|
+
const [url, options, callback] = normalizeClientRequestArgs('https:', [
|
|
175
|
+
new URL('https://mswjs.io/resource'),
|
|
176
|
+
{
|
|
177
|
+
agent: false,
|
|
178
|
+
headers: {
|
|
179
|
+
'Content-Type': 'text/plain',
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
function cb() {},
|
|
183
|
+
])
|
|
184
|
+
|
|
185
|
+
// URL must be preserved.
|
|
186
|
+
expect(url.href).toEqual('https://mswjs.io/resource')
|
|
187
|
+
|
|
188
|
+
// Options must be preserved.
|
|
189
|
+
// `urlToHttpOptions` from `node:url` generates additional
|
|
190
|
+
// ClientRequest options, some of which are not legally allowed.
|
|
191
|
+
expect(options).toMatchObject<RequestOptions>({
|
|
192
|
+
agent: false,
|
|
193
|
+
_defaultAgent: httpsGlobalAgent,
|
|
194
|
+
protocol: url.protocol,
|
|
195
|
+
method: 'GET',
|
|
196
|
+
headers: {
|
|
197
|
+
'Content-Type': 'text/plain',
|
|
198
|
+
},
|
|
199
|
+
hostname: url.hostname,
|
|
200
|
+
path: url.pathname,
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
// Callback must be preserved.
|
|
204
|
+
expect(callback).toBeTypeOf('function')
|
|
205
|
+
expect(callback?.name).toEqual('cb')
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
it('handles [URL, RequestOptions] where options have custom "hostname"', () => {
|
|
209
|
+
const [url, options] = normalizeClientRequestArgs('http:', [
|
|
210
|
+
new URL('http://example.com/path-from-url'),
|
|
211
|
+
{
|
|
212
|
+
hostname: 'host-from-options.com',
|
|
213
|
+
},
|
|
214
|
+
])
|
|
215
|
+
expect(url.href).toBe('http://host-from-options.com/path-from-url')
|
|
216
|
+
expect(options).toMatchObject({
|
|
217
|
+
hostname: 'host-from-options.com',
|
|
218
|
+
path: '/path-from-url',
|
|
219
|
+
})
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
it('handles [URL, RequestOptions] where options contain "host" and "path" and "port"', () => {
|
|
223
|
+
const [url, options] = normalizeClientRequestArgs('http:', [
|
|
224
|
+
new URL('http://example.com/path-from-url?a=b&c=d'),
|
|
225
|
+
{
|
|
226
|
+
hostname: 'host-from-options.com',
|
|
227
|
+
path: '/path-from-options',
|
|
228
|
+
port: 1234,
|
|
229
|
+
},
|
|
230
|
+
])
|
|
231
|
+
// Must remove the query string since it's not specified in "options.path"
|
|
232
|
+
expect(url.href).toBe('http://host-from-options.com:1234/path-from-options')
|
|
233
|
+
expect(options).toMatchObject<RequestOptions>({
|
|
234
|
+
hostname: 'host-from-options.com',
|
|
235
|
+
path: '/path-from-options',
|
|
236
|
+
port: 1234,
|
|
237
|
+
})
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
it('handles [URL, RequestOptions] where options contain "path" with query string', () => {
|
|
241
|
+
const [url, options] = normalizeClientRequestArgs('http:', [
|
|
242
|
+
new URL('http://example.com/path-from-url?a=b&c=d'),
|
|
243
|
+
{
|
|
244
|
+
path: '/path-from-options?foo=bar&baz=xyz',
|
|
245
|
+
},
|
|
246
|
+
])
|
|
247
|
+
expect(url.href).toBe('http://example.com/path-from-options?foo=bar&baz=xyz')
|
|
248
|
+
expect(options).toMatchObject<RequestOptions>({
|
|
249
|
+
hostname: 'example.com',
|
|
250
|
+
path: '/path-from-options?foo=bar&baz=xyz',
|
|
251
|
+
})
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
it('handles [RequestOptions, callback] input', () => {
|
|
255
|
+
const initialOptions = {
|
|
256
|
+
method: 'POST',
|
|
257
|
+
protocol: 'https:',
|
|
258
|
+
host: 'mswjs.io',
|
|
259
|
+
/**
|
|
260
|
+
* @see https://github.com/mswjs/msw/issues/705
|
|
261
|
+
*/
|
|
262
|
+
origin: 'https://mswjs.io',
|
|
263
|
+
path: '/resource',
|
|
264
|
+
headers: {
|
|
265
|
+
'Content-Type': 'text/plain',
|
|
266
|
+
},
|
|
267
|
+
}
|
|
268
|
+
const [url, options, callback] = normalizeClientRequestArgs('https:', [
|
|
269
|
+
initialOptions,
|
|
270
|
+
function cb() {},
|
|
271
|
+
])
|
|
272
|
+
|
|
273
|
+
// URL must be derived from request options.
|
|
274
|
+
expect(url.href).toEqual('https://mswjs.io/resource')
|
|
275
|
+
|
|
276
|
+
// Request options must be preserved.
|
|
277
|
+
expect(options).toMatchObject(initialOptions)
|
|
278
|
+
|
|
279
|
+
// Callback must be preserved.
|
|
280
|
+
expect(callback).toBeTypeOf('function')
|
|
281
|
+
expect(callback?.name).toEqual('cb')
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
it('handles [Empty RequestOptions, callback] input', () => {
|
|
285
|
+
const [_, options, callback] = normalizeClientRequestArgs('https:', [
|
|
286
|
+
{},
|
|
287
|
+
function cb() {},
|
|
288
|
+
])
|
|
289
|
+
|
|
290
|
+
expect(options.protocol).toEqual('https:')
|
|
291
|
+
|
|
292
|
+
// Callback must be preserved
|
|
293
|
+
expect(callback?.name).toEqual('cb')
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* @see https://github.com/mswjs/interceptors/issues/19
|
|
298
|
+
*/
|
|
299
|
+
it('handles [PartialRequestOptions, callback] input', () => {
|
|
300
|
+
const initialOptions = {
|
|
301
|
+
method: 'GET',
|
|
302
|
+
port: '50176',
|
|
303
|
+
path: '/resource',
|
|
304
|
+
host: '127.0.0.1',
|
|
305
|
+
ca: undefined,
|
|
306
|
+
key: undefined,
|
|
307
|
+
pfx: undefined,
|
|
308
|
+
cert: undefined,
|
|
309
|
+
passphrase: undefined,
|
|
310
|
+
agent: false,
|
|
311
|
+
}
|
|
312
|
+
const [url, options, callback] = normalizeClientRequestArgs('https:', [
|
|
313
|
+
initialOptions,
|
|
314
|
+
function cb() {},
|
|
315
|
+
])
|
|
316
|
+
|
|
317
|
+
// URL must be derived from request options.
|
|
318
|
+
expect(url.toJSON()).toEqual(
|
|
319
|
+
new URL('https://127.0.0.1:50176/resource').toJSON()
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
// Request options must be preserved.
|
|
323
|
+
expect(options).toMatchObject(initialOptions)
|
|
324
|
+
|
|
325
|
+
// Options protocol must be inferred from the request issuing module.
|
|
326
|
+
expect(options.protocol).toEqual('https:')
|
|
327
|
+
|
|
328
|
+
// Callback must be preserved.
|
|
329
|
+
expect(callback).toBeTypeOf('function')
|
|
330
|
+
expect(callback?.name).toEqual('cb')
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
it('sets the default Agent for HTTP request', () => {
|
|
334
|
+
const [, options] = normalizeClientRequestArgs('http:', [
|
|
335
|
+
'http://github.com',
|
|
336
|
+
{},
|
|
337
|
+
])
|
|
338
|
+
|
|
339
|
+
expect(options._defaultAgent).toEqual(httpGlobalAgent)
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
it('sets the default Agent for HTTPS request', () => {
|
|
343
|
+
const [, options] = normalizeClientRequestArgs('https:', [
|
|
344
|
+
'https://github.com',
|
|
345
|
+
{},
|
|
346
|
+
])
|
|
347
|
+
|
|
348
|
+
expect(options._defaultAgent).toEqual(httpsGlobalAgent)
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
it('preserves a custom default Agent when set', () => {
|
|
352
|
+
const [, options] = normalizeClientRequestArgs('https:', [
|
|
353
|
+
'https://github.com',
|
|
354
|
+
{
|
|
355
|
+
/**
|
|
356
|
+
* @note Intentionally incorrect Agent for HTTPS request.
|
|
357
|
+
*/
|
|
358
|
+
_defaultAgent: httpGlobalAgent,
|
|
359
|
+
},
|
|
360
|
+
])
|
|
361
|
+
|
|
362
|
+
expect(options._defaultAgent).toEqual(httpGlobalAgent)
|
|
363
|
+
})
|
|
364
|
+
|
|
365
|
+
it('merges URL-based RequestOptions with the custom RequestOptions', () => {
|
|
366
|
+
const [url, options] = normalizeClientRequestArgs('https:', [
|
|
367
|
+
'https://github.com/graphql',
|
|
368
|
+
{
|
|
369
|
+
method: 'GET',
|
|
370
|
+
pfx: 'PFX_KEY',
|
|
371
|
+
},
|
|
372
|
+
])
|
|
373
|
+
|
|
374
|
+
expect(url.href).toEqual('https://github.com/graphql')
|
|
375
|
+
|
|
376
|
+
// Original request options must be preserved.
|
|
377
|
+
expect(options.method).toEqual('GET')
|
|
378
|
+
expect(options.pfx).toEqual('PFX_KEY')
|
|
379
|
+
|
|
380
|
+
// Other options must be inferred from the URL.
|
|
381
|
+
expect(options.protocol).toEqual(url.protocol)
|
|
382
|
+
expect(options.hostname).toEqual(url.hostname)
|
|
383
|
+
expect(options.path).toEqual(url.pathname)
|
|
384
|
+
})
|
|
385
|
+
|
|
386
|
+
it('respects custom "options.path" over URL path', () => {
|
|
387
|
+
const [url, options] = normalizeClientRequestArgs('http:', [
|
|
388
|
+
new URL('http://example.com/path-from-url'),
|
|
389
|
+
{
|
|
390
|
+
path: '/path-from-options',
|
|
391
|
+
},
|
|
392
|
+
])
|
|
393
|
+
|
|
394
|
+
expect(url.href).toBe('http://example.com/path-from-options')
|
|
395
|
+
expect(options.protocol).toBe('http:')
|
|
396
|
+
expect(options.hostname).toBe('example.com')
|
|
397
|
+
expect(options.path).toBe('/path-from-options')
|
|
398
|
+
})
|
|
399
|
+
|
|
400
|
+
it('respects custom "options.path" over URL path with query string', () => {
|
|
401
|
+
const [url, options] = normalizeClientRequestArgs('http:', [
|
|
402
|
+
new URL('http://example.com/path-from-url?a=b&c=d'),
|
|
403
|
+
{
|
|
404
|
+
path: '/path-from-options',
|
|
405
|
+
},
|
|
406
|
+
])
|
|
407
|
+
|
|
408
|
+
// Must replace both the path and the query string.
|
|
409
|
+
expect(url.href).toBe('http://example.com/path-from-options')
|
|
410
|
+
expect(options.protocol).toBe('http:')
|
|
411
|
+
expect(options.hostname).toBe('example.com')
|
|
412
|
+
expect(options.path).toBe('/path-from-options')
|
|
413
|
+
})
|
|
414
|
+
|
|
415
|
+
it('preserves URL query string', () => {
|
|
416
|
+
const [url, options] = normalizeClientRequestArgs('http:', [
|
|
417
|
+
new URL('http://example.com:8080/resource?a=b&c=d'),
|
|
418
|
+
])
|
|
419
|
+
|
|
420
|
+
expect(url.href).toBe('http://example.com:8080/resource?a=b&c=d')
|
|
421
|
+
expect(options.protocol).toBe('http:')
|
|
422
|
+
// expect(options.host).toBe('example.com:8080')
|
|
423
|
+
expect(options.hostname).toBe('example.com')
|
|
424
|
+
// Query string is a part of the options path.
|
|
425
|
+
expect(options.path).toBe('/resource?a=b&c=d')
|
|
426
|
+
expect(options.port).toBe(8080)
|
|
427
|
+
})
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { urlToHttpOptions } from 'node:url'
|
|
2
|
+
import {
|
|
3
|
+
Agent as HttpAgent,
|
|
4
|
+
globalAgent as httpGlobalAgent,
|
|
5
|
+
IncomingMessage,
|
|
6
|
+
} from 'node:http'
|
|
7
|
+
import {
|
|
8
|
+
RequestOptions,
|
|
9
|
+
Agent as HttpsAgent,
|
|
10
|
+
globalAgent as httpsGlobalAgent,
|
|
11
|
+
} from 'node:https'
|
|
12
|
+
import {
|
|
13
|
+
/**
|
|
14
|
+
* @note Use the Node.js URL instead of the global URL
|
|
15
|
+
* because environments like JSDOM may override the global,
|
|
16
|
+
* breaking the compatibility with Node.js.
|
|
17
|
+
* @see https://github.com/node-fetch/node-fetch/issues/1376#issuecomment-966435555
|
|
18
|
+
*/
|
|
19
|
+
URL,
|
|
20
|
+
Url as LegacyURL,
|
|
21
|
+
parse as parseUrl,
|
|
22
|
+
} from 'node:url'
|
|
23
|
+
import { Logger } from '@open-draft/logger'
|
|
24
|
+
import {
|
|
25
|
+
ResolvedRequestOptions,
|
|
26
|
+
getUrlByRequestOptions,
|
|
27
|
+
} from '../../../utils/getUrlByRequestOptions'
|
|
28
|
+
import { cloneObject } from '../../../utils/cloneObject'
|
|
29
|
+
import { isObject } from '../../../utils/isObject'
|
|
30
|
+
|
|
31
|
+
const logger = new Logger('http normalizeClientRequestArgs')
|
|
32
|
+
|
|
33
|
+
export type HttpRequestCallback = (response: IncomingMessage) => void
|
|
34
|
+
|
|
35
|
+
export type ClientRequestArgs =
|
|
36
|
+
// Request without any arguments is also possible.
|
|
37
|
+
| []
|
|
38
|
+
| [string | URL | LegacyURL, HttpRequestCallback?]
|
|
39
|
+
| [string | URL | LegacyURL, RequestOptions, HttpRequestCallback?]
|
|
40
|
+
| [RequestOptions, HttpRequestCallback?]
|
|
41
|
+
|
|
42
|
+
function resolveRequestOptions(
|
|
43
|
+
args: ClientRequestArgs,
|
|
44
|
+
url: URL
|
|
45
|
+
): RequestOptions {
|
|
46
|
+
// Calling `fetch` provides only URL to `ClientRequest`
|
|
47
|
+
// without any `RequestOptions` or callback.
|
|
48
|
+
if (typeof args[1] === 'undefined' || typeof args[1] === 'function') {
|
|
49
|
+
logger.info('request options not provided, deriving from the url', url)
|
|
50
|
+
return urlToHttpOptions(url)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (args[1]) {
|
|
54
|
+
logger.info('has custom RequestOptions!', args[1])
|
|
55
|
+
const requestOptionsFromUrl = urlToHttpOptions(url)
|
|
56
|
+
|
|
57
|
+
logger.info('derived RequestOptions from the URL:', requestOptionsFromUrl)
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Clone the request options to lock their state
|
|
61
|
+
* at the moment they are provided to `ClientRequest`.
|
|
62
|
+
* @see https://github.com/mswjs/interceptors/issues/86
|
|
63
|
+
*/
|
|
64
|
+
logger.info('cloning RequestOptions...')
|
|
65
|
+
const clonedRequestOptions = cloneObject(args[1])
|
|
66
|
+
logger.info('successfully cloned RequestOptions!', clonedRequestOptions)
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
...requestOptionsFromUrl,
|
|
70
|
+
...clonedRequestOptions,
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
logger.info('using an empty object as request options')
|
|
75
|
+
return {} as RequestOptions
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Overrides the given `URL` instance with the explicit properties provided
|
|
80
|
+
* on the `RequestOptions` object. The options object takes precedence,
|
|
81
|
+
* and will replace URL properties like "host", "path", and "port", if specified.
|
|
82
|
+
*/
|
|
83
|
+
function overrideUrlByRequestOptions(url: URL, options: RequestOptions): URL {
|
|
84
|
+
url.host = options.host || url.host
|
|
85
|
+
url.hostname = options.hostname || url.hostname
|
|
86
|
+
url.port = options.port ? options.port.toString() : url.port
|
|
87
|
+
|
|
88
|
+
if (options.path) {
|
|
89
|
+
const parsedOptionsPath = parseUrl(options.path, false)
|
|
90
|
+
url.pathname = parsedOptionsPath.pathname || ''
|
|
91
|
+
url.search = parsedOptionsPath.search || ''
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return url
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function resolveCallback(
|
|
98
|
+
args: ClientRequestArgs
|
|
99
|
+
): HttpRequestCallback | undefined {
|
|
100
|
+
return typeof args[1] === 'function' ? args[1] : args[2]
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export type NormalizedClientRequestArgs = [
|
|
104
|
+
url: URL,
|
|
105
|
+
options: ResolvedRequestOptions,
|
|
106
|
+
callback?: HttpRequestCallback
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Normalizes parameters given to a `http.request` call
|
|
111
|
+
* so it always has a `URL` and `RequestOptions`.
|
|
112
|
+
*/
|
|
113
|
+
export function normalizeClientRequestArgs(
|
|
114
|
+
defaultProtocol: string,
|
|
115
|
+
args: ClientRequestArgs
|
|
116
|
+
): NormalizedClientRequestArgs {
|
|
117
|
+
let url: URL
|
|
118
|
+
let options: ResolvedRequestOptions
|
|
119
|
+
let callback: HttpRequestCallback | undefined
|
|
120
|
+
|
|
121
|
+
logger.info('arguments', args)
|
|
122
|
+
logger.info('using default protocol:', defaultProtocol)
|
|
123
|
+
|
|
124
|
+
// Support "http.request()" calls without any arguments.
|
|
125
|
+
// That call results in a "GET http://localhost" request.
|
|
126
|
+
if (args.length === 0) {
|
|
127
|
+
const url = new URL('http://localhost')
|
|
128
|
+
const options = resolveRequestOptions(args, url)
|
|
129
|
+
return [url, options]
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Convert a url string into a URL instance
|
|
133
|
+
// and derive request options from it.
|
|
134
|
+
if (typeof args[0] === 'string') {
|
|
135
|
+
logger.info('first argument is a location string:', args[0])
|
|
136
|
+
|
|
137
|
+
url = new URL(args[0])
|
|
138
|
+
logger.info('created a url:', url)
|
|
139
|
+
|
|
140
|
+
const requestOptionsFromUrl = urlToHttpOptions(url)
|
|
141
|
+
logger.info('request options from url:', requestOptionsFromUrl)
|
|
142
|
+
|
|
143
|
+
options = resolveRequestOptions(args, url)
|
|
144
|
+
logger.info('resolved request options:', options)
|
|
145
|
+
|
|
146
|
+
callback = resolveCallback(args)
|
|
147
|
+
}
|
|
148
|
+
// Handle a given URL instance as-is
|
|
149
|
+
// and derive request options from it.
|
|
150
|
+
else if (args[0] instanceof URL) {
|
|
151
|
+
url = args[0]
|
|
152
|
+
logger.info('first argument is a URL:', url)
|
|
153
|
+
|
|
154
|
+
// Check if the second provided argument is RequestOptions.
|
|
155
|
+
// If it is, check if "options.path" was set and rewrite it
|
|
156
|
+
// on the input URL.
|
|
157
|
+
// Do this before resolving options from the URL below
|
|
158
|
+
// to prevent query string from being duplicated in the path.
|
|
159
|
+
if (typeof args[1] !== 'undefined' && isObject<RequestOptions>(args[1])) {
|
|
160
|
+
url = overrideUrlByRequestOptions(url, args[1])
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
options = resolveRequestOptions(args, url)
|
|
164
|
+
logger.info('derived request options:', options)
|
|
165
|
+
|
|
166
|
+
callback = resolveCallback(args)
|
|
167
|
+
}
|
|
168
|
+
// Handle a legacy URL instance and re-normalize from either a RequestOptions object
|
|
169
|
+
// or a WHATWG URL.
|
|
170
|
+
else if ('hash' in args[0] && !('method' in args[0])) {
|
|
171
|
+
const [legacyUrl] = args
|
|
172
|
+
logger.info('first argument is a legacy URL:', legacyUrl)
|
|
173
|
+
|
|
174
|
+
if (legacyUrl.hostname === null) {
|
|
175
|
+
/**
|
|
176
|
+
* We are dealing with a relative url, so use the path as an "option" and
|
|
177
|
+
* merge in any existing options, giving priority to existing options -- i.e. a path in any
|
|
178
|
+
* existing options will take precedence over the one contained in the url. This is consistent
|
|
179
|
+
* with the behaviour in ClientRequest.
|
|
180
|
+
* @see https://github.com/nodejs/node/blob/d84f1312915fe45fe0febe888db692c74894c382/lib/_http_client.js#L122
|
|
181
|
+
*/
|
|
182
|
+
logger.info('given legacy URL is relative (no hostname)')
|
|
183
|
+
|
|
184
|
+
return isObject(args[1])
|
|
185
|
+
? normalizeClientRequestArgs(defaultProtocol, [
|
|
186
|
+
{ path: legacyUrl.path, ...args[1] },
|
|
187
|
+
args[2],
|
|
188
|
+
])
|
|
189
|
+
: normalizeClientRequestArgs(defaultProtocol, [
|
|
190
|
+
{ path: legacyUrl.path },
|
|
191
|
+
args[1] as HttpRequestCallback,
|
|
192
|
+
])
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
logger.info('given legacy url is absolute')
|
|
196
|
+
|
|
197
|
+
// We are dealing with an absolute URL, so convert to WHATWG and try again.
|
|
198
|
+
const resolvedUrl = new URL(legacyUrl.href)
|
|
199
|
+
|
|
200
|
+
return args[1] === undefined
|
|
201
|
+
? normalizeClientRequestArgs(defaultProtocol, [resolvedUrl])
|
|
202
|
+
: typeof args[1] === 'function'
|
|
203
|
+
? normalizeClientRequestArgs(defaultProtocol, [resolvedUrl, args[1]])
|
|
204
|
+
: normalizeClientRequestArgs(defaultProtocol, [
|
|
205
|
+
resolvedUrl,
|
|
206
|
+
args[1],
|
|
207
|
+
args[2],
|
|
208
|
+
])
|
|
209
|
+
}
|
|
210
|
+
// Handle a given "RequestOptions" object as-is
|
|
211
|
+
// and derive the URL instance from it.
|
|
212
|
+
else if (isObject(args[0])) {
|
|
213
|
+
options = { ...(args[0] as any) }
|
|
214
|
+
logger.info('first argument is RequestOptions:', options)
|
|
215
|
+
|
|
216
|
+
// When handling a "RequestOptions" object without an explicit "protocol",
|
|
217
|
+
// infer the protocol from the request issuing module (http/https).
|
|
218
|
+
options.protocol = options.protocol || defaultProtocol
|
|
219
|
+
logger.info('normalized request options:', options)
|
|
220
|
+
|
|
221
|
+
url = getUrlByRequestOptions(options)
|
|
222
|
+
logger.info('created a URL from RequestOptions:', url.href)
|
|
223
|
+
|
|
224
|
+
callback = resolveCallback(args)
|
|
225
|
+
} else {
|
|
226
|
+
throw new Error(
|
|
227
|
+
`Failed to construct ClientRequest with these parameters: ${args}`
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
options.protocol = options.protocol || url.protocol
|
|
232
|
+
options.method = options.method || 'GET'
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Ensure that the default Agent is always set.
|
|
236
|
+
* This prevents the protocol mismatch for requests with { agent: false },
|
|
237
|
+
* where the global Agent is inferred.
|
|
238
|
+
* @see https://github.com/mswjs/msw/issues/1150
|
|
239
|
+
* @see https://github.com/nodejs/node/blob/418ff70b810f0e7112d48baaa72932a56cfa213b/lib/_http_client.js#L130
|
|
240
|
+
* @see https://github.com/nodejs/node/blob/418ff70b810f0e7112d48baaa72932a56cfa213b/lib/_http_client.js#L157-L159
|
|
241
|
+
*/
|
|
242
|
+
if (!options._defaultAgent) {
|
|
243
|
+
logger.info(
|
|
244
|
+
'has no default agent, setting the default agent for "%s"',
|
|
245
|
+
options.protocol
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
options._defaultAgent =
|
|
249
|
+
options.protocol === 'https:' ? httpsGlobalAgent : httpGlobalAgent
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
logger.info('successfully resolved url:', url.href)
|
|
253
|
+
logger.info('successfully resolved options:', options)
|
|
254
|
+
logger.info('successfully resolved callback:', callback)
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* @note If the user-provided URL is not a valid URL in Node.js,
|
|
258
|
+
* (e.g. the one provided by the JSDOM polyfills), case it to
|
|
259
|
+
* string. Otherwise, this throws on Node.js incompatibility
|
|
260
|
+
* (`ERR_INVALID_ARG_TYPE` on the connection listener)
|
|
261
|
+
* @see https://github.com/node-fetch/node-fetch/issues/1376#issuecomment-966435555
|
|
262
|
+
*/
|
|
263
|
+
if (!(url instanceof URL)) {
|
|
264
|
+
url = (url as any).toString()
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return [url, options, callback]
|
|
268
|
+
}
|