diff --git a/packages/playwright-core/src/server/socksClientCertificatesInterceptor.ts b/packages/playwright-core/src/server/socksClientCertificatesInterceptor.ts index 32a7b1cebd..2dd900bf89 100644 --- a/packages/playwright-core/src/server/socksClientCertificatesInterceptor.ts +++ b/packages/playwright-core/src/server/socksClientCertificatesInterceptor.ts @@ -169,6 +169,10 @@ class SocksProxyConnection { this.target.removeListener('close', this._targetCloseEventListener); // @ts-expect-error const session: http2.ServerHttp2Session = http2.performServerHandshake(internalTLS); + session.on('error', () => { + this.target.destroy(); + this._targetCloseEventListener(); + }); session.once('stream', (stream: http2.ServerHttp2Stream) => { stream.respond({ 'content-type': 'text/html', diff --git a/tests/library/client-certificates.spec.ts b/tests/library/client-certificates.spec.ts index a6f6628569..807af5154c 100644 --- a/tests/library/client-certificates.spec.ts +++ b/tests/library/client-certificates.spec.ts @@ -461,7 +461,7 @@ test.describe('browser', () => { }); await new Promise(resolve => server.listen(0, 'localhost', resolve)); - const port = (server.address() as import('net').AddressInfo).port; + const port = (server.address() as net.AddressInfo).port; const origin = 'https://' + (browserName === 'webkit' && platform === 'darwin' ? 'local.playwright' : 'localhost'); const serverUrl = `${origin}:${port}`; @@ -671,6 +671,39 @@ test.describe('browser', () => { await page.close(); }); + test('should handle rejected certificate in handshake with HTTP/2', async ({ browser, asset, browserName, platform }) => { + const server: http2.Http2SecureServer = createHttp2Server({ + key: fs.readFileSync(asset('client-certificates/server/server_key.pem')), + cert: fs.readFileSync(asset('client-certificates/server/server_cert.pem')), + ca: [fs.readFileSync(asset('client-certificates/server/server_cert.pem'))], + requestCert: true, + }, async (req: http2.Http2ServerRequest, res: http2.Http2ServerResponse) => { + res.writeHead(200, { 'Content-Type': 'text/html' }); + res.end('Hello world'); + }); + + await new Promise(resolve => server.listen(0, 'localhost', resolve)); + const port = (server.address() as net.AddressInfo).port; + const serverUrl = 'https://' + (browserName === 'webkit' && platform === 'darwin' ? 'local.playwright' : 'localhost') + ':' + port; + + const context = await browser.newContext({ + ignoreHTTPSErrors: true, + clientCertificates: [{ + origin: 'https://just-there-that-the-client-certificates-proxy-server-is-getting-launched.com', + certPath: asset('client-certificates/client/trusted/cert.pem'), + keyPath: asset('client-certificates/client/trusted/key.pem'), + }], + }); + + const page = await context.newPage(); + + // This was triggering an unhandled error before. + await page.goto(serverUrl).catch(() => {}); + + await context.close(); + await new Promise(resolve => server.close(() => resolve())); + }); + test.describe('persistentContext', () => { test('validate input', async ({ launchPersistent }) => { test.slow();