@mswjs/interceptors 0.22.1 → 0.22.3
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 +2 -2
- package/lib/node/RemoteHttpInterceptor.js +2 -2
- package/lib/node/RemoteHttpInterceptor.mjs +1 -1
- package/lib/node/{chunk-SWJ33XIS.mjs → chunk-FGPCRIW6.mjs} +49 -24
- package/lib/node/{chunk-PRX3F52M.js → chunk-XLZJAPVS.js} +49 -24
- package/lib/node/interceptors/ClientRequest/index.js +2 -2
- package/lib/node/interceptors/ClientRequest/index.mjs +1 -1
- package/package.json +1 -1
- package/src/utils/getUrlByRequestOptions.test.ts +92 -98
- package/src/utils/getUrlByRequestOptions.ts +78 -34
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"main": "../lib/node/interceptors/ClientRequest.js",
|
|
3
|
-
"module": "../lib/node/interceptors/ClientRequest.mjs",
|
|
2
|
+
"main": "../lib/node/interceptors/ClientRequest/index.js",
|
|
3
|
+
"module": "../lib/node/interceptors/ClientRequest/index.mjs",
|
|
4
4
|
"browser": null,
|
|
5
5
|
"types": "../lib/node/interceptors/ClientRequest/index.d.ts"
|
|
6
6
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
var _chunkQ56TMOP5js = require('./chunk-Q56TMOP5.js');
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
var
|
|
6
|
+
var _chunkXLZJAPVSjs = require('./chunk-XLZJAPVS.js');
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
var _chunkGGD5JOGBjs = require('./chunk-GGD5JOGB.js');
|
|
@@ -23,7 +23,7 @@ var RemoteHttpInterceptor = class extends _chunkQ56TMOP5js.BatchInterceptor {
|
|
|
23
23
|
super({
|
|
24
24
|
name: "remote-interceptor",
|
|
25
25
|
interceptors: [
|
|
26
|
-
new (0,
|
|
26
|
+
new (0, _chunkXLZJAPVSjs.ClientRequestInterceptor)(),
|
|
27
27
|
new (0, _chunkGGD5JOGBjs.XMLHttpRequestInterceptor)()
|
|
28
28
|
]
|
|
29
29
|
});
|
|
@@ -404,7 +404,6 @@ var debug3 = __require("debug")("utils getUrlByRequestOptions");
|
|
|
404
404
|
var DEFAULT_PATH = "/";
|
|
405
405
|
var DEFAULT_PROTOCOL = "http:";
|
|
406
406
|
var DEFAULT_HOST = "localhost";
|
|
407
|
-
var DEFAULT_PORT = 80;
|
|
408
407
|
var SSL_PORT = 443;
|
|
409
408
|
function getAgent(options) {
|
|
410
409
|
return options.agent instanceof Agent ? options.agent : void 0;
|
|
@@ -424,16 +423,30 @@ function getProtocolByRequestOptions(options) {
|
|
|
424
423
|
return isSecureRequest ? "https:" : ((_a = options.uri) == null ? void 0 : _a.protocol) || DEFAULT_PROTOCOL;
|
|
425
424
|
}
|
|
426
425
|
function getPortByRequestOptions(options) {
|
|
426
|
+
if (options.port) {
|
|
427
|
+
return Number(options.port);
|
|
428
|
+
}
|
|
429
|
+
if (options.hostname != null) {
|
|
430
|
+
const [, extractedPort] = options.hostname.match(/:(\d+)$/) || [];
|
|
431
|
+
if (extractedPort != null) {
|
|
432
|
+
return Number(extractedPort);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
427
435
|
const agent = getAgent(options);
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
return Number(
|
|
436
|
+
if (agent == null ? void 0 : agent.options.port) {
|
|
437
|
+
return Number(agent.options.port);
|
|
438
|
+
}
|
|
439
|
+
if (agent == null ? void 0 : agent.defaultPort) {
|
|
440
|
+
return Number(agent.defaultPort);
|
|
433
441
|
}
|
|
442
|
+
return void 0;
|
|
434
443
|
}
|
|
435
444
|
function getHostByRequestOptions(options) {
|
|
436
|
-
|
|
445
|
+
const { hostname, host } = options;
|
|
446
|
+
if (hostname != null) {
|
|
447
|
+
return hostname.replace(/:\d+$/, "");
|
|
448
|
+
}
|
|
449
|
+
return host || DEFAULT_HOST;
|
|
437
450
|
}
|
|
438
451
|
function getAuthByRequestOptions(options) {
|
|
439
452
|
if (options.auth) {
|
|
@@ -444,30 +457,42 @@ function getAuthByRequestOptions(options) {
|
|
|
444
457
|
function isRawIPv6Address(host) {
|
|
445
458
|
return host.includes(":") && !host.startsWith("[") && !host.endsWith("]");
|
|
446
459
|
}
|
|
460
|
+
function getHostname(host, port) {
|
|
461
|
+
const portString = typeof port !== "undefined" ? `:${port}` : "";
|
|
462
|
+
if (isRawIPv6Address(host)) {
|
|
463
|
+
return `[${host}]${portString}`;
|
|
464
|
+
}
|
|
465
|
+
if (typeof port === "undefined") {
|
|
466
|
+
return host;
|
|
467
|
+
}
|
|
468
|
+
return `${host}${portString}`;
|
|
469
|
+
}
|
|
447
470
|
function getUrlByRequestOptions(options) {
|
|
448
471
|
debug3("request options", options);
|
|
472
|
+
if (options.uri) {
|
|
473
|
+
debug3(
|
|
474
|
+
'constructing url from explicitly provided "options.uri": %s',
|
|
475
|
+
options.uri
|
|
476
|
+
);
|
|
477
|
+
return new URL(options.uri.href);
|
|
478
|
+
}
|
|
479
|
+
debug3("figuring out url from request options...");
|
|
449
480
|
const protocol = getProtocolByRequestOptions(options);
|
|
450
|
-
const host = getHostByRequestOptions(options);
|
|
451
|
-
const port = getPortByRequestOptions(options);
|
|
452
|
-
const path = options.path || DEFAULT_PATH;
|
|
453
|
-
const auth = getAuthByRequestOptions(options);
|
|
454
481
|
debug3("protocol", protocol);
|
|
482
|
+
const host = getHostByRequestOptions(options);
|
|
455
483
|
debug3("host", host);
|
|
484
|
+
const port = getPortByRequestOptions(options);
|
|
456
485
|
debug3("port", port);
|
|
486
|
+
const hostname = getHostname(host, port);
|
|
487
|
+
debug3("hostname", hostname);
|
|
488
|
+
const path = options.path || DEFAULT_PATH;
|
|
457
489
|
debug3("path", path);
|
|
458
|
-
const
|
|
459
|
-
debug3("
|
|
460
|
-
const
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
}
|
|
465
|
-
if (auth) {
|
|
466
|
-
debug3("resolved auth", auth);
|
|
467
|
-
url.username = auth.username;
|
|
468
|
-
url.password = auth.password;
|
|
469
|
-
}
|
|
470
|
-
debug3("created URL:", url);
|
|
490
|
+
const credentials = getAuthByRequestOptions(options);
|
|
491
|
+
debug3("credentials", credentials);
|
|
492
|
+
const authString = credentials ? `${credentials.username}:${credentials.password}@` : "";
|
|
493
|
+
debug3("auth string:", authString);
|
|
494
|
+
const url = new URL(`${protocol}//${authString}${hostname}${path}`);
|
|
495
|
+
debug3("created url:", url);
|
|
471
496
|
return url;
|
|
472
497
|
}
|
|
473
498
|
|
|
@@ -404,7 +404,6 @@ var debug3 = _chunkWWHITCCIjs.__require.call(void 0, "debug")("utils getUrlByReq
|
|
|
404
404
|
var DEFAULT_PATH = "/";
|
|
405
405
|
var DEFAULT_PROTOCOL = "http:";
|
|
406
406
|
var DEFAULT_HOST = "localhost";
|
|
407
|
-
var DEFAULT_PORT = 80;
|
|
408
407
|
var SSL_PORT = 443;
|
|
409
408
|
function getAgent(options) {
|
|
410
409
|
return options.agent instanceof _http.Agent ? options.agent : void 0;
|
|
@@ -424,16 +423,30 @@ function getProtocolByRequestOptions(options) {
|
|
|
424
423
|
return isSecureRequest ? "https:" : ((_a = options.uri) == null ? void 0 : _a.protocol) || DEFAULT_PROTOCOL;
|
|
425
424
|
}
|
|
426
425
|
function getPortByRequestOptions(options) {
|
|
426
|
+
if (options.port) {
|
|
427
|
+
return Number(options.port);
|
|
428
|
+
}
|
|
429
|
+
if (options.hostname != null) {
|
|
430
|
+
const [, extractedPort] = options.hostname.match(/:(\d+)$/) || [];
|
|
431
|
+
if (extractedPort != null) {
|
|
432
|
+
return Number(extractedPort);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
427
435
|
const agent = getAgent(options);
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
return Number(
|
|
436
|
+
if (agent == null ? void 0 : agent.options.port) {
|
|
437
|
+
return Number(agent.options.port);
|
|
438
|
+
}
|
|
439
|
+
if (agent == null ? void 0 : agent.defaultPort) {
|
|
440
|
+
return Number(agent.defaultPort);
|
|
433
441
|
}
|
|
442
|
+
return void 0;
|
|
434
443
|
}
|
|
435
444
|
function getHostByRequestOptions(options) {
|
|
436
|
-
|
|
445
|
+
const { hostname, host } = options;
|
|
446
|
+
if (hostname != null) {
|
|
447
|
+
return hostname.replace(/:\d+$/, "");
|
|
448
|
+
}
|
|
449
|
+
return host || DEFAULT_HOST;
|
|
437
450
|
}
|
|
438
451
|
function getAuthByRequestOptions(options) {
|
|
439
452
|
if (options.auth) {
|
|
@@ -444,30 +457,42 @@ function getAuthByRequestOptions(options) {
|
|
|
444
457
|
function isRawIPv6Address(host) {
|
|
445
458
|
return host.includes(":") && !host.startsWith("[") && !host.endsWith("]");
|
|
446
459
|
}
|
|
460
|
+
function getHostname(host, port) {
|
|
461
|
+
const portString = typeof port !== "undefined" ? `:${port}` : "";
|
|
462
|
+
if (isRawIPv6Address(host)) {
|
|
463
|
+
return `[${host}]${portString}`;
|
|
464
|
+
}
|
|
465
|
+
if (typeof port === "undefined") {
|
|
466
|
+
return host;
|
|
467
|
+
}
|
|
468
|
+
return `${host}${portString}`;
|
|
469
|
+
}
|
|
447
470
|
function getUrlByRequestOptions(options) {
|
|
448
471
|
debug3("request options", options);
|
|
472
|
+
if (options.uri) {
|
|
473
|
+
debug3(
|
|
474
|
+
'constructing url from explicitly provided "options.uri": %s',
|
|
475
|
+
options.uri
|
|
476
|
+
);
|
|
477
|
+
return new URL(options.uri.href);
|
|
478
|
+
}
|
|
479
|
+
debug3("figuring out url from request options...");
|
|
449
480
|
const protocol = getProtocolByRequestOptions(options);
|
|
450
|
-
const host = getHostByRequestOptions(options);
|
|
451
|
-
const port = getPortByRequestOptions(options);
|
|
452
|
-
const path = options.path || DEFAULT_PATH;
|
|
453
|
-
const auth = getAuthByRequestOptions(options);
|
|
454
481
|
debug3("protocol", protocol);
|
|
482
|
+
const host = getHostByRequestOptions(options);
|
|
455
483
|
debug3("host", host);
|
|
484
|
+
const port = getPortByRequestOptions(options);
|
|
456
485
|
debug3("port", port);
|
|
486
|
+
const hostname = getHostname(host, port);
|
|
487
|
+
debug3("hostname", hostname);
|
|
488
|
+
const path = options.path || DEFAULT_PATH;
|
|
457
489
|
debug3("path", path);
|
|
458
|
-
const
|
|
459
|
-
debug3("
|
|
460
|
-
const
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
}
|
|
465
|
-
if (auth) {
|
|
466
|
-
debug3("resolved auth", auth);
|
|
467
|
-
url.username = auth.username;
|
|
468
|
-
url.password = auth.password;
|
|
469
|
-
}
|
|
470
|
-
debug3("created URL:", url);
|
|
490
|
+
const credentials = getAuthByRequestOptions(options);
|
|
491
|
+
debug3("credentials", credentials);
|
|
492
|
+
const authString = credentials ? `${credentials.username}:${credentials.password}@` : "";
|
|
493
|
+
debug3("auth string:", authString);
|
|
494
|
+
const url = new URL(`${protocol}//${authString}${hostname}${path}`);
|
|
495
|
+
debug3("created url:", url);
|
|
471
496
|
return url;
|
|
472
497
|
}
|
|
473
498
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkXLZJAPVSjs = require('../../chunk-XLZJAPVS.js');
|
|
4
4
|
require('../../chunk-ZJOF5MEZ.js');
|
|
5
5
|
require('../../chunk-WWHITCCI.js');
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
exports.ClientRequestInterceptor =
|
|
8
|
+
exports.ClientRequestInterceptor = _chunkXLZJAPVSjs.ClientRequestInterceptor;
|
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.22.
|
|
4
|
+
"version": "0.22.3",
|
|
5
5
|
"main": "./lib/node/index.js",
|
|
6
6
|
"module": "./lib/node/index.mjs",
|
|
7
7
|
"types": "./lib/node/index.d.ts",
|
|
@@ -4,138 +4,132 @@ import { RequestOptions, Agent as HttpsAgent } from 'https'
|
|
|
4
4
|
import { getUrlByRequestOptions } from './getUrlByRequestOptions'
|
|
5
5
|
|
|
6
6
|
it('returns a URL based on the basic RequestOptions', () => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
expect(url).toBeInstanceOf(URL)
|
|
15
|
-
expect(url).toHaveProperty('port', '')
|
|
16
|
-
expect(url).toHaveProperty('href', 'https://127.0.0.1/resource')
|
|
7
|
+
expect(
|
|
8
|
+
getUrlByRequestOptions({
|
|
9
|
+
protocol: 'https:',
|
|
10
|
+
host: '127.0.0.1',
|
|
11
|
+
path: '/resource',
|
|
12
|
+
}).href
|
|
13
|
+
).toBe('https://127.0.0.1/resource')
|
|
17
14
|
})
|
|
18
15
|
|
|
19
16
|
it('inherits protocol and port from http.Agent, if set', () => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
expect(url).toBeInstanceOf(URL)
|
|
28
|
-
expect(url).toHaveProperty('protocol', 'http:')
|
|
29
|
-
expect(url).toHaveProperty('port', '')
|
|
30
|
-
expect(url).toHaveProperty('href', 'http://127.0.0.1/')
|
|
17
|
+
expect(
|
|
18
|
+
getUrlByRequestOptions({
|
|
19
|
+
host: '127.0.0.1',
|
|
20
|
+
path: '/',
|
|
21
|
+
agent: new HttpAgent(),
|
|
22
|
+
}).href
|
|
23
|
+
).toBe('http://127.0.0.1/')
|
|
31
24
|
})
|
|
32
25
|
|
|
33
26
|
it('inherits protocol and port from https.Agent, if set', () => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
expect(url).toBeInstanceOf(URL)
|
|
44
|
-
expect(url).toHaveProperty('protocol', 'https:')
|
|
45
|
-
expect(url).toHaveProperty('port', '3080')
|
|
46
|
-
expect(url).toHaveProperty('href', 'https://127.0.0.1:3080/')
|
|
27
|
+
expect(
|
|
28
|
+
getUrlByRequestOptions({
|
|
29
|
+
host: '127.0.0.1',
|
|
30
|
+
path: '/',
|
|
31
|
+
agent: new HttpsAgent({
|
|
32
|
+
port: 3080,
|
|
33
|
+
}),
|
|
34
|
+
}).href
|
|
35
|
+
).toBe('https://127.0.0.1:3080/')
|
|
47
36
|
})
|
|
48
37
|
|
|
49
38
|
it('resolves protocol to "http" given no explicit protocol and no certificate', () => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
expect(url).toBeInstanceOf(URL)
|
|
57
|
-
expect(url).toHaveProperty('protocol', 'http:')
|
|
58
|
-
expect(url).toHaveProperty('port', '')
|
|
59
|
-
expect(url).toHaveProperty('href', 'http://127.0.0.1/')
|
|
39
|
+
expect(
|
|
40
|
+
getUrlByRequestOptions({
|
|
41
|
+
host: '127.0.0.1',
|
|
42
|
+
path: '/',
|
|
43
|
+
}).href
|
|
44
|
+
).toBe('http://127.0.0.1/')
|
|
60
45
|
})
|
|
61
46
|
|
|
62
47
|
it('resolves protocol to "https" given no explicit protocol, but certificate', () => {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
expect(url).toBeInstanceOf(URL)
|
|
71
|
-
expect(url).toHaveProperty('protocol', 'https:')
|
|
72
|
-
expect(url).toHaveProperty('port', '')
|
|
73
|
-
expect(url).toHaveProperty('href', 'https://127.0.0.1/secure')
|
|
48
|
+
expect(
|
|
49
|
+
getUrlByRequestOptions({
|
|
50
|
+
host: '127.0.0.1',
|
|
51
|
+
path: '/secure',
|
|
52
|
+
cert: '<!-- SSL certificate -->',
|
|
53
|
+
}).href
|
|
54
|
+
).toBe('https://127.0.0.1/secure')
|
|
74
55
|
})
|
|
75
56
|
|
|
76
57
|
it('resolves protocol to "https" given no explicit protocol, but port is 443', () => {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
expect(url).toBeInstanceOf(URL)
|
|
85
|
-
expect(url).toHaveProperty('port', '')
|
|
86
|
-
expect(url).toHaveProperty('href', 'https://127.0.0.1/resource')
|
|
58
|
+
expect(
|
|
59
|
+
getUrlByRequestOptions({
|
|
60
|
+
host: '127.0.0.1',
|
|
61
|
+
port: 443,
|
|
62
|
+
path: '/resource',
|
|
63
|
+
}).href
|
|
64
|
+
).toBe('https://127.0.0.1/resource')
|
|
87
65
|
})
|
|
88
66
|
|
|
89
67
|
it('resolves protocol to "https" given no explicit protocol, but agent port is 443', () => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
expect(url).toBeInstanceOf(URL)
|
|
100
|
-
expect(url).toHaveProperty('port', '')
|
|
101
|
-
expect(url).toHaveProperty('href', 'https://127.0.0.1/resource')
|
|
68
|
+
expect(
|
|
69
|
+
getUrlByRequestOptions({
|
|
70
|
+
host: '127.0.0.1',
|
|
71
|
+
agent: new HttpsAgent({
|
|
72
|
+
port: 443,
|
|
73
|
+
}),
|
|
74
|
+
path: '/resource',
|
|
75
|
+
}).href
|
|
76
|
+
).toBe('https://127.0.0.1/resource')
|
|
102
77
|
})
|
|
103
78
|
|
|
104
|
-
it('
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
expect(url).toBeInstanceOf(URL)
|
|
114
|
-
expect(url).toHaveProperty('port', '4002')
|
|
115
|
-
expect(url).toHaveProperty('protocol', 'http:')
|
|
116
|
-
expect(url).toHaveProperty('href', 'http://127.0.0.1:4002/')
|
|
79
|
+
it('respects explicitly provided port', () => {
|
|
80
|
+
expect(
|
|
81
|
+
getUrlByRequestOptions({
|
|
82
|
+
protocol: 'http:',
|
|
83
|
+
host: '127.0.0.1',
|
|
84
|
+
port: 4002,
|
|
85
|
+
path: '/',
|
|
86
|
+
}).href
|
|
87
|
+
).toBe('http://127.0.0.1:4002/')
|
|
117
88
|
})
|
|
118
89
|
|
|
119
90
|
it('inherits "username" and "password"', () => {
|
|
120
|
-
const
|
|
91
|
+
const url = getUrlByRequestOptions({
|
|
121
92
|
protocol: 'https:',
|
|
122
93
|
host: '127.0.0.1',
|
|
123
94
|
path: '/user',
|
|
124
95
|
auth: 'admin:abc-123',
|
|
125
|
-
}
|
|
126
|
-
const url = getUrlByRequestOptions(options)
|
|
96
|
+
})
|
|
127
97
|
|
|
128
98
|
expect(url).toBeInstanceOf(URL)
|
|
129
99
|
expect(url).toHaveProperty('username', 'admin')
|
|
130
100
|
expect(url).toHaveProperty('password', 'abc-123')
|
|
131
|
-
expect(url).toHaveProperty('protocol', 'https:')
|
|
132
101
|
expect(url).toHaveProperty('href', 'https://admin:abc-123@127.0.0.1/user')
|
|
133
102
|
})
|
|
134
103
|
|
|
135
104
|
it('resolves hostname to localhost if none provided', () => {
|
|
136
|
-
|
|
105
|
+
expect(getUrlByRequestOptions({}).hostname).toBe('localhost')
|
|
106
|
+
})
|
|
137
107
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
108
|
+
it('supports "hostname" instead of "host" and "port"', () => {
|
|
109
|
+
const options: RequestOptions = {
|
|
110
|
+
protocol: 'https:',
|
|
111
|
+
hostname: '127.0.0.1:1234',
|
|
112
|
+
path: '/resource',
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
expect(getUrlByRequestOptions(options).href).toBe(
|
|
116
|
+
'https://127.0.0.1:1234/resource'
|
|
117
|
+
)
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('handles IPv6 hostnames', () => {
|
|
121
|
+
expect(
|
|
122
|
+
getUrlByRequestOptions({
|
|
123
|
+
host: '::1',
|
|
124
|
+
path: '/resource',
|
|
125
|
+
}).href
|
|
126
|
+
).toBe('http://[::1]/resource')
|
|
127
|
+
|
|
128
|
+
expect(
|
|
129
|
+
getUrlByRequestOptions({
|
|
130
|
+
host: '::1',
|
|
131
|
+
port: 3001,
|
|
132
|
+
path: '/resource',
|
|
133
|
+
}).href
|
|
134
|
+
).toBe('http://[::1]:3001/resource')
|
|
141
135
|
})
|
|
@@ -15,7 +15,6 @@ export type ResolvedRequestOptions = RequestOptions & RequestSelf
|
|
|
15
15
|
export const DEFAULT_PATH = '/'
|
|
16
16
|
const DEFAULT_PROTOCOL = 'http:'
|
|
17
17
|
const DEFAULT_HOST = 'localhost'
|
|
18
|
-
const DEFAULT_PORT = 80
|
|
19
18
|
const SSL_PORT = 443
|
|
20
19
|
|
|
21
20
|
function getAgent(
|
|
@@ -45,20 +44,45 @@ function getProtocolByRequestOptions(options: ResolvedRequestOptions): string {
|
|
|
45
44
|
function getPortByRequestOptions(
|
|
46
45
|
options: ResolvedRequestOptions
|
|
47
46
|
): number | undefined {
|
|
47
|
+
// Use the explicitly provided port.
|
|
48
|
+
if (options.port) {
|
|
49
|
+
return Number(options.port)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Extract the port from the hostname.
|
|
53
|
+
if (options.hostname != null) {
|
|
54
|
+
const [, extractedPort] = options.hostname.match(/:(\d+)$/) || []
|
|
55
|
+
|
|
56
|
+
if (extractedPort != null) {
|
|
57
|
+
return Number(extractedPort)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Otherwise, try to resolve port from the agent.
|
|
48
62
|
const agent = getAgent(options)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
(agent as
|
|
52
|
-
const optionsPort = options.port
|
|
53
|
-
|
|
54
|
-
if (optionsPort || agentPort) {
|
|
55
|
-
const explicitPort = optionsPort || agentPort || DEFAULT_PORT
|
|
56
|
-
return Number(explicitPort)
|
|
63
|
+
|
|
64
|
+
if ((agent as HttpsAgent)?.options.port) {
|
|
65
|
+
return Number((agent as HttpsAgent).options.port)
|
|
57
66
|
}
|
|
67
|
+
|
|
68
|
+
if ((agent as RequestOptions)?.defaultPort) {
|
|
69
|
+
return Number((agent as RequestOptions).defaultPort)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Lastly, return undefined indicating that the port
|
|
73
|
+
// must inferred from the protocol. Do not infer it here.
|
|
74
|
+
return undefined
|
|
58
75
|
}
|
|
59
76
|
|
|
60
77
|
function getHostByRequestOptions(options: ResolvedRequestOptions): string {
|
|
61
|
-
|
|
78
|
+
const { hostname, host } = options
|
|
79
|
+
|
|
80
|
+
// If the hostname is specified, resolve the host from the "host:port" string.
|
|
81
|
+
if (hostname != null) {
|
|
82
|
+
return hostname.replace(/:\d+$/, '')
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return host || DEFAULT_HOST
|
|
62
86
|
}
|
|
63
87
|
|
|
64
88
|
function getAuthByRequestOptions(options: ResolvedRequestOptions) {
|
|
@@ -77,45 +101,65 @@ function isRawIPv6Address(host: string): boolean {
|
|
|
77
101
|
return host.includes(':') && !host.startsWith('[') && !host.endsWith(']')
|
|
78
102
|
}
|
|
79
103
|
|
|
104
|
+
function getHostname(host: string, port?: number): string {
|
|
105
|
+
const portString = typeof port !== 'undefined' ? `:${port}` : ''
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @note As of Node >= 17, hosts (including "localhost") can resolve to IPv6
|
|
109
|
+
* addresses, so construct valid URL by surrounding the IPv6 host with brackets.
|
|
110
|
+
*/
|
|
111
|
+
if (isRawIPv6Address(host)) {
|
|
112
|
+
return `[${host}]${portString}`
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (typeof port === 'undefined') {
|
|
116
|
+
return host
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return `${host}${portString}`
|
|
120
|
+
}
|
|
121
|
+
|
|
80
122
|
/**
|
|
81
123
|
* Creates a `URL` instance from a given `RequestOptions` object.
|
|
82
124
|
*/
|
|
83
125
|
export function getUrlByRequestOptions(options: ResolvedRequestOptions): URL {
|
|
84
126
|
debug('request options', options)
|
|
85
127
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
128
|
+
if (options.uri) {
|
|
129
|
+
debug(
|
|
130
|
+
'constructing url from explicitly provided "options.uri": %s',
|
|
131
|
+
options.uri
|
|
132
|
+
)
|
|
133
|
+
return new URL(options.uri.href)
|
|
134
|
+
}
|
|
91
135
|
|
|
136
|
+
debug('figuring out url from request options...')
|
|
137
|
+
|
|
138
|
+
const protocol = getProtocolByRequestOptions(options)
|
|
92
139
|
debug('protocol', protocol)
|
|
140
|
+
|
|
141
|
+
const host = getHostByRequestOptions(options)
|
|
93
142
|
debug('host', host)
|
|
94
|
-
debug('port', port)
|
|
95
|
-
debug('path', path)
|
|
96
143
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
* addresses, so construct valid URL by surrounding the IPv6 host with brackets.
|
|
100
|
-
*/
|
|
101
|
-
const baseUrl = `${protocol}//${isRawIPv6Address(host) ? `[${host}]` : host}`
|
|
102
|
-
debug('base URL:', baseUrl)
|
|
144
|
+
const port = getPortByRequestOptions(options)
|
|
145
|
+
debug('port', port)
|
|
103
146
|
|
|
104
|
-
const
|
|
147
|
+
const hostname = getHostname(host, port)
|
|
148
|
+
debug('hostname', hostname)
|
|
105
149
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
url.port = port.toString()
|
|
109
|
-
}
|
|
150
|
+
const path = options.path || DEFAULT_PATH
|
|
151
|
+
debug('path', path)
|
|
110
152
|
|
|
111
|
-
|
|
112
|
-
|
|
153
|
+
const credentials = getAuthByRequestOptions(options)
|
|
154
|
+
debug('credentials', credentials)
|
|
113
155
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
156
|
+
const authString = credentials
|
|
157
|
+
? `${credentials.username}:${credentials.password}@`
|
|
158
|
+
: ''
|
|
159
|
+
debug('auth string:', authString)
|
|
117
160
|
|
|
118
|
-
|
|
161
|
+
const url = new URL(`${protocol}//${authString}${hostname}${path}`)
|
|
162
|
+
debug('created url:', url)
|
|
119
163
|
|
|
120
164
|
return url
|
|
121
165
|
}
|