Skip to content

Commit 220103d

Browse files
feat: add support for localaddress (nodejs#1659)
* build(deps-dev): bump @types/node from 17.0.45 to 18.0.3 (#10) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 17.0.45 to 18.0.3. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat: add support for localaddress * tests: add testing * revert: missed test Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1 parent 6714f9d commit 220103d

File tree

9 files changed

+50
-16
lines changed

9 files changed

+50
-16
lines changed

lib/client.js

+17-6
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ const {
6060
kClose,
6161
kDestroy,
6262
kDispatch,
63-
kInterceptors
63+
kInterceptors,
64+
kLocalAddress
6465
} = require('./core/symbols')
6566

6667
const kClosedResolve = Symbol('kClosedResolve')
@@ -102,7 +103,8 @@ class Client extends DispatcherBase {
102103
maxCachedSessions,
103104
maxRedirections,
104105
connect,
105-
maxRequestsPerClient
106+
maxRequestsPerClient,
107+
localAddress
106108
} = {}) {
107109
super()
108110

@@ -170,6 +172,10 @@ class Client extends DispatcherBase {
170172
throw new InvalidArgumentError('maxRequestsPerClient must be a positive number')
171173
}
172174

175+
if (localAddress != null && (typeof localAddress !== 'string' || net.isIP(localAddress) === 0)) {
176+
throw new InvalidArgumentError('localAddress must be valid string IP address')
177+
}
178+
173179
if (typeof connect !== 'function') {
174180
connect = buildConnector({
175181
...tls,
@@ -193,6 +199,7 @@ class Client extends DispatcherBase {
193199
this[kKeepAliveTimeoutThreshold] = keepAliveTimeoutThreshold == null ? 1e3 : keepAliveTimeoutThreshold
194200
this[kKeepAliveTimeoutValue] = this[kKeepAliveDefaultTimeout]
195201
this[kServerName] = null
202+
this[kLocalAddress] = localAddress != null ? localAddress : null
196203
this[kResuming] = 0 // 0, idle, 1, scheduled, 2 resuming
197204
this[kNeedDrain] = 0 // 0, idle, 1, scheduled, 2 resuming
198205
this[kHostHeader] = `host: ${this[kUrl].hostname}${this[kUrl].port ? `:${this[kUrl].port}` : ''}\r\n`
@@ -1020,7 +1027,8 @@ async function connect (client) {
10201027
hostname,
10211028
protocol,
10221029
port,
1023-
servername: client[kServerName]
1030+
servername: client[kServerName],
1031+
localAddress: client[kLocalAddress]
10241032
},
10251033
connector: client[kConnector]
10261034
})
@@ -1033,7 +1041,8 @@ async function connect (client) {
10331041
hostname,
10341042
protocol,
10351043
port,
1036-
servername: client[kServerName]
1044+
servername: client[kServerName],
1045+
localAddress: client[kLocalAddress]
10371046
}, (err, socket) => {
10381047
if (err) {
10391048
reject(err)
@@ -1076,7 +1085,8 @@ async function connect (client) {
10761085
hostname,
10771086
protocol,
10781087
port,
1079-
servername: client[kServerName]
1088+
servername: client[kServerName],
1089+
localAddress: client[kLocalAddress]
10801090
},
10811091
connector: client[kConnector],
10821092
socket
@@ -1093,7 +1103,8 @@ async function connect (client) {
10931103
hostname,
10941104
protocol,
10951105
port,
1096-
servername: client[kServerName]
1106+
servername: client[kServerName],
1107+
localAddress: client[kLocalAddress]
10971108
},
10981109
connector: client[kConnector],
10991110
error: err

lib/core/connect.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ function buildConnector ({ maxCachedSessions, socketPath, timeout, ...opts }) {
2121
timeout = timeout == null ? 10e3 : timeout
2222
maxCachedSessions = maxCachedSessions == null ? 100 : maxCachedSessions
2323

24-
return function connect ({ hostname, host, protocol, port, servername, httpSocket }, callback) {
24+
return function connect ({ hostname, host, protocol, port, servername, localAddress, httpSocket }, callback) {
2525
let socket
2626
if (protocol === 'https:') {
2727
if (!tls) {
@@ -39,6 +39,7 @@ function buildConnector ({ maxCachedSessions, socketPath, timeout, ...opts }) {
3939
...options,
4040
servername,
4141
session,
42+
localAddress,
4243
socket: httpSocket, // upgrade socket connection
4344
port: port || 443,
4445
host: hostname
@@ -70,6 +71,7 @@ function buildConnector ({ maxCachedSessions, socketPath, timeout, ...opts }) {
7071
socket = net.connect({
7172
highWaterMark: 64 * 1024, // Same as nodejs fs streams.
7273
...options,
74+
localAddress,
7375
port: port || 80,
7476
host: hostname
7577
})

lib/core/symbols.js

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ module.exports = {
1717
kHeadersTimeout: Symbol('headers timeout'),
1818
kBodyTimeout: Symbol('body timeout'),
1919
kServerName: Symbol('server name'),
20+
kLocalAddress: Symbol('local address'),
2021
kHost: Symbol('host'),
2122
kNoRef: Symbol('no ref'),
2223
kBodyUsed: Symbol('used'),

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
},
6767
"devDependencies": {
6868
"@sinonjs/fake-timers": "^9.1.2",
69-
"@types/node": "^17.0.45",
69+
"@types/node": "^18.0.3",
7070
"abort-controller": "^3.0.0",
7171
"atomic-sleep": "^1.0.0",
7272
"chai": "^4.3.4",

test/client-errors.js

+20
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,26 @@ test('invalid options throws', (t) => {
307307
t.equal(err.message, 'invalid keepAliveTimeout')
308308
}
309309

310+
try {
311+
new Client(new URL('http://localhost:200'), { // eslint-disable-line
312+
localAddress: 123
313+
}) // eslint-disable-line
314+
t.fail()
315+
} catch (err) {
316+
t.type(err, errors.InvalidArgumentError)
317+
t.equal(err.message, 'localAddress must be valid string IP address')
318+
}
319+
320+
try {
321+
new Client(new URL('http://localhost:200'), { // eslint-disable-line
322+
localAddress: 'abcd123'
323+
}) // eslint-disable-line
324+
t.fail()
325+
} catch (err) {
326+
t.type(err, errors.InvalidArgumentError)
327+
t.equal(err.message, 'localAddress must be valid string IP address')
328+
}
329+
310330
try {
311331
new Client(new URL('http://localhost:200'), { // eslint-disable-line
312332
keepAliveMaxTimeout: 'asd'

test/diagnostics-channel/connect-error.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ diagnosticsChannel.channel('undici:client:beforeConnect').subscribe(({ connectPa
2222
_connector = connector
2323

2424
t.equal(typeof _connector, 'function')
25-
t.equal(Object.keys(connectParams).length, 5)
25+
t.equal(Object.keys(connectParams).length, 6)
2626

2727
const { host, hostname, protocol, port, servername } = connectParams
2828

@@ -34,7 +34,7 @@ diagnosticsChannel.channel('undici:client:beforeConnect').subscribe(({ connectPa
3434
})
3535

3636
diagnosticsChannel.channel('undici:client:connectError').subscribe(({ error, connectParams, connector }) => {
37-
t.equal(Object.keys(connectParams).length, 5)
37+
t.equal(Object.keys(connectParams).length, 6)
3838
t.equal(_connector, connector)
3939

4040
const { host, hostname, protocol, port, servername } = connectParams

test/diagnostics-channel/get.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ diagnosticsChannel.channel('undici:client:beforeConnect').subscribe(({ connectPa
4949
_connector = connector
5050

5151
t.equal(typeof _connector, 'function')
52-
t.equal(Object.keys(connectParams).length, 5)
52+
t.equal(Object.keys(connectParams).length, 6)
5353

5454
const { host, hostname, protocol, port, servername } = connectParams
5555

@@ -65,7 +65,7 @@ diagnosticsChannel.channel('undici:client:connected').subscribe(({ connectParams
6565
_socket = socket
6666

6767
t.equal(_connector, connector)
68-
t.equal(Object.keys(connectParams).length, 5)
68+
t.equal(Object.keys(connectParams).length, 6)
6969

7070
const { host, hostname, protocol, port, servername } = connectParams
7171

test/diagnostics-channel/post-stream.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ diagnosticsChannel.channel('undici:client:beforeConnect').subscribe(({ connectPa
5252
_connector = connector
5353

5454
t.equal(typeof _connector, 'function')
55-
t.equal(Object.keys(connectParams).length, 5)
55+
t.equal(Object.keys(connectParams).length, 6)
5656

5757
const { host, hostname, protocol, port, servername } = connectParams
5858

@@ -67,7 +67,7 @@ let _socket
6767
diagnosticsChannel.channel('undici:client:connected').subscribe(({ connectParams, socket, connector }) => {
6868
_socket = socket
6969

70-
t.equal(Object.keys(connectParams).length, 5)
70+
t.equal(Object.keys(connectParams).length, 6)
7171
t.equal(_connector, connector)
7272

7373
const { host, hostname, protocol, port, servername } = connectParams

test/diagnostics-channel/post.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ diagnosticsChannel.channel('undici:client:beforeConnect').subscribe(({ connectPa
5050
_connector = connector
5151

5252
t.equal(typeof _connector, 'function')
53-
t.equal(Object.keys(connectParams).length, 5)
53+
t.equal(Object.keys(connectParams).length, 6)
5454

5555
const { host, hostname, protocol, port, servername } = connectParams
5656

@@ -65,7 +65,7 @@ let _socket
6565
diagnosticsChannel.channel('undici:client:connected').subscribe(({ connectParams, socket, connector }) => {
6666
_socket = socket
6767

68-
t.equal(Object.keys(connectParams).length, 5)
68+
t.equal(Object.keys(connectParams).length, 6)
6969
t.equal(_connector, connector)
7070

7171
const { host, hostname, protocol, port, servername } = connectParams

0 commit comments

Comments
 (0)