| 1 | import * as Effect from "effect/Effect"; |
| 2 | import type * as NodeHttp from "node:http"; |
| 3 | import { 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 | */ |
| 14 | const 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. */ |
| 22 | export const toConnectableHost = (host: string): string => |
| 23 | UNSPECIFIED_ADDRESSES.has(host) ? "127.0.0.1" : host; |
| 24 | |
| 25 | export 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 | }; |