mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-07 07:42:13 +03:00
Validated in local merge-train (diegosouzapw batch)
This commit is contained in:
committed by
GitHub
parent
8fdb67f1d3
commit
5ea43c7a9d
@@ -353,6 +353,7 @@ ALLOW_API_KEY_REVEAL=false
|
||||
# instead of growing an unbounded string until the V8 heap is exhausted.
|
||||
# Used by: open-sse/handlers/chatCore/nonStreamingResponseBody.ts
|
||||
# Default: 67108864 (64 MB)
|
||||
# OMNIROUTE_FORWARDING_HEADER_BUDGET_BYTES=768
|
||||
# OMNIROUTE_MAX_NONSTREAMING_RESPONSE_BYTES=67108864
|
||||
|
||||
# CORS configuration — controls which cross-origin browser clients can call the API.
|
||||
|
||||
1
changelog.d/features/9243-forwarded-header-budget-env.md
Normal file
1
changelog.d/features/9243-forwarded-header-budget-env.md
Normal file
@@ -0,0 +1 @@
|
||||
- feat: make forwarded upstream response-header budget configurable via env var (#9243)
|
||||
@@ -196,6 +196,7 @@ OmniRoute uses **SQLite** (via `better-sqlite3`) for all persistence. These vari
|
||||
| `OMNIROUTE_CHAT_HEAVY_ESTIMATED_TOKENS` | `32000` | `src/shared/middleware/chatBodyAdmission.ts` | Conservative string-size token estimate that classifies a request as heavyweight; this is an admission-cost proxy, not provider billing tokenization. |
|
||||
| `OMNIROUTE_CHAT_HARD_MAX_MESSAGES` | `800` | `src/shared/middleware/chatBodyAdmission.ts` | Hard chat history cap. Requests above it receive structured compact-required `413` before compression, translation, or provider dispatch. |
|
||||
| `OMNIROUTE_MAX_NONSTREAMING_RESPONSE_BYTES` | `67108864` (64 MB) | `open-sse/handlers/chatCore/nonStreamingResponseBody.ts` | Hard cap for a non-streaming upstream response buffered fully into memory. Past this the upstream reader is cancelled and the request fails fast instead of growing an unbounded string until the heap is exhausted. |
|
||||
| `OMNIROUTE_FORWARDING_HEADER_BUDGET_BYTES` | `768` | `open-sse/handlers/chatCore/responseHeaders.ts` | Max wire bytes forwarded from upstream response headers. When the budget is exceeded, lower-priority headers (e.g., custom `x-codex-*`, `x-oai-request-id`) are dropped to stay within common reverse-proxy header limits. Set higher to forward more upstream metadata at the cost of larger response header size. |
|
||||
| `CORS_ORIGIN` | _(unset)_ | `src/server/cors/origins.ts` | Legacy single-origin CORS allowlist. Prefer `CORS_ALLOWED_ORIGINS` for new deployments. CORS is only for cross-origin browser API clients; authenticated dashboard writes use same-origin requests plus session-bound CSRF protection instead. |
|
||||
| `CORS_ALLOWED_ORIGINS` | _(unset)_ | `src/server/cors/origins.ts` | Comma-separated CORS allowlist. No wildcard is sent unless `CORS_ALLOW_ALL=true` is explicitly configured. |
|
||||
| `CORS_ALLOW_ALL` | `false` | `src/server/cors/origins.ts` | Development-only escape hatch to echo any browser `Origin`. Do not enable on shared or production deployments. |
|
||||
|
||||
@@ -30,12 +30,27 @@ const STREAMING_RESPONSE_HEADER_DENYLIST = new Set([
|
||||
"x-accel-buffering",
|
||||
]);
|
||||
|
||||
const DEFAULT_FORWARDED_HEADER_BUDGET_BYTES = 768;
|
||||
|
||||
/**
|
||||
* Resolve the forwarded upstream response-header budget from an optional string value
|
||||
* (typically `process.env.OMNIROUTE_FORWARDING_HEADER_BUDGET_BYTES`). Returns the
|
||||
* default of 768 when the input is unset, empty, or non-positive.
|
||||
* Extracted as a pure function so unit tests can pass values directly without
|
||||
* module-cache manipulation.
|
||||
*/
|
||||
export function resolveForwardedHeaderBudget(env?: string): number {
|
||||
const parsed = Number.parseInt(String(env ?? process.env.OMNIROUTE_FORWARDING_HEADER_BUDGET_BYTES), 10);
|
||||
return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_FORWARDED_HEADER_BUDGET_BYTES;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep upstream-derived headers comfortably below common reverse-proxy response-header limits.
|
||||
* This budget includes each header name, separator, value, and trailing CRLF. OmniRoute's own
|
||||
* response metadata and framework/security headers are added separately.
|
||||
* Override with `OMNIROUTE_FORWARDING_HEADER_BUDGET_BYTES`.
|
||||
*/
|
||||
export const MAX_FORWARDED_UPSTREAM_RESPONSE_HEADER_BYTES = 768;
|
||||
export const MAX_FORWARDED_UPSTREAM_RESPONSE_HEADER_BYTES = resolveForwardedHeaderBudget();
|
||||
const MAX_LOGGED_DROPPED_RESPONSE_HEADERS = 20;
|
||||
const responseHeaderEncoder = new TextEncoder();
|
||||
|
||||
|
||||
@@ -208,6 +208,7 @@
|
||||
"tests/unit/executor-antigravity.test.ts",
|
||||
"tests/unit/executor-web-cookie-sweep.test.ts",
|
||||
"tests/unit/format-provider-error-cause.test.ts",
|
||||
"tests/unit/forwarded-header-budget.test.ts",
|
||||
"tests/unit/gemini-web-missing-browser-3516.test.ts",
|
||||
"tests/unit/grok-cli-oauth.test.ts",
|
||||
"tests/unit/guardrails-api-3496.test.ts",
|
||||
|
||||
31
tests/unit/forwarded-header-budget.test.ts
Normal file
31
tests/unit/forwarded-header-budget.test.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { describe, it } from "node:test";
|
||||
import { equal } from "node:assert/strict";
|
||||
|
||||
describe("Forwarded upstream response-header budget (#9243)", () => {
|
||||
it("resolveForwardedHeaderBudget returns default 768 when env is unset", async () => {
|
||||
const { resolveForwardedHeaderBudget } = await import(
|
||||
"@/../open-sse/handlers/chatCore/responseHeaders"
|
||||
);
|
||||
equal(resolveForwardedHeaderBudget(undefined), 768);
|
||||
equal(resolveForwardedHeaderBudget(), 768);
|
||||
});
|
||||
|
||||
it("resolveForwardedHeaderBudget overrides with a valid value", async () => {
|
||||
const { resolveForwardedHeaderBudget } = await import(
|
||||
"@/../open-sse/handlers/chatCore/responseHeaders"
|
||||
);
|
||||
equal(resolveForwardedHeaderBudget("2048"), 2048);
|
||||
equal(resolveForwardedHeaderBudget("1"), 1);
|
||||
equal(resolveForwardedHeaderBudget("4096"), 4096);
|
||||
});
|
||||
|
||||
it("resolveForwardedHeaderBudget falls back to default on invalid input", async () => {
|
||||
const { resolveForwardedHeaderBudget } = await import(
|
||||
"@/../open-sse/handlers/chatCore/responseHeaders"
|
||||
);
|
||||
equal(resolveForwardedHeaderBudget(""), 768, "empty string");
|
||||
equal(resolveForwardedHeaderBudget("abc"), 768, "non-numeric");
|
||||
equal(resolveForwardedHeaderBudget("0"), 768, "zero");
|
||||
equal(resolveForwardedHeaderBudget("-1"), 768, "negative");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user