Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 41 additions & 3 deletions src/frame/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,47 @@ impl Data<Bytes> {
}
}

/// If this frame is PADDED, it returns the pad len + 1 (length field).
pub(crate) fn padded_len(&self) -> Option<u8> {
self.pad_len.map(|n| n + 1)
}

#[cfg(test)]
mod tests {
use super::*;
use bytes::Bytes;

fn data_frame(data: &[u8], pad_len: Option<u8>) -> Data<Bytes> {
Data {
stream_id: StreamId::from(1),
data: Bytes::copy_from_slice(data),
flags: DataFlags::default(),
pad_len,
}
}

#[test]
fn padding_overhead_no_padding() {
let frame = data_frame(b"hello", None);
assert_eq!(frame.flow_controlled_len() - frame.payload().len(), 0);
}

#[test]
fn padding_overhead_small() {
let frame = data_frame(b"hello", Some(10));
assert_eq!(frame.flow_controlled_len() - frame.payload().len(), 11);
}

#[test]
fn padding_overhead_max_does_not_overflow() {
// Regression: the old padded_len() returned u8, so pad_len=255
// caused 255u8 + 1 = 0. The correct overhead is 256.
let frame = data_frame(b"", Some(255));
assert_eq!(frame.flow_controlled_len() - frame.payload().len(), 256);
}

#[test]
fn padding_overhead_max_with_data() {
let frame = data_frame(b"hello", Some(255));
assert_eq!(frame.flow_controlled_len() - frame.payload().len(), 256);
assert_eq!(frame.flow_controlled_len(), 261);
}
}

Expand Down
12 changes: 7 additions & 5 deletions src/proto/streams/recv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -736,14 +736,16 @@ impl Recv {
// Track the data as in-flight
stream.in_flight_recv_data += sz;

// We auto-release the padded length, since the user cannot.
if let Some(padded_len) = frame.padded_len() {
// Auto-release padding overhead (pad_len field + padding bytes),
// since the user only sees the data payload via `payload()`.
let padding = (frame.flow_controlled_len() - frame.payload().len()) as WindowSize;
if padding > 0 {
tracing::trace!(
"recv_data; auto-releasing padded length of {:?} for {:?}",
padded_len,
"recv_data; auto-releasing padding of {:?} for {:?}",
padding,
stream.id,
);
let _res = self.release_capacity(padded_len.into(), stream, &mut None);
let _res = self.release_capacity(padding, stream, &mut None);
// cannot fail, we JUST added more in_flight data above.
debug_assert!(_res.is_ok());
}
Expand Down
Loading