I may have always misunderstood the RFC, or maybe we have an actual bug?
I see STREAM_DATA_BLOCKED and DATA_BLOCKED frames sent already when the application's write buffer is larger than remaining flow control credit, not when credit is actually exhausted. I think this violates RFC 9000 Section 4.1:
"If a sender has sent data up to the limit, it will be unable to send new data and is considered blocked. A sender SHOULD send a STREAM_DATA_BLOCKED or DATA_BLOCKED frame to indicate to the receiver that it has data to write but is blocked by flow control limits."
The frame should be sent when available() == 0, not when available() < app_write_size?
fn send_blocked_if_space_needed(&mut self, needed_space: usize) {
if fc.available() <= needed_space { // stream-level
fc.blocked();
}
if conn_fc.borrow().available() <= needed_space { // connection-level
conn_fc.borrow_mut().blocked();
}
}
When an application writes 100MB to a stream with a 1MB FC limit, blocked() fires immediately (1MB < 100MB) even though the sender has nearly 1MB of credit remaining.
The other call site, send_blocked_if_space_needed(0) after mark_as_sent, is correct — it checks for actual credit exhaustion.
I may have always misunderstood the RFC, or maybe we have an actual bug?
I see
STREAM_DATA_BLOCKEDandDATA_BLOCKEDframes sent already when the application's write buffer is larger than remaining flow control credit, not when credit is actually exhausted. I think this violates RFC 9000 Section 4.1:The frame should be sent when
available() == 0, not whenavailable() < app_write_size?When an application writes 100MB to a stream with a 1MB FC limit,
blocked()fires immediately (1MB < 100MB) even though the sender has nearly 1MB of credit remaining.The other call site,
send_blocked_if_space_needed(0)aftermark_as_sent, is correct — it checks for actual credit exhaustion.