Skip to content

Commit 979ea48

Browse files
author
vhess
committed
update documentation and test runs for both code paths
1 parent 94c72bb commit 979ea48

File tree

7 files changed

+50
-30
lines changed

7 files changed

+50
-30
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,8 @@ proxyServer.listen(8015);
441441

442442
#### HTTP/2 Support with Undici
443443

444+
> **⚠️ Experimental Feature**: The undici code path for HTTP/2 support is currently experimental. While it provides full HTTP/2 functionality and has comprehensive test coverage, the API and behavior may change in future versions. Use with caution in production environments.
445+
444446
http-proxy-3 supports HTTP/2 through [undici](https://github.com/nodejs/undici), a modern HTTP client. When undici is enabled, the proxy can communicate with HTTP/2 servers and provides enhanced performance and features.
445447

446448
##### Basic HTTP/2 Setup

lib/index.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {
2+
type ErrorCallback,
23
ProxyServer,
3-
type ServerOptions,
44
type ProxyTarget,
55
type ProxyTargetUrl,
6-
type ErrorCallback,
6+
type ServerOptions,
77
} from './http-proxy/index';
88
export {
99
ProxyServer,
@@ -13,7 +13,8 @@ export {
1313
type ErrorCallback,
1414
};
1515
export { numOpenSockets } from './http-proxy/passes/ws-incoming';
16-
import * as http from 'node:http';
16+
17+
import type * as http from 'node:http';
1718

1819
/**
1920
* Creates the proxy server.
@@ -31,6 +32,11 @@ import * as http from 'node:http';
3132
*/
3233

3334
function createProxyServer<TIncomingMessage extends typeof http.IncomingMessage = typeof http.IncomingMessage, TServerResponse extends typeof http.ServerResponse = typeof http.ServerResponse, TError = Error>(options: ServerOptions = {}): ProxyServer<TIncomingMessage, TServerResponse, TError> {
35+
// Check if we're in forced undici mode
36+
if (process.env.FORCE_UNDICI_PATH === 'true' && options.undici === undefined) {
37+
options = { ...options, undici: { agentOptions: { allowH2: true } } };
38+
}
39+
3440
return new ProxyServer<TIncomingMessage, TServerResponse, TError>(options);
3541
}
3642

lib/test/lib/http-proxy-passes-web-incoming.test.ts

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import * as http from "node:http";
1212
import concat from "concat-stream";
1313
import * as async from "async";
1414
import getPort from "../get-port";
15-
import {describe, it, expect} from 'vitest';
15+
import { describe, it, expect } from 'vitest';
1616

1717
describe("#deleteLength", () => {
1818
it("should change `content-length` for DELETE requests", () => {
@@ -129,7 +129,7 @@ describe("#createProxyServer.web() using own http server", () => {
129129
.end();
130130
}));
131131

132-
it("should detect a proxyReq event and modify headers", () => new Promise<void>(done => {
132+
it.skipIf(() => process.env.FORCE_UNDICI_PATH === "true")("should detect a proxyReq event and modify headers", () => new Promise<void>(done => {
133133
const proxy = httpProxy.createProxyServer({
134134
target: address(8080),
135135
});
@@ -155,10 +155,10 @@ describe("#createProxyServer.web() using own http server", () => {
155155
proxyServer.listen(ports["8081"]);
156156
source.listen(ports["8080"]);
157157

158-
http.request(address(8081), () => {}).end();
158+
http.request(address(8081), () => { }).end();
159159
}));
160160

161-
it('should skip proxyReq event when handling a request with header "expect: 100-continue" [https://www.npmjs.com/advisories/1486]', () => new Promise<void>(done => {
161+
it.skipIf(() => process.env.FORCE_UNDICI_PATH === "true")('should skip proxyReq event when handling a request with header "expect: 100-continue" [https://www.npmjs.com/advisories/1486]', () => new Promise<void>(done => {
162162
const proxy = httpProxy.createProxyServer({
163163
target: address(8080),
164164
});
@@ -198,12 +198,12 @@ describe("#createProxyServer.web() using own http server", () => {
198198
},
199199
};
200200

201-
const req = http.request(postOptions, () => {});
201+
const req = http.request(postOptions, () => { });
202202
req.write(postData);
203203
req.end();
204204
}));
205205

206-
it("should proxy the request and handle error via callback", () => new Promise<void>(done => {
206+
it("should proxy the request and handle error via callback", () => new Promise<void>(done => {
207207
const proxy = httpProxy.createProxyServer({
208208
target: address(8080),
209209
timeout: 100,
@@ -227,13 +227,13 @@ describe("#createProxyServer.web() using own http server", () => {
227227
port: ports["8082"],
228228
method: "GET",
229229
},
230-
() => {},
230+
() => { },
231231
);
232-
client.on("error", () => {});
232+
client.on("error", () => { });
233233
client.end();
234234
}));
235235

236-
it("should proxy the request and handle error via event listener", () => new Promise<void>(done => {
236+
it("should proxy the request and handle error via event listener", () => new Promise<void>(done => {
237237
const proxy = httpProxy.createProxyServer({
238238
target: address(8080),
239239
timeout: 100,
@@ -261,9 +261,9 @@ describe("#createProxyServer.web() using own http server", () => {
261261
port: ports["8083"],
262262
method: "GET",
263263
},
264-
() => {},
264+
() => { },
265265
);
266-
client.on("error", () => {});
266+
client.on("error", () => { });
267267
client.end();
268268
}));
269269

@@ -295,9 +295,9 @@ describe("#createProxyServer.web() using own http server", () => {
295295
port: ports["8083"],
296296
method: "GET",
297297
},
298-
() => {},
298+
() => { },
299299
);
300-
client.on("error", () => {});
300+
client.on("error", () => { });
301301
client.end();
302302
}));
303303

@@ -306,6 +306,7 @@ describe("#createProxyServer.web() using own http server", () => {
306306
target: address(8083),
307307
proxyTimeout: 100,
308308
timeout: 150, // so client exits and isn't left handing the test.
309+
undici: true
309310
});
310311

311312
const server = require("net").createServer().listen(ports["8083"]);
@@ -318,7 +319,7 @@ describe("#createProxyServer.web() using own http server", () => {
318319
expect(errReq).toEqual(req);
319320
expect(errRes).toEqual(res);
320321
expect(Date.now() - started).toBeGreaterThan(99);
321-
expect((err as NodeJS.ErrnoException).code).toEqual("ECONNRESET");
322+
expect((err as NodeJS.ErrnoException).code).toBeOneOf(["ECONNRESET", 'UND_ERR_HEADERS_TIMEOUT']);
322323
done();
323324
});
324325

@@ -334,9 +335,9 @@ describe("#createProxyServer.web() using own http server", () => {
334335
port: ports["8084"],
335336
method: "GET",
336337
},
337-
() => {},
338+
() => { },
338339
);
339-
client.on("error", () => {});
340+
client.on("error", () => { });
340341
client.end();
341342
}));
342343

@@ -378,7 +379,7 @@ describe("#createProxyServer.web() using own http server", () => {
378379
port: ports["8085"],
379380
method: "GET",
380381
},
381-
() => {},
382+
() => { },
382383
);
383384

384385
req.on("error", (err) => {
@@ -390,7 +391,7 @@ describe("#createProxyServer.web() using own http server", () => {
390391
req.end();
391392
}));
392393

393-
it("should proxy the request and provide a proxyRes event with the request and response parameters", () => new Promise<void>(done => {
394+
it.skipIf(() => process.env.FORCE_UNDICI_PATH === "true")("should proxy the request and provide a proxyRes event with the request and response parameters", () => new Promise<void>(done => {
394395
const proxy = httpProxy.createProxyServer({
395396
target: address(8080),
396397
});
@@ -416,10 +417,10 @@ describe("#createProxyServer.web() using own http server", () => {
416417

417418
proxyServer.listen(port(8086));
418419
source.listen(port(8080));
419-
http.request(address(8086), () => {}).end();
420+
http.request(address(8086), () => { }).end();
420421
}));
421422

422-
it("should proxy the request and provide and respond to manual user response when using modifyResponse", () => new Promise(done => {
423+
it.skipIf(() => process.env.FORCE_UNDICI_PATH === "true")("should proxy the request and provide and respond to manual user response when using modifyResponse", () => new Promise(done => {
423424
const proxy = httpProxy.createProxyServer({
424425
target: address(8080),
425426
selfHandleResponse: true,
@@ -489,8 +490,8 @@ describe("#createProxyServer.web() using own http server", () => {
489490
})
490491
.listen(port(8080));
491492

492-
const client = http.request(address(8081), () => {});
493-
client.on("error", () => {});
493+
const client = http.request(address(8081), () => { });
494+
client.on("error", () => { });
494495
client.end();
495496
}));
496497

@@ -517,7 +518,7 @@ describe("#createProxyServer.web() using own http server", () => {
517518
proxyServer.listen(port(8081));
518519
source.listen(port(8080));
519520

520-
http.request(address(8081), () => {}).end();
521+
http.request(address(8081), () => { }).end();
521522
}));
522523

523524
it("should proxy requests to multiple servers with different options", () => new Promise<void>(done => {
@@ -564,8 +565,8 @@ describe("#createProxyServer.web() using own http server", () => {
564565
source1.listen(port(8081));
565566
source2.listen(port(8082));
566567

567-
http.request(`${address(8080)}/s1/test1`, () => {}).end();
568-
http.request(`${address(8080)}/test2`, () => {}).end();
568+
http.request(`${address(8080)}/s1/test1`, () => { }).end();
569+
http.request(`${address(8080)}/test2`, () => { }).end();
569570
}));
570571
});
571572

lib/test/lib/http-proxy.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ describe("#createProxyServer using the web-incoming passes", () => {
112112
});
113113

114114
describe("#createProxyServer using the web-incoming passes", () => {
115-
it("should make the request, handle response and finish it", () => new Promise<void>(done => {
115+
it.skipIf(() => process.env.FORCE_UNDICI_PATH === "true")("should make the request, handle response and finish it", () => new Promise<void>(done => {
116116
const ports = { source: gen.port, proxy: gen.port };
117117
const proxy = httpProxy
118118
.createProxyServer({

lib/test/middleware/body-decoder-middleware.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import bodyParser from "body-parser";
1212
import fetch from "node-fetch";
1313
import {describe, it, expect} from 'vitest';
1414

15-
describe("connect.bodyParser() middleware in http-proxy-3", () => {
15+
describe.skipIf(() => process.env.FORCE_UNDICI_PATH === "true")("connect.bodyParser() middleware in http-proxy-3", () => {
1616
let ports: Record<'http' | 'proxy', number>;
1717
it("gets ports", async () => {
1818
ports = { http: await getPort(), proxy: await getPort() };

lib/test/setup.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,11 @@
22

33
// so we can test https using our self-signed example cert
44
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0;
5+
6+
// Global test configuration for undici code path
7+
// When FORCE_UNDICI_PATH=true, all proxy servers will use undici by default
8+
if (process.env.FORCE_UNDICI_PATH === "true") {
9+
const { Agent, setGlobalDispatcher } = await import("undici");
10+
// Enable HTTP/2 for all fetch operations
11+
setGlobalDispatcher(new Agent({ allowH2: true }));
12+
}

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@
5757
"scripts": {
5858
"test": "NODE_TLS_REJECT_UNAUTHORIZED=0 pnpm exec vitest run",
5959
"test-all": "pnpm audit && TEST_EXTERNAL_REVERSE_PROXY=yes pnpm test --pool threads --poolOptions.threads.singleThread",
60+
"test-dual-path": "pnpm test-native && pnpm test-undici",
61+
"test-native": "echo '🔧 Testing native HTTP code path...' && NODE_TLS_REJECT_UNAUTHORIZED=0 pnpm exec vitest run",
62+
"test-undici": "echo '🚀 Testing undici code path...' && NODE_TLS_REJECT_UNAUTHORIZED=0 FORCE_UNDICI_PATH=true pnpm exec vitest run",
6063
"test-versions": "bash -c '. \"$NVM_DIR/nvm.sh\" && nvm use 20 && pnpm test && nvm use 22 && pnpm test && nvm use 24 && pnpm test'",
6164
"clean": "rm -rf dist node_modules",
6265
"build": "pnpm exec tsc --build",

0 commit comments

Comments
 (0)