-
Notifications
You must be signed in to change notification settings - Fork 99
Description
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:
-
Constructor doesn't store
fragmentation: Thefragmentationfield fromServerConfigis
never assigned tothis, sothis.fragmentationis alwaysundefined. -
DefaultStreamRequestHandlerhardcodesfragmentSize=0: Even ifthis.fragmentationwere
stored, the stream handler is created withfragmentSize=0instead 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)