1import * as Effect from "effect/Effect";
2import type * as NodeHttp from "node:http";
3import { SystemError } from "../RuntimeError.shared.ts";
4
5/**
6 * Addresses that mean "listen on every interface". They are valid *bind*
7 * addresses but must never be used as a *connect* target: on Linux/macOS
8 * connecting to `0.0.0.0` is quietly treated as "this host", but on Windows
9 * `ConnectEx` fails with `ERROR_DUP_NAME` (#52, "a duplicate name exists on
10 * the network"). workerd consumes the addresses we produce here as external
11 * service connect targets, so we always normalize unspecified addresses to
12 * `127.0.0.1` (matching miniflare's behavior).
13 */
14const UNSPECIFIED_ADDRESSES: ReadonlySet<string> = new Set([
15 "0.0.0.0",
16 "::",
17 "::0",
18 "0000:0000:0000:0000:0000:0000:0000:0000",
19]);
20
21/** Maps listen-all/unspecified hosts to a loopback host that is safe to connect to on every platform. */
22export const toConnectableHost = (host: string): string =>
23 UNSPECIFIED_ADDRESSES.has(host) ? "127.0.0.1" : host;
24
25export const getAddress = (
26 server: NodeHttp.Server,
27): Effect.Effect<string, SystemError> => {
28 const address = server.address();
29 if (address === null) {
30 return Effect.fail(
31 new SystemError({
32 subtag: "ServerAddressNotAvailable",
33 message: "Server address is not available.",
34 detail: { server },
35 }),
36 );
37 }
38 if (typeof address === "string") {
39 return Effect.succeed(address);
40 }
41 return Effect.succeed(
42 `${toConnectableHost(address.address)}:${address.port}`,
43 );
44};