mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
fix(http): respect port numbers in NO_PROXY environment variable (#26347)
## Summary - Fix NO_PROXY environment variable to properly respect port numbers like Node.js and curl do - Previously `NO_PROXY=localhost:1234` would bypass proxy for all requests to localhost regardless of port - Now entries with ports (e.g., `localhost:8080`) do exact host:port matching, while entries without ports continue to use suffix matching ## Test plan - Added tests in `test/js/bun/http/proxy.test.js` covering: - [x] Bypass proxy when NO_PROXY matches host:port exactly - [x] Use proxy when NO_PROXY has different port - [x] Bypass proxy when NO_PROXY has host only (no port) - existing behavior preserved - [x] Handle NO_PROXY with multiple entries including port - Verified existing proxy tests still pass 🤖 Generated with [Claude Code](https://claude.ai/code) --------- Co-authored-by: Claude Bot <claude-bot@bun.sh> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
This commit is contained in:
@@ -15,10 +15,17 @@ beforeAll(() => {
|
||||
|
||||
// simple http proxy
|
||||
if (request.url.startsWith("http://")) {
|
||||
return await fetch(request.url, {
|
||||
const response = await fetch(request.url, {
|
||||
method: request.method,
|
||||
body: await request.text(),
|
||||
});
|
||||
// Add marker header to indicate request went through proxy
|
||||
const headers = new Headers(response.headers);
|
||||
headers.set("x-proxy-used", "1");
|
||||
return new Response(response.body, {
|
||||
status: response.status,
|
||||
headers,
|
||||
});
|
||||
}
|
||||
|
||||
// no TLS support here
|
||||
@@ -257,4 +264,129 @@ describe.concurrent(() => {
|
||||
}
|
||||
expect(exitCode).toBe(0);
|
||||
});
|
||||
|
||||
// Test that NO_PROXY respects port numbers like Node.js and curl do
|
||||
describe("NO_PROXY port handling", () => {
|
||||
it("should bypass proxy when NO_PROXY matches host:port exactly", async () => {
|
||||
// NO_PROXY includes the exact host:port, should bypass proxy
|
||||
const {
|
||||
exited,
|
||||
stdout,
|
||||
stderr: stderrStream,
|
||||
} = Bun.spawn({
|
||||
cmd: [
|
||||
bunExe(),
|
||||
"-e",
|
||||
`const resp = await fetch("http://localhost:${server.port}/test"); console.log(resp.headers.get("x-proxy-used") || "no-proxy");`,
|
||||
],
|
||||
env: {
|
||||
...bunEnv,
|
||||
http_proxy: `http://localhost:${proxy.port}`,
|
||||
NO_PROXY: `localhost:${server.port}`,
|
||||
},
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
});
|
||||
|
||||
const [exitCode, out, stderr] = await Promise.all([exited, stdout.text(), stderrStream.text()]);
|
||||
if (exitCode !== 0) {
|
||||
console.error("stderr:", stderr);
|
||||
}
|
||||
// Should connect directly, not through proxy (no x-proxy-used header)
|
||||
expect(out.trim()).toBe("no-proxy");
|
||||
expect(exitCode).toBe(0);
|
||||
});
|
||||
|
||||
it("should use proxy when NO_PROXY has different port", async () => {
|
||||
const differentPort = server.port + 1000;
|
||||
// NO_PROXY includes a different port, should NOT bypass proxy
|
||||
const {
|
||||
exited,
|
||||
stdout,
|
||||
stderr: stderrStream,
|
||||
} = Bun.spawn({
|
||||
cmd: [
|
||||
bunExe(),
|
||||
"-e",
|
||||
`const resp = await fetch("http://localhost:${server.port}/test"); console.log(resp.headers.get("x-proxy-used") || "no-proxy");`,
|
||||
],
|
||||
env: {
|
||||
...bunEnv,
|
||||
http_proxy: `http://localhost:${proxy.port}`,
|
||||
NO_PROXY: `localhost:${differentPort}`,
|
||||
},
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
});
|
||||
|
||||
const [exitCode, out, stderr] = await Promise.all([exited, stdout.text(), stderrStream.text()]);
|
||||
if (exitCode !== 0) {
|
||||
console.error("stderr:", stderr);
|
||||
}
|
||||
// The proxy adds x-proxy-used header, verify it was used
|
||||
expect(out.trim()).toBe("1");
|
||||
expect(exitCode).toBe(0);
|
||||
});
|
||||
|
||||
it("should bypass proxy when NO_PROXY has host only (no port)", async () => {
|
||||
// NO_PROXY includes just the host (no port), should bypass proxy for all ports
|
||||
const {
|
||||
exited,
|
||||
stdout,
|
||||
stderr: stderrStream,
|
||||
} = Bun.spawn({
|
||||
cmd: [
|
||||
bunExe(),
|
||||
"-e",
|
||||
`const resp = await fetch("http://localhost:${server.port}/test"); console.log(resp.headers.get("x-proxy-used") || "no-proxy");`,
|
||||
],
|
||||
env: {
|
||||
...bunEnv,
|
||||
http_proxy: `http://localhost:${proxy.port}`,
|
||||
NO_PROXY: `localhost`,
|
||||
},
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
});
|
||||
|
||||
const [exitCode, out, stderr] = await Promise.all([exited, stdout.text(), stderrStream.text()]);
|
||||
if (exitCode !== 0) {
|
||||
console.error("stderr:", stderr);
|
||||
}
|
||||
// Should connect directly, not through proxy (no x-proxy-used header)
|
||||
expect(out.trim()).toBe("no-proxy");
|
||||
expect(exitCode).toBe(0);
|
||||
});
|
||||
|
||||
it("should handle NO_PROXY with multiple entries including port", async () => {
|
||||
const differentPort = server.port + 1000;
|
||||
// NO_PROXY includes multiple entries, one of which matches exactly
|
||||
const {
|
||||
exited,
|
||||
stdout,
|
||||
stderr: stderrStream,
|
||||
} = Bun.spawn({
|
||||
cmd: [
|
||||
bunExe(),
|
||||
"-e",
|
||||
`const resp = await fetch("http://localhost:${server.port}/test"); console.log(resp.headers.get("x-proxy-used") || "no-proxy");`,
|
||||
],
|
||||
env: {
|
||||
...bunEnv,
|
||||
http_proxy: `http://localhost:${proxy.port}`,
|
||||
NO_PROXY: `example.com, localhost:${differentPort}, localhost:${server.port}`,
|
||||
},
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
});
|
||||
|
||||
const [exitCode, out, stderr] = await Promise.all([exited, stdout.text(), stderrStream.text()]);
|
||||
if (exitCode !== 0) {
|
||||
console.error("stderr:", stderr);
|
||||
}
|
||||
// Should connect directly, not through proxy (no x-proxy-used header)
|
||||
expect(out.trim()).toBe("no-proxy");
|
||||
expect(exitCode).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user