@antelopejs/dms-frontend 0.3.6 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antelopejs/dms-frontend",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "description": "Frontend-agnostic loader for AntelopeJS DMS, shipping the Vue 3 renderer (Vite, Inertia, SSR)",
5
5
  "keywords": [
6
6
  "antelope",
@@ -0,0 +1,41 @@
1
+ // Answers for requests Node rejects before the request handler runs. Without
2
+ // a `clientError` listener Node answers on its own and logs nothing, so a page
3
+ // refused for its headers left no trace in the server output.
4
+
5
+ const HEADER_OVERFLOW = "HPE_HEADER_OVERFLOW";
6
+ const HEADER_OVERFLOW_RESPONSE =
7
+ "HTTP/1.1 431 Request Header Fields Too Large\r\nConnection: close\r\n\r\n";
8
+ const BAD_REQUEST_RESPONSE =
9
+ "HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n";
10
+ // A browser retries a refused page with the same cookies: one hint per minute
11
+ // is enough to explain them all.
12
+ const HEADER_OVERFLOW_HINT_INTERVAL_MS = 60_000;
13
+
14
+ let lastHeaderOverflowHint = -Infinity;
15
+
16
+ function warnHeaderOverflow(maxHeaderSize) {
17
+ const now = Date.now();
18
+ if (now - lastHeaderOverflowHint < HEADER_OVERFLOW_HINT_INTERVAL_MS) return;
19
+ lastHeaderOverflowHint = now;
20
+ console.warn(
21
+ `DMS refused a request with 431: its headers exceed the ${maxHeaderSize}-byte limit. ` +
22
+ "This is most often cookies accumulated on this host (browsers share " +
23
+ "localhost cookies across ports); clear this site's cookies and reload.",
24
+ );
25
+ }
26
+
27
+ /**
28
+ * The server's `clientError` listener: explains a 431 in the logs, and
29
+ * otherwise answers as Node does without a listener.
30
+ */
31
+ export function handleClientError(error, socket, maxHeaderSize) {
32
+ let response = BAD_REQUEST_RESPONSE;
33
+ if (error.code === HEADER_OVERFLOW) {
34
+ response = HEADER_OVERFLOW_RESPONSE;
35
+ warnHeaderOverflow(maxHeaderSize);
36
+ }
37
+ // Once a response went out on this connection, a status line would land in
38
+ // the middle of it.
39
+ if (socket.writable && socket.bytesWritten === 0) socket.write(response);
40
+ socket.destroy();
41
+ }
@@ -1,5 +1,5 @@
1
1
  import { createReadStream, existsSync, readFileSync, statSync } from "node:fs";
2
- import { createServer } from "node:http";
2
+ import { createServer, maxHeaderSize } from "node:http";
3
3
  import { extname, join, resolve, sep } from "node:path";
4
4
  import { Readable } from "node:stream";
5
5
  import { pipeline } from "node:stream/promises";
@@ -19,6 +19,7 @@ import {
19
19
  redirectAccessRefusal,
20
20
  UNEXPECTED_ERROR_BODY,
21
21
  } from "./server/backend-response.mjs";
22
+ import { handleClientError } from "./server/client-error.mjs";
22
23
  import { productionHtmlTemplate } from "./server/client-manifest.mjs";
23
24
  import { writeContent } from "./server/content.mjs";
24
25
  import {
@@ -489,6 +490,9 @@ if (
489
490
  import.meta.url === new URL(`file://${process.argv[1]}`).href
490
491
  ) {
491
492
  frontendHttpServer = createServer(handleRequestSafely);
493
+ frontendHttpServer.on("clientError", (error, socket) =>
494
+ handleClientError(error, socket, maxHeaderSize),
495
+ );
492
496
  frontendHttpServer.listen(
493
497
  Number(process.env.PORT ?? 3001),
494
498
  process.env.HOST ?? "0.0.0.0",