Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,9 @@ function _createProxyFn<
http.ServerResponse | http2.Http2ServerResponse
>,
head,
(error) => {
(error, _req, _res, url) => {
if (server.listenerCount("error") > 0) {
server.emit("error", error, req, res as ProxyServerRes | net.Socket);
server.emit("error", error, req, res as ProxyServerRes | net.Socket, url);
_resolve();
} else {
_reject(error);
Expand All @@ -245,7 +245,13 @@ function _createProxyFn<
);
} catch (error) {
if (server.listenerCount("error") > 0) {
server.emit("error", error as Error, req, res as ProxyServerRes | net.Socket);
server.emit(
"error",
error as Error,
req,
res as ProxyServerRes | net.Socket,
requestOptions.target,
);
_resolve();
} else {
_reject(error);
Expand Down
28 changes: 28 additions & 0 deletions test/http-proxy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,34 @@ describe("http-proxy", () => {

await promise.catch(() => {});
});

it("should forward the target URL as the 4th argument of the error event", async () => {
const target = "http://127.0.0.1:1";
const proxy = httpProxy.createProxyServer({ target });

const { promise, resolve } = Promise.withResolvers<URL | undefined>();
proxy.on("error", (_err, _req, _res, url) => {
proxy.close(() => {});
resolve(url as URL | undefined);
});

const proxyPort = await proxyListen(proxy);

http
.request(
{
hostname: "127.0.0.1",
port: proxyPort,
method: "GET",
},
() => {},
)
.end();

const url = await promise;
expect(url).toBeInstanceOf(URL);
expect((url as URL).href).toBe(new URL(target).href);
});
});

describe("#createProxyServer setting the correct timeout value", () => {
Expand Down
70 changes: 70 additions & 0 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,76 @@ describe("middleware pass exceptions", () => {
}
});

it("should forward the target URL as the 4th argument when a pass throws", async () => {
const target = await new Promise<{
close: () => Promise<void>;
url: string;
}>((resolve, reject) => {
const server = http.createServer((_req, res) => {
res.end("ok");
});
server.once("error", reject);
server.listen(0, "127.0.0.1", () => {
const { port } = server.address() as AddressInfo;
resolve({
close: () =>
new Promise<void>((r, j) => {
server.close((e) => (e ? j(e) : r()));
}),
url: `http://127.0.0.1:${port}/`,
});
});
});

const proxy = createProxyServer({ target: target.url });

proxy.before("web", "", () => {
throw new TypeError("Invalid character in header");
});

const proxyServer = await new Promise<{
close: () => Promise<void>;
url: string;
}>((resolve, reject) => {
const server = http.createServer((req, res) => {
void proxy.web(req, res);
});
server.once("error", reject);
server.listen(0, "127.0.0.1", () => {
const { port } = server.address() as AddressInfo;
resolve({
close: () =>
new Promise<void>((r, j) => {
server.close((e) => (e ? j(e) : r()));
}),
url: `http://127.0.0.1:${port}/`,
});
});
});

try {
const urlPromise = new Promise<URL | undefined>((resolve) => {
proxy.on("error", (_err, _req, res, url) => {
resolve(url as URL | undefined);
if (res && "writeHead" in res && !res.headersSent) {
res.writeHead(502);
res.end();
}
});
});

await $fetch(proxyServer.url, { ignoreResponseError: true }).catch(() => {});

const url = await urlPromise;
expect(url).toBeInstanceOf(URL);
expect((url as URL).href).toBe(new URL(target.url).href);
} finally {
proxy.close();
await proxyServer.close();
await target.close();
}
});

it("should reject promise when no error listener and pass throws", async () => {
const target = await new Promise<{
close: () => Promise<void>;
Expand Down