Skip to content

fix(fns): harden and speed up the server function chunk reader - #2331

Open
lxsmnsyc wants to merge 1 commit into
mainfrom
fix/seroval-chunk-reader
Open

lxsmnsyc wants to merge 1 commit into
mainfrom
fix/seroval-chunk-reader

Conversation

@lxsmnsyc

@lxsmnsyc lxsmnsyc commented Oct 4, 2026

Copy link
Copy Markdown
Member

Fixes error handling, input checks and performance in SerovalChunkReader, which reads server function request and response streams.

Problems

  • Unhandled rejections. deserializeJSONStream returns after the first chunk and reads the rest with void reader.drain(...). A client could send a valid first chunk followed by a bad header, invalid JSON or a truncated body, and each one caused an unhandled rejection on the server. Nitro catches these and logs them. On a host that does not, Node exits the process.
  • Quadratic buffering. readChunk copied the whole buffer every time a piece arrived. A 16MB chunk read in 16KB pieces took about 2 seconds.
  • Loose header checks. The ; delimiters were never checked, and parseInt accepted partial hex such as 0x12zz. There was no size limit, so a client could make the server buffer up to 4GB for a single chunk.
  • No cleanup. The body was never cancelled after a parse error.

Changes

  • drain cancels the reader on error and rethrows. Both deserializers attach a handler that logs the error with console.error.
  • A failure while reading or parsing the first chunk also cancels the body.
  • deserializeJSStream now deletes $R[id] on failure as well as on success.
  • The reader keeps incoming pieces in a list and copies bytes only when a chunk spans more than one piece. Each byte is copied at most once.
  • The header must be ;0x plus 8 hex digits plus ;. Anything else throws Malformed server function stream.
  • SerovalChunkReader takes an optional maxChunkSize. extractBody passes 64MB (MAX_REQUEST_CHUNK_SIZE) when the server reads a client body. Responses read by the client have no limit.
  • createChunk is replaced by enqueueChunk. It writes the 12-byte header directly and enqueues the header and data as two pieces, so the data is not copied. One TextEncoder and one TextDecoder are shared at module level.

The wire format is unchanged.

Testing

  • New specs in serialization.spec.ts:
    • The header format.
    • Chunks split at every byte, including inside multi-byte characters.
    • A 16MB chunk in 16KB pieces, which now takes about 27ms.
    • Each malformed header case.
    • The size limit.
    • A bad later chunk logging instead of causing an unhandled rejection.
    • Cancelling the body when the first chunk fails.
  • 7 of the new specs fail against the old reader.
  • vitest run passes in packages/start (170 tests). pnpm typecheck is clean.
  • In apps/tests, the unit tests (after vite build) and the full Playwright e2e suite pass. That is 37 tests, including the 22 server function tests.

🤖 Generated with Claude Code

- Report errors from chunks after the first one instead of leaving an unhandled rejection.
- Cancel the stream when a chunk cannot be read or parsed.
- Check the chunk header strictly and reject chunks a client sends that are over 64MB.
- Keep incoming pieces in a list and join them once per chunk, so reading is linear.
- Reuse one TextEncoder and TextDecoder, and enqueue the header and data separately.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Oct 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 5c129f8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@solidjs/start Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@netlify

netlify Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for solid-start-landing-page ready!

Name Link
🔨 Latest commit 5c129f8
🔍 Latest deploy log https://app.netlify.com/projects/solid-start-landing-page/deploys/6ac1e4a33b573d000822c34d
😎 Deploy Preview https://deploy-preview-2331--solid-start-landing-page.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@pkg-pr-new

pkg-pr-new Bot commented Oct 4, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@solidjs/start@2331

commit: 5c129f8

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