mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-09 09:48:15 +08:00
Add net socket address fields, write and end callbacks, and server connection limits (#1052)
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
// A socket's address fields, byte counts and state: the remote fields
|
||||
// are cached at first read and stay readable after close, the local ones
|
||||
// are undefined while connecting and after close, and readyState follows
|
||||
// the open halves.
|
||||
import * as net from "node:net";
|
||||
|
||||
// The server's 'connection' and the client's 'connect' race (either can
|
||||
// run first), so each side records its line and both print once both
|
||||
// have run.
|
||||
let serverLine: string | null = null;
|
||||
let clientLine: string | null = null;
|
||||
let startClient: (() => void) | null = null;
|
||||
function bothConnected(): void {
|
||||
if (serverLine === null || clientLine === null || startClient === null) return;
|
||||
console.log(serverLine);
|
||||
console.log(clientLine);
|
||||
startClient();
|
||||
}
|
||||
|
||||
const server = net.createServer((sock) => {
|
||||
const port = (server.address() as net.AddressInfo).port;
|
||||
serverLine =
|
||||
`server side ${sock.remoteAddress} ${sock.remoteFamily} ${typeof sock.remotePort} ` +
|
||||
`${sock.localAddress} ${sock.localPort === port} ${sock.localFamily}`;
|
||||
bothConnected();
|
||||
sock.on("data", (d: Buffer) => {
|
||||
console.log("server got", d.toString(), sock.bytesRead);
|
||||
sock.end("bye");
|
||||
});
|
||||
});
|
||||
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const port = (server.address() as net.AddressInfo).port;
|
||||
const c = net.connect(port, "127.0.0.1");
|
||||
console.log(
|
||||
"before connect",
|
||||
c.readyState,
|
||||
c.connecting,
|
||||
c.pending,
|
||||
c.remoteAddress,
|
||||
c.remotePort,
|
||||
c.localAddress,
|
||||
c.localPort,
|
||||
c.bytesRead,
|
||||
);
|
||||
c.on("connect", () => {
|
||||
clientLine =
|
||||
`connected ${c.readyState} ${c.connecting} ${c.pending} ${c.remotePort === port} ` +
|
||||
`${c.remoteFamily} ${c.localAddress} ${typeof c.localPort} ${c.localFamily}`;
|
||||
startClient = () => c.write("hello");
|
||||
bothConnected();
|
||||
});
|
||||
c.on("data", (d: Buffer) => console.log("client got", d.toString(), c.bytesRead));
|
||||
c.on("end", () => console.log("end", c.readyState, c.bytesRead, c.bytesWritten));
|
||||
c.on("close", () => {
|
||||
console.log(
|
||||
"closed",
|
||||
c.readyState,
|
||||
c.pending,
|
||||
c.remoteAddress,
|
||||
c.remotePort === port,
|
||||
c.localAddress,
|
||||
c.localPort,
|
||||
);
|
||||
const d = net.connect(port, "127.0.0.1");
|
||||
d.destroy();
|
||||
console.log("destroyed before connect", d.readyState, d.connecting, d.pending, d.remoteAddress);
|
||||
d.on("close", () => server.close());
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,72 @@
|
||||
// write and end callbacks, close listeners with hadError, the 'ready'
|
||||
// event, string 'data' chunks after setEncoding, setTimeout with a callback (and its msecs checks) and
|
||||
// setKeepAlive's chaining.
|
||||
import * as net from "node:net";
|
||||
|
||||
// Each side keeps its own list: the client's callbacks and the server's
|
||||
// events can interleave either way, so the lists print one after the
|
||||
// other at the end.
|
||||
const events: string[] = [];
|
||||
const serverEvents: string[] = [];
|
||||
let serverSockets = 0;
|
||||
const server = net.createServer((sock) => {
|
||||
sock.setEncoding("utf8");
|
||||
sock.on("data", (d: string) => {
|
||||
serverEvents.push(`server data ${typeof d} ${d}`);
|
||||
sock.end("pong", () => serverEvents.push("server end callback"));
|
||||
});
|
||||
// the first connection's server side (the timeout connection's close
|
||||
// order against the client's depends on the event loop phase)
|
||||
if (serverSockets++ === 0) {
|
||||
sock.on("close", (hadError: boolean) => serverEvents.push(`server close ${hadError}`));
|
||||
}
|
||||
});
|
||||
|
||||
function attempt(label: string, f: () => void): void {
|
||||
try {
|
||||
f();
|
||||
events.push(`${label} ok`);
|
||||
} catch (err) {
|
||||
const e = err as NodeJS.ErrnoException;
|
||||
events.push(`${label} ${e.name} ${e.code} ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const port = (server.address() as net.AddressInfo).port;
|
||||
const c = net.connect(port, "127.0.0.1");
|
||||
c.on("connect", () => {
|
||||
events.push("connect");
|
||||
c.write("ping", (err?: Error | null) => events.push(`write callback ${err === null}`));
|
||||
events.push(`setKeepAlive chains ${c.setKeepAlive(true, 1000) === c}`);
|
||||
});
|
||||
c.on("ready", () => events.push("ready"));
|
||||
c.on("data", (d: Buffer) => events.push(`client data ${d.toString()}`));
|
||||
c.on("end", () => {
|
||||
events.push("client end");
|
||||
c.end(() => events.push("client end callback"));
|
||||
});
|
||||
c.on("close", (hadError: boolean) => {
|
||||
events.push(`client close ${hadError}`);
|
||||
const t = net.connect(port, "127.0.0.1", () => {
|
||||
attempt("negative", () => t.setTimeout(-1));
|
||||
attempt("NaN", () => t.setTimeout(NaN));
|
||||
attempt("Infinity", () => t.setTimeout(Infinity));
|
||||
const never = () => events.push("removed callback ran");
|
||||
t.setTimeout(20, never);
|
||||
t.setTimeout(0, never);
|
||||
t.setTimeout(30, () => {
|
||||
events.push("timeout callback");
|
||||
t.destroy();
|
||||
});
|
||||
});
|
||||
t.on("timeout", () => events.push("timeout event"));
|
||||
t.on("close", (hadError: boolean) => {
|
||||
events.push(`t close ${hadError}`);
|
||||
server.close(() => {
|
||||
console.log(serverEvents.join("\n"));
|
||||
console.log(events.join("\n"));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,44 @@
|
||||
// server.maxConnections turns away connections past the cap with a
|
||||
// 'drop' event carrying their addresses, and getConnections reports the
|
||||
// open count on the next tick.
|
||||
import * as net from "node:net";
|
||||
|
||||
const server = net.createServer((sock) => {
|
||||
sock.on("data", () => {});
|
||||
});
|
||||
console.log("default", server.maxConnections);
|
||||
server.maxConnections = 1;
|
||||
console.log("set", server.maxConnections);
|
||||
server.on("drop", (data?: net.DropArgument) => {
|
||||
console.log(
|
||||
"drop",
|
||||
data?.localAddress,
|
||||
typeof data?.localPort,
|
||||
data?.localFamily,
|
||||
data?.remoteAddress,
|
||||
typeof data?.remotePort,
|
||||
data?.remoteFamily,
|
||||
);
|
||||
});
|
||||
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const port = (server.address() as net.AddressInfo).port;
|
||||
const first = net.connect(port, "127.0.0.1", () => {
|
||||
const second = net.connect(port, "127.0.0.1");
|
||||
second.resume();
|
||||
second.on("close", () => {
|
||||
console.log("second closed");
|
||||
process.nextTick(() => console.log("tick before"));
|
||||
const same = server.getConnections((err: Error | null, count: number) => {
|
||||
console.log("connections", err, count);
|
||||
});
|
||||
console.log("getConnections chains", same === server);
|
||||
process.nextTick(() => console.log("tick after"));
|
||||
Promise.resolve().then(() => console.log("microtask"));
|
||||
server.maxConnections = undefined;
|
||||
console.log("unset", server.maxConnections);
|
||||
first.destroy();
|
||||
server.close(() => console.log("server closed"));
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
// net.isIP, isIPv4 and isIPv6 follow Node's address patterns: dotted
|
||||
// decimal without leading zeros, and IPv6 text forms with one "::", an
|
||||
// IPv4 tail and an optional %zone.
|
||||
import * as net from "node:net";
|
||||
|
||||
const inputs = [
|
||||
"1.2.3.4",
|
||||
"255.255.255.255",
|
||||
"01.2.3.4",
|
||||
"256.1.1.1",
|
||||
"1.2.3",
|
||||
"1.2.3.4.5",
|
||||
"::",
|
||||
"::1",
|
||||
"fe80::1%eth0",
|
||||
"fe80::1%",
|
||||
"1:2:3:4:5:6:7:8",
|
||||
"1:2:3:4:5:6:7::",
|
||||
"::1:2:3:4:5:6:7",
|
||||
"1:2:3:4:5:6:7:8:9",
|
||||
"1::2::3",
|
||||
":1::",
|
||||
"1:",
|
||||
"::ffff:1.2.3.4",
|
||||
"1:2:3:4:5:6:1.2.3.4",
|
||||
"1:2:3:4:5:6:7:1.2.3.4",
|
||||
"12345::1",
|
||||
"abcd:EF01::",
|
||||
"",
|
||||
"localhost",
|
||||
];
|
||||
for (const input of inputs) {
|
||||
console.log(JSON.stringify(input), net.isIP(input), net.isIPv4(input), net.isIPv6(input));
|
||||
}
|
||||
Reference in New Issue
Block a user