Skip to content

Commit 57e3184

Browse files
committed
support node 18 and 24 officially
- this required switching to node-fetch for a lot of tests - a very small number of tests are disabled with node 18 - add to github CI - script to automate testing locally on all platforms (if you have nvm setup)
1 parent 373a00a commit 57e3184

23 files changed

+178
-117
lines changed

.github/workflows/test.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ on:
2020
required: false
2121
default: false
2222

23-
env:
24-
GITHUB_ACTIONS: yes
25-
2623
jobs:
2724
build:
2825
runs-on: ubuntu-latest
@@ -31,8 +28,10 @@ jobs:
3128
matrix:
3229
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
3330
node-version:
31+
- "18"
3432
- "20"
3533
- "22"
34+
- "24"
3635

3736
steps:
3837
- uses: actions/checkout@v4

README.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ can be done using nginx or haproxy.
1313

1414
**PR's welcome!**
1515

16-
May 10, 2025 STATUS compared to [http-proxy](https://www.npmjs.com/package/http-proxy) and [httpxy](https://www.npmjs.com/package/httpxy):
16+
May 11, 2025 STATUS compared to [http-proxy](https://www.npmjs.com/package/http-proxy) and [httpxy](https://www.npmjs.com/package/httpxy):
1717

1818
- Library entirely rewritten in Typescript in a modern style, with many typings added internally.
1919
- All dependent packages updated to latest versions, addressing all security vulnerabilities according to `pnpm audit`.
@@ -34,6 +34,12 @@ I've been adding load tests to the unit tests in various places. Generally speak
3434

3535
- https://github.com/unjs/httpxy: it has the same motivation as this project -- it's a modern maintained rewrite of http-proxy. Unfortunately, it seems to have [very little unit testing](https://github.com/unjs/httpxy/tree/main/test). In http-proxy-3 (and the original http-proxy), there's an order of magnitude more unit test code than code in the actual library.
3636

37+
**Officially supported platforms:**
38+
39+
We run GitHUB CI on the following:
40+
41+
- nodejs versions 18, 20, 22, and 24
42+
3743
**Development:**
3844

3945
```sh
@@ -52,8 +58,6 @@ pnpm tsc
5258

5359
and make changes to code under lib/.
5460

55-
Tested with nodejs versions 20 and 22.
56-
5761
[![Build package and run tests](https://github.com/sagemathinc/http-proxy-3/actions/workflows/test.yml/badge.svg)](https://github.com/sagemathinc/http-proxy-3/actions/workflows/test.yml)
5862

5963
## User's Guide
@@ -601,7 +605,7 @@ pnpm test
601605

602606
### Contributing and Issues
603607

604-
- Submit a PR! I want this project to be active again! Port ideas from [https://github.com/http\-party/node\-http\-proxy/pulls](https://github.com/http-party/node-http-proxy/pulls) and [https://github.com/http\-party/node\-http\-proxy/issues](https://github.com/http-party/node-http-proxy/issues). Email me at [[email protected]](mailto:[email protected]).
608+
- Submit a PR! I want this project to be active again! Port ideas from [https://github.com/http\-party/node\-http\-proxy/pulls](https://github.com/http-party/node-http-proxy/pulls) and [https://github.com/http\-party/node\-http\-proxy/issues](https://github.com/http-party/node-http-proxy/issues). Email me at [[email protected]](mailto:[email protected]).
605609

606610
**[Back to top](#table-of-contents)**
607611

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "http-proxy-3",
3-
"version": "1.20.0",
3+
"version": "1.20.1",
44
"repository": {
55
"type": "git",
66
"url": "https://github.com/sagemathinc/http-proxy-3.git"
@@ -46,14 +46,15 @@
4646
"scripts": {
4747
"preinstall": "npx only-allow pnpm",
4848
"test": "NODE_TLS_REJECT_UNAUTHORIZED=0 pnpm exec jest",
49-
"version": "auto-changelog -p && git add CHANGELOG.md",
49+
"test-all": "pnpm audit && TEST_EXTERNAL_REVERSE_PROXY=yes pnpm test --runInBand",
50+
"test-versions": ". \"$NVM_DIR/nvm.sh\" && nvm use 18 && pnpm test && nvm use 20 && pnpm test && nvm use 22 && pnpm test && nvm use 24 && pnpm test && nvm use 20",
5051
"clean": "rm -rf dist node_modules",
5152
"build": "pnpm exec tsc --build .tsconfig-bootstrap.json && pnpm exec tsc --build",
5253
"tsc": "pnpm exec tsc --watch --pretty --preserveWatchOutput",
53-
"prepublishOnly": "pnpm audit && pnpm test --runInBand && rm -f dist/*.tsbuildinfo dist/.tsconfig-bootstrap* && rm -rf dist/test"
54+
"prepublishOnly": "pnpm test-versions && pnpm test-all && rm -f dist/*.tsbuildinfo dist/.tsconfig-bootstrap* && rm -rf dist/test"
5455
},
5556
"engines": {
56-
"node": ">=20.0.0"
57+
"node": ">=18"
5758
},
5859
"license": "MIT"
5960
}

test/README.md

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Testing Nodes
2+
3+
## Ports
4+
15
A note about ports. These tests use a large number of ports and are run in
26
parallel. There will sometimes be failures sometimes due to a port conflict
37
between different tests being run at the same time.
@@ -6,4 +10,41 @@ Use `pnpm test --runInBand` to avoid this by running the tests in serial. This
610
is good for CI and release testing. Just use `pnpm test` for dev, since it's
711
much faster.
812

9-
Another issue is that sometimes tests that proxy google.com will get rejected by Google due to anti-abuse by them. If you set the environment variable GITHUB_ACTIONS then those tests are not run.
13+
## Reverse Proxy test
14+
15+
There are a few unit tests that involve a reverse proxy of google.com. These will often fail due to Google rejecting these robotic requests, so they are not run unless you
16+
set this environment variable:
17+
18+
```sh
19+
TEST_EXTERNAL_REVERSE_PROXY=yes
20+
```
21+
22+
I run these manually before making a release, but not as part of CI. Use
23+
24+
```sh
25+
pnpm test-all
26+
```
27+
to include these tests and also pnpm audit.
28+
29+
## fetch
30+
31+
We use
32+
33+
```
34+
import fetch from "node-fetch";
35+
```
36+
37+
in the unit tests instead of the fetch builtin to nodejs, since in node 18 the builtin fetch leaves an open handling hanging the test suite.
38+
39+
An exception is blacklist-headers.test.ts, where we can't even run the test using node-fetch, since it blocks it.
40+
41+
In particular, it is not acceptable for the test suite to exit with: _"A worker process has failed to exit gracefully and has been force exited. This is likely caused by tests leaking due to improper teardown. Try running with --detectOpenHandles to find leaks. Active timers can also cause this, ensure that .unref() was called on them."_
42+
43+
## WARNINGS
44+
45+
These warnings in the test suite are expected, because we're testing ssl using self signed certs:
46+
47+
```
48+
(node:52812) Warning: Setting the NODE_TLS_REJECT_UNAUTHORIZED environment variable to '0' makes TLS connections and HTTPS requests insecure by disabling certificate verification.
49+
(Use `node --trace-warnings ...` to show where the warning was created)
50+
```

test/balancer/simple-balancer-with-websockets.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as http from "http";
88
import * as httpProxy from "../..";
99
import getPort from "../get-port";
1010
import { once } from "../wait";
11+
import fetch from "node-fetch";
1112

1213
describe("A simple round-robin load balancer that supports websockets", () => {
1314
let addresses;

test/balancer/simple-balancer.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pnpm test simple-balancer.test.ts
77
import * as http from "http";
88
import * as httpProxy from "../..";
99
import getPort from "../get-port";
10+
import fetch from "node-fetch";
1011

1112
describe("A simple round-robin load balancing strategy.", () => {
1213
let addresses;

test/http/basic-proxy.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import * as http from "http";
1010
import * as httpProxy from "../..";
1111
import log from "../log";
1212
import getPort from "../get-port";
13+
import fetch from "node-fetch";
1314

1415
export async function server() {
1516
const httpPort = await getPort();

test/http/custom-proxy-error.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pnpm test ./custom-proxy-error.test.ts
66

77
import * as httpProxy from "../..";
88
import getPort from "../get-port";
9+
import fetch from "node-fetch";
910

1011
const CUSTOM_ERROR =
1112
"Something went wrong. And we are reporting a custom error message.";

test/http/error-handling.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as http from "http";
77
import getPort from "../get-port";
88
import log from "../log";
99
import { callback } from "awaiting";
10+
import fetch from "node-fetch";
1011

1112
const CUSTOM_ERROR = "There was an error proxying your request";
1213

test/http/forward-and-target-proxy.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import * as httpProxy from "../..";
1212
import log from "../log";
1313
import getPort from "../get-port";
1414
import wait from "../wait";
15+
import fetch from "node-fetch";
1516

1617
describe("Example of proxying over HTTP with additional forward proxy to a different server", () => {
1718
let ports;

test/http/forward-proxy.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import * as httpProxy from "../..";
1414
import log from "../log";
1515
import getPort from "../get-port";
1616
import wait from "../wait";
17+
import fetch from "node-fetch";
1718

1819
describe("Example of proxying over HTTP with additional forward proxy", () => {
1920
let forwardingServer,

test/http/proxy-http-to-https.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ We proxy https://google.com via a local non-https http server.
77
import * as https from "https";
88
import * as httpProxy from "../..";
99
import getPort from "../get-port";
10+
import fetch from "node-fetch";
1011

1112
describe(" Basic example of proxying over HTTP to a target HTTPS server", () => {
1213
let port, server;
@@ -24,7 +25,7 @@ describe(" Basic example of proxying over HTTP to a target HTTPS server", () =>
2425
});
2526

2627
it("queries the proxy server as a test", async () => {
27-
if (process.env.GITHUB_ACTIONS) {
28+
if (!process.env.TEST_EXTERNAL_REVERSE_PROXY) {
2829
// google tends to block CI
2930
return;
3031
}

test/http/proxy-https-to-http.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as httpProxy from "../..";
77
import getPort from "../get-port";
88
import { join } from "path";
99
import { readFile } from "fs/promises";
10+
import fetch from "node-fetch";
1011

1112
const fixturesDir = join(__dirname, "..", "fixtures");
1213

test/http/proxy-https-to-https.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as httpProxy from "../..";
88
import getPort from "../get-port";
99
import { join } from "path";
1010
import { readFile } from "fs/promises";
11+
import fetch from "node-fetch";
1112

1213
const fixturesDir = join(__dirname, "..", "fixtures");
1314

test/http/reverse-proxy.test.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import * as http from "http";
88
import * as httpProxy from "../..";
99
import getPort from "../get-port";
1010
import * as net from "net";
11-
import * as url from "url";
1211
import log from "../log";
1312
import { HttpsProxyAgent } from "https-proxy-agent";
1413
import fetch from "node-fetch";
@@ -25,8 +24,8 @@ describe("Reverse proxying -- create a server that...", () => {
2524
server = http
2625
.createServer((req, res) => {
2726
log("Receiving reverse proxy request for:", req.url);
28-
const parsedUrl = url.parse(req.url ?? "");
29-
const target = parsedUrl.protocol + "//" + parsedUrl.hostname;
27+
const urlObj = new URL(req.url ?? "", "http://dummy.org");
28+
const target = urlObj.origin;
3029
proxy.web(req, res, { target, secure: false });
3130
})
3231
.listen(port);
@@ -35,10 +34,9 @@ describe("Reverse proxying -- create a server that...", () => {
3534
server.on("connect", (req, socket) => {
3635
log("Receiving reverse proxy request for:", req.url);
3736

38-
const serverUrl = url.parse("https://" + req.url);
39-
37+
const serverUrl = new URL(`https://${req.url}`);
4038
const srvSocket = net.connect(
41-
parseInt(serverUrl.port ?? "0"),
39+
parseInt(serverUrl.port ? serverUrl.port : "443"),
4240
serverUrl.hostname!,
4341
() => {
4442
socket.write(
@@ -54,7 +52,7 @@ describe("Reverse proxying -- create a server that...", () => {
5452
});
5553

5654
it("Tests the reverse proxy out to access https://www.google.com using an http proxy running on localhost.", async () => {
57-
if (process.env.GITHUB_ACTIONS) {
55+
if (!process.env.TEST_EXTERNAL_REVERSE_PROXY) {
5856
// google tends to block CI
5957
return;
6058
}
@@ -69,7 +67,7 @@ describe("Reverse proxying -- create a server that...", () => {
6967
});
7068

7169
it("Tests the reverse proxy out to access http://www.google.com and https://www.google.com using an http proxy running on localhost.", async () => {
72-
if (process.env.GITHUB_ACTIONS) {
70+
if (!process.env.TEST_EXTERNAL_REVERSE_PROXY) {
7371
// google tends to block CI
7472
return;
7573
}

test/http/server-sent-events.test.ts

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import getPort from "../get-port";
1010
import { createSession } from "better-sse";
1111
import { EventSource } from "eventsource";
1212
import { callback } from "awaiting";
13+
import fetch from "node-fetch";
1314

1415
describe("proxying server sent events over HTTP", () => {
1516
let ports;
@@ -42,18 +43,6 @@ describe("proxying server sent events over HTTP", () => {
4243
servers.http.listen(ports.http);
4344
});
4445

45-
it("test receiving an SSE WITHOUT using the proxy", async () => {
46-
const f = (cb) => {
47-
const sse = new EventSource(`http://localhost:${ports.http}/sse`);
48-
sse.addEventListener("message", ({ data }) => {
49-
sse.close();
50-
cb(undefined, JSON.parse(data));
51-
});
52-
};
53-
const resp = await callback(f);
54-
expect(resp).toEqual("Hello world! - 1");
55-
});
56-
5746
it("creates the proxy server", () => {
5847
servers.proxy = httpProxy
5948
.createProxyServer({
@@ -67,17 +56,33 @@ describe("proxying server sent events over HTTP", () => {
6756
expect(a).toContain("request successfully proxied");
6857
});
6958

70-
it("test receiving an SSE USING the proxy", async () => {
71-
const f = (cb) => {
72-
const sse = new EventSource(`http://localhost:${ports.proxy}/sse`);
73-
sse.addEventListener("message", ({ data }) => {
74-
sse.close();
75-
cb(undefined, JSON.parse(data));
76-
});
77-
};
78-
const resp = await callback(f);
79-
expect(resp).toEqual("Hello world! - 2");
80-
});
59+
if (!process.version.startsWith("v18.")) {
60+
// These two tests leave open handles on node v18, so we disable them ONLY
61+
// with node v18.
62+
it("test receiving an SSE WITHOUT using the proxy", async () => {
63+
const f = (cb) => {
64+
const sse = new EventSource(`http://localhost:${ports.http}/sse`);
65+
sse.addEventListener("message", ({ data }) => {
66+
sse.close();
67+
cb(undefined, JSON.parse(data));
68+
});
69+
};
70+
const resp = await callback(f);
71+
expect(resp).toEqual("Hello world! - 1");
72+
});
73+
74+
it("test receiving an SSE USING the proxy", async () => {
75+
const f = (cb) => {
76+
const sse = new EventSource(`http://localhost:${ports.proxy}/sse`);
77+
sse.addEventListener("message", ({ data }) => {
78+
sse.close();
79+
cb(undefined, JSON.parse(data));
80+
});
81+
};
82+
const resp = await callback(f);
83+
expect(resp).toEqual("Hello world! - 2");
84+
});
85+
}
8186

8287
it("Clean up", () => {
8388
Object.values(servers).map((x: any) => x?.close());

0 commit comments

Comments
 (0)