mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-14 04:39:43 +08:00
106 lines
3.5 KiB
TypeScript
106 lines
3.5 KiB
TypeScript
/* The http CLIENT and SERVER in one program (the mixed differential:
|
|
* under Node this is real http.request against a real http.Server; the
|
|
* compiled lane runs the runtime's client against the runtime's server,
|
|
* and every log line must land in the same order). Covers: the
|
|
* options-object GET, statusCode/headers/body reads on the response, the
|
|
* client event order (res 'end' → req 'close' → res 'close'), a POST
|
|
* with a headers option and end(body) (Content-Length framing both
|
|
* ways), and http.get's eager end. Strict ping-pong: one exchange in
|
|
* flight at a time, so every line is causally ordered. */
|
|
import { createServer, request, get } from "node:http";
|
|
|
|
const server = createServer((req, res) => {
|
|
let body = "";
|
|
req.on("data", (chunk: Buffer) => {
|
|
body += chunk.toString("utf8");
|
|
});
|
|
req.on("end", () => {
|
|
const ct = req.headers["content-type"];
|
|
const cl = req.headers["content-length"];
|
|
console.log(
|
|
`srv ${req.method} ${req.url} ct=${ct !== undefined ? ct : "-"} cl=${cl !== undefined ? cl : "-"} body=${body}`,
|
|
);
|
|
if (req.url === "/post") {
|
|
res.writeHead(201, { "x-made": "yes" });
|
|
res.end(`got:${body}`);
|
|
return;
|
|
}
|
|
if (req.url === "/quit") {
|
|
// The CLIENT closes the server from its own 'end' (closing here
|
|
// races the pooled-connection teardown differently between lanes).
|
|
res.end("bye");
|
|
return;
|
|
}
|
|
res.setHeader("content-type", "text/plain");
|
|
res.end("hello client");
|
|
});
|
|
});
|
|
|
|
function logResponse(tag: string, sc: number | undefined, ct: string | undefined, cl: string | undefined): void {
|
|
console.log(
|
|
`${tag} status=${sc !== undefined ? sc : -1} ct=${ct !== undefined ? ct : "-"} cl=${cl !== undefined ? cl : "-"}`,
|
|
);
|
|
}
|
|
|
|
function stepGet(port: number): void {
|
|
const req = request({ hostname: "127.0.0.1", port, path: "/get", method: "GET" }, (res) => {
|
|
logResponse("cli /get", res.statusCode, res.headers["content-type"], res.headers["content-length"]);
|
|
let body = "";
|
|
res.on("data", (chunk: Buffer) => {
|
|
body += chunk.toString("utf8");
|
|
});
|
|
res.on("end", () => console.log(`cli /get body=${body}`));
|
|
res.on("close", () => {
|
|
console.log("cli /get res close");
|
|
stepPost(port);
|
|
});
|
|
});
|
|
req.on("close", () => console.log("cli /get req close"));
|
|
req.end();
|
|
}
|
|
|
|
function stepPost(port: number): void {
|
|
const req = request(
|
|
{
|
|
hostname: "127.0.0.1",
|
|
port,
|
|
path: "/post",
|
|
method: "POST",
|
|
headers: { "content-type": "text/plain; charset=utf-8" },
|
|
},
|
|
(res) => {
|
|
logResponse("cli /post", res.statusCode, res.headers["x-made"], res.headers["content-length"]);
|
|
let body = "";
|
|
res.on("data", (chunk: Buffer) => {
|
|
body += chunk.toString("utf8");
|
|
});
|
|
res.on("end", () => console.log(`cli /post body=${body}`));
|
|
res.on("close", () => {
|
|
console.log("cli /post res close");
|
|
stepQuit(port);
|
|
});
|
|
},
|
|
);
|
|
req.on("close", () => console.log("cli /post req close"));
|
|
req.end("héllo wörld 😀");
|
|
}
|
|
|
|
function stepQuit(port: number): void {
|
|
const req = get({ hostname: "127.0.0.1", port, path: "/quit" }, (res) => {
|
|
let body = "";
|
|
res.on("data", (chunk: Buffer) => {
|
|
body += chunk.toString("utf8");
|
|
});
|
|
res.on("end", () => {
|
|
console.log(`cli /quit body=${body}`);
|
|
server.close(() => console.log("server closed"));
|
|
});
|
|
});
|
|
req.on("error", (err) => console.log(`cli /quit error ${err.message}`));
|
|
}
|
|
|
|
server.listen(0, () => {
|
|
console.log("listening");
|
|
stepGet(server.address().port);
|
|
});
|