diff --git a/scripts/fixtures/page-cdp-proxy.mjs b/scripts/fixtures/page-cdp-proxy.mjs index 6a002e9d8..faf43eff3 100644 --- a/scripts/fixtures/page-cdp-proxy.mjs +++ b/scripts/fixtures/page-cdp-proxy.mjs @@ -11,6 +11,7 @@ import WebSocket, { WebSocketServer } from "ws"; */ export async function startPageCdpProxy(upstreamEndpoint) { const clients = new Set(); + const upstreams = new Set(); const server = createServer(async (request, response) => { try { if (request.url !== "/json/version" && request.url !== "/json/list") { @@ -43,13 +44,18 @@ export async function startPageCdpProxy(upstreamEndpoint) { const upstream = new WebSocket( new URL(request.url, upstreamEndpoint).href.replace(/^http/, "ws"), ); + upstreams.add(upstream); const pending = []; clients.add(client); - const close = () => { + const closeClient = () => { clients.delete(client); if (client.readyState < WebSocket.CLOSING) client.close(); if (upstream.readyState < WebSocket.CLOSING) upstream.close(); }; + const finishUpstream = () => { + upstreams.delete(upstream); + closeClient(); + }; client.on("message", (data, binary) => { if (upstream.readyState === WebSocket.OPEN) upstream.send(data, { binary }); @@ -63,10 +69,10 @@ export async function startPageCdpProxy(upstreamEndpoint) { pending.length = 0; webSockets.emit("connection", client, request); }); - client.on("close", close); - client.on("error", close); - upstream.on("close", close); - upstream.on("error", close); + client.on("close", closeClient); + client.on("error", closeClient); + upstream.on("close", finishUpstream); + upstream.on("error", closeClient); }); }); await new Promise((resolve, reject) => { @@ -81,10 +87,20 @@ export async function startPageCdpProxy(upstreamEndpoint) { endpoint, disconnectClients() { for (const client of clients) client.terminate(); + for (const upstream of upstreams) upstream.terminate(); }, async close() { - for (const client of clients) client.terminate(); - webSockets.close(); + const activeClients = [...clients]; + const activeUpstreams = [...upstreams]; + await Promise.all([ + terminateSockets(activeClients), + terminateSockets(activeUpstreams), + ]); + await new Promise((resolve, reject) => + webSockets.close((error) => + error === undefined ? resolve() : reject(error), + ), + ); await new Promise((resolve, reject) => server.close((error) => error === undefined ? resolve() : reject(error), @@ -94,6 +110,19 @@ export async function startPageCdpProxy(upstreamEndpoint) { }; } +async function terminateSockets(sockets) { + const closing = [...sockets] + .filter((socket) => socket.readyState !== WebSocket.CLOSED) + .map( + (socket) => + new Promise((resolve) => { + socket.once("close", resolve); + socket.terminate(); + }), + ); + await Promise.all(closing); +} + async function pageScopedVersion(upstreamEndpoint, version) { const targets = await upstreamJson(upstreamEndpoint, "/json/list"); const page = targets.find( diff --git a/scripts/verify-real-browser.mjs b/scripts/verify-real-browser.mjs index e1102667c..5209df8ed 100644 --- a/scripts/verify-real-browser.mjs +++ b/scripts/verify-real-browser.mjs @@ -363,8 +363,11 @@ try { verified: true, }; } finally { + process.stderr.write("Browser verifier cleanup: closing page proxy\n"); if (pageProxy !== undefined) await pageProxy.close(); + process.stderr.write("Browser verifier cleanup: stopping owned Chrome\n"); if (browser !== undefined) await stopProcess(browser); + process.stderr.write("Browser verifier cleanup: closing fixture site\n"); await site.close(); await rm(profile, { recursive: true,