@mswjs/interceptors 0.25.4 → 0.25.5
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/lib/node/RemoteHttpInterceptor.js +2 -2
- package/lib/node/RemoteHttpInterceptor.mjs +1 -1
- package/lib/node/{chunk-6HZYLI7O.mjs → chunk-4B3HXVWT.mjs} +17 -2
- package/lib/node/{chunk-BAS5F5A4.js → chunk-C3TKZUFL.js} +17 -2
- package/lib/node/interceptors/ClientRequest/index.js +2 -2
- package/lib/node/interceptors/ClientRequest/index.mjs +1 -1
- package/lib/node/presets/node.js +2 -2
- package/lib/node/presets/node.mjs +1 -1
- package/package.json +1 -1
- package/src/interceptors/ClientRequest/utils/createRequest.test.ts +40 -0
- package/src/interceptors/ClientRequest/utils/createRequest.ts +2 -2
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.test.ts +96 -0
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts +29 -1
- package/src/utils/isObject.ts +1 -1
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
var _chunkUF7QIAQ5js = require('./chunk-UF7QIAQ5.js');
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
var
|
|
6
|
+
var _chunkC3TKZUFLjs = require('./chunk-C3TKZUFL.js');
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
var _chunkJCWVLTP7js = require('./chunk-JCWVLTP7.js');
|
|
@@ -24,7 +24,7 @@ var RemoteHttpInterceptor = class extends _chunkUF7QIAQ5js.BatchInterceptor {
|
|
|
24
24
|
super({
|
|
25
25
|
name: "remote-interceptor",
|
|
26
26
|
interceptors: [
|
|
27
|
-
new (0,
|
|
27
|
+
new (0, _chunkC3TKZUFLjs.ClientRequestInterceptor)(),
|
|
28
28
|
new (0, _chunkJCWVLTP7js.XMLHttpRequestInterceptor)()
|
|
29
29
|
]
|
|
30
30
|
});
|
|
@@ -152,8 +152,8 @@ function createRequest(clientRequest) {
|
|
|
152
152
|
headers.append(headerName, value.toString());
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
|
-
if (clientRequest.url.username
|
|
156
|
-
const auth = `${clientRequest.url.username}:${clientRequest.url.password}`;
|
|
155
|
+
if (clientRequest.url.username || clientRequest.url.password) {
|
|
156
|
+
const auth = `${clientRequest.url.username || ""}:${clientRequest.url.password || ""}`;
|
|
157
157
|
headers.set("Authorization", `Basic ${btoa(auth)}`);
|
|
158
158
|
clientRequest.url.username = "";
|
|
159
159
|
clientRequest.url.password = "";
|
|
@@ -468,6 +468,7 @@ import {
|
|
|
468
468
|
Agent as HttpsAgent,
|
|
469
469
|
globalAgent as httpsGlobalAgent
|
|
470
470
|
} from "https";
|
|
471
|
+
import { parse as parseUrl } from "url";
|
|
471
472
|
import { Logger as Logger5 } from "@open-draft/logger";
|
|
472
473
|
|
|
473
474
|
// src/utils/getRequestOptionsByUrl.ts
|
|
@@ -642,6 +643,17 @@ function resolveRequestOptions(args, url) {
|
|
|
642
643
|
logger5.info("using an empty object as request options");
|
|
643
644
|
return {};
|
|
644
645
|
}
|
|
646
|
+
function overrideUrlByRequestOptions(url, options) {
|
|
647
|
+
url.host = options.host || url.host;
|
|
648
|
+
url.hostname = options.hostname || url.hostname;
|
|
649
|
+
url.port = options.port ? options.port.toString() : url.port;
|
|
650
|
+
if (options.path) {
|
|
651
|
+
const parsedOptionsPath = parseUrl(options.path, false);
|
|
652
|
+
url.pathname = parsedOptionsPath.pathname || "";
|
|
653
|
+
url.search = parsedOptionsPath.search || "";
|
|
654
|
+
}
|
|
655
|
+
return url;
|
|
656
|
+
}
|
|
645
657
|
function resolveCallback(args) {
|
|
646
658
|
return typeof args[1] === "function" ? args[1] : args[2];
|
|
647
659
|
}
|
|
@@ -663,6 +675,9 @@ function normalizeClientRequestArgs(defaultProtocol, ...args) {
|
|
|
663
675
|
} else if (args[0] instanceof URL) {
|
|
664
676
|
url = args[0];
|
|
665
677
|
logger5.info("first argument is a URL:", url);
|
|
678
|
+
if (typeof args[1] !== "undefined" && isObject(args[1])) {
|
|
679
|
+
url = overrideUrlByRequestOptions(url, args[1]);
|
|
680
|
+
}
|
|
666
681
|
options = resolveRequestOptions(args, url);
|
|
667
682
|
logger5.info("derived request options:", options);
|
|
668
683
|
callback = resolveCallback(args);
|
|
@@ -152,8 +152,8 @@ function createRequest(clientRequest) {
|
|
|
152
152
|
headers.append(headerName, value.toString());
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
|
-
if (clientRequest.url.username
|
|
156
|
-
const auth = `${clientRequest.url.username}:${clientRequest.url.password}`;
|
|
155
|
+
if (clientRequest.url.username || clientRequest.url.password) {
|
|
156
|
+
const auth = `${clientRequest.url.username || ""}:${clientRequest.url.password || ""}`;
|
|
157
157
|
headers.set("Authorization", `Basic ${btoa(auth)}`);
|
|
158
158
|
clientRequest.url.username = "";
|
|
159
159
|
clientRequest.url.password = "";
|
|
@@ -468,6 +468,7 @@ NodeClientRequest.suppressErrorCodes = [
|
|
|
468
468
|
|
|
469
469
|
|
|
470
470
|
|
|
471
|
+
var _url = require('url');
|
|
471
472
|
|
|
472
473
|
|
|
473
474
|
// src/utils/getRequestOptionsByUrl.ts
|
|
@@ -642,6 +643,17 @@ function resolveRequestOptions(args, url) {
|
|
|
642
643
|
logger5.info("using an empty object as request options");
|
|
643
644
|
return {};
|
|
644
645
|
}
|
|
646
|
+
function overrideUrlByRequestOptions(url, options) {
|
|
647
|
+
url.host = options.host || url.host;
|
|
648
|
+
url.hostname = options.hostname || url.hostname;
|
|
649
|
+
url.port = options.port ? options.port.toString() : url.port;
|
|
650
|
+
if (options.path) {
|
|
651
|
+
const parsedOptionsPath = _url.parse.call(void 0, options.path, false);
|
|
652
|
+
url.pathname = parsedOptionsPath.pathname || "";
|
|
653
|
+
url.search = parsedOptionsPath.search || "";
|
|
654
|
+
}
|
|
655
|
+
return url;
|
|
656
|
+
}
|
|
645
657
|
function resolveCallback(args) {
|
|
646
658
|
return typeof args[1] === "function" ? args[1] : args[2];
|
|
647
659
|
}
|
|
@@ -663,6 +675,9 @@ function normalizeClientRequestArgs(defaultProtocol, ...args) {
|
|
|
663
675
|
} else if (args[0] instanceof URL) {
|
|
664
676
|
url = args[0];
|
|
665
677
|
logger5.info("first argument is a URL:", url);
|
|
678
|
+
if (typeof args[1] !== "undefined" && isObject(args[1])) {
|
|
679
|
+
url = overrideUrlByRequestOptions(url, args[1]);
|
|
680
|
+
}
|
|
666
681
|
options = resolveRequestOptions(args, url);
|
|
667
682
|
logger5.info("derived request options:", options);
|
|
668
683
|
callback = resolveCallback(args);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkC3TKZUFLjs = require('../../chunk-C3TKZUFL.js');
|
|
4
4
|
require('../../chunk-OGN3ZR35.js');
|
|
5
5
|
require('../../chunk-5PTPJLB7.js');
|
|
6
6
|
require('../../chunk-3XFLRXRY.js');
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
exports.ClientRequestInterceptor =
|
|
9
|
+
exports.ClientRequestInterceptor = _chunkC3TKZUFLjs.ClientRequestInterceptor;
|
package/lib/node/presets/node.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkC3TKZUFLjs = require('../chunk-C3TKZUFL.js');
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var _chunkJCWVLTP7js = require('../chunk-JCWVLTP7.js');
|
|
@@ -12,7 +12,7 @@ require('../chunk-3XFLRXRY.js');
|
|
|
12
12
|
|
|
13
13
|
// src/presets/node.ts
|
|
14
14
|
var node_default = [
|
|
15
|
-
new (0,
|
|
15
|
+
new (0, _chunkC3TKZUFLjs.ClientRequestInterceptor)(),
|
|
16
16
|
new (0, _chunkJCWVLTP7js.XMLHttpRequestInterceptor)()
|
|
17
17
|
];
|
|
18
18
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mswjs/interceptors",
|
|
3
3
|
"description": "Low-level HTTP/HTTPS/XHR/fetch request interception library.",
|
|
4
|
-
"version": "0.25.
|
|
4
|
+
"version": "0.25.5",
|
|
5
5
|
"main": "./lib/node/index.js",
|
|
6
6
|
"module": "./lib/node/index.mjs",
|
|
7
7
|
"types": "./lib/node/index.d.ts",
|
|
@@ -83,3 +83,43 @@ it('creates a fetch Request with an empty string body', async () => {
|
|
|
83
83
|
expect(request.url).toBe('https://api.github.com/')
|
|
84
84
|
expect(request.body).toBe(null)
|
|
85
85
|
})
|
|
86
|
+
|
|
87
|
+
it('creates a fetch Request with an empty password', async () => {
|
|
88
|
+
const clientRequest = new NodeClientRequest(
|
|
89
|
+
[
|
|
90
|
+
new URL('https://api.github.com'),
|
|
91
|
+
{ auth: 'username:' },
|
|
92
|
+
() => {},
|
|
93
|
+
],
|
|
94
|
+
{
|
|
95
|
+
emitter,
|
|
96
|
+
logger,
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
clientRequest.write('')
|
|
100
|
+
|
|
101
|
+
const request = createRequest(clientRequest)
|
|
102
|
+
|
|
103
|
+
expect(request.headers.get('Authorization')).toBe(`Basic ${btoa('username:')}`)
|
|
104
|
+
expect(request.url).toBe('https://api.github.com/')
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('creates a fetch Request with an empty username', async () => {
|
|
108
|
+
const clientRequest = new NodeClientRequest(
|
|
109
|
+
[
|
|
110
|
+
new URL('https://api.github.com'),
|
|
111
|
+
{ auth: ':password' },
|
|
112
|
+
() => {},
|
|
113
|
+
],
|
|
114
|
+
{
|
|
115
|
+
emitter,
|
|
116
|
+
logger,
|
|
117
|
+
}
|
|
118
|
+
)
|
|
119
|
+
clientRequest.write('')
|
|
120
|
+
|
|
121
|
+
const request = createRequest(clientRequest)
|
|
122
|
+
|
|
123
|
+
expect(request.headers.get('Authorization')).toBe(`Basic ${btoa(':password')}`)
|
|
124
|
+
expect(request.url).toBe('https://api.github.com/')
|
|
125
|
+
})
|
|
@@ -25,8 +25,8 @@ export function createRequest(clientRequest: NodeClientRequest): Request {
|
|
|
25
25
|
* the request "Authorization" header.
|
|
26
26
|
* @see https://github.com/mswjs/interceptors/issues/438
|
|
27
27
|
*/
|
|
28
|
-
if (clientRequest.url.username
|
|
29
|
-
const auth = `${clientRequest.url.username}:${clientRequest.url.password}`
|
|
28
|
+
if (clientRequest.url.username || clientRequest.url.password) {
|
|
29
|
+
const auth = `${clientRequest.url.username || ''}:${clientRequest.url.password || ''}`
|
|
30
30
|
headers.set('Authorization', `Basic ${btoa(auth)}`)
|
|
31
31
|
|
|
32
32
|
// Remove the credentials from the URL since you cannot
|
|
@@ -212,6 +212,55 @@ it('handles [URL, RequestOptions, callback] input', () => {
|
|
|
212
212
|
expect(callback?.name).toEqual('cb')
|
|
213
213
|
})
|
|
214
214
|
|
|
215
|
+
it('handles [URL, RequestOptions] where options have custom "hostname"', () => {
|
|
216
|
+
const [url, options] = normalizeClientRequestArgs(
|
|
217
|
+
'http:',
|
|
218
|
+
new URL('http://example.com/path-from-url'),
|
|
219
|
+
{
|
|
220
|
+
hostname: 'host-from-options.com',
|
|
221
|
+
}
|
|
222
|
+
)
|
|
223
|
+
expect(url.href).toBe('http://host-from-options.com/path-from-url')
|
|
224
|
+
expect(options).toMatchObject({
|
|
225
|
+
host: 'host-from-options.com',
|
|
226
|
+
path: '/path-from-url',
|
|
227
|
+
})
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
it('handles [URL, RequestOptions] where options contain "host" and "path" and "port"', () => {
|
|
231
|
+
const [url, options] = normalizeClientRequestArgs(
|
|
232
|
+
'http:',
|
|
233
|
+
new URL('http://example.com/path-from-url?a=b&c=d'),
|
|
234
|
+
{
|
|
235
|
+
hostname: 'host-from-options.com',
|
|
236
|
+
path: '/path-from-options',
|
|
237
|
+
port: 1234,
|
|
238
|
+
}
|
|
239
|
+
)
|
|
240
|
+
// Must remove the query string since it's not specified in "options.path"
|
|
241
|
+
expect(url.href).toBe('http://host-from-options.com:1234/path-from-options')
|
|
242
|
+
expect(options).toMatchObject({
|
|
243
|
+
host: 'host-from-options.com:1234',
|
|
244
|
+
path: '/path-from-options',
|
|
245
|
+
port: 1234,
|
|
246
|
+
})
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
it('handles [URL, RequestOptions] where options contain "path" with query string', () => {
|
|
250
|
+
const [url, options] = normalizeClientRequestArgs(
|
|
251
|
+
'http:',
|
|
252
|
+
new URL('http://example.com/path-from-url?a=b&c=d'),
|
|
253
|
+
{
|
|
254
|
+
path: '/path-from-options?foo=bar&baz=xyz',
|
|
255
|
+
}
|
|
256
|
+
)
|
|
257
|
+
expect(url.href).toBe('http://example.com/path-from-options?foo=bar&baz=xyz')
|
|
258
|
+
expect(options).toMatchObject({
|
|
259
|
+
host: 'example.com',
|
|
260
|
+
path: '/path-from-options?foo=bar&baz=xyz',
|
|
261
|
+
})
|
|
262
|
+
})
|
|
263
|
+
|
|
215
264
|
it('handles [RequestOptions, callback] input', () => {
|
|
216
265
|
const initialOptions = {
|
|
217
266
|
method: 'POST',
|
|
@@ -371,3 +420,50 @@ it('merges URL-based RequestOptions with the custom RequestOptions', () => {
|
|
|
371
420
|
expect(options.hostname).toEqual(url.hostname)
|
|
372
421
|
expect(options.path).toEqual(url.pathname)
|
|
373
422
|
})
|
|
423
|
+
|
|
424
|
+
it('respects custom "options.path" over URL path', () => {
|
|
425
|
+
const [url, options] = normalizeClientRequestArgs(
|
|
426
|
+
'http:',
|
|
427
|
+
new URL('http://example.com/path-from-url'),
|
|
428
|
+
{
|
|
429
|
+
path: '/path-from-options',
|
|
430
|
+
}
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
expect(url.href).toBe('http://example.com/path-from-options')
|
|
434
|
+
expect(options.protocol).toBe('http:')
|
|
435
|
+
expect(options.host).toBe('example.com')
|
|
436
|
+
expect(options.hostname).toBe('example.com')
|
|
437
|
+
expect(options.path).toBe('/path-from-options')
|
|
438
|
+
})
|
|
439
|
+
|
|
440
|
+
it('respects custom "options.path" over URL path with query string', () => {
|
|
441
|
+
const [url, options] = normalizeClientRequestArgs(
|
|
442
|
+
'http:',
|
|
443
|
+
new URL('http://example.com/path-from-url?a=b&c=d'),
|
|
444
|
+
{
|
|
445
|
+
path: '/path-from-options',
|
|
446
|
+
}
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
// Must replace both the path and the query string.
|
|
450
|
+
expect(url.href).toBe('http://example.com/path-from-options')
|
|
451
|
+
expect(options.protocol).toBe('http:')
|
|
452
|
+
expect(options.host).toBe('example.com')
|
|
453
|
+
expect(options.hostname).toBe('example.com')
|
|
454
|
+
expect(options.path).toBe('/path-from-options')
|
|
455
|
+
})
|
|
456
|
+
|
|
457
|
+
it('preserves URL query string', () => {
|
|
458
|
+
const [url, options] = normalizeClientRequestArgs(
|
|
459
|
+
'http:',
|
|
460
|
+
new URL('http://example.com/resource?a=b&c=d')
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
expect(url.href).toBe('http://example.com/resource?a=b&c=d')
|
|
464
|
+
expect(options.protocol).toBe('http:')
|
|
465
|
+
expect(options.host).toBe('example.com')
|
|
466
|
+
expect(options.hostname).toBe('example.com')
|
|
467
|
+
// Query string is a part of the options path.
|
|
468
|
+
expect(options.path).toBe('/resource?a=b&c=d')
|
|
469
|
+
})
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
Agent as HttpsAgent,
|
|
9
9
|
globalAgent as httpsGlobalAgent,
|
|
10
10
|
} from 'https'
|
|
11
|
-
import { Url as LegacyURL } from 'url'
|
|
11
|
+
import { Url as LegacyURL, parse as parseUrl } from 'url'
|
|
12
12
|
import { Logger } from '@open-draft/logger'
|
|
13
13
|
import { getRequestOptionsByUrl } from '../../../utils/getRequestOptionsByUrl'
|
|
14
14
|
import {
|
|
@@ -63,6 +63,25 @@ function resolveRequestOptions(
|
|
|
63
63
|
return {} as RequestOptions
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Overrides the given `URL` instance with the explicit properties provided
|
|
68
|
+
* on the `RequestOptions` object. The options object takes precedence,
|
|
69
|
+
* and will replace URL properties like "host", "path", and "port", if specified.
|
|
70
|
+
*/
|
|
71
|
+
function overrideUrlByRequestOptions(url: URL, options: RequestOptions): URL {
|
|
72
|
+
url.host = options.host || url.host
|
|
73
|
+
url.hostname = options.hostname || url.hostname
|
|
74
|
+
url.port = options.port ? options.port.toString() : url.port
|
|
75
|
+
|
|
76
|
+
if (options.path) {
|
|
77
|
+
const parsedOptionsPath = parseUrl(options.path, false)
|
|
78
|
+
url.pathname = parsedOptionsPath.pathname || ''
|
|
79
|
+
url.search = parsedOptionsPath.search || ''
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return url
|
|
83
|
+
}
|
|
84
|
+
|
|
66
85
|
function resolveCallback(
|
|
67
86
|
args: ClientRequestArgs
|
|
68
87
|
): HttpRequestCallback | undefined {
|
|
@@ -112,6 +131,15 @@ export function normalizeClientRequestArgs(
|
|
|
112
131
|
url = args[0]
|
|
113
132
|
logger.info('first argument is a URL:', url)
|
|
114
133
|
|
|
134
|
+
// Check if the second provided argument is RequestOptions.
|
|
135
|
+
// If it is, check if "options.path" was set and rewrite it
|
|
136
|
+
// on the input URL.
|
|
137
|
+
// Do this before resolving options from the URL below
|
|
138
|
+
// to prevent query string from being duplicated in the path.
|
|
139
|
+
if (typeof args[1] !== 'undefined' && isObject<RequestOptions>(args[1])) {
|
|
140
|
+
url = overrideUrlByRequestOptions(url, args[1])
|
|
141
|
+
}
|
|
142
|
+
|
|
115
143
|
options = resolveRequestOptions(args, url)
|
|
116
144
|
logger.info('derived request options:', options)
|
|
117
145
|
|
package/src/utils/isObject.ts
CHANGED