mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-02 21:32:10 +03:00
* fix(sse): silence noisy proxy-failure log on caller-initiated abort The pinned-proxy dispatch path in proxyFetch.ts logged every failure — including a plain caller abort or the caller's own AbortSignal timeout firing — as "[ProxyFetch] Proxy request failed ... fail-closed". A client cancelling its own request is not a proxy transport failure and shouldn't be misreported as one in ops logs/alerting; it still propagates to the caller unchanged (fail-closed behavior is untouched). Co-authored-by: TuyulSpam <287281626+TuyulSpam@users.noreply.github.com> Inspired-by: https://github.com/decolua/9router/pull/2589 * chore(changelog): fragment for #7266 --------- Co-authored-by: TuyulSpam <287281626+TuyulSpam@users.noreply.github.com>
107 lines
3.7 KiB
TypeScript
107 lines
3.7 KiB
TypeScript
/**
|
|
* Ported from decolua/9router#2589 ("harden proxy routing"): the pinned-proxy
|
|
* dispatch path in `proxyFetch.ts` logged every failure — including a plain
|
|
* caller-initiated abort/timeout — as `console.error("[ProxyFetch] Proxy
|
|
* request failed ... fail-closed")`. A client cancelling its own request (or
|
|
* its own AbortSignal.timeout firing) is not a proxy transport failure; it
|
|
* shouldn't be misreported as one in ops logs/alerting.
|
|
*
|
|
* This only changes what gets logged — the abort error itself still
|
|
* propagates to the caller unchanged (fail-closed behavior is untouched).
|
|
*/
|
|
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import http from "node:http";
|
|
|
|
import proxyFetch, { runWithProxyContext } from "../../open-sse/utils/proxyFetch.ts";
|
|
|
|
async function withHttpServer(handler, fn) {
|
|
const server = http.createServer(handler);
|
|
await new Promise((resolve, reject) => {
|
|
server.once("error", reject);
|
|
server.listen(0, "127.0.0.1", resolve);
|
|
});
|
|
const address = server.address();
|
|
assert.ok(address && typeof address === "object");
|
|
try {
|
|
return await fn(`http://127.0.0.1:${address.port}`);
|
|
} finally {
|
|
await new Promise((resolve, reject) => {
|
|
server.close((error) => (error ? reject(error) : resolve()));
|
|
});
|
|
}
|
|
}
|
|
|
|
test("pinned-proxy dispatch does not log a noisy 'Proxy request failed' error for a caller-initiated abort", async () => {
|
|
await withHttpServer(
|
|
(_req, res) => res.end("proxy-reachable"),
|
|
async (proxyUrl) => {
|
|
const parsed = new URL(proxyUrl);
|
|
const originalConsoleError = console.error;
|
|
const loggedMessages: string[] = [];
|
|
console.error = (...args: unknown[]) => {
|
|
loggedMessages.push(args.map(String).join(" "));
|
|
};
|
|
|
|
try {
|
|
const controller = new AbortController();
|
|
controller.abort();
|
|
|
|
await assert.rejects(
|
|
runWithProxyContext(
|
|
{ type: "http", host: parsed.hostname, port: parsed.port },
|
|
async () =>
|
|
proxyFetch("https://example.invalid/", {
|
|
signal: controller.signal,
|
|
})
|
|
)
|
|
);
|
|
} finally {
|
|
console.error = originalConsoleError;
|
|
}
|
|
|
|
assert.ok(
|
|
!loggedMessages.some((m) => m.includes("Proxy request failed")),
|
|
`expected no 'Proxy request failed' log for a caller abort, got: ${JSON.stringify(loggedMessages)}`
|
|
);
|
|
}
|
|
);
|
|
});
|
|
|
|
test("pinned-proxy dispatch still logs genuine (non-abort) proxy transport failures", async () => {
|
|
await withHttpServer(
|
|
(_req, res) => res.end("proxy-reachable"),
|
|
async (proxyUrl) => {
|
|
const parsed = new URL(proxyUrl);
|
|
const originalConsoleError = console.error;
|
|
const loggedMessages: string[] = [];
|
|
console.error = (...args: unknown[]) => {
|
|
loggedMessages.push(args.map(String).join(" "));
|
|
};
|
|
// Inject a throwing undici mock — a real dispatcher-level transport
|
|
// failure (e.g. tunnel refused), NOT a caller abort — must still log.
|
|
const throwingUndici = async () => {
|
|
throw new Error("proxy tunnel refused");
|
|
};
|
|
|
|
try {
|
|
await assert.rejects(
|
|
runWithProxyContext(
|
|
{ type: "http", host: parsed.hostname, port: parsed.port },
|
|
async () =>
|
|
proxyFetch("https://example.invalid/", {}, { undiciFetch: throwingUndici })
|
|
),
|
|
/proxy tunnel refused/
|
|
);
|
|
} finally {
|
|
console.error = originalConsoleError;
|
|
}
|
|
|
|
assert.ok(
|
|
loggedMessages.some((m) => m.includes("Proxy request failed")),
|
|
`expected a 'Proxy request failed' log for a genuine transport failure, got: ${JSON.stringify(loggedMessages)}`
|
|
);
|
|
}
|
|
);
|
|
});
|