Repository navigation
Expand file tree
/
Copy pathhttpResponseErrorGuard.ts
More file actions
51 lines (49 loc) · 1.85 KB
/
Copy pathhttpResponseErrorGuard.ts
File metadata and controls
51 lines (49 loc) · 1.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// These guards run on the raw Node HTTP server before Effect handles requests.
// @effect-diagnostics nodeBuiltinImport:off
import type * as NodeHttp from "node:http";
import type * as NodeStream from "node:stream";
export function guardHttpResponseWriteErrors<T extends NodeHttp.Server>(
server: T,
onError?: (error: unknown) => void,
): T {
server.on("request", (_request, response) => {
response.on("error", (error) => {
onError?.(error);
});
});
server.on("upgrade", (_request, socket) => {
socket.on("error", (error) => {
onError?.(error);
});
});
return server;
}
/**
* NodeHttpServer listens before serve() attaches its handlers, so requests in
* between would hang. Install this after the write-error guards so only the
* serving handlers trigger the handoff.
*/
export function rejectRequestsUntilServing<T extends NodeHttp.Server>(server: T): T {
const rejectRequest = (_request: NodeHttp.IncomingMessage, response: NodeHttp.ServerResponse) => {
response.writeHead(503, { "retry-after": "1", connection: "close" }).end();
};
const rejectUpgrade = (_request: NodeHttp.IncomingMessage, socket: NodeStream.Duplex) => {
socket.end(
"HTTP/1.1 503 Service Unavailable\r\nRetry-After: 1\r\nConnection: close\r\nContent-Length: 0\r\n\r\n",
);
};
server.on("request", rejectRequest);
server.on("upgrade", rejectUpgrade);
// Node emits newListener before adding the handler, making the handoff synchronous.
server.on("newListener", function onNewListener(event) {
if (event === "request") server.off("request", rejectRequest);
if (event === "upgrade") server.off("upgrade", rejectUpgrade);
if (
!server.listeners("request").includes(rejectRequest) &&
!server.listeners("upgrade").includes(rejectUpgrade)
) {
server.off("newListener", onNewListener);
}
});
return server;
}