Skip to content

Commit ae2425f

Browse files
committed
fix(browser): report malformed relay CDP frames
1 parent 19f7b72 commit ae2425f

2 files changed

Lines changed: 66 additions & 9 deletions

File tree

extensions/browser/src/browser/extension-relay/relay-bridge.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,34 @@ describe("ExtensionRelayBridge", () => {
324324
expect(bridge.extensionConnected).toBe(false);
325325
});
326326

327+
it("reports malformed CDP client JSON instead of leaving the client waiting", () => {
328+
const bridge = new ExtensionRelayBridge();
329+
const client = new FakeSocket();
330+
const cdp = bridge.attachCdpClientSocket(client);
331+
332+
cdp.onMessage("{");
333+
334+
expect(client.frames()).toEqual([
335+
{ id: null, error: { code: -32700, message: "Parse error" } },
336+
]);
337+
});
338+
339+
it("reports invalid CDP client requests instead of leaving the client waiting", () => {
340+
const bridge = new ExtensionRelayBridge();
341+
const client = new FakeSocket();
342+
const cdp = bridge.attachCdpClientSocket(client);
343+
344+
cdp.onMessage(JSON.stringify({ id: 7, sessionId: "session-1", params: {} }));
345+
346+
expect(client.frames()).toEqual([
347+
{
348+
id: 7,
349+
sessionId: "session-1",
350+
error: { code: -32600, message: "Invalid request" },
351+
},
352+
]);
353+
});
354+
327355
it("reaps child sessions when a tab leaves the group (no stale routing)", async () => {
328356
const bridge = new ExtensionRelayBridge();
329357
const { handlers } = wireExtension(bridge);

extensions/browser/src/browser/extension-relay/relay-bridge.ts

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ type CdpRequest = {
4141
sessionId?: string;
4242
};
4343

44+
type CdpRequestParseResult =
45+
| { ok: true; request: CdpRequest }
46+
| { ok: false; id: number | null; sessionId?: string; message: string; code: number };
47+
4448
type PendingExtensionCommand = {
4549
resolve: (result: unknown) => void;
4650
reject: (err: Error) => void;
@@ -74,10 +78,37 @@ type ExtensionIdentity = {
7478
extensionVersion: string;
7579
};
7680

77-
function toErrorPayload(id: number, sessionId: string | undefined, message: string, code = -32000) {
81+
function toErrorPayload(
82+
id: number | null,
83+
sessionId: string | undefined,
84+
message: string,
85+
code = -32000,
86+
) {
7887
return JSON.stringify({ id, ...(sessionId ? { sessionId } : {}), error: { code, message } });
7988
}
8089

90+
function parseCdpRequest(raw: string): CdpRequestParseResult {
91+
let parsed: unknown;
92+
try {
93+
parsed = JSON.parse(raw);
94+
} catch {
95+
return { ok: false, id: null, message: "Parse error", code: -32700 };
96+
}
97+
98+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
99+
return { ok: false, id: null, message: "Invalid request", code: -32600 };
100+
}
101+
102+
const request = parsed as Record<string, unknown>;
103+
const id = typeof request.id === "number" ? request.id : null;
104+
const sessionId = typeof request.sessionId === "string" ? request.sessionId : undefined;
105+
if (typeof request.id !== "number" || typeof request.method !== "string") {
106+
return { ok: false, id, sessionId, message: "Invalid request", code: -32600 };
107+
}
108+
109+
return { ok: true, request: parsed as CdpRequest };
110+
}
111+
81112
/**
82113
* One relay bridge per extension-driver profile. Accepts at most one extension
83114
* connection (a newer one replaces the old — MV3 workers restart freely) and
@@ -494,16 +525,14 @@ export class ExtensionRelayBridge {
494525
const client: CdpClientState = { socket, autoAttach: false, announcedSessions: new Set() };
495526
this.clients.add(client);
496527
const onMessage = (raw: string) => {
497-
let request: CdpRequest;
498-
try {
499-
request = JSON.parse(raw) as CdpRequest;
500-
} catch {
501-
return;
502-
}
503-
if (typeof request?.id !== "number" || typeof request?.method !== "string") {
528+
const parsed = parseCdpRequest(raw);
529+
if (!parsed.ok) {
530+
client.socket.send(
531+
toErrorPayload(parsed.id, parsed.sessionId, parsed.message, parsed.code),
532+
);
504533
return;
505534
}
506-
void this.handleCdpRequest(client, request);
535+
void this.handleCdpRequest(client, parsed.request);
507536
};
508537
const onClose = () => {
509538
this.clients.delete(client);

0 commit comments

Comments
 (0)