40 lines
1.5 KiB
TypeScript
40 lines
1.5 KiB
TypeScript
import type { Server } from "node:http";
|
|
import type { AddressInfo } from "node:net";
|
|
|
|
// WHATWG Fetch blocks a fixed list of ports. Node's HTTP adapter uses fetch,
|
|
// so e2e mock servers must avoid ephemeral assignments like :6000.
|
|
const FETCH_BLOCKED_PORTS = new Set([
|
|
1, 7, 9, 11, 13, 15, 17, 19, 20, 21, 22, 23, 25, 37, 42, 43, 53, 69, 77, 79,
|
|
87, 95, 101, 102, 103, 104, 109, 110, 111, 113, 115, 117, 119, 123, 135, 137,
|
|
139, 143, 161, 179, 389, 427, 465, 512, 513, 514, 515, 526, 530, 531, 532, 540,
|
|
548, 554, 556, 563, 587, 601, 636, 989, 990, 993, 995, 1719, 1720, 1723,
|
|
2049, 3659, 4045, 4190, 5060, 5061, 6000, 6566, 6665, 6666, 6667, 6668, 6669,
|
|
6697, 10080,
|
|
]);
|
|
|
|
export async function listenOnFetchAllowedPort(server: Server): Promise<number> {
|
|
for (let attempt = 0; attempt < 20; attempt += 1) {
|
|
await new Promise<void>((resolve, reject) => {
|
|
const onError = (error: Error) => {
|
|
server.off("error", onError);
|
|
reject(error);
|
|
};
|
|
server.once("error", onError);
|
|
server.listen(0, "127.0.0.1", () => {
|
|
server.off("error", onError);
|
|
resolve();
|
|
});
|
|
});
|
|
|
|
const address = server.address() as AddressInfo | null;
|
|
const port = address?.port;
|
|
if (port && !FETCH_BLOCKED_PORTS.has(port)) return port;
|
|
|
|
await new Promise<void>((resolve, reject) => {
|
|
server.close((error) => error ? reject(error) : resolve());
|
|
});
|
|
}
|
|
|
|
throw new Error("Unable to allocate a Fetch-allowed local test server port");
|
|
}
|