Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1752,6 +1752,11 @@ export function startServer(port?: number, deps: StartServerDeps = {}): Server<W
if (!isAllowedRequestOrigin(req, policy)) {
return withCors(formatErrorResponse(403, "origin_rejected", "cross-origin data-plane request blocked"), req, policy);
}
// Compaction buffers the whole upstream turn before the first byte reaches the
// client, so the server-level `idleTimeout` (255 s) would close this connection
// under a long remote compact even though the upstream is still working. Opt out
// the same way the other buffered data-plane routes above and below do.
disableResponsesRequestTimeout(req, requestServer);
const start = Date.now();
const requestId = nextRequestLogId(start);
const logCtx: RequestLogContext = {
Expand Down
13 changes: 13 additions & 0 deletions tests/server/server-auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,19 @@ describe("server local API auth", () => {
})).toBe(false);
});

test("compact route opts out of the request timeout before it buffers the compaction", () => {
// `/v1/responses/compact` answers only after the whole upstream turn has been collected,
// so unlike the streaming route it never sends a byte that would keep the connection
// alive. Without this opt-out the server-level `idleTimeout` closes a long remote
// compact mid-flight and the client sees a truncated body, not an error.
const source = readFileSync(new URL("../../src/server/index.ts", import.meta.url), "utf8");
const compactStart = source.indexOf('url.pathname === "/v1/responses/compact" && req.method === "POST"');
expect(compactStart).toBeGreaterThan(-1);
const handlerCall = source.indexOf("await handleResponsesCompact(req, config, logCtx", compactStart);
expect(handlerCall).toBeGreaterThan(compactStart);
expect(source.slice(compactStart, handlerCall)).toContain("disableResponsesRequestTimeout(req, requestServer);");
});

test("responses handler keeps the request timeout until the body is fully accepted", async () => {
let controller!: ReadableStreamDefaultController<Uint8Array>;
const body = new ReadableStream<Uint8Array>({
Expand Down
Loading