diff options
author | 2023-04-10 21:57:28 -0300 | |
---|---|---|
committer | 2023-04-10 21:57:28 -0300 | |
commit | 9029b03ab5aac4f22800310738ada3ebd6d16a34 (patch) | |
tree | 2305a6dd15bc5f53de2e1245047bf9089d38d38e | |
parent | f91dc8c0d308f2b21a725aeccc58c3cfb78c1339 (diff) | |
download | bun-9029b03ab5aac4f22800310738ada3ebd6d16a34.tar.gz bun-9029b03ab5aac4f22800310738ada3ebd6d16a34.tar.zst bun-9029b03ab5aac4f22800310738ada3ebd6d16a34.zip |
add http_proxy connect support on tests and fix fetch proxy behavior
-rw-r--r-- | .github/workflows/bun-linux-build.yml | 3 | ||||
-rw-r--r-- | .github/workflows/bun-mac-aarch64.yml | 3 | ||||
-rw-r--r-- | .github/workflows/bun-mac-x64-baseline.yml | 3 | ||||
-rw-r--r-- | .github/workflows/bun-mac-x64.yml | 3 | ||||
-rw-r--r-- | src/http_client_async.zig | 11 | ||||
-rw-r--r-- | test/js/bun/http/proxy.test.js | 136 | ||||
-rw-r--r-- | test/js/bun/http/proxy.test.ts | 157 |
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(); + }); + }); +} |