Bad client may send arbitrary (very large, limited only by connection bandwidth) number of channel request messages regardless of server allowed with requestN, which then are blindly accepted by spring-rsocket and delivered to end user's handler.
Usually user's handler is not prepared to receive more messages than requested, and likely either queues messages in memory, or overwhelms its downstream resources.
Trivial reproducer is at channel-overflow using springboot 2.5.4
./server.sh
, ./channel_overflow.sh
Particularly, server reports
2021-09-23 22:20:15.039 INFO 5047 --- [ parallel-2] example.service.Service : payload requested: 5, received: 49929
2021-09-23 22:20:16.039 INFO 5047 --- [ parallel-2] example.service.Service : payload requested: 5, received: 50076
2021-09-23 22:20:17.039 INFO 5047 --- [ parallel-2] example.service.Service : payload requested: 5, received: 50042
2021-09-23 22:20:18.039 INFO 5047 --- [ parallel-2] example.service.Service : payload requested: 5, received: 49988
2021-09-23 22:20:19.039 INFO 5047 --- [ parallel-2] example.service.Service : payload requested: 5, received: 50023
2021-09-23 22:20:20.039 INFO 5047 --- [ parallel-2] example.service.Service : payload requested: 5, received: 49975
Comment From: OlegDokuka
as the spec suggests:
Lack of REQUEST_N frames that stops a stream is an application concern and SHALL NOT be handled by the protocol
The mentioned scenario is an application concern and should be handled by the application https://github.com/rsocket/rsocket/blob/master/Protocol.md#handling-the-unexpected
Comment From: bclozel
Thanks @OlegDokuka , I'll close this issue as invalid since this is covered by the spec already.
Comment From: mostroverkhov
as the spec suggests:
Lack of REQUEST_N frames that stops a stream is an application concern and SHALL NOT be handled by the protocol
The mentioned scenario is an application concern and should be handled by the application https://github.com/rsocket/rsocket/blob/master/Protocol.md#handling-the-unexpected
This is completely not related to the issue reported here - not sure why It was linked:
the reproducer clearly shows there is periodic requestN=5
sent by receiver every second,
so stream is not stopped / stalled: payload requested: 5
.
The problem reported here is responder does not respect requested demand - and responder is free to send messages at arbitrarily high rate: payload requested: 5, received: 49929
because is allowed to do so by rsocket/rsocket-java.
This is obvious omission - backpressure/flow control has to be enforced on receiver side if this library
is intended for servers accessed by non-trusted clients (internet clients, cloud application 3rd party clients) -
same way how http2
flow control is enforced on receiver side: if peer receives more bytes than requested by stream,
connection is closed.
@bclozel I suggest Spring team to have another look at this and reopen the issue:
The mentioned scenario is an application concern and should be handled by the application
It basically requires from spring / rsocket-java library users to have this for each channel request (pseudocode):
.doOnSignal(signal -> {
if(signal is requestN) {
totalRequestN+=requestN.value
} else if (signal is next) {
totalRequestN--
if(totalRequestN<0) {
rsocket.close("stream flow control violation")
}
}
})
When moving over untrusted boundary, protocol rules validation is responsibility of library implementation - not of the application code.
Comment From: rstoyanchev
There is now a separate issue to track this https://github.com/rsocket/rsocket-java/issues/1064.