diff --git a/packages/playwright-core/src/server/socksClientCertificatesInterceptor.ts b/packages/playwright-core/src/server/socksClientCertificatesInterceptor.ts index d4923d6847..f16a60fe00 100644 --- a/packages/playwright-core/src/server/socksClientCertificatesInterceptor.ts +++ b/packages/playwright-core/src/server/socksClientCertificatesInterceptor.ts @@ -81,23 +81,19 @@ class SocksProxyConnection { target!: net.Socket; // In case of http, we just pipe data to the target socket and they are |undefined|. internal: stream.Duplex | undefined; - _interceptClose = false; + private _targetCloseEventListener: () => void; constructor(socksProxy: ClientCertificatesProxy, uid: string, host: string, port: number) { this.socksProxy = socksProxy; this.uid = uid; this.host = host; this.port = port; + this._targetCloseEventListener = () => this.socksProxy._socksProxy.sendSocketEnd({ uid: this.uid }); } async connect() { this.target = await createSocket(rewriteToLocalhostIfNeeded(this.host), this.port); - this.target.on('close', () => { - // In case of an 'error' event on the target connection, we still need to perform the http2 handshake on the browser side. - // This is an async operation, so we need to intercept the close event to prevent the socket from being closed too early. - if (!this._interceptClose) - this.socksProxy._socksProxy.sendSocketEnd({ uid: this.uid }); - }); + this.target.on('close', this._targetCloseEventListener); this.target.on('error', error => this.socksProxy._socksProxy.sendSocketError({ uid: this.uid, error: error.message })); this.socksProxy._socksProxy.socketConnected({ uid: this.uid, @@ -181,9 +177,11 @@ class SocksProxyConnection { if (internalTLS?.alpnProtocol === 'h2') { // This method is available only in Node.js 20+ if ('performServerHandshake' in http2) { - this._interceptClose = true; + // In case of an 'error' event on the target connection, we still need to perform the http2 handshake on the browser side. + // This is an async operation, so we need to intercept the close event to prevent the socket from being closed too early. + this.target.removeListener('close', this._targetCloseEventListener); // @ts-expect-error - const session = http2.performServerHandshake(internalTLS); + const session: http2.ServerHttp2Session = http2.performServerHandshake(internalTLS); session.on('stream', (stream: http2.ServerHttp2Stream) => { stream.respond({ 'content-type': 'text/html', @@ -193,6 +191,7 @@ class SocksProxyConnection { session.close(); closeBothSockets(); }); + stream.on('error', () => closeBothSockets()); }); } else { closeBothSockets();