Tolerate invalid control chars in RPC JSON

This commit is contained in:
Codex Bot
2026-03-24 01:05:29 +01:00
parent a6d8178100
commit e4d57a91de

View File

@@ -8,6 +8,60 @@ type JsonRpcEnvelope<T> = {
};
};
function escapeControlCharactersInStrings(payload: string): string {
let result = "";
let inString = false;
let escaping = false;
for (let index = 0; index < payload.length; index += 1) {
const char = payload[index];
if (!inString) {
if (char === "\"") {
inString = true;
}
result += char;
continue;
}
if (escaping) {
result += char;
escaping = false;
continue;
}
if (char === "\\") {
result += char;
escaping = true;
continue;
}
if (char === "\"") {
result += char;
inString = false;
continue;
}
const code = char.charCodeAt(0);
if (code <= 0x1f) {
result += `\\u${code.toString(16).padStart(4, "0")}`;
continue;
}
result += char;
}
return result;
}
function parseRpcPayload<T>(payload: string): T {
try {
return JSON.parse(payload) as T;
} catch {
return JSON.parse(escapeControlCharactersInStrings(payload)) as T;
}
}
export type RpcBlockHeader = {
hash: string;
height: number;
@@ -94,7 +148,7 @@ export class PeyaRpcClient {
throw new Error(`RPC ${method} failed with HTTP ${response.status}`);
}
const payload = (await response.json()) as JsonRpcEnvelope<T>;
const payload = parseRpcPayload<JsonRpcEnvelope<T>>(await response.text());
if (payload.error) {
throw new Error(`RPC ${method} failed: ${payload.error.code} ${payload.error.message}`);
}
@@ -109,7 +163,7 @@ export class PeyaRpcClient {
if (!response.ok) {
throw new Error(`GET /getheight failed with HTTP ${response.status}`);
}
return (await response.json()) as RpcGetHeightResult;
return parseRpcPayload<RpcGetHeightResult>(await response.text());
}
async getBlock(height: number): Promise<RpcGetBlockResult> {
@@ -135,7 +189,7 @@ export class PeyaRpcClient {
if (!response.ok) {
throw new Error(`POST /gettransactions failed with HTTP ${response.status}`);
}
return (await response.json()) as RpcGetTransactionsResult;
return parseRpcPayload<RpcGetTransactionsResult>(await response.text());
}
async getYieldInfo(fromHeight: number, toHeight: number): Promise<RpcYieldInfoResult> {