chore: handle unexpected ws response (#17714)
This commit is contained in:
parent
a97deb1600
commit
e09945c637
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
import { ws } from '../utilsBundle';
|
import { ws } from '../utilsBundle';
|
||||||
import type { WebSocket } from '../utilsBundle';
|
import type { WebSocket } from '../utilsBundle';
|
||||||
|
import type { ClientRequest, IncomingMessage } from 'http';
|
||||||
import type { Progress } from './progress';
|
import type { Progress } from './progress';
|
||||||
import { makeWaitForNextTask } from '../utils';
|
import { makeWaitForNextTask } from '../utils';
|
||||||
|
|
||||||
|
|
@ -62,15 +63,26 @@ export class WebSocketTransport implements ConnectionTransport {
|
||||||
await transport.closeAndWait().catch(e => null);
|
await transport.closeAndWait().catch(e => null);
|
||||||
});
|
});
|
||||||
await new Promise<WebSocketTransport>((fulfill, reject) => {
|
await new Promise<WebSocketTransport>((fulfill, reject) => {
|
||||||
transport._ws.addEventListener('open', async () => {
|
transport._ws.on('open', async () => {
|
||||||
progress.log(`<ws connected> ${url}`);
|
progress.log(`<ws connected> ${url}`);
|
||||||
fulfill(transport);
|
fulfill(transport);
|
||||||
});
|
});
|
||||||
transport._ws.addEventListener('error', event => {
|
transport._ws.on('error', event => {
|
||||||
progress.log(`<ws connect error> ${url} ${event.message}`);
|
progress.log(`<ws connect error> ${url} ${event.message}`);
|
||||||
reject(new Error('WebSocket error: ' + event.message));
|
reject(new Error('WebSocket error: ' + event.message));
|
||||||
transport._ws.close();
|
transport._ws.close();
|
||||||
});
|
});
|
||||||
|
transport._ws.on('unexpected-response', (request: ClientRequest, response: IncomingMessage) => {
|
||||||
|
const chunks: Buffer[] = [];
|
||||||
|
const errorPrefix = `${url} ${response.statusCode} ${response.statusMessage}`;
|
||||||
|
response.on('data', chunk => chunks.push(chunk));
|
||||||
|
response.on('close', () => {
|
||||||
|
const error = chunks.length ? `${errorPrefix}\n${Buffer.concat(chunks)}` : errorPrefix;
|
||||||
|
progress.log(`<ws unexpected response> ${error}`);
|
||||||
|
reject(new Error('WebSocket error: ' + error));
|
||||||
|
transport._ws.close();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
success = true;
|
success = true;
|
||||||
return transport;
|
return transport;
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,13 @@ test('should connect over wss', async ({ browserType, startRemoteServer, httpsSe
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should print HTTP error', async ({ browserType, server, mode }) => {
|
||||||
|
test.skip(mode !== 'default'); // Out of process transport does not allow us to set env vars dynamically.
|
||||||
|
const error = await browserType.connect(`ws://localhost:${server.PORT}/ws-401`).catch(e => e);
|
||||||
|
expect(error.message).toContain('401');
|
||||||
|
expect(error.message).toContain('Unauthorized body');
|
||||||
|
});
|
||||||
|
|
||||||
test('should be able to reconnect to a browser', async ({ browserType, startRemoteServer, server }) => {
|
test('should be able to reconnect to a browser', async ({ browserType, startRemoteServer, server }) => {
|
||||||
const remoteServer = await startRemoteServer();
|
const remoteServer = await startRemoteServer();
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ it.describe('launch server', () => {
|
||||||
const browserServer = await browserType.launchServer();
|
const browserServer = await browserType.launchServer();
|
||||||
const error = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() + '-foo' }).catch(e => e);
|
const error = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() + '-foo' }).catch(e => e);
|
||||||
await browserServer.close();
|
await browserServer.close();
|
||||||
expect(error.message).toContain('Unexpected server response: 400');
|
expect(error.message).toContain('400 Bad Request');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fire "close" event during kill', async ({ browserType }) => {
|
it('should fire "close" event during kill', async ({ browserType }) => {
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,11 @@ export class TestServer {
|
||||||
this._wsServer = new ws.WebSocketServer({ noServer: true });
|
this._wsServer = new ws.WebSocketServer({ noServer: true });
|
||||||
this._server.on('upgrade', async (request, socket, head) => {
|
this._server.on('upgrade', async (request, socket, head) => {
|
||||||
const pathname = url.parse(request.url!).path;
|
const pathname = url.parse(request.url!).path;
|
||||||
|
if (pathname === '/ws-401') {
|
||||||
|
socket.write('HTTP/1.1 401 Unauthorized\r\n\r\nUnauthorized body');
|
||||||
|
socket.destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (pathname === '/ws-slow')
|
if (pathname === '/ws-slow')
|
||||||
await new Promise(f => setTimeout(f, 2000));
|
await new Promise(f => setTimeout(f, 2000));
|
||||||
if (!['/ws', '/ws-slow'].includes(pathname)) {
|
if (!['/ws', '/ws-slow'].includes(pathname)) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue