use std::mem::MaybeUninit;
use crate::buffers::BufFactory;
use super::Error;
use super::Result;
use super::frame;
pub const HTTP3_CONTROL_STREAM_TYPE_ID: u64 = 0x0;
pub const HTTP3_PUSH_STREAM_TYPE_ID: u64 = 0x1;
pub const QPACK_ENCODER_STREAM_TYPE_ID: u64 = 0x2;
pub const QPACK_DECODER_STREAM_TYPE_ID: u64 = 0x3;
const MAX_STATE_BUF_SIZE: usize = (1 << 24) - 1;
const MAX_STATE_BUF_ALLOC_SIZE: usize = 4096;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Type {
Control,
Request,
Push,
QpackEncoder,
QpackDecoder,
Unknown,
}
impl Type {
#[cfg(feature = "qlog")]
pub fn to_qlog(self) -> qlog::events::http3::StreamType {
match self {
Type::Control => qlog::events::http3::StreamType::Control,
Type::Request => qlog::events::http3::StreamType::Request,
Type::Push => qlog::events::http3::StreamType::Push,
Type::QpackEncoder => qlog::events::http3::StreamType::QpackEncode,
Type::QpackDecoder => qlog::events::http3::StreamType::QpackDecode,
Type::Unknown => qlog::events::http3::StreamType::Unknown,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum State {
StreamType,
FrameType,
FramePayloadLen,
FramePayload,
Data,
PushId,
QpackInstruction,
SkipFramePayload,
Drain,
Finished,
}
impl Type {
pub fn deserialize(v: u64) -> Result<Type> {
match v {
HTTP3_CONTROL_STREAM_TYPE_ID => Ok(Type::Control),
HTTP3_PUSH_STREAM_TYPE_ID => Ok(Type::Push),
QPACK_ENCODER_STREAM_TYPE_ID => Ok(Type::QpackEncoder),
QPACK_DECODER_STREAM_TYPE_ID => Ok(Type::QpackDecoder),
_ => Ok(Type::Unknown),
}
}
}
#[derive(Debug)]
pub struct Stream {
id: u64,
ty: Option<Type>,
state: State,
state_buf: Vec<u8>,
state_len: usize,
state_off: usize,
frame_type: Option<u64>,
is_local: bool,
remote_initialized: bool,
local_initialized: bool,
local_finished: bool,
data_event_triggered: bool,
last_priority_update: Option<Vec<u8>>,
headers_received_count: usize,
data_received: bool,
trailers_sent: bool,
trailers_received: bool,
max_encoded_headers_payload_size: u64,
max_priority_update_size: u64,
}
impl Stream {
pub fn new(
id: u64, is_local: bool, max_field_section_size: u64,
max_priority_update_size: u64,
) -> Stream {
let (ty, state) = if crate::stream::is_bidi(id) {
(Some(Type::Request), State::FrameType)
} else {
(None, State::StreamType)
};
let max_encoded_headers_payload_size =
max_field_section_size.saturating_add(max_field_section_size / 2);
Stream {
id,
ty,
state,
state_buf: Vec::with_capacity(16),
state_len: 1,
state_off: 0,
frame_type: None,
is_local,
remote_initialized: false,
local_initialized: false,
local_finished: false,
data_event_triggered: false,
last_priority_update: None,
headers_received_count: 0,
data_received: false,
trailers_sent: false,
trailers_received: false,
max_encoded_headers_payload_size,
max_priority_update_size,
}
}
pub fn ty(&self) -> Option<Type> {
self.ty
}
pub fn state(&self) -> State {
self.state
}
pub fn set_ty(&mut self, ty: Type) -> Result<()> {
assert_eq!(self.state, State::StreamType);
self.ty = Some(ty);
let state = match ty {
Type::Control | Type::Request => State::FrameType,
Type::Push => State::PushId,
Type::QpackEncoder | Type::QpackDecoder => {
self.remote_initialized = true;
State::QpackInstruction
},
Type::Unknown => State::Drain,
};
self.state_transition(state, 1, true)?;
Ok(())
}
pub fn set_push_id(&mut self, _id: u64) -> Result<()> {
assert_eq!(self.state, State::PushId);
self.state_transition(State::FrameType, 1, true)?;
Ok(())
}
pub fn set_frame_type(&mut self, ty: u64) -> Result<()> {
assert_eq!(self.state, State::FrameType);
match self.ty {
Some(Type::Control) => {
match (ty, self.remote_initialized) {
(frame::SETTINGS_FRAME_TYPE_ID, false) =>
self.remote_initialized = true,
(_, false) => return Err(Error::MissingSettings),
(frame::SETTINGS_FRAME_TYPE_ID, true) =>
return Err(Error::FrameUnexpected),
(frame::DATA_FRAME_TYPE_ID, true) =>
return Err(Error::FrameUnexpected),
(frame::HEADERS_FRAME_TYPE_ID, true) =>
return Err(Error::FrameUnexpected),
(frame::PUSH_PROMISE_FRAME_TYPE_ID, true) =>
return Err(Error::FrameUnexpected),
(_, true) => (),
}
},
Some(Type::Request) => {
self.validate_request_frame_type(ty)?;
},
Some(Type::Push) => {
match ty {
frame::CANCEL_PUSH_FRAME_TYPE_ID =>
return Err(Error::FrameUnexpected),
frame::SETTINGS_FRAME_TYPE_ID =>
return Err(Error::FrameUnexpected),
frame::PUSH_PROMISE_FRAME_TYPE_ID =>
return Err(Error::FrameUnexpected),
frame::GOAWAY_FRAME_TYPE_ID =>
return Err(Error::FrameUnexpected),
frame::MAX_PUSH_FRAME_TYPE_ID =>
return Err(Error::FrameUnexpected),
_ => (),
}
},
_ => return Err(Error::FrameUnexpected),
}
self.frame_type = Some(ty);
self.state_transition(State::FramePayloadLen, 1, true)?;
Ok(())
}
fn validate_request_frame_type(&mut self, ty: u64) -> Result<()> {
if matches!(
ty,
frame::CANCEL_PUSH_FRAME_TYPE_ID |
frame::SETTINGS_FRAME_TYPE_ID |
frame::GOAWAY_FRAME_TYPE_ID |
frame::MAX_PUSH_FRAME_TYPE_ID |
frame::PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID |
frame::PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID
) {
return Err(Error::FrameUnexpected);
}
if self.is_local {
return Ok(());
}
match (ty, self.remote_initialized) {
(frame::HEADERS_FRAME_TYPE_ID, false) => {
self.remote_initialized = true;
},
(frame::DATA_FRAME_TYPE_ID, false) =>
return Err(Error::FrameUnexpected),
(frame::HEADERS_FRAME_TYPE_ID, true) => {
if self.trailers_received {
return Err(Error::FrameUnexpected);
}
if self.data_received {
self.trailers_received = true;
}
},
(frame::DATA_FRAME_TYPE_ID, true) => {
if self.trailers_received {
return Err(Error::FrameUnexpected);
}
self.data_received = true;
},
_ => (),
}
Ok(())
}
pub fn frame_type(&self) -> Option<u64> {
self.frame_type
}
pub fn set_frame_payload_len(&mut self, len: u64) -> Result<()> {
assert_eq!(self.state, State::FramePayloadLen);
if !matches!(self.ty, Some(Type::Control | Type::Request | Type::Push)) {
return Err(Error::InternalError);
}
let (state, resize) = match self.frame_type {
Some(frame::DATA_FRAME_TYPE_ID) => (State::Data, false),
Some(frame::HEADERS_FRAME_TYPE_ID) => {
if len > self.max_encoded_headers_payload_size {
return Err(Error::ExcessiveLoad);
}
(State::FramePayload, true)
},
Some(frame::CANCEL_PUSH_FRAME_TYPE_ID) |
Some(frame::GOAWAY_FRAME_TYPE_ID) |
Some(frame::MAX_PUSH_FRAME_TYPE_ID) => {
if !(1..=8).contains(&len) {
return Err(Error::FrameError);
}
(State::FramePayload, true)
},
Some(frame::SETTINGS_FRAME_TYPE_ID) => {
if len > frame::MAX_SETTINGS_PAYLOAD_SIZE as u64 {
return Err(Error::FrameError);
}
(State::FramePayload, true)
},
Some(frame::PUSH_PROMISE_FRAME_TYPE_ID) => {
let max_push_promise_size =
self.max_encoded_headers_payload_size.saturating_add(8);
if len == 0 {
return Err(Error::FrameError);
}
if len > max_push_promise_size {
return Err(Error::ExcessiveLoad);
}
(State::FramePayload, true)
},
Some(frame::PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID) |
Some(frame::PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID) => {
if len == 0 {
return Err(Error::FrameError);
}
if len > self.max_priority_update_size {
return Err(Error::ExcessiveLoad);
}
(State::FramePayload, true)
},
_ => {
if len > MAX_STATE_BUF_SIZE as u64 {
return Err(Error::ExcessiveLoad);
}
(State::SkipFramePayload, false)
},
};
self.state_transition(state, len as usize, resize)?;
Ok(())
}
fn spare_state_buf(&mut self) -> &mut [u8] {
let need = self.state_len - self.state_off;
let spare = self
.state_buf
.capacity()
.saturating_sub(self.state_buf.len());
if spare == 0 {
let additional = std::cmp::min(MAX_STATE_BUF_ALLOC_SIZE, need);
self.state_buf.reserve(additional);
}
let buf = self.state_buf.spare_capacity_mut();
let usable = std::cmp::min(need, buf.len());
unsafe {
std::mem::transmute::<&mut [MaybeUninit<u8>], &mut [u8]>(
&mut buf[..usable],
)
}
}
fn commit_state_buf_read(&mut self, read: usize) {
let buf_len = self.state_buf.len();
debug_assert!(buf_len + read <= self.state_buf.capacity());
unsafe { self.state_buf.set_len(buf_len + read) };
self.state_off += read;
}
pub fn try_fill_buffer<F: BufFactory>(
&mut self, conn: &mut crate::Connection<F>,
) -> Result<()> {
if self.state_buffer_complete() {
return Ok(());
}
loop {
let stream_id = self.id;
let spare_buf = self.spare_state_buf();
let spare_len = spare_buf.len();
match conn.stream_recv(stream_id, spare_buf) {
Ok((read, fin)) => {
self.commit_state_buf_read(read);
if self.critical_stream_closed(fin) {
super::close_conn_critical_stream(conn)?;
}
trace!(
"{} read {} bytes on stream {}",
conn.trace_id(),
read,
self.id,
);
if read < spare_len {
break;
}
if self.state_buffer_complete() {
return Ok(());
}
},
Err(e @ crate::Error::StreamReset(_)) => {
if self.critical_stream_closed(true) {
super::close_conn_critical_stream(conn)?;
}
return Err(e.into());
},
Err(e) => {
if e == crate::Error::Done {
self.reset_data_event();
}
return Err(e.into());
},
};
}
if !self.state_buffer_complete() {
self.reset_data_event();
return Err(Error::Done);
}
Ok(())
}
pub fn try_skip_data<F: BufFactory>(
&mut self, conn: &mut crate::Connection<F>,
) -> Result<()> {
if self.state_buffer_complete() {
return Ok(());
}
let len = self.state_len - self.state_off;
let read = match conn.stream_discard(self.id, len) {
Ok((len, fin)) => {
if self.critical_stream_closed(fin) {
super::close_conn_critical_stream(conn)?;
}
len
},
Err(e @ crate::Error::StreamReset(_)) => {
if self.critical_stream_closed(true) {
super::close_conn_critical_stream(conn)?;
}
return Err(e.into());
},
Err(e) => {
if e == crate::Error::Done {
self.reset_data_event();
}
return Err(e.into());
},
};
trace!(
"{} discarded {} bytes on stream {}",
conn.trace_id(),
read,
self.id,
);
self.state_off += read;
if !self.state_buffer_complete() {
self.reset_data_event();
return Err(Error::Done);
}
Ok(())
}
pub fn initialize_local(&mut self) {
self.local_initialized = true
}
pub fn local_initialized(&self) -> bool {
self.local_initialized
}
pub fn finish_local(&mut self) {
self.local_finished = true
}
pub fn local_finished(&self) -> bool {
self.local_finished
}
pub fn increment_headers_received(&mut self) {
self.headers_received_count =
self.headers_received_count.saturating_add(1);
}
pub fn headers_received_count(&self) -> usize {
self.headers_received_count
}
pub fn mark_trailers_sent(&mut self) {
self.trailers_sent = true;
}
pub fn trailers_sent(&self) -> bool {
self.trailers_sent
}
#[cfg(test)]
fn try_fill_buffer_for_tests(
&mut self, stream: &mut std::io::Cursor<Vec<u8>>,
) -> Result<()> {
if self.state_buffer_complete() {
return Ok(());
}
loop {
let spare_buf = self.spare_state_buf();
let spare_len = spare_buf.len();
let read = match std::io::Read::read(stream, spare_buf) {
Ok(0) => {
break;
},
Ok(v) => v,
Err(_) => {
panic!("Test buffer reading should never fail");
},
};
self.commit_state_buf_read(read);
if read < spare_len {
break;
}
if self.state_buffer_complete() {
break;
}
}
if !self.state_buffer_complete() {
return Err(Error::Done);
}
Ok(())
}
pub fn try_consume_varint(&mut self) -> Result<u64> {
if self.state_off == 1 {
self.state_len = octets::varint_parse_len(self.state_buf[0]);
self.state_buf.reserve(self.state_len);
}
if !self.state_buffer_complete() {
return Err(Error::Done);
}
let varint = octets::Octets::with_slice(&self.state_buf).get_varint()?;
Ok(varint)
}
pub fn try_consume_frame(&mut self) -> Result<(frame::Frame, u64)> {
debug_assert_eq!(self.state, State::FramePayload);
self.reset_data_event();
let payload_len = self.state_len as u64;
let frame = frame::Frame::from_bytes(
self.frame_type.unwrap(),
payload_len,
&self.state_buf,
)?;
self.state_transition(State::FrameType, 1, true)?;
Ok((frame, payload_len))
}
pub fn try_skip_frame<F: BufFactory>(
&mut self, conn: &mut crate::Connection<F>,
) -> Result<()> {
self.try_skip_data(conn)?;
self.reset_data_event();
self.state_transition(State::FrameType, 1, true)?;
Ok(())
}
pub fn try_consume_data<F: BufFactory, OUT: bytes::BufMut>(
&mut self, conn: &mut crate::Connection<F>, out: OUT,
) -> Result<(usize, bool)> {
debug_assert_eq!(self.state, State::Data);
let out = out.limit(self.state_len - self.state_off);
let (len, fin) = match conn.stream_recv_buf(self.id, out) {
Ok(v) => v,
Err(e) => {
if e == crate::Error::Done {
self.reset_data_event();
}
return Err(e.into());
},
};
self.state_off += len;
debug_assert!(self.state_len >= self.state_off);
if !conn.stream_readable(self.id) {
self.reset_data_event();
}
if self.state_buffer_complete() {
self.state_transition(State::FrameType, 1, true)?;
}
Ok((len, fin))
}
pub fn finished(&mut self) {
let _ = self.state_transition(State::Finished, 0, false);
}
#[cfg(test)]
fn try_consume_data_for_tests(
&mut self, stream: &mut std::io::Cursor<Vec<u8>>, out: &mut [u8],
) -> Result<usize> {
let left = std::cmp::min(out.len(), self.state_len - self.state_off);
let len = std::io::Read::read(stream, &mut out[..left]).unwrap();
self.state_off += len;
if self.state_buffer_complete() {
self.state_transition(State::FrameType, 1, true)?;
}
Ok(len)
}
pub fn try_trigger_data_event(&mut self) -> bool {
if self.data_event_triggered {
return false;
}
self.data_event_triggered = true;
true
}
fn reset_data_event(&mut self) {
self.data_event_triggered = false;
}
pub fn set_last_priority_update(&mut self, priority_update: Option<Vec<u8>>) {
self.last_priority_update = priority_update;
}
pub fn take_last_priority_update(&mut self) -> Option<Vec<u8>> {
self.last_priority_update.take()
}
pub fn has_last_priority_update(&self) -> bool {
self.last_priority_update.is_some()
}
fn critical_stream_closed(&self, fin: bool) -> bool {
fin && matches!(
self.ty,
Some(Type::Control) |
Some(Type::QpackEncoder) |
Some(Type::QpackDecoder)
)
}
fn state_buffer_complete(&self) -> bool {
self.state_off == self.state_len
}
fn state_transition(
&mut self, new_state: State, expected_len: usize, resize: bool,
) -> Result<()> {
self.state_buf.clear();
if resize {
if expected_len > MAX_STATE_BUF_SIZE {
return Err(Error::ExcessiveLoad);
}
let reserve_len =
std::cmp::min(expected_len, MAX_STATE_BUF_ALLOC_SIZE);
self.state_buf.reserve(reserve_len);
}
self.state = new_state;
self.state_off = 0;
self.state_len = expected_len;
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::h3::frame::*;
use crate::h3::PRIORITY_UPDATE_FRAME_PAYLOAD_MAX_SIZE_DEFAULT;
use crate::h3::SETTINGS_MAX_FIELD_SECTION_SIZE_DEFAULT;
use super::*;
fn open_uni(b: &mut octets::OctetsMut, ty: u64) -> Result<Stream> {
let stream = <Stream>::new(
2,
false,
SETTINGS_MAX_FIELD_SECTION_SIZE_DEFAULT,
PRIORITY_UPDATE_FRAME_PAYLOAD_MAX_SIZE_DEFAULT,
);
assert_eq!(stream.state, State::StreamType);
b.put_varint(ty)?;
Ok(stream)
}
fn open_remote_request_stream() -> Stream {
Stream::new(
0,
false,
SETTINGS_MAX_FIELD_SECTION_SIZE_DEFAULT,
PRIORITY_UPDATE_FRAME_PAYLOAD_MAX_SIZE_DEFAULT,
)
}
fn parse_uni(
stream: &mut Stream, ty: u64, cursor: &mut std::io::Cursor<Vec<u8>>,
) -> Result<()> {
stream.try_fill_buffer_for_tests(cursor)?;
let stream_ty = stream.try_consume_varint()?;
assert_eq!(stream_ty, ty);
stream.set_ty(Type::deserialize(stream_ty).unwrap())?;
Ok(())
}
fn parse_multibyte_varint(
stream: &mut Stream, cursor: &mut std::io::Cursor<Vec<u8>>,
) -> Result<u64> {
stream.try_fill_buffer_for_tests(cursor)?;
assert_eq!(stream.try_consume_varint(), Err(Error::Done));
stream.try_fill_buffer_for_tests(cursor)?;
stream.try_consume_varint()
}
fn parse_skip_frame(
stream: &mut Stream, cursor: &mut std::io::Cursor<Vec<u8>>,
) -> Result<()> {
stream.try_fill_buffer_for_tests(cursor)?;
let frame_ty = stream.try_consume_varint()?;
stream.set_frame_type(frame_ty)?;
assert_eq!(stream.state, State::FramePayloadLen);
stream.try_fill_buffer_for_tests(cursor)?;
let frame_payload_len = stream.try_consume_varint()?;
stream.set_frame_payload_len(frame_payload_len)?;
assert_eq!(stream.state, State::FramePayload);
stream.try_fill_buffer_for_tests(cursor)?;
stream.try_consume_frame()?;
assert_eq!(stream.state, State::FrameType);
Ok(())
}
#[test]
fn control_good() {
let mut d = vec![42; 40];
let mut b = octets::OctetsMut::with_slice(&mut d);
let raw_settings = vec![
(SETTINGS_MAX_FIELD_SECTION_SIZE, 0),
(SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
(SETTINGS_QPACK_BLOCKED_STREAMS, 0),
];
let frame = Frame::Settings {
max_field_section_size: Some(0),
qpack_max_table_capacity: Some(0),
qpack_blocked_streams: Some(0),
connect_protocol_enabled: None,
h3_datagram: None,
grease: None,
additional_settings: None,
raw: Some(raw_settings),
};
let mut stream = open_uni(&mut b, HTTP3_CONTROL_STREAM_TYPE_ID).unwrap();
frame.to_bytes(&mut b).unwrap();
let mut cursor = std::io::Cursor::new(d);
parse_uni(&mut stream, HTTP3_CONTROL_STREAM_TYPE_ID, &mut cursor)
.unwrap();
assert_eq!(stream.state, State::FrameType);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(frame_ty, SETTINGS_FRAME_TYPE_ID);
stream.set_frame_type(frame_ty).unwrap();
assert_eq!(stream.state, State::FramePayloadLen);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_payload_len = stream.try_consume_varint().unwrap();
assert_eq!(frame_payload_len, 6);
stream.set_frame_payload_len(frame_payload_len).unwrap();
assert_eq!(stream.state, State::FramePayload);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
assert_eq!(stream.try_consume_frame(), Ok((frame, 6)));
assert_eq!(stream.state, State::FrameType);
}
#[test]
fn control_empty_settings() {
let mut d = vec![42; 40];
let mut b = octets::OctetsMut::with_slice(&mut d);
let frame = Frame::Settings {
max_field_section_size: None,
qpack_max_table_capacity: None,
qpack_blocked_streams: None,
connect_protocol_enabled: None,
h3_datagram: None,
grease: None,
additional_settings: None,
raw: Some(vec![]),
};
let mut stream = open_uni(&mut b, HTTP3_CONTROL_STREAM_TYPE_ID).unwrap();
frame.to_bytes(&mut b).unwrap();
let mut cursor = std::io::Cursor::new(d);
parse_uni(&mut stream, HTTP3_CONTROL_STREAM_TYPE_ID, &mut cursor)
.unwrap();
assert_eq!(stream.state, State::FrameType);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(frame_ty, SETTINGS_FRAME_TYPE_ID);
stream.set_frame_type(frame_ty).unwrap();
assert_eq!(stream.state, State::FramePayloadLen);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_payload_len = stream.try_consume_varint().unwrap();
assert_eq!(frame_payload_len, 0);
stream.set_frame_payload_len(frame_payload_len).unwrap();
assert_eq!(stream.state, State::FramePayload);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
assert_eq!(stream.try_consume_frame(), Ok((frame, 0)));
assert_eq!(stream.state, State::FrameType);
}
#[test]
fn control_bad_multiple_settings() {
let mut d = vec![42; 40];
let mut b = octets::OctetsMut::with_slice(&mut d);
let raw_settings = vec![
(SETTINGS_MAX_FIELD_SECTION_SIZE, 0),
(SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
(SETTINGS_QPACK_BLOCKED_STREAMS, 0),
];
let frame = Frame::Settings {
max_field_section_size: Some(0),
qpack_max_table_capacity: Some(0),
qpack_blocked_streams: Some(0),
connect_protocol_enabled: None,
h3_datagram: None,
grease: None,
additional_settings: None,
raw: Some(raw_settings),
};
let mut stream = open_uni(&mut b, HTTP3_CONTROL_STREAM_TYPE_ID).unwrap();
frame.to_bytes(&mut b).unwrap();
frame.to_bytes(&mut b).unwrap();
let mut cursor = std::io::Cursor::new(d);
parse_uni(&mut stream, HTTP3_CONTROL_STREAM_TYPE_ID, &mut cursor)
.unwrap();
assert_eq!(stream.state, State::FrameType);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(frame_ty, SETTINGS_FRAME_TYPE_ID);
stream.set_frame_type(frame_ty).unwrap();
assert_eq!(stream.state, State::FramePayloadLen);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_payload_len = stream.try_consume_varint().unwrap();
assert_eq!(frame_payload_len, 6);
stream.set_frame_payload_len(frame_payload_len).unwrap();
assert_eq!(stream.state, State::FramePayload);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
assert_eq!(stream.try_consume_frame(), Ok((frame, 6)));
assert_eq!(stream.state, State::FrameType);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(stream.set_frame_type(frame_ty), Err(Error::FrameUnexpected));
}
#[test]
fn control_bad_late_settings() {
let mut d = vec![42; 40];
let mut b = octets::OctetsMut::with_slice(&mut d);
let goaway = Frame::GoAway { id: 0 };
let raw_settings = vec![
(SETTINGS_MAX_FIELD_SECTION_SIZE, 0),
(SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
(SETTINGS_QPACK_BLOCKED_STREAMS, 0),
];
let settings = Frame::Settings {
max_field_section_size: Some(0),
qpack_max_table_capacity: Some(0),
qpack_blocked_streams: Some(0),
connect_protocol_enabled: None,
h3_datagram: None,
grease: None,
additional_settings: None,
raw: Some(raw_settings),
};
let mut stream = open_uni(&mut b, HTTP3_CONTROL_STREAM_TYPE_ID).unwrap();
goaway.to_bytes(&mut b).unwrap();
settings.to_bytes(&mut b).unwrap();
let mut cursor = std::io::Cursor::new(d);
parse_uni(&mut stream, HTTP3_CONTROL_STREAM_TYPE_ID, &mut cursor)
.unwrap();
assert_eq!(stream.state, State::FrameType);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(stream.set_frame_type(frame_ty), Err(Error::MissingSettings));
}
#[test]
fn control_bad_frame() {
let mut d = vec![42; 40];
let mut b = octets::OctetsMut::with_slice(&mut d);
let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
let hdrs = Frame::Headers { header_block };
let raw_settings = vec![
(SETTINGS_MAX_FIELD_SECTION_SIZE, 0),
(SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
(SETTINGS_QPACK_BLOCKED_STREAMS, 0),
(33, 33),
];
let settings = Frame::Settings {
max_field_section_size: Some(0),
qpack_max_table_capacity: Some(0),
qpack_blocked_streams: Some(0),
connect_protocol_enabled: None,
h3_datagram: None,
grease: None,
additional_settings: None,
raw: Some(raw_settings),
};
let mut stream = open_uni(&mut b, HTTP3_CONTROL_STREAM_TYPE_ID).unwrap();
settings.to_bytes(&mut b).unwrap();
hdrs.to_bytes(&mut b).unwrap();
let mut cursor = std::io::Cursor::new(d);
parse_uni(&mut stream, HTTP3_CONTROL_STREAM_TYPE_ID, &mut cursor)
.unwrap();
assert_eq!(stream.state, State::FrameType);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
stream.set_frame_type(frame_ty).unwrap();
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_payload_len = stream.try_consume_varint().unwrap();
stream.set_frame_payload_len(frame_payload_len).unwrap();
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
assert!(stream.try_consume_frame().is_ok());
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(stream.set_frame_type(frame_ty), Err(Error::FrameUnexpected));
}
#[test]
fn request_no_data() {
let mut stream = open_remote_request_stream();
assert_eq!(stream.ty, Some(Type::Request));
assert_eq!(stream.state, State::FrameType);
assert_eq!(stream.try_consume_varint(), Err(Error::Done));
}
#[test]
fn request_good() {
let mut stream = open_remote_request_stream();
let mut d = vec![42; 128];
let mut b = octets::OctetsMut::with_slice(&mut d);
let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
let payload = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
let hdrs = Frame::Headers { header_block };
let data = Frame::Data {
payload: payload.clone(),
};
hdrs.to_bytes(&mut b).unwrap();
data.to_bytes(&mut b).unwrap();
let mut cursor = std::io::Cursor::new(d);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(frame_ty, HEADERS_FRAME_TYPE_ID);
stream.set_frame_type(frame_ty).unwrap();
assert_eq!(stream.state, State::FramePayloadLen);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_payload_len = stream.try_consume_varint().unwrap();
assert_eq!(frame_payload_len, 12);
stream.set_frame_payload_len(frame_payload_len).unwrap();
assert_eq!(stream.state, State::FramePayload);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
assert_eq!(stream.try_consume_frame(), Ok((hdrs, 12)));
assert_eq!(stream.state, State::FrameType);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(frame_ty, DATA_FRAME_TYPE_ID);
stream.set_frame_type(frame_ty).unwrap();
assert_eq!(stream.state, State::FramePayloadLen);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_payload_len = stream.try_consume_varint().unwrap();
assert_eq!(frame_payload_len, 12);
stream.set_frame_payload_len(frame_payload_len).unwrap();
assert_eq!(stream.state, State::Data);
let mut recv_buf = vec![0; payload.len()];
assert_eq!(
stream.try_consume_data_for_tests(&mut cursor, &mut recv_buf),
Ok(payload.len())
);
assert_eq!(payload, recv_buf);
assert_eq!(stream.state, State::FrameType);
}
#[test]
fn push_good() {
let mut d = vec![42; 128];
let mut b = octets::OctetsMut::with_slice(&mut d);
let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
let payload = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
let hdrs = Frame::Headers { header_block };
let data = Frame::Data {
payload: payload.clone(),
};
let mut stream = open_uni(&mut b, HTTP3_PUSH_STREAM_TYPE_ID).unwrap();
b.put_varint(1).unwrap();
hdrs.to_bytes(&mut b).unwrap();
data.to_bytes(&mut b).unwrap();
let mut cursor = std::io::Cursor::new(d);
parse_uni(&mut stream, HTTP3_PUSH_STREAM_TYPE_ID, &mut cursor).unwrap();
assert_eq!(stream.state, State::PushId);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let push_id = stream.try_consume_varint().unwrap();
assert_eq!(push_id, 1);
stream.set_push_id(push_id).unwrap();
assert_eq!(stream.state, State::FrameType);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(frame_ty, HEADERS_FRAME_TYPE_ID);
stream.set_frame_type(frame_ty).unwrap();
assert_eq!(stream.state, State::FramePayloadLen);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_payload_len = stream.try_consume_varint().unwrap();
assert_eq!(frame_payload_len, 12);
stream.set_frame_payload_len(frame_payload_len).unwrap();
assert_eq!(stream.state, State::FramePayload);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
assert_eq!(stream.try_consume_frame(), Ok((hdrs, 12)));
assert_eq!(stream.state, State::FrameType);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(frame_ty, DATA_FRAME_TYPE_ID);
stream.set_frame_type(frame_ty).unwrap();
assert_eq!(stream.state, State::FramePayloadLen);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_payload_len = stream.try_consume_varint().unwrap();
assert_eq!(frame_payload_len, 12);
stream.set_frame_payload_len(frame_payload_len).unwrap();
assert_eq!(stream.state, State::Data);
let mut recv_buf = vec![0; payload.len()];
assert_eq!(
stream.try_consume_data_for_tests(&mut cursor, &mut recv_buf),
Ok(payload.len())
);
assert_eq!(payload, recv_buf);
assert_eq!(stream.state, State::FrameType);
}
#[test]
fn grease() {
let mut d = vec![42; 20];
let mut b = octets::OctetsMut::with_slice(&mut d);
let mut stream = open_uni(&mut b, 33).unwrap();
let mut cursor = std::io::Cursor::new(d);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let stream_ty = stream.try_consume_varint().unwrap();
assert_eq!(stream_ty, 33);
stream
.set_ty(Type::deserialize(stream_ty).unwrap())
.unwrap();
assert_eq!(stream.state, State::Drain);
}
#[test]
fn data_before_headers() {
let mut stream = open_remote_request_stream();
let mut d = vec![42; 128];
let mut b = octets::OctetsMut::with_slice(&mut d);
let data = Frame::Data {
payload: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
};
data.to_bytes(&mut b).unwrap();
let mut cursor = std::io::Cursor::new(d);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(frame_ty, DATA_FRAME_TYPE_ID);
assert_eq!(stream.set_frame_type(frame_ty), Err(Error::FrameUnexpected));
}
#[test]
fn additional_headers() {
let mut stream = open_remote_request_stream();
let mut d = vec![42; 128];
let mut b = octets::OctetsMut::with_slice(&mut d);
let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
let payload = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
let info_hdrs = Frame::Headers {
header_block: header_block.clone(),
};
let non_info_hdrs = Frame::Headers {
header_block: header_block.clone(),
};
let trailers = Frame::Headers { header_block };
let data = Frame::Data {
payload: payload.clone(),
};
info_hdrs.to_bytes(&mut b).unwrap();
non_info_hdrs.to_bytes(&mut b).unwrap();
data.to_bytes(&mut b).unwrap();
trailers.to_bytes(&mut b).unwrap();
let mut cursor = std::io::Cursor::new(d);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(frame_ty, HEADERS_FRAME_TYPE_ID);
stream.set_frame_type(frame_ty).unwrap();
assert_eq!(stream.state, State::FramePayloadLen);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_payload_len = stream.try_consume_varint().unwrap();
assert_eq!(frame_payload_len, 12);
stream.set_frame_payload_len(frame_payload_len).unwrap();
assert_eq!(stream.state, State::FramePayload);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
assert_eq!(stream.try_consume_frame(), Ok((info_hdrs, 12)));
assert_eq!(stream.state, State::FrameType);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(frame_ty, HEADERS_FRAME_TYPE_ID);
stream.set_frame_type(frame_ty).unwrap();
assert_eq!(stream.state, State::FramePayloadLen);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_payload_len = stream.try_consume_varint().unwrap();
assert_eq!(frame_payload_len, 12);
stream.set_frame_payload_len(frame_payload_len).unwrap();
assert_eq!(stream.state, State::FramePayload);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
assert_eq!(stream.try_consume_frame(), Ok((non_info_hdrs, 12)));
assert_eq!(stream.state, State::FrameType);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(frame_ty, DATA_FRAME_TYPE_ID);
stream.set_frame_type(frame_ty).unwrap();
assert_eq!(stream.state, State::FramePayloadLen);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_payload_len = stream.try_consume_varint().unwrap();
assert_eq!(frame_payload_len, 12);
stream.set_frame_payload_len(frame_payload_len).unwrap();
assert_eq!(stream.state, State::Data);
let mut recv_buf = vec![0; payload.len()];
assert_eq!(
stream.try_consume_data_for_tests(&mut cursor, &mut recv_buf),
Ok(payload.len())
);
assert_eq!(payload, recv_buf);
assert_eq!(stream.state, State::FrameType);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(frame_ty, HEADERS_FRAME_TYPE_ID);
stream.set_frame_type(frame_ty).unwrap();
assert_eq!(stream.state, State::FramePayloadLen);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_payload_len = stream.try_consume_varint().unwrap();
assert_eq!(frame_payload_len, 12);
stream.set_frame_payload_len(frame_payload_len).unwrap();
assert_eq!(stream.state, State::FramePayload);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
assert_eq!(stream.try_consume_frame(), Ok((trailers, 12)));
assert_eq!(stream.state, State::FrameType);
}
fn frame_type_id(frame: &Frame) -> u64 {
match frame {
Frame::Data { .. } => DATA_FRAME_TYPE_ID,
Frame::Headers { .. } => HEADERS_FRAME_TYPE_ID,
Frame::CancelPush { .. } => CANCEL_PUSH_FRAME_TYPE_ID,
Frame::Settings { .. } => SETTINGS_FRAME_TYPE_ID,
Frame::PushPromise { .. } => PUSH_PROMISE_FRAME_TYPE_ID,
Frame::GoAway { .. } => GOAWAY_FRAME_TYPE_ID,
Frame::MaxPushId { .. } => MAX_PUSH_FRAME_TYPE_ID,
Frame::PriorityUpdateRequest { .. } =>
PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID,
Frame::PriorityUpdatePush { .. } =>
PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID,
Frame::Unknown { .. } => unreachable!(),
}
}
fn check_large_frame_size_limit(
stream: &mut Stream, frame: Frame, expected_payload_len: u64,
expect_accept: bool,
) {
let expected_type_id = frame_type_id(&frame);
let mut d = vec![42; 20000];
let mut b = octets::OctetsMut::with_slice(&mut d);
frame.to_bytes(&mut b).unwrap();
let mut cursor = std::io::Cursor::new(d);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(frame_ty, expected_type_id);
stream.set_frame_type(frame_ty).unwrap();
assert_eq!(stream.state, State::FramePayloadLen);
let frame_payload_len =
parse_multibyte_varint(stream, &mut cursor).unwrap();
assert_eq!(frame_payload_len, expected_payload_len);
if expect_accept {
stream.set_frame_payload_len(frame_payload_len).unwrap();
assert_eq!(stream.state, State::FramePayload);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
assert_eq!(
stream.try_consume_frame(),
Ok((frame, expected_payload_len))
);
assert_eq!(stream.state, State::FrameType);
} else {
assert_eq!(
stream.set_frame_payload_len(frame_payload_len),
Err(Error::ExcessiveLoad)
);
}
}
#[test]
fn large_headers_default_limit() {
let mut stream = open_remote_request_stream();
let header_block = vec![0; 16384];
let frame = Frame::Headers {
header_block: header_block.clone(),
};
check_large_frame_size_limit(&mut stream, frame, 16384, true);
}
#[test]
fn large_headers_limit_with_huffman() {
let mut stream = Stream::new(
0,
false,
4196,
PRIORITY_UPDATE_FRAME_PAYLOAD_MAX_SIZE_DEFAULT,
);
let header_block = vec![0; 6294];
let frame = Frame::Headers {
header_block: header_block.clone(),
};
check_large_frame_size_limit(&mut stream, frame, 6294, true);
}
#[test]
fn large_headers_small_limit() {
let mut stream = Stream::new(
0,
false,
4196,
PRIORITY_UPDATE_FRAME_PAYLOAD_MAX_SIZE_DEFAULT,
);
let header_block = vec![0; 16384];
let frame = Frame::Headers {
header_block: header_block.clone(),
};
check_large_frame_size_limit(&mut stream, frame, 16384, false);
}
#[test]
fn large_push_promise_default_limit() {
let mut stream = open_remote_request_stream();
let header_block = vec![0; 16384];
let frame = Frame::PushPromise {
push_id: 0,
header_block: header_block.clone(),
};
check_large_frame_size_limit(&mut stream, frame, 1 + 16384, true);
}
#[test]
fn large_push_promise_limit_with_huffman() {
let mut stream = Stream::new(
0,
false,
4196,
PRIORITY_UPDATE_FRAME_PAYLOAD_MAX_SIZE_DEFAULT,
);
let header_block = vec![0; 6294];
let frame = Frame::PushPromise {
push_id: 0,
header_block: header_block.clone(),
};
check_large_frame_size_limit(&mut stream, frame, 1 + 6294, true);
}
#[test]
fn large_push_promise_small_limit() {
let mut stream = Stream::new(
0,
false,
4196,
PRIORITY_UPDATE_FRAME_PAYLOAD_MAX_SIZE_DEFAULT,
);
let header_block = vec![0; 16384];
let frame = Frame::PushPromise {
push_id: 0,
header_block: header_block.clone(),
};
check_large_frame_size_limit(&mut stream, frame, 1 + 16384, false);
}
#[test]
fn large_priority_update_large_limit() {
let settings = Frame::Settings {
max_field_section_size: None,
qpack_max_table_capacity: None,
qpack_blocked_streams: None,
connect_protocol_enabled: None,
h3_datagram: None,
grease: None,
additional_settings: None,
raw: Some(vec![]),
};
let mut d = vec![42; 20000];
let mut b = octets::OctetsMut::with_slice(&mut d);
let mut stream = <Stream>::new(
2,
false,
SETTINGS_MAX_FIELD_SECTION_SIZE_DEFAULT,
20000,
);
b.put_varint(HTTP3_CONTROL_STREAM_TYPE_ID).unwrap();
settings.to_bytes(&mut b).unwrap();
let priority_field_value = vec![0; 16384];
let pu = Frame::PriorityUpdateRequest {
prioritized_element_id: 0,
priority_field_value,
};
pu.to_bytes(&mut b).unwrap();
let mut cursor = std::io::Cursor::new(d);
parse_uni(&mut stream, HTTP3_CONTROL_STREAM_TYPE_ID, &mut cursor)
.unwrap();
parse_skip_frame(&mut stream, &mut cursor).unwrap();
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
assert_eq!(stream.try_consume_varint(), Err(Error::Done));
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(frame_ty, PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID);
stream.set_frame_type(frame_ty).unwrap();
assert_eq!(stream.state, State::FramePayloadLen);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
assert_eq!(stream.try_consume_varint(), Err(Error::Done));
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_payload_len = stream.try_consume_varint().unwrap();
assert_eq!(frame_payload_len, 1 + 16384);
stream.set_frame_payload_len(frame_payload_len).unwrap();
assert_eq!(stream.state, State::FramePayload);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
assert_eq!(stream.try_consume_frame(), Ok((pu, 1 + 16384)));
assert_eq!(stream.state, State::FrameType);
}
#[test]
fn large_priority_update_small_limit() {
let settings = Frame::Settings {
max_field_section_size: None,
qpack_max_table_capacity: None,
qpack_blocked_streams: None,
connect_protocol_enabled: None,
h3_datagram: None,
grease: None,
additional_settings: None,
raw: Some(vec![]),
};
let mut d = vec![42; 20000];
let mut b = octets::OctetsMut::with_slice(&mut d);
let mut stream =
<Stream>::new(2, false, SETTINGS_MAX_FIELD_SECTION_SIZE_DEFAULT, 123);
b.put_varint(HTTP3_CONTROL_STREAM_TYPE_ID).unwrap();
settings.to_bytes(&mut b).unwrap();
let priority_field_value = vec![0; 16384];
let pu = Frame::PriorityUpdateRequest {
prioritized_element_id: 0,
priority_field_value,
};
pu.to_bytes(&mut b).unwrap();
let mut cursor = std::io::Cursor::new(d);
parse_uni(&mut stream, HTTP3_CONTROL_STREAM_TYPE_ID, &mut cursor)
.unwrap();
parse_skip_frame(&mut stream, &mut cursor).unwrap();
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
assert_eq!(stream.try_consume_varint(), Err(Error::Done));
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(frame_ty, PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID);
stream.set_frame_type(frame_ty).unwrap();
assert_eq!(stream.state, State::FramePayloadLen);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
assert_eq!(stream.try_consume_varint(), Err(Error::Done));
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_payload_len = stream.try_consume_varint().unwrap();
assert_eq!(frame_payload_len, 1 + 16384);
assert_eq!(
stream.set_frame_payload_len(frame_payload_len),
Err(Error::ExcessiveLoad)
);
}
#[test]
fn finite_sized_frame_limits() {
let settings = Frame::Settings {
max_field_section_size: None,
qpack_max_table_capacity: None,
qpack_blocked_streams: None,
connect_protocol_enabled: None,
h3_datagram: None,
grease: None,
additional_settings: None,
raw: Some(vec![]),
};
for ty in [
CANCEL_PUSH_FRAME_TYPE_ID,
GOAWAY_FRAME_TYPE_ID,
MAX_PUSH_FRAME_TYPE_ID,
] {
for size in [0, 9] {
let mut d = vec![42; 128];
let mut b = octets::OctetsMut::with_slice(&mut d);
let mut stream =
open_uni(&mut b, HTTP3_CONTROL_STREAM_TYPE_ID).unwrap();
settings.to_bytes(&mut b).unwrap();
b.put_varint(ty).unwrap();
b.put_varint(size).unwrap();
let mut cursor = std::io::Cursor::new(d);
parse_uni(&mut stream, HTTP3_CONTROL_STREAM_TYPE_ID, &mut cursor)
.unwrap();
parse_skip_frame(&mut stream, &mut cursor).unwrap();
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(frame_ty, ty);
stream.set_frame_type(frame_ty).unwrap();
assert_eq!(stream.state, State::FramePayloadLen);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_payload_len = stream.try_consume_varint().unwrap();
assert_eq!(
Err(Error::FrameError),
stream.set_frame_payload_len(frame_payload_len)
);
}
}
}
#[test]
fn zero_length_push_promise() {
let mut d = vec![42; 128];
let mut b = octets::OctetsMut::with_slice(&mut d);
let mut stream = open_remote_request_stream();
assert_eq!(stream.ty, Some(Type::Request));
assert_eq!(stream.state, State::FrameType);
b.put_varint(PUSH_PROMISE_FRAME_TYPE_ID).unwrap();
b.put_varint(0).unwrap();
let mut cursor = std::io::Cursor::new(d);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(frame_ty, PUSH_PROMISE_FRAME_TYPE_ID);
stream.set_frame_type(frame_ty).unwrap();
assert_eq!(stream.state, State::FramePayloadLen);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_payload_len = stream.try_consume_varint().unwrap();
assert_eq!(
Err(Error::FrameError),
stream.set_frame_payload_len(frame_payload_len)
);
}
#[test]
fn large_state_buf_exact_spare_drip_feed() {
const LARGE_HEADER_LEN: usize = 16384;
let mut stream = Stream::new(
0,
false,
LARGE_HEADER_LEN as u64,
PRIORITY_UPDATE_FRAME_PAYLOAD_MAX_SIZE_DEFAULT,
);
let mut d = vec![42; 20000];
let mut b = octets::OctetsMut::with_slice(&mut d);
let header_block = vec![0xAB; LARGE_HEADER_LEN];
let hdrs = Frame::Headers {
header_block: header_block.clone(),
};
hdrs.to_bytes(&mut b).unwrap();
let mut cursor = std::io::Cursor::new(d);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(frame_ty, HEADERS_FRAME_TYPE_ID);
stream.set_frame_type(frame_ty).unwrap();
let frame_payload_len =
parse_multibyte_varint(&mut stream, &mut cursor).unwrap();
assert_eq!(frame_payload_len, LARGE_HEADER_LEN as u64);
stream.set_frame_payload_len(frame_payload_len).unwrap();
assert_eq!(stream.state, State::FramePayload);
assert_eq!(stream.state_buf.capacity(), MAX_STATE_BUF_ALLOC_SIZE);
assert_eq!(stream.state_buf.len(), 0);
let full_data = cursor.into_inner();
let pos = 5; let payload_data = &full_data[pos..pos + LARGE_HEADER_LEN];
let mut fed = 0;
while fed + MAX_STATE_BUF_ALLOC_SIZE <= LARGE_HEADER_LEN {
let chunk = &payload_data[fed..fed + MAX_STATE_BUF_ALLOC_SIZE];
let mut chunk_cursor = std::io::Cursor::new(chunk.to_vec());
let result = stream.try_fill_buffer_for_tests(&mut chunk_cursor);
fed += MAX_STATE_BUF_ALLOC_SIZE;
if fed < LARGE_HEADER_LEN {
assert_eq!(result, Err(Error::Done));
assert_eq!(stream.state_off, fed);
assert!(stream.state_buf.capacity() >= fed);
} else {
assert_eq!(result, Ok(()));
assert_eq!(stream.state_off, LARGE_HEADER_LEN);
}
}
assert_eq!(
stream.try_consume_frame(),
Ok((hdrs, LARGE_HEADER_LEN as u64))
);
assert_eq!(stream.state, State::FrameType);
}
#[test]
fn large_state_buf_small_leftover_spare() {
const LARGE_HEADER_LEN: usize = 260000;
let mut stream = Stream::new(
0,
false,
LARGE_HEADER_LEN as u64,
PRIORITY_UPDATE_FRAME_PAYLOAD_MAX_SIZE_DEFAULT,
);
let mut d = vec![42; LARGE_HEADER_LEN + 10];
let mut b = octets::OctetsMut::with_slice(&mut d);
let header_block = vec![0; LARGE_HEADER_LEN];
let hdrs = Frame::Headers {
header_block: header_block.clone(),
};
hdrs.to_bytes(&mut b).unwrap();
let mut cursor = std::io::Cursor::new(d);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(frame_ty, HEADERS_FRAME_TYPE_ID);
stream.set_frame_type(frame_ty).unwrap();
let frame_payload_len =
parse_multibyte_varint(&mut stream, &mut cursor).unwrap();
assert_eq!(frame_payload_len, LARGE_HEADER_LEN as u64);
stream.set_frame_payload_len(frame_payload_len).unwrap();
assert_eq!(stream.state, State::FramePayload);
assert_eq!(stream.state_buf.capacity(), MAX_STATE_BUF_ALLOC_SIZE);
let full_data = cursor.into_inner();
let pos = 5; let payload_data = &full_data[pos..pos + LARGE_HEADER_LEN];
let chunk_size = 1000;
let mut fed = 0;
while fed < LARGE_HEADER_LEN {
let end = std::cmp::min(fed + chunk_size, LARGE_HEADER_LEN);
let chunk = &payload_data[fed..end];
let mut chunk_cursor = std::io::Cursor::new(chunk.to_vec());
let result = stream.try_fill_buffer_for_tests(&mut chunk_cursor);
fed = end;
if fed < LARGE_HEADER_LEN {
assert_eq!(result, Err(Error::Done));
assert_eq!(stream.state_off, fed);
assert!(stream.state_buf.capacity() >= stream.state_buf.len());
assert!(
stream.state_buf.capacity() <=
(fed + MAX_STATE_BUF_ALLOC_SIZE) * 2,
"capacity {} grew too far ahead of bytes read {} \
(max alloc size {})",
stream.state_buf.capacity(),
fed,
MAX_STATE_BUF_ALLOC_SIZE,
);
} else {
assert_eq!(result, Ok(()));
}
}
assert_eq!(
stream.try_consume_frame(),
Ok((hdrs, LARGE_HEADER_LEN as u64))
);
assert_eq!(stream.state, State::FrameType);
}
#[test]
fn large_state_buf_allocation() {
const LARGE_HEADER_LEN: usize = 260000;
let mut stream = Stream::new(
0,
false,
LARGE_HEADER_LEN as u64,
PRIORITY_UPDATE_FRAME_PAYLOAD_MAX_SIZE_DEFAULT,
);
assert_eq!(stream.state_buf.capacity(), 16);
let mut d = vec![42; 5];
let mut b = octets::OctetsMut::with_slice(&mut d);
b.put_varint(HEADERS_FRAME_TYPE_ID).unwrap();
b.put_varint(LARGE_HEADER_LEN as u64).unwrap();
let mut cursor = std::io::Cursor::new(d);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
assert_eq!(stream.state_buf.capacity(), 16);
let frame_ty = stream.try_consume_varint().unwrap();
assert_eq!(frame_ty, HEADERS_FRAME_TYPE_ID);
assert_eq!(stream.state_buf.capacity(), 16);
stream.set_frame_type(frame_ty).unwrap();
assert_eq!(stream.state_buf.capacity(), 16);
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
assert_eq!(stream.state_buf.capacity(), 16);
assert_eq!(stream.try_consume_varint(), Err(Error::Done));
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
assert_eq!(stream.state_buf.capacity(), 16);
let frame_payload_len = stream.try_consume_varint().unwrap();
assert_eq!(frame_payload_len, LARGE_HEADER_LEN as u64);
assert_eq!(stream.state_buf.capacity(), 16);
stream.set_frame_payload_len(frame_payload_len).unwrap();
assert_eq!(stream.state_buf.capacity(), MAX_STATE_BUF_ALLOC_SIZE);
fn assert_state_buf_props(
stream: &Stream, len: usize, off: usize, capacity: usize,
) {
assert_eq!(stream.state_len, len, "state_len");
assert_eq!(stream.state_off, off, "state_off");
assert_eq!(stream.state_buf.capacity(), capacity, "capacity");
}
assert_eq!(
stream.try_fill_buffer_for_tests(&mut cursor),
Err(Error::Done)
);
assert_state_buf_props(
&stream,
LARGE_HEADER_LEN,
0,
MAX_STATE_BUF_ALLOC_SIZE,
);
cursor.get_mut().extend_from_slice(&[123; 2048]);
assert_eq!(
stream.try_fill_buffer_for_tests(&mut cursor),
Err(Error::Done)
);
assert_state_buf_props(
&stream,
LARGE_HEADER_LEN,
2048,
MAX_STATE_BUF_ALLOC_SIZE,
);
cursor.get_mut().extend_from_slice(&[123; 1024]);
assert_eq!(
stream.try_fill_buffer_for_tests(&mut cursor),
Err(Error::Done)
);
assert_state_buf_props(
&stream,
LARGE_HEADER_LEN,
3072,
MAX_STATE_BUF_ALLOC_SIZE,
);
cursor.get_mut().extend_from_slice(&[123; 512]);
assert_eq!(
stream.try_fill_buffer_for_tests(&mut cursor),
Err(Error::Done)
);
assert_state_buf_props(
&stream,
LARGE_HEADER_LEN,
3584,
MAX_STATE_BUF_ALLOC_SIZE,
);
cursor.get_mut().extend_from_slice(&[123; 4096]);
assert_eq!(
stream.try_fill_buffer_for_tests(&mut cursor),
Err(Error::Done)
);
assert_state_buf_props(
&stream,
LARGE_HEADER_LEN,
7680,
MAX_STATE_BUF_ALLOC_SIZE * 2,
);
cursor.get_mut().extend_from_slice(&[123; 8192]);
assert_eq!(
stream.try_fill_buffer_for_tests(&mut cursor),
Err(Error::Done)
);
assert_state_buf_props(
&stream,
LARGE_HEADER_LEN,
15872,
MAX_STATE_BUF_ALLOC_SIZE * 4,
);
cursor.get_mut().extend_from_slice(&[123; 16384]);
assert_eq!(
stream.try_fill_buffer_for_tests(&mut cursor),
Err(Error::Done)
);
assert_state_buf_props(
&stream,
LARGE_HEADER_LEN,
32256,
MAX_STATE_BUF_ALLOC_SIZE * 8,
);
cursor.get_mut().extend_from_slice(&[123; 32768]);
assert_eq!(
stream.try_fill_buffer_for_tests(&mut cursor),
Err(Error::Done)
);
assert_state_buf_props(
&stream,
LARGE_HEADER_LEN,
65024,
MAX_STATE_BUF_ALLOC_SIZE * 16,
);
cursor.get_mut().extend_from_slice(&[123; 65536]);
assert_eq!(
stream.try_fill_buffer_for_tests(&mut cursor),
Err(Error::Done)
);
assert_state_buf_props(
&stream,
LARGE_HEADER_LEN,
130560,
MAX_STATE_BUF_ALLOC_SIZE * 32,
);
let remaining = LARGE_HEADER_LEN - 130560;
cursor.get_mut().extend_from_slice(&vec![123; remaining]);
assert_eq!(stream.try_fill_buffer_for_tests(&mut cursor), Ok(()));
assert_state_buf_props(
&stream,
LARGE_HEADER_LEN,
LARGE_HEADER_LEN,
MAX_STATE_BUF_ALLOC_SIZE * 64,
);
let header_block = vec![123; LARGE_HEADER_LEN];
let hdrs = Frame::Headers {
header_block: header_block.clone(),
};
assert_eq!(
stream.try_consume_frame(),
Ok((hdrs, LARGE_HEADER_LEN as u64))
);
assert_eq!(stream.state, State::FrameType);
assert_state_buf_props(&stream, 1, 0, MAX_STATE_BUF_ALLOC_SIZE * 64);
}
}