Tolerate invalid control chars in RPC JSON
This commit is contained in:
@@ -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> {
|
||||
|
||||
Reference in New Issue
Block a user