Skip to content

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

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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions