diff --git a/.changeset/slick-wings-sing.md b/.changeset/slick-wings-sing.md new file mode 100644 index 00000000..67620ed3 --- /dev/null +++ b/.changeset/slick-wings-sing.md @@ -0,0 +1,5 @@ +--- +'http-proxy-agent': patch +--- + +Set the HTTPS proxy hostname as the default TLS servername. diff --git a/packages/http-proxy-agent/src/index.ts b/packages/http-proxy-agent/src/index.ts index 7ffb5a7a..6c9db0a3 100644 --- a/packages/http-proxy-agent/src/index.ts +++ b/packages/http-proxy-agent/src/index.ts @@ -17,6 +17,25 @@ export type { OnProxyAuthCallback, ProxyAuthParams, ProxyAuthResponse }; const debug = createDebug('http-proxy-agent'); +const setServernameFromNonIpHost = < + T extends { host?: string; servername?: string } +>( + options: T +) => { + if ( + options.servername === undefined && + options.host && + !net.isIP(options.host) + ) { + return { + ...options, + servername: options.host, + }; + } + return options; +}; + + export interface ProxyConnect { socket: net.Socket; } @@ -177,7 +196,7 @@ export class HttpProxyAgent extends Agent { let socket: net.Socket; if (this.proxy.protocol === 'https:') { debug('Creating `tls.Socket`: %o', this.connectOpts); - socket = tls.connect(this.connectOpts); + socket = tls.connect(setServernameFromNonIpHost(this.connectOpts)); } else { debug('Creating `net.Socket`: %o', this.connectOpts); socket = net.connect(this.connectOpts); diff --git a/packages/http-proxy-agent/test/test.ts b/packages/http-proxy-agent/test/test.ts index c286f165..0c213970 100644 --- a/packages/http-proxy-agent/test/test.ts +++ b/packages/http-proxy-agent/test/test.ts @@ -278,5 +278,30 @@ describe('HttpProxyAgent', () => { agent.destroy(); } }); + + it('should use the HTTPS proxy hostname as SNI by default', async () => { + let receivedServername: string | false | undefined; + + httpServer.once('request', (_req, res) => { + res.end(); + }); + + sslProxy.once('secureConnection', (socket) => { + receivedServername = socket.servername; + }); + + const hostnameProxyUrl = new URL(sslProxyUrl); + hostnameProxyUrl.hostname = 'localhost'; + + const agent = new HttpProxyAgent(hostnameProxyUrl, { + rejectUnauthorized: false, + }); + + const res = await req(httpServerUrl, { agent }); + res.resume(); + await once(res, 'end'); + + expect(receivedServername).toBe('localhost'); + }); }); });