tunnel: 10MB MAX_MESSAGE_SIZE cap is inconsistent with the 20MB body-limit default and ignores base64 framing overhead · Issue #567 · JavaScriptSolidServer/JavaScriptSolidServer · GitHub
Follow-up surfaced in the #563 / #566 review (default request body limit raised 10MB → 20MB).
Problem
The tunnel proxy has its own hard-coded 10 MB cap that #563's body-limit change does not touch, so the tunnel path is now the bottleneck — and it's inconsistent in three ways.
src/tunnel/index.js:
constMAX_MESSAGE_SIZE=10*1024*1024;// 10MB (line 82)
...
socket.on('message',(data)=>{constraw=Buffer.isBuffer(data) ? data : Buffer.from(data);if(raw.byteLength>MAX_MESSAGE_SIZE){// line 137socket.send(JSON.stringify({type: 'error',message: 'Message too large'}));return;}
1. Inconsistent with the new 20MB HTTP body default
config.defaults.bodyLimit is now 20 MiB (#563) and configurable via --body-limit / JSS_BODY_LIMIT. MAX_MESSAGE_SIZE is a separate, hard-coded 10 MB constant with no knob. A deployment that raises --body-limit to accept larger payloads still silently caps anything traversing a tunnel at 10 MB.
2. Direction-specific, and the cap bites responses
MAX_MESSAGE_SIZE is enforced only in socket.on('message') — i.e. messages the relay receives from the tunnel client, which are the response frames carrying the HTTP response body. So a tunnelled download (e.g. git clone/fetch of a repo, or any large GET) whose body exceeds the cap fails with Message too large. The request direction (relay→client, e.g. a push upload) is governed instead by the relay's HTTP bodyLimit on intake — a different limit on a different leg. The two legs of one tunnelled round-trip are bounded by two unrelated, unaligned numbers.
3. base64 framing overhead isn't accounted for
Bodies are base64-encoded into the JSON frames (tunnelReq.body = …toString('base64'), and the response side likewise). base64 inflates ~33%, so the effective content limit is ~7.5 MB, not 10 MB — and a body sized right at a configured limit won't fit once framed.
Suggested direction
Derive the tunnel message cap from the effective bodyLimit (plus base64 headroom, ~×1.4) instead of a separate constant, OR make it independently configurable and document the relationship.
Apply a consistent bound to both legs (request frame out, response frame in) so a tunnelled round-trip has one predictable size budget.
Account for base64 inflation so a payload at the body limit actually traverses the tunnel.
This reads like a one-constant change but isn't — flagging for anyone who picks it up:
The plugin has no access to bodyLimit today. tunnelPlugin is registered with only { path: tunnelPath } (src/server.js:389); its options don't carry the configured body limit. So "derive the cap from bodyLimit" first requires threading config through plugin registration — a server.js wiring change, not just editing the constant.
The cap's direction has to be understood first. MAX_MESSAGE_SIZE is enforced only in socket.on('message') (src/tunnel/index.js:137) — messages the relay receives from the client, i.e. response frames. So it bounds the response/download leg (clone, large GET), while the request/upload leg is bounded by the relay's HTTP bodyLimit on intake — a different limit on the other leg. Aligning them means reasoning about both directions, not one number.
base64 headroom is a real design call. Bodies are base64-framed (~+33%), so a derived cap needs a ~×1.4 factor or payloads at the body limit won't traverse the tunnel — and over-provisioning widens the memory-DoS surface on a credential-carrying proxy.
Labelled help wanted rather than good first issue for those reasons: well-specified, but needs tunnel-protocol context + a config-wiring change + size-budget judgment, not a mechanical edit.
Activity
melvincarvalho commented on Jun 15, 2026
Difficulty note (why not good first issue)
This reads like a one-constant change but isn't — flagging for anyone who picks it up:
Labelled help wanted rather than good first issue for those reasons: well-specified, but needs tunnel-protocol context + a config-wiring change + size-budget judgment, not a mechanical edit.