From 9123b27030df824a9a0a8d81945b5d0d1c92db37 Mon Sep 17 00:00:00 2001 From: Melvin Carvalho Date: Mon, 15 Jun 2026 09:21:16 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20raise=20default=20body=20limit=2010MB?= =?UTF-8?q?=20=E2=86=92=2020MB=20(#563)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A more generous out-of-the-box request body cap for common workloads (larger `git push`, media uploads, bigger RDF documents). Still fully configurable via --body-limit / JSS_BODY_LIMIT / createServer({ bodyLimit }) — deployments wanting tighter memory-DoS protection lower it. - config.defaults.bodyLimit: 10 MiB → 20 MiB - bin/jss.js --body-limit help text: 'default 10MB' → 'default 20MB' - refreshed two now-stale doc comments that claimed the default 'matches the previous hard-coded 10 MiB cap' (config.js, server.js) - new regression test pins the EFFECTIVE wired default via Fastify's initialConfig.bodyLimit (config.defaults → createServer → Fastify), so the default can't silently drift Scope note: the tunnel proxy has a SEPARATE 10 MiB WS message cap (src/tunnel/index.js MAX_MESSAGE_SIZE) that this change does not touch — a >10 MiB push over a tunnel would clear the body limit but hit that cap. Out of scope for #563 (request-body default); worth a follow-up if tunnelled large pushes become a real need. Full suite: 962/962 passing. Closes #563. --- bin/jss.js | 2 +- src/config.js | 11 ++++++----- src/server.js | 4 ++-- test/body-limit.test.js | 14 ++++++++++++-- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/bin/jss.js b/bin/jss.js index a4c3ef0e..44b51187 100755 --- a/bin/jss.js +++ b/bin/jss.js @@ -112,7 +112,7 @@ program .option('--cors-proxy-max-bytes ', 'CORS proxy upstream response size cap (default 50MB)', parseInt) .option('--cors-proxy-timeout-ms ', 'CORS proxy upstream request timeout (default 30s)', parseInt) .option('--cors-proxy-max-redirects ', 'CORS proxy max redirect hops, each re-validated (default 5)', parseInt) - .option('--body-limit ', 'Maximum request body size, e.g. 100MB or 1GB (default 10MB). Raise to accept larger `git push`; lower for tighter memory-DoS protection.') + .option('--body-limit ', 'Maximum request body size, e.g. 100MB or 1GB (default 20MB). Raise to accept larger `git push`; lower for tighter memory-DoS protection.') .option('--nostr', 'Enable Nostr relay') .option('--no-nostr', 'Disable Nostr relay') .option('--nostr-path ', 'Nostr relay WebSocket path (default: /relay)') diff --git a/src/config.js b/src/config.js index 98db704f..e416bcc7 100644 --- a/src/config.js +++ b/src/config.js @@ -20,11 +20,12 @@ export const defaults = { host: '0.0.0.0', root: './data', // Maximum request body size in bytes (or a size string when supplied - // via CLI / config file, e.g. "100MB"). Default 10 MiB matches the - // previous hard-coded Fastify limit. Operators hosting personal pods - // may want to raise this so that large `git push` of an established - // app repo doesn't 413 — see #474. - bodyLimit: 10 * 1024 * 1024, + // via CLI / config file, e.g. "100MB"). 20 MiB default (#563) — a + // generous out-of-the-box limit for common workloads (larger `git + // push`, media uploads, bigger RDF documents). Raise via --body-limit + // / JSS_BODY_LIMIT for established app repos (#474); lower it for + // tighter memory-DoS protection. + bodyLimit: 20 * 1024 * 1024, // SSL sslKey: null, diff --git a/src/server.js b/src/server.js index 1044e979..6643ca81 100644 --- a/src/server.js +++ b/src/server.js @@ -187,8 +187,8 @@ export function createServer(options = {}) { // already coerced by parseEnvValue) pass through unchanged; strings // ("100MB" from CLI / config files) go through parseSize for // size-shorthand support. The typeof check matters because parseSize - // calls `.match` on its input and would throw on a raw number. Default - // matches the previous hard-coded 10 MiB cap. See #474. + // calls `.match` on its input and would throw on a raw number. Falls + // back to defaults.bodyLimit (20 MiB, #563) when unset. See #474. const bodyLimit = options.bodyLimit == null ? defaults.bodyLimit : (typeof options.bodyLimit === 'number' ? options.bodyLimit : parseSize(options.bodyLimit)); diff --git a/test/body-limit.test.js b/test/body-limit.test.js index 4d76ea60..411f8b0d 100644 --- a/test/body-limit.test.js +++ b/test/body-limit.test.js @@ -12,8 +12,8 @@ * * Tests here verify the surface end-to-end — server actually rejects * over-size requests with 413, AND the size-string parsing path works - * the same as the numeric path. The default (10 MiB) is covered - * implicitly by every other test in the suite continuing to pass. + * the same as the numeric path. The out-of-the-box default (20 MiB + * since #563) is pinned explicitly via Fastify's initialConfig. */ import { describe, it, before, after, afterEach } from 'node:test'; @@ -102,4 +102,14 @@ describe('configurable bodyLimit (#474)', () => { assert.notStrictEqual(res.status, 413, `100-byte body under a 10KB cap should not 413; got ${res.status}`); }); + + it('defaults to a 20 MiB body limit when none is configured (#563)', async () => { + await fs.emptyDir(TEST_DATA_DIR); + server = createServer({ logger: false, forceCloseConnections: true, root: TEST_DATA_DIR }); + // Pin the EFFECTIVE wired default, not the constant in isolation: + // Fastify freezes resolved options into initialConfig, so this + // exercises config.defaults.bodyLimit → createServer → Fastify. + assert.strictEqual(server.initialConfig.bodyLimit, 20 * 1024 * 1024, + `expected the out-of-the-box default to be 20 MiB; got ${server.initialConfig.bodyLimit}`); + }); });