aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/bun-linux-build.yml3
-rw-r--r--.github/workflows/bun-mac-aarch64.yml3
-rw-r--r--.github/workflows/bun-mac-x64-baseline.yml3
-rw-r--r--.github/workflows/bun-mac-x64.yml3
-rw-r--r--src/http_client_async.zig11
-rw-r--r--test/js/bun/http/proxy.test.js136
-rw-r--r--test/js/bun/http/proxy.test.ts157
7 files changed, 174 insertions, 142 deletions
diff --git a/.github/workflows/bun-linux-build.yml b/.github/workflows/bun-linux-build.yml
index a448b3ac1..eea989dab 100644
--- a/.github/workflows/bun-linux-build.yml
+++ b/.github/workflows/bun-linux-build.yml
@@ -182,6 +182,9 @@ jobs:
cd bun-${{matrix.tag}}
chmod +x bun
sudo mv bun /usr/local/bin/bun
+ curl -L -o ./http_proxy https://github.com/cirospaciari/http-proxy/raw/main/bin/linux/http_proxy
+ chmod +x ./http_proxy
+ sudo mv ./http_proxy /usr/local/bin/http_proxy
bun --version
- id: test
name: Test (node runner)
diff --git a/.github/workflows/bun-mac-aarch64.yml b/.github/workflows/bun-mac-aarch64.yml
index f85c233a5..030b55bd1 100644
--- a/.github/workflows/bun-mac-aarch64.yml
+++ b/.github/workflows/bun-mac-aarch64.yml
@@ -419,6 +419,9 @@ jobs:
cd ${{matrix.tag}}
chmod +x bun
sudo mv bun /usr/local/bin/bun
+ curl -L -o ./http_proxy https://github.com/cirospaciari/http-proxy/raw/main/bin/macos-arm64/http_proxy
+ chmod +x ./http_proxy
+ sudo mv ./http_proxy /usr/local/bin/http_proxy
bun --version
- id: test
name: Test (node runner)
diff --git a/.github/workflows/bun-mac-x64-baseline.yml b/.github/workflows/bun-mac-x64-baseline.yml
index 7d127cab3..fefcda748 100644
--- a/.github/workflows/bun-mac-x64-baseline.yml
+++ b/.github/workflows/bun-mac-x64-baseline.yml
@@ -423,6 +423,9 @@ jobs:
cd ${{matrix.tag}}
chmod +x bun
sudo mv bun /usr/local/bin/bun
+ curl -L -o ./http_proxy https://github.com/cirospaciari/http-proxy/raw/main/bin/macos/http_proxy
+ chmod +x ./http_proxy
+ sudo mv ./http_proxy /usr/local/bin/http_proxy
bun --version
- id: test
name: Test (node runner)
diff --git a/.github/workflows/bun-mac-x64.yml b/.github/workflows/bun-mac-x64.yml
index 0d690916a..f8bbfd855 100644
--- a/.github/workflows/bun-mac-x64.yml
+++ b/.github/workflows/bun-mac-x64.yml
@@ -425,6 +425,9 @@ jobs:
cd ${{matrix.tag}}
chmod +x bun
sudo mv bun /usr/local/bin/bun
+ curl -L -o ./http_proxy https://github.com/cirospaciari/http-proxy/raw/main/bin/macos/http_proxy
+ chmod +x ./http_proxy
+ sudo mv ./http_proxy /usr/local/bin/http_proxy
bun --version
- id: test
name: Test (node runner)
diff --git a/src/http_client_async.zig b/src/http_client_async.zig
index c75883ad7..db77f84fb 100644
--- a/src/http_client_async.zig
+++ b/src/http_client_async.zig
@@ -2702,13 +2702,12 @@ pub fn handleResponseMetadata(
}
if (this.proxy_tunneling and this.proxy_tunnel == null) {
- //proxy denied connection
- if (this.state.pending_response.status_code != 200) {
- return error.ConnectionRefused;
+ if (this.state.pending_response.status_code == 200) {
+ //signal to continue the proxing
+ return true;
}
-
- //signal to continue the proxing
- return true;
+ //proxy denied connection so return proxy result (407, 403 etc)
+ this.proxy_tunneling = false;
}
const is_redirect = this.state.pending_response.status_code >= 300 and this.state.pending_response.status_code <= 399;
diff --git a/test/js/bun/http/proxy.test.js b/test/js/bun/http/proxy.test.js
deleted file mode 100644
index 203cbc294..000000000
--- a/test/js/bun/http/proxy.test.js
+++ /dev/null
@@ -1,136 +0,0 @@
-import { afterAll, beforeAll, describe, expect, it } from "bun:test";
-import { gc } from "harness";
-
-let proxy, auth_proxy, server;
-
-// TODO: Proxy with TLS requests
-
-beforeAll(() => {
- proxy = Bun.serve({
- port: 0,
- async fetch(request) {
- // if is not an proxy connection just drop it
- if (!request.headers.has("proxy-connection")) {
- return new Response("Bad Request", { status: 400 });
- }
-
- // simple http proxy
- if (request.url.startsWith("http://")) {
- return await fetch(request.url, {
- method: request.method,
- body: await request.text(),
- });
- }
-
- // no TLS support here
- return new Response("Bad Request", { status: 400 });
- },
- });
- auth_proxy = Bun.serve({
- port: 0,
- async fetch(request) {
- // if is not an proxy connection just drop it
- if (!request.headers.has("proxy-connection")) {
- return new Response("Bad Request", { status: 400 });
- }
-
- if (!request.headers.has("proxy-authorization")) {
- return new Response("Proxy Authentication Required", { status: 407 });
- }
-
- const auth = Buffer.from(
- request.headers.get("proxy-authorization").replace("Basic ", "").trim(),
- "base64",
- ).toString("utf8");
- if (auth !== "squid_user:ASD123@123asd") {
- return new Response("Forbidden", { status: 403 });
- }
-
- // simple http proxy
- if (request.url.startsWith("http://")) {
- return await fetch(request.url, {
- method: request.method,
- body: await request.text(),
- });
- }
-
- // no TLS support here
- return new Response("Bad Request", { status: 400 });
- },
- });
- server = Bun.serve({
- port: 0,
- async fetch(request) {
- if (request.method === "POST") {
- const text = await request.text();
- return new Response(text, { status: 200 });
- }
- return new Response("Hello, World", { status: 200 });
- },
- });
-});
-
-afterAll(() => {
- server.stop();
- proxy.stop();
- auth_proxy.stop();
-});
-
-it("proxy non-TLS", async () => {
- const url = `http://localhost:${server.port}`;
- const auth_proxy_url = `http://squid_user:ASD123%40123asd@localhost:${auth_proxy.port}`;
- const proxy_url = `localhost:${proxy.port}`;
- const requests = [
- [new Request(url), auth_proxy_url],
- [
- new Request(url, {
- method: "POST",
- body: "Hello, World",
- }),
- auth_proxy_url,
- ],
- [url, auth_proxy_url],
- [new Request(url), proxy_url],
- [
- new Request(url, {
- method: "POST",
- body: "Hello, World",
- }),
- proxy_url,
- ],
- [url, proxy_url],
- ];
- for (let [request, proxy] of requests) {
- gc();
- const response = await fetch(request, { verbose: true, proxy });
- gc();
- const text = await response.text();
- gc();
- expect(text).toBe("Hello, World");
- }
-});
-
-it("proxy non-TLS auth can fail", async () => {
- const url = `http://localhost:${server.port}`;
-
- {
- try {
- const response = await fetch(url, { verbose: true, proxy: `http://localhost:${auth_proxy.port}` });
- expect(response.statusText).toBe("Proxy Authentication Required");
- } catch (err) {
- expect(err).toBe("Proxy Authentication Required");
- }
- }
-
- {
- try {
- const response = await fetch(url, {
- verbose: true,
- proxy: `http://squid_user:asdf123@localhost:${auth_proxy.port}`,
- });
- expect(response.statusText).toBe("Forbidden");
- } catch (err) {
- expect(err).toBe("Forbidden");
- }
- }
-});
diff --git a/test/js/bun/http/proxy.test.ts b/test/js/bun/http/proxy.test.ts
new file mode 100644
index 000000000..f5cfe2478
--- /dev/null
+++ b/test/js/bun/http/proxy.test.ts
@@ -0,0 +1,157 @@
+import { which } from "bun";
+import { afterAll, beforeAll, describe, expect, it } from "bun:test";
+import { gc } from "harness";
+import { spawn } from "node:child_process";
+import { readFileSync } from "node:fs";
+import { join } from "node:path";
+type ProxyServer = { port: number | null; stop(): void };
+
+let proxy: ProxyServer, auth_proxy: ProxyServer, server: ProxyServer, server_tls: ProxyServer;
+
+const HTTP_PROXY_PATH = which("http_proxy");
+const test = HTTP_PROXY_PATH ? it : it.skip;
+
+const rawKeyFile = join(import.meta.dir, "../../node/tls", "fixtures", "rsa_private.pem");
+const certFile = join(import.meta.dir, "../../node/tls", "fixtures", "rsa_cert.crt");
+
+beforeAll(async () => {
+ if (!HTTP_PROXY_PATH) return;
+
+ function startProxyServer(options: Array<string>): Promise<ProxyServer> {
+ return new Promise((resolve, reject) => {
+ const proxy = spawn(HTTP_PROXY_PATH, options);
+ proxy.stdout.on("data", data => {
+ const [type, value] = data.toString().split(" ");
+
+ switch (type) {
+ case "[LISTEN]":
+ let port = value?.trim()?.split(":")[1];
+ if (port) {
+ port = parseInt(port, 10);
+ }
+ resolve({
+ port,
+ stop() {
+ proxy.kill();
+ },
+ });
+ case "[LISTEN-FAILURE]":
+ reject({ port: null, stop: () => {} });
+ break;
+ default:
+ console.log("Unknown type", data.toString());
+ }
+ });
+ if (proxy.exitCode) {
+ reject({ port: null, stop: () => {} });
+ }
+ });
+ }
+
+ proxy = await startProxyServer(["--port", "0"]);
+ auth_proxy = await startProxyServer(["--port", "0", "--auth", "squid_user:ASD@123asd"]);
+ server = Bun.serve({
+ port: 0,
+ async fetch(request) {
+ if (request.method === "POST") {
+ const text = await request.text();
+ return new Response(text, { status: 200 });
+ }
+ return new Response("Hello, World", { status: 200 });
+ },
+ });
+ server_tls = Bun.serve({
+ port: 0,
+ certFile: certFile,
+ keyFile: rawKeyFile,
+ async fetch(request) {
+ if (request.method === "POST") {
+ const text = await request.text();
+ return new Response(text, { status: 200 });
+ }
+ return new Response("Hello, World", { status: 200 });
+ },
+ });
+});
+
+afterAll(() => {
+ server.stop();
+ proxy.stop();
+ auth_proxy.stop();
+ server_tls.stop();
+});
+
+for (let is_tls of [false, true]) {
+ describe(`server ${is_tls ? "TLS" : "non-TLS"}`, () => {
+ test("fetch proxy", async done => {
+ const url = `${is_tls ? "https" : "http"}://127.0.0.1:${is_tls ? server_tls.port : server.port}`;
+ const auth_proxy_url = `http://squid_user:ASD%40123asd@127.0.0.1:${auth_proxy.port}`;
+ const proxy_url = `http://127.0.0.1:${proxy.port}`;
+ const requests: Array<[Request | string, string]> = [
+ [new Request(url), auth_proxy_url],
+ [
+ new Request(url, {
+ method: "POST",
+ body: "Hello, World",
+ }),
+ auth_proxy_url,
+ ],
+ [url, auth_proxy_url],
+ [new Request(url), proxy_url],
+ [
+ new Request(url, {
+ method: "POST",
+ body: "Hello, World",
+ }),
+ proxy_url,
+ ],
+ [url, proxy_url],
+ ];
+ for (let [request, proxy] of requests) {
+ try {
+ gc();
+ const response = await fetch(request, { keepalive: false, verbose: true, proxy });
+ gc();
+ expect(response.status).toBe(200);
+ } catch (err) {
+ console.error(err);
+ expect(true).toBeFalsy();
+ }
+ }
+ done();
+ });
+
+ test("fetch proxy auth can fail", async done => {
+ const url = `${is_tls ? "https" : "http"}://localhost:${is_tls ? server_tls.port : server.port}`;
+ {
+ try {
+ const response = await fetch(url, {
+ keepalive: false,
+ verbose: true,
+ proxy: `http://localhost:${auth_proxy.port}`,
+ });
+ expect(response.status).toBe(407);
+ } catch (err) {
+ console.error(err);
+ expect(true).toBeFalsy();
+ }
+ }
+
+ {
+ try {
+ const response = await fetch(url, {
+ keepalive: false,
+ verbose: true,
+ proxy: `http://squid_user:asdf123@localhost:${auth_proxy.port}`,
+ });
+ expect(response.status).toBe(403);
+ } catch (err) {
+ console.error(err);
+ expect(true).toBeFalsy();
+ }
+ }
+
+ done();
+ });
+ });
+}