From 1d3e433d7b6e0d320c8de55fcd764b49d312c174 Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Tue, 19 Aug 2025 13:58:30 +0200 Subject: [PATCH 1/2] chore: drop raw-body dependency --- package-lock.json | 1 - package.json | 3 +-- src/server/sse.ts | 25 ++++++++++++++++++++++--- src/server/streamableHttp.ts | 8 ++++---- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1e0b12ed7..7edfed055 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,6 @@ "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" }, diff --git a/package.json b/package.json index 697b051be..7aa5fbdac 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,6 @@ "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" }, @@ -100,4 +99,4 @@ "resolutions": { "strip-ansi": "6.0.1" } -} \ No newline at end of file +} diff --git a/src/server/sse.ts b/src/server/sse.ts index e07256867..cad5dc87f 100644 --- a/src/server/sse.ts +++ b/src/server/sse.ts @@ -2,12 +2,11 @@ import { randomUUID } from "node:crypto"; import { IncomingMessage, ServerResponse } from "node:http"; import { Transport } from "../shared/transport.js"; import { JSONRPCMessage, JSONRPCMessageSchema, MessageExtraInfo, RequestInfo } from "../types.js"; -import getRawBody from "raw-body"; import contentType from "content-type"; import { AuthInfo } from "./auth/types.js"; import { URL } from 'url'; -const MAXIMUM_MESSAGE_SIZE = "4mb"; +const MAXIMUM_MESSAGE_SIZE = 4 * 1024 * 1024; // 4MB /** * Configuration options for SSEServerTransport. @@ -161,7 +160,7 @@ export class SSEServerTransport implements Transport { body = parsedBody ?? await getRawBody(req, { limit: MAXIMUM_MESSAGE_SIZE, - encoding: ct.parameters.charset ?? "utf-8", + encoding: (ct.parameters.charset as BufferEncoding) ?? "utf-8", }); } catch (error) { res.writeHead(400).end(String(error)); @@ -219,3 +218,23 @@ export class SSEServerTransport implements Transport { return this._sessionId; } } + +export function getRawBody(req: IncomingMessage, { limit, encoding }: { limit: number, encoding: BufferEncoding }) { + return new Promise((resolve, reject) => { + let received = 0; + + const chunks: Buffer[] = []; + req.on("data", (chunk: Buffer) => { + received += chunk.length; + if (received > limit) + return reject(new Error(`Message size exceeds limit of ${limit} bytes`)); + chunks.push(chunk); + }); + req.on('end', () => { + resolve(Buffer.concat(chunks).toString(encoding)); + }); + req.on('error', (error) => { + reject(error); + }); + }); +} \ No newline at end of file diff --git a/src/server/streamableHttp.ts b/src/server/streamableHttp.ts index 3bf84e430..aef475df7 100644 --- a/src/server/streamableHttp.ts +++ b/src/server/streamableHttp.ts @@ -1,12 +1,12 @@ import { IncomingMessage, ServerResponse } from "node:http"; import { Transport } from "../shared/transport.js"; import { MessageExtraInfo, RequestInfo, isInitializeRequest, isJSONRPCError, isJSONRPCRequest, isJSONRPCResponse, JSONRPCMessage, JSONRPCMessageSchema, RequestId, SUPPORTED_PROTOCOL_VERSIONS, DEFAULT_NEGOTIATED_PROTOCOL_VERSION } from "../types.js"; -import getRawBody from "raw-body"; import contentType from "content-type"; import { randomUUID } from "node:crypto"; import { AuthInfo } from "./auth/types.js"; +import { getRawBody } from "./sse.js"; -const MAXIMUM_MESSAGE_SIZE = "4mb"; +const MAXIMUM_MESSAGE_SIZE = 4 * 1024 * 1024; // 4MB export type StreamId = string; export type EventId = string; @@ -412,9 +412,9 @@ export class StreamableHTTPServerTransport implements Transport { const parsedCt = contentType.parse(ct); const body = await getRawBody(req, { limit: MAXIMUM_MESSAGE_SIZE, - encoding: parsedCt.parameters.charset ?? "utf-8", + encoding: (parsedCt.parameters.charset as BufferEncoding) ?? "utf-8", }); - rawMessage = JSON.parse(body.toString()); + rawMessage = JSON.parse(body); } let messages: JSONRPCMessage[]; From 343c48fe29def617235431a70f5c350990a935ce Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Wed, 20 Aug 2025 07:31:33 +0200 Subject: [PATCH 2/2] catch encoding error --- src/server/sse.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/server/sse.ts b/src/server/sse.ts index cad5dc87f..aa4e9cfd1 100644 --- a/src/server/sse.ts +++ b/src/server/sse.ts @@ -231,7 +231,11 @@ export function getRawBody(req: IncomingMessage, { limit, encoding }: { limit: n chunks.push(chunk); }); req.on('end', () => { - resolve(Buffer.concat(chunks).toString(encoding)); + try { + resolve(Buffer.concat(chunks).toString(encoding)); + } catch (error) { + reject(error); + } }); req.on('error', (error) => { reject(error);