diff --git a/src/http.ts b/src/http.ts index b04caf9c4..995d2f83e 100644 --- a/src/http.ts +++ b/src/http.ts @@ -23,11 +23,42 @@ export interface IAttachment { body: NodeJS.ReadableStream; } -function getPortFromUrl(url: URL): string { - if (url.port) return url.port; - if (url.protocol.toLowerCase() === 'https:') return '443'; - if (url.protocol.toLowerCase() === 'http:') return '80'; - return ''; +// The URL API normalizes away default ports (:80 on http, :443 on https), +// so parse the port from the raw URL string to preserve ports. +function getPortFromUrl(url: string): string { + // Capture the authority section (everything between :// and the first /?#) + const authorityMatch = /^[a-z][a-z0-9+.-]*:\/\/([^/?#]+)/i.exec(url); + if (!authorityMatch) { + return ''; + } + + const hostPort = authorityMatch[1]; + + // IPv6 address: [::1] or [::1]:port + if (hostPort.startsWith('[')) { + const bracketEnd = hostPort.indexOf(']'); + if (bracketEnd !== -1 && hostPort[bracketEnd + 1] === ':') { + const port = hostPort.slice(bracketEnd + 2); + return /^\d+$/.test(port) ? port : ''; + } + return ''; + } + + // IPv4 / hostname: host or host:port + const colonIndex = hostPort.lastIndexOf(':'); + if (colonIndex === -1) { + return ''; + } + const port = hostPort.slice(colonIndex + 1); + return /^\d+$/.test(port) ? port : ''; +} + +// Add brackets to IPv6 addresses +function bracketIPv6(hostname: string): string { + if (hostname.startsWith('[') || hostname.indexOf(':') === -1) { + return hostname; + } + return `[${hostname}]`; } /** @@ -59,16 +90,15 @@ export class HttpClient implements IHttpClient { const curl = new URL(rurl); const method = data ? 'POST' : 'GET'; - const host = curl.hostname; - - const port = getPortFromUrl(curl); + const port = getPortFromUrl(rurl); + const host = port ? `${bracketIPv6(curl.hostname)}:${port}` : curl.host || curl.hostname; const headers: IHeaders = { 'User-Agent': 'node-soap/' + version, 'Accept': 'text/html,application/xhtml+xml,application/xml,text/xml;q=0.9,*/*;q=0.8', 'Accept-Encoding': 'none', 'Accept-Charset': 'utf-8', ...(exoptions.forever && { Connection: 'keep-alive' }), - 'Host': host + (port ? ':' + port : ''), + 'Host': host, }; const mergeOptions = ['headers']; diff --git a/test/client-customHttp-test.js b/test/client-customHttp-test.js index 09a88aeeb..c56e88b8b 100644 --- a/test/client-customHttp-test.js +++ b/test/client-customHttp-test.js @@ -116,3 +116,16 @@ it('should allow customization of httpClient and the wsdl file download should p done(); }); }); + +it('should not append default ports to Host header', function () { + var client = new httpClient(); + + var httpsReq = client.buildRequest('https://example.com/service?wsdl', null); + assert.equal(httpsReq.headers.Host, 'example.com'); + + var httpReq = client.buildRequest('http://example.com/service?wsdl', null); + assert.equal(httpReq.headers.Host, 'example.com'); + + var explicitPortReq = client.buildRequest('https://example.com:8443/service?wsdl', null); + assert.equal(explicitPortReq.headers.Host, 'example.com:8443'); +}); diff --git a/tsconfig.json b/tsconfig.json index e6de16066..30c6a58e5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,8 @@ "sourceMap": true, "declaration": true, "stripInternal": true, - "skipLibCheck": true + "skipLibCheck": true, + "types": ["node"] }, "include": ["src", "./eslint.config.mjs"], "exclude": ["node_modules"]