Skip to content

fix: bound incoming transport message sizes - #259

Merged
benbrandt merged 1 commit into
mainfrom
fix/bound-incoming-messages
Sep 23, 2026
Merged

benbrandt merged 1 commit into
mainfrom
fix/bound-incoming-messages

Conversation

@benbrandt

Copy link
Copy Markdown
Member

Summary

Bound incoming message assembly for NDJSON and HTTP/SSE transports while retaining enough default headroom for multimodal ACP prompts.

Changes

  • Add an optional maxMessageBytes setting with a 32 MiB default, plus shared DEFAULT_MAX_MESSAGE_BYTES and MessageTooLargeError exports for the stable, v2, and HTTP entry points.
  • Replace retained chunk arrays with a bounded, geometrically growing byte buffer and yield completed lines lazily.
  • Bound both unfinished SSE lines and accumulated event data. Discard comments and unused fields immediately, account for framing separately, and reset the payload budget per event.
  • Clear buffered data, cancel the input, and error the connection on overflow rather than silently dropping requests or responses.
  • Bound HTTP initialization JSON and error response bodies, and cancel unused successful POST/DELETE response bodies without waiting indefinitely for cleanup.
  • Preserve existing below-limit parsing behavior, including UTF-8 chunk boundaries, BOM handling, CRLF, multiline SSE, and accepted EOF-terminated messages.

Compatibility and scope

  • Existing call sites remain valid, but the finite default intentionally rejects previously accepted oversized input. Callers can supply a larger positive safe-integer limit where required.
  • The limit controls incoming encoded data, not outgoing serialization or peak process memory. Oversized input terminates the connection.
  • The 32 MiB default accommodates more image-heavy prompts: three 4 MiB images already exceed a 16 MiB frame after base64 encoding and JSON overhead.
  • The Node HTTP server's existing 16 MiB maxRequestBodyBytes default is unchanged. Deployments accepting larger HTTP prompts must configure that server-side setting separately.
  • This change bounds individual message assembly. Completed-message queue backpressure, aggregate connection budgets, and WebSocket limits remain separate work.

Validation

  • CI=1 npm run check passed: schema generation checks, lint, formatting, spelling, build, 886 test executions including source/compiled copies, and TypeDoc verification.
  • 2,172 bounded differential parsing cases matched the original implementation's messages, protocol-error responses, and warning counts below the limit.
  • Bounded probes verified exact limits, UTF-8/CRLF/BOM accounting, multiline SSE limits, cancellation, and default/override propagation.
  • A synthetic prompt sized for three 4 MiB images succeeds with the default and fails with a 16 MiB override; unterminated input cancels on the first 1 MiB chunk past 32 MiB.
  • Successful HTTP response cleanup was checked with resolving, rejecting, stalled, already-errored, and absent bodies.
  • Node stream-adapter and loopback HTTP/SSE checks verified underlying source shutdown and connection cleanup.

No test or documentation files were added; the additional cases were exercised with bounded inline probes.

@benbrandt
benbrandt merged commit 69fda37 into main Sep 23, 2026
6 checks passed
@benbrandt
benbrandt deleted the fix/bound-incoming-messages branch September 23, 2026 15:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant