parse error

This commit is contained in:
Connor Peet
2026-03-12 23:40:52 -07:00
parent 2da8aa0354
commit 247bd102ef
3 changed files with 46 additions and 2 deletions

View File

@@ -76,6 +76,7 @@ export function isJsonRpcResponse(msg: IProtocolMessage): msg is IJsonRpcRespons
// ---- JSON-RPC error codes ---------------------------------------------------
export const JSON_RPC_PARSE_ERROR = -32700;
export const JSON_RPC_INTERNAL_ERROR = -32603;
// ---- Shared data types ------------------------------------------------------

View File

@@ -10,7 +10,7 @@ import { Emitter } from '../../../base/common/event.js';
import { Disposable } from '../../../base/common/lifecycle.js';
import { connectionTokenQueryName } from '../../../base/common/network.js';
import { ILogService } from '../../log/common/log.js';
import type { IProtocolMessage } from '../common/state/sessionProtocol.js';
import { JSON_RPC_PARSE_ERROR, type IProtocolMessage } from '../common/state/sessionProtocol.js';
import type { IProtocolServer, IProtocolTransport } from '../common/state/sessionTransport.js';
import { protocolReplacer, protocolReviver } from '../common/state/jsonSerialization.js';
@@ -58,7 +58,7 @@ export class WebSocketProtocolTransport extends Disposable implements IProtocolT
const message = JSON.parse(text, protocolReviver) as IProtocolMessage;
this._onMessage.fire(message);
} catch {
// Malformed message — drop. No logger available at transport level.
this.send({ jsonrpc: '2.0', id: null!, error: { code: JSON_RPC_PARSE_ERROR, message: 'Parse error' } });
}
});

View File

@@ -13,6 +13,7 @@ import { protocolReplacer, protocolReviver } from '../../common/state/jsonSerial
import {
isJsonRpcNotification,
isJsonRpcResponse,
JSON_RPC_PARSE_ERROR,
type IActionBroadcastParams,
type IFetchTurnsResult,
type IJsonRpcErrorResponse,
@@ -140,6 +141,31 @@ class TestProtocolClient {
return predicate ? this._notifications.filter(predicate) : [...this._notifications];
}
/** Send a raw string over the WebSocket without JSON serialization. */
sendRaw(data: string): void {
this._ws.send(data);
}
/** Wait for the next raw message from the server. */
waitForRawMessage(timeoutMs = 5000): Promise<unknown> {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
cleanup();
reject(new Error(`Timeout waiting for raw message (${timeoutMs}ms)`));
}, timeoutMs);
const onMsg = (data: Buffer | string) => {
cleanup();
const text = typeof data === 'string' ? data : data.toString('utf-8');
resolve(JSON.parse(text));
};
const cleanup = () => {
clearTimeout(timer);
this._ws.removeListener('message', onMsg);
};
this._ws.on('message', onMsg);
});
}
close(): void {
for (const w of this._notifWaiters) {
w.reject(new Error('Client closed'));
@@ -636,4 +662,21 @@ suite('Protocol WebSocket E2E', function () {
const state = snapshot.state as ISessionState;
assert.strictEqual(state.summary.model, 'new-mock-model');
});
test('malformed JSON message returns parse error', async function () {
this.timeout(10_000);
const raw = new TestProtocolClient(server.port);
await raw.connect();
const responsePromise = raw.waitForRawMessage();
raw.sendRaw('this is not valid json{{{');
const response = await responsePromise as IJsonRpcErrorResponse;
assert.strictEqual(response.jsonrpc, '2.0');
assert.strictEqual(response.id, null);
assert.strictEqual(response.error.code, JSON_RPC_PARSE_ERROR);
raw.close();
});
});