mirror of
https://github.com/morluto/rea.git
synced 2026-11-03 05:16:16 +00:00
fix(mcp): ignore zero-quality Accept ranges in the session takeover guard
Addresses a thirteenth automated review finding: `application/json;q=0` explicitly refuses JSON, so it no longer counts toward the exact Accept ranges a session takeover requires. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a1da7ffef1
commit
2deed2eb77
3 files changed
+38
-2
No files matched your search
@@ -762,3 +762,22 @@ it("closes the connection when a route read only part of the body and keeps it a
|
||||
agent.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
it("does not let a zero-quality Accept range qualify a session takeover", async () => {
|
||||
const { served } = await start();
|
||||
const { client } = await connect(served.url);
|
||||
const url = new URL(served.url);
|
||||
const refused = await rawHttpRequest(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
host: `127.0.0.1:${url.port}`,
|
||||
"content-type": "application/json",
|
||||
accept: "application/json;q=0, text/event-stream",
|
||||
},
|
||||
body: await initializeRequest().text(),
|
||||
});
|
||||
expect(refused.status).toBeGreaterThanOrEqual(400);
|
||||
expect(refused.status).toBeLessThan(500);
|
||||
expect(await echo(client, "kept")).toEqual([{ type: "text", text: "kept" }]);
|
||||
await client.close();
|
||||
});
|
||||
@@ -115,10 +115,20 @@ const SHUTTING_DOWN = (): Response =>
|
||||
/** The media type proper of one header value or Accept range: no parameters, lowercase. */
|
||||
const mediaType = (value: string): string =>
|
||||
(value.split(";")[0] ?? "").trim().toLowerCase();
|
||||
/** An Accept range's quality weight; a missing or unreadable `q` counts as 1, as in RFC 9110. */
|
||||
const quality = (range: string): number => {
|
||||
const q = /;\s*q\s*=\s*([0-9.]+)/iu.exec(range)?.[1];
|
||||
const value = q === undefined ? 1 : Number(q);
|
||||
return Number.isFinite(value) ? value : 1;
|
||||
};
|
||||
const hasStreamablePostHeaders = (request: Request): boolean => {
|
||||
// Exact media ranges and type: `application/json-patch+json` or `text/event-streaming` do not count.
|
||||
// Exact media ranges with a positive weight: `application/json-patch+json`, `text/event-streaming`
|
||||
// and `application/json;q=0` do not count.
|
||||
const accepted = new Set(
|
||||
(request.headers.get("accept") ?? "").split(",").map(mediaType),
|
||||
(request.headers.get("accept") ?? "")
|
||||
.split(",")
|
||||
.filter((range) => quality(range) > 0)
|
||||
.map(mediaType),
|
||||
);
|
||||
return (
|
||||
accepted.has("application/json") &&
|
||||
|
||||
Reference in new issue
Block a user