Skip to content

fix(rsocket-core): Pass fragmentation config to server-side responder streams #306

@Niteesh

Description

@Niteesh

Description

Bug

RSocketServer accepts a fragmentation.maxOutboundFragmentSize config, but it only applies to
the requester side (server-initiated requests). The responder side (server responses to client
requests) always uses fragmentSize=0, meaning responses are never fragmented.

This causes a crash when the server tries to send a response larger than 16MB (the RSocket frame
length field is 24-bit, max 16,777,215 bytes), because writeUInt24BE overflows:

RangeError: The value of "value" is out of range. It must be >= 0 and <= 255.
    at writeUInt24BE (rsocket-core/src/Codecs.ts:80)
    at serializeFrameWithLength (rsocket-core/src/Codecs.ts:161)

Root Cause

Two issues in packages/rsocket-core/src/RSocketServer.ts:

  1. Constructor doesn't store fragmentation: The fragmentation field from ServerConfig is
    never assigned to this, so this.fragmentation is always undefined.

  2. DefaultStreamRequestHandler hardcodes fragmentSize=0: Even if this.fragmentation were
    stored, the stream handler is created with fragmentSize=0 instead of using the configured value.

Fix

 constructor(config: ServerConfig) {
     this.acceptor = config.acceptor;
     this.transport = config.transport;
     this.lease = config.lease;
+    this.fragmentation = config.fragmentation;
     this.serverSideKeepAlive = config.serverSideKeepAlive;
-const streamsHandler = new DefaultStreamRequestHandler(responder, 0);
+const streamsHandler = new DefaultStreamRequestHandler(
+    responder,
+    this.fragmentation?.maxOutboundFragmentSize ?? 0,
+);

Impact

Without this fix, any RSocket server using rsocket-core v1 cannot send responses larger than ~16MB.
The fragmentation infrastructure (Fragmenter.ts, RequestResponseResponderStream.onNext) already
exists and works correctly — it just never receives a non-zero fragmentSize.

Reproduction

const server = new RSocketServer({
    transport: new TcpServerTransport({ listenOptions: { port: 9090 } }),
    fragmentation: { maxOutboundFragmentSize: (1 << 24) - 1 - 9 }, // This is ignored!
    acceptor: {
        async accept() {
            return {
                requestResponse(payload, responder) {
                    // This crashes if payload response > 16MB
                    responder.onNext({ data: Buffer.alloc(20_000_000) }, true);
                    return { cancel() {}, onExtension() {} };
                },
            };
        },
    },
});

Files Changed

  • packages/rsocket-core/src/RSocketServer.ts (2 lines)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions