diff --git a/lib/internal/socketaddress.js b/lib/internal/socketaddress.js index 724ffd90cf77f1..29ea1ccb80bc61 100644 --- a/lib/internal/socketaddress.js +++ b/lib/internal/socketaddress.js @@ -1,6 +1,7 @@ 'use strict'; const { + NumberParseInt, ObjectSetPrototypeOf, Symbol, } = primordials; @@ -153,18 +154,25 @@ class SocketAddress { // other pieces here that do... the destucturing, the SocketAddress // constructor, etc. So we wrap this in a try/catch to be safe. try { - const { - hostname: address, + // url.port strips default HTTP ports (e.g. 80), so parse the port from + // the raw input string instead. + const { hostname: address } = URLParse(`http://${input}`); + + const isIPv6 = address[0] === '[' && address.endsWith(']'); + + // Strip userinfo (e.g. "user:pass@") before searching for port separator. + // For IPv6, indexOf(']:') + 1 points at ':' (or 0 if absent, treated as no port). + // For IPv4, lastIndexOf(':') points at ':' (or -1 if absent). + const atIdx = input.lastIndexOf('@'); + const hostPart = atIdx >= 0 ? input.slice(atIdx + 1) : input; + const sepIdx = isIPv6 ? hostPart.indexOf(']:') + 1 : hostPart.lastIndexOf(':'); + const port = sepIdx > 0 ? NumberParseInt(hostPart.slice(sepIdx + 1), 10) || 0 : 0; + + return new SocketAddress({ + address: isIPv6 ? address.slice(1, -1) : address, port, - } = URLParse(`http://${input}`); - if (address.startsWith('[') && address.endsWith(']')) { - return new SocketAddress({ - address: address.slice(1, -1), - port: port | 0, - family: 'ipv6', - }); - } - return new SocketAddress({ address, port: port | 0 }); + family: isIPv6 ? 'ipv6' : 'ipv4', + }); } catch { // Ignore errors here. Return undefined if the input cannot // be successfully parsed or is not a proper socket address. diff --git a/test/parallel/test-socketaddress.js b/test/parallel/test-socketaddress.js index cf29795a48fcfa..2544a01ab8a9ae 100644 --- a/test/parallel/test-socketaddress.js +++ b/test/parallel/test-socketaddress.js @@ -148,6 +148,16 @@ describe('net.SocketAddress...', () => { { input: '0x.0x.0', address: '0.0.0.0', port: 0, family: 'ipv4' }, { input: '[1:0::]', address: '1::', port: 0, family: 'ipv6' }, { input: '[1::8]:123', address: '1::8', port: 123, family: 'ipv6' }, + { input: '127.0.0.1:80', address: '127.0.0.1', port: 80, family: 'ipv4' }, + { input: '127.0.0.1:443', address: '127.0.0.1', port: 443, family: 'ipv4' }, + { input: '[::1]:80', address: '::1', port: 80, family: 'ipv6' }, + { input: '[::1]:443', address: '::1', port: 443, family: 'ipv6' }, + { input: 'user:80@1.2.3.4', address: '1.2.3.4', port: 0, family: 'ipv4' }, + { input: 'user:80@1.2.3.4:80', address: '1.2.3.4', port: 80, family: 'ipv4' }, + { input: 'user:80@1.2.3.4:123', address: '1.2.3.4', port: 123, family: 'ipv4' }, + { input: 'user:80@[::1]', address: '::1', port: 0, family: 'ipv6' }, + { input: 'user:80@[::1]:80', address: '::1', port: 80, family: 'ipv6' }, + { input: 'user:80@[::1]:123', address: '::1', port: 123, family: 'ipv6' }, ]; good.forEach((i) => {