Skip to content
Merged
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
4 changes: 4 additions & 0 deletions docs/content/docs/limitations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,10 @@ title: "Limitations"

<include>../limitations/udp-socket-options.mdx</include>

### Unix domain sockets and request options

<include>../limitations/unix-domain-sockets.mdx</include>

### Process arguments and errors

<include>../limitations/process-arguments-and-errors.mdx</include>
Expand Down
2 changes: 2 additions & 0 deletions docs/content/limitations/unix-domain-sockets.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
`server.listen(path)` and the `socketPath` option of `http.request()` and `https.request()` use Unix domain sockets on Linux and macOS. On Windows, where Node maps these paths to named pipes, they fail with `ENOTSUP`. `server.address()` on a server listening on a Unix socket returns the socket path, as in Node, when the result is typed `string | AddressInfo | null` (the @types/node declaration). Where it is typed as the `{ address, family, port }` record alone, which cannot hold the path, the call throws an error for such a server. `listen(path, backlog, callback)` is refused at compile time; pass `listen(path, callback)`.
When the options of `http.request()` come from a variable, or from an object literal that spreads one, they are read at run time with Node's validation errors. The `auth`, `createConnection`, `family`, `hints`, `insecureHTTPParser`, `joinDuplicateHeaders`, `localAddress`, `localPort`, `lookup` and `uniqueHeaders` options then throw a runtime error when they hold a value, and so do `setHost: false` and `setDefaultHeaders: false`.
29 changes: 25 additions & 4 deletions packages/compiler/ambient/scriptc-node-fallback.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4694,6 +4694,11 @@ declare module "net" {
on(event: "close", listener: (hadError: boolean) => void): void;
on(event: "error", listener: (err: Error) => void): void;
on(event: "session", listener: (session: Buffer) => void): void;
/* The host name's resolution, before the connect. */
on(
event: "lookup",
listener: (err: Error | null, address: string, family: number, host: string) => void,
): void;
/* addListener IS on (Node aliases them) — the suite spells both. */
addListener(event: "data", listener: (chunk: Buffer) => void): void;
/* After setEncoding the chunk is a string. */
Expand All @@ -4705,6 +4710,11 @@ declare module "net" {
addListener(event: "close", listener: (hadError: boolean) => void): void;
addListener(event: "error", listener: (err: Error) => void): void;
addListener(event: "session", listener: (session: Buffer) => void): void;
/* The host name's resolution, before the connect. */
addListener(
event: "lookup",
listener: (err: Error | null, address: string, family: number, host: string) => void,
): void;
once(event: "data", listener: (chunk: Buffer) => void): void;
/* After setEncoding the chunk is a string. */
once(event: "data", listener: (chunk: string) => void): void;
Expand All @@ -4715,6 +4725,11 @@ declare module "net" {
once(event: "close", listener: (hadError: boolean) => void): void;
once(event: "error", listener: (err: Error) => void): void;
once(event: "session", listener: (session: Buffer) => void): void;
/* The host name's resolution, before the connect. */
once(
event: "lookup",
listener: (err: Error | null, address: string, family: number, host: string) => void,
): void;
}
export interface Server {
/* Whether the server keeps the event loop alive (ref'd by default). */
Expand All @@ -4733,6 +4748,8 @@ declare module "net" {
/* The positional bind address (the options form's host in argument
* spelling). */
listen(port: number, host: string, callback?: () => void): Server;
/* A Unix-socket server; the socket file is removed when it closes. */
listen(path: string, callback?: () => void): Server;
/* The explicit-interface bind: host is an IP literal (absent = the
* host-less dual-stack any); ipv6Only sets IPV6_V6ONLY and reusePort
* requests kernel connection distribution where Node supports it. */
Expand Down Expand Up @@ -5056,10 +5073,11 @@ declare module "http" {
* callback receives the response as an IncomingMessage (statusCode,
* headers, body via on("data"/"end")). */
export interface RequestOptions {
hostname?: string;
host?: string;
port?: number;
path?: string;
hostname?: string | null;
host?: string | null;
/* A string port (a URL's .port) is accepted, as by Node. */
port?: number | string | null;
path?: string | null;
method?: string;
timeout?: number;
headers?: OutgoingHttpHeaders;
Expand All @@ -5073,6 +5091,8 @@ declare module "http" {
agent?: Agent | boolean | null;
/* Aborting destroys the request with an AbortError. */
signal?: AbortSignal;
/* HTTP over the Unix socket at this path instead of host:port. */
socketPath?: string;
/* The options-record stance: Node ignores an options record's
* unknown keys, so every key typechecks here — the option WALK in
* the lowering decides per key (lower, fence by name, or drop
Expand Down Expand Up @@ -5348,6 +5368,7 @@ declare module "https" {
agent?: Agent | boolean | null;
/* Aborting destroys the request with an AbortError. */
signal?: AbortSignal;
socketPath?: string;
/* The options-record stance (see http.RequestOptions). */
[option: string]: unknown;
}
Expand Down
3 changes: 3 additions & 0 deletions packages/compiler/src/backend/llvm/emit-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ export function emitModuleParts(emitter: LlEmitter): string[] {
// programs additionally stamp the httpReq/httpRes ops — the C main's
// install lines, gated on the same predicates native/executable.ts links by.
const usesNet = runtimeFeatures.net;
const usesNetLookup = runtimeFeatures.netLookup;
const usesDgram = runtimeFeatures.dgram;
const usesHttp2 = runtimeFeatures.http2;
const usesHttp = runtimeFeatures.http;
Expand Down Expand Up @@ -226,6 +227,7 @@ export function emitModuleParts(emitter: LlEmitter): string[] {
if (usesFsWatch) emitter.declare(`declare void @scr_watch_install()`);
if (emitter.ffiHasForeignCallback) emitter.declare(`declare void @scr_ffi_install()`);
if (usesStream) emitter.declare(`declare void @scr_stream_install()`);
if (usesNetLookup) emitter.declare(`declare void @scr_net_lookup_install()`);
if (usesNet) {
emitter.declare(`declare void @scr_net_install()`);
emitter.declare(`declare void @scr_net_dyn_install()`);
Expand Down Expand Up @@ -837,6 +839,7 @@ export function emitModuleParts(emitter: LlEmitter): string[] {
...(snapshotsTlsCa ? [` call void @scr_tls_ca_install()`] : []),
...(usesFetch ? [` call void @scr_fetch_install()`] : []),
...(usesNet ? [` call void @scr_net_install()`, ` call void @scr_net_dyn_install()`] : []),
...(usesNetLookup ? [` call void @scr_net_lookup_install()`] : []),
...(usesHttp ? [` call void @scr_http_dyn_install()`] : []),
...(usesDgram ? [` call void @scr_dgram_install()`] : []),
...(usesHttp2 ? [` call void @scr_http2_dyn_install()`] : []),
Expand Down
47 changes: 47 additions & 0 deletions packages/compiler/src/backend/llvm/lib-network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,54 @@ export function emitNetworkHttpLibCall(host: LlvmEmitterContext, e: LibCallExpr)
...handler,
]);
}
if (
e.fn === "http.requestDyn" ||
e.fn === "http.requestDynCb" ||
e.fn === "https.requestDyn" ||
e.fn === "https.requestDynCb"
) {
// [options, autoEnd(, cb)]: the runtime walks the options record and
// attaches its signal through events.addAbortListener (the event-target
// unit, linked for these calls by runtime-features).
const args = e.args.map((arg) => host.emitExpr(arg));
host.usesTimers = true;
const cb = args[2];
const handler =
cb === undefined
? [ptr(), ptr()]
: callbackAdapter(
host,
cb,
callbackType(cb).params.length === 0
? "scr_http_resp_thunk0"
: "scr_http_resp_thunk_res",
["ptr", "ptr"],
);
host.declare(`declare ptr @scr_events_add_abort_listener(ptr, ptr)`);
return finishRuntimeCall(
host,
e,
e.fn.startsWith("https.") ? "scr_https_request_dyn" : "scr_http_request_dyn",
[
abiValue(host, args[0]!),
abiValue(host, args[1]!),
...handler,
ptr("@scr_events_add_abort_listener"),
],
);
}
const B = host.B;
if (e.fn === "net.listenPath" || e.fn === "net.listenPathCb") {
const args = e.args.map((a) => host.emitExpr(a));
let cb = "null";
if (e.fn === "net.listenPathCb") {
host.toHeap(args[2]!);
cb = args[2]!.name;
}
host.declare(`declare void @scr_net_listen_path(ptr, ptr, ptr)`);
B.line(`call void @scr_net_listen_path(ptr ${args[0]!.name}, ptr ${args[1]!.name}, ptr ${cb})`);
return { name: "", type: e.type };
}
if (e.fn === "net.connectOptsChk") {
return emitAlwaysThrowLibCall(host, e, "scr_net_connect_opts_chk");
}
Expand Down
10 changes: 10 additions & 0 deletions packages/compiler/src/backend/llvm/lib-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1157,6 +1157,10 @@ export const LIB_FN_SYMS: Record<string, string> = {
"net.sockReadyState": "scr_net_sock_ready_state",
"net.sockSetKeepAlive": "scr_net_sock_set_keepalive_ret",
"net.sockOnCloseDyn": "scr_net_sock_on_close_dyn",
"net.sockOnLookup": "scr_net_sock_on_lookup",
"net.serverCloseDyn": "scr_net_server_close_dyn",
"net.serverUnixPath": "scr_net_server_unix_path",
"net.serverAddressCheck": "scr_net_server_address_check",
"net.sockOnWriteFlushDyn": "scr_net_sock_on_write_flush_dyn",
"net.sockOnFinishDyn": "scr_net_sock_on_finish_dyn",
"net.isIP": "scr_net_is_ip",
Expand Down Expand Up @@ -1632,6 +1636,8 @@ export const USES_TIMERS_LIB_FNS = new Set<string>([
"sc.arrayBuffer",
"net.listen",
"net.listenCb",
"net.listenPath",
"net.listenPathCb",
"net.listenOpts",
"net.listenOptsCb",
"net.listenOptsReusePort",
Expand All @@ -1650,6 +1656,10 @@ export const USES_TIMERS_LIB_FNS = new Set<string>([
"http.requestCb",
"http.requestUrl",
"http.requestUrlCb",
"http.requestDyn",
"http.requestDynCb",
"https.requestDyn",
"https.requestDynCb",
"https.request",
"https.requestCb",
"https.requestUrl",
Expand Down
Loading
Loading