use buffet::{IntoHalves, Piece};
use enumflags2::BitFlags;
use loona_h2::{
ContinuationFlags, Frame, FrameType, GoAway, HeadersFlags, IntoPiece, KnownErrorCode,
PrioritySpec, Setting, SettingPairs, SettingsFlags, StreamId,
};
use crate::{dummy_bytes, Conn, ErrorC, FrameT};
pub async fn sends_data_frame_with_zero_stream_id<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
conn.write_data(StreamId::CONNECTION, true, b"test").await?;
conn.verify_connection_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_data_frame_on_invalid_stream_state<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
let stream_id = StreamId(1);
conn.handshake().await?;
let block_fragment = conn.encode_headers(&conn.common_headers("POST"))?;
conn.write_headers(
stream_id,
HeadersFlags::EndStream | HeadersFlags::EndHeaders,
block_fragment,
)
.await?;
conn.write_data(stream_id, true, b"test").await?;
conn.verify_stream_error(ErrorC::StreamClosed).await?;
Ok(())
}
pub async fn sends_data_frame_with_invalid_pad_length<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
let stream_id = StreamId(1);
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append("content-length", "4");
let block_fragment = conn.encode_headers(&headers)?;
conn.write_headers(stream_id, HeadersFlags::EndHeaders, block_fragment)
.await?;
conn.send(b"\x00\x00\x05\x00\x09\x00\x00\x00\x01").await?;
conn.send(b"\x06\x54\x65\x73\x74").await?;
conn.verify_connection_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_headers_frame_with_zero_stream_id<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let block_fragment = conn.encode_headers(&conn.common_headers("POST"))?;
conn.write_headers(
StreamId::CONNECTION,
HeadersFlags::EndStream | HeadersFlags::EndHeaders,
block_fragment,
)
.await?;
conn.verify_connection_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_headers_frame_with_invalid_pad_length<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let block_fragment = conn.encode_headers(&conn.common_headers("POST"))?;
let frame = Frame::new(
FrameType::Headers(
HeadersFlags::Padded | HeadersFlags::EndHeaders | HeadersFlags::EndStream,
),
StreamId(1),
)
.with_len((block_fragment.len() + 1) as _);
let frame_header = frame.into_piece(&mut conn.scratch)?;
conn.send(frame_header).await?;
conn.send(vec![(block_fragment.len() + 2) as u8]).await?;
conn.send(block_fragment).await?;
conn.verify_connection_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_priority_frame_with_zero_stream_id<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
conn.write_priority(
StreamId::CONNECTION,
PrioritySpec {
stream_dependency: StreamId::CONNECTION,
exclusive: false,
weight: 255,
},
)
.await?;
conn.verify_connection_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_priority_frame_with_invalid_length<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
let stream_id = StreamId(1);
conn.handshake().await?;
let block_fragment = conn.encode_headers(&conn.common_headers("POST"))?;
conn.write_headers(
stream_id,
HeadersFlags::EndStream | HeadersFlags::EndHeaders,
block_fragment,
)
.await?;
conn.write_frame(
Frame::new(FrameType::Priority, stream_id),
b"\x80\x00\x00\x01",
)
.await?;
conn.verify_stream_error(ErrorC::FrameSizeError).await?;
Ok(())
}
pub async fn sends_rst_stream_frame_with_zero_stream_id<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
conn.write_rst_stream(StreamId::CONNECTION, ErrorC::Cancel)
.await?;
conn.verify_connection_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_rst_stream_frame_on_idle_stream<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
conn.write_rst_stream(StreamId(1), ErrorC::Cancel).await?;
conn.verify_connection_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_rst_stream_frame_with_invalid_length<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
let stream_id = StreamId(1);
conn.handshake().await?;
let block_fragment = conn.encode_headers(&conn.common_headers("POST"))?;
conn.write_headers(
stream_id,
HeadersFlags::EndStream | HeadersFlags::EndHeaders,
block_fragment,
)
.await?;
let frame = Frame::new(FrameType::RstStream, StreamId(1)).with_len(3);
let frame_header = frame.into_piece(&mut conn.scratch)?;
conn.send(frame_header).await?;
conn.send(b"\x00\x00\x00").await?;
conn.verify_stream_error(ErrorC::FrameSizeError).await?;
Ok(())
}
pub async fn sends_settings_frame_with_ack_and_payload<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
conn.write_frame(
Frame::new(
FrameType::Settings(SettingsFlags::Ack.into()),
StreamId::CONNECTION,
),
b"\x00",
)
.await?;
conn.verify_connection_error(ErrorC::FrameSizeError).await?;
Ok(())
}
pub async fn sends_settings_frame_with_non_zero_stream_id<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
conn.write_frame(
Frame::new(FrameType::Settings(Default::default()), StreamId(1)).with_len(6),
SettingPairs(&[(Setting::MaxConcurrentStreams, 0x64)]),
)
.await?;
conn.verify_connection_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_settings_frame_with_invalid_length<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
conn.write_frame(
Frame::new(
FrameType::Settings(Default::default()),
StreamId::CONNECTION,
),
b"\x00\x03\x00",
)
.await?;
conn.verify_connection_error(ErrorC::FrameSizeError).await?;
Ok(())
}
pub async fn sends_settings_enable_push_with_invalid_value<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
conn.write_settings(&[(Setting::EnablePush, 2)]).await?;
conn.verify_connection_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_settings_initial_window_size_with_invalid_value<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
conn.write_settings(&[(Setting::InitialWindowSize, 1 << 31)])
.await?;
conn.verify_connection_error(ErrorC::FlowControlError)
.await?;
Ok(())
}
pub async fn sends_settings_max_frame_size_with_invalid_value_below_initial<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
conn.write_settings(&[(Setting::MaxFrameSize, (1 << 14) - 1)])
.await?;
conn.verify_connection_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_settings_max_frame_size_with_invalid_value_above_max<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
conn.write_settings(&[(Setting::MaxFrameSize, 1 << 24)])
.await?;
conn.verify_connection_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_settings_frame_with_unknown_identifier<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
conn.write_frame(
Frame::new(
FrameType::Settings(Default::default()),
StreamId::CONNECTION,
)
.with_len(6),
b"\x00\xff\x00\x00\x00\x00",
)
.await?;
conn.verify_connection_still_alive().await?;
Ok(())
}
pub async fn sends_multiple_values_of_settings_initial_window_size<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
let stream_id = StreamId(1);
conn.handshake().await?;
conn.write_frame(
Frame::new(
FrameType::Settings(Default::default()),
StreamId::CONNECTION,
),
SettingPairs(&[
(Setting::InitialWindowSize, 100),
(Setting::InitialWindowSize, 1),
]),
)
.await?;
conn.verify_settings_frame_with_ack().await?;
let block_fragment = conn.encode_headers(&conn.common_headers("POST"))?;
conn.write_headers(
stream_id,
HeadersFlags::EndStream | HeadersFlags::EndHeaders,
block_fragment,
)
.await?;
let (frame, _payload) = conn.wait_for_frame(FrameT::Data).await.unwrap();
assert_eq!(frame.len, 1);
Ok(())
}
pub async fn sends_settings_frame_without_ack_flag<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
conn.write_frame(
Frame::new(
FrameType::Settings(Default::default()),
StreamId::CONNECTION,
),
SettingPairs(&[(Setting::EnablePush, 0)]),
)
.await?;
conn.verify_settings_frame_with_ack().await?;
Ok(())
}
pub async fn sends_ping_frame<IO: IntoHalves>(mut conn: Conn<IO>) -> eyre::Result<()> {
conn.handshake().await?;
let data = b"h2spec\0\0";
conn.write_ping(false, data.to_vec()).await?;
conn.verify_ping_frame_with_ack(data).await?;
Ok(())
}
pub async fn sends_ping_frame_with_ack<IO: IntoHalves>(mut conn: Conn<IO>) -> eyre::Result<()> {
conn.handshake().await?;
let unexpected_data = b"invalid\0";
let expected_data = b"h2spec\0\0";
conn.write_ping(true, unexpected_data.to_vec()).await?;
conn.write_ping(false, expected_data.to_vec()).await?;
conn.verify_ping_frame_with_ack(expected_data).await?;
Ok(())
}
pub async fn sends_ping_frame_with_non_zero_stream_id<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
conn.write_frame(
Frame::new(FrameType::Ping(Default::default()), StreamId(1)),
dummy_bytes(8),
)
.await?;
conn.verify_connection_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_ping_frame_with_invalid_length<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
conn.write_frame(
Frame::new(FrameType::Ping(Default::default()), StreamId::CONNECTION),
dummy_bytes(6),
)
.await?;
conn.verify_connection_error(ErrorC::FrameSizeError).await?;
Ok(())
}
pub async fn sends_goaway_frame_with_non_zero_stream_id<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
conn.write_frame(
Frame::new(FrameType::GoAway, StreamId(1)),
GoAway {
additional_debug_data: Piece::empty(),
error_code: KnownErrorCode::NoError.into(),
last_stream_id: StreamId(0),
},
)
.await?;
conn.verify_connection_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_window_update_frame_with_zero_increment<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
conn.write_window_update(StreamId::CONNECTION, 0).await?;
conn.verify_connection_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_window_update_frame_with_zero_increment_on_stream<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
let stream_id = StreamId(1);
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append(":method", "POST");
let block_fragment = conn.encode_headers(&headers)?;
conn.write_headers(stream_id, HeadersFlags::EndHeaders, block_fragment)
.await?;
conn.write_window_update(stream_id, 0).await?;
conn.verify_stream_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_window_update_frame_with_invalid_length<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
conn.write_frame(
Frame::new(FrameType::WindowUpdate, StreamId::CONNECTION),
b"\x00\x00\x01",
)
.await?;
conn.verify_connection_error(ErrorC::FrameSizeError).await?;
Ok(())
}
pub async fn sends_settings_frame_to_set_initial_window_size_to_1_and_sends_headers_frame<
IO: IntoHalves,
>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
let stream_id = StreamId(1);
conn.handshake().await?;
conn.write_and_ack_settings(&[(Setting::InitialWindowSize, 1)])
.await?;
conn.encode_and_write_headers(
stream_id,
HeadersFlags::EndStream | HeadersFlags::EndHeaders,
&conn.common_headers("POST"),
)
.await?;
let (frame, _payload) = conn.wait_for_frame(FrameT::Data).await.unwrap();
assert_eq!(frame.len, 1);
Ok(())
}
pub async fn sends_multiple_window_update_frames_increasing_flow_control_window_above_max<
IO: IntoHalves,
>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
conn.write_window_update(StreamId::CONNECTION, (1 << 31) - 1)
.await?;
conn.write_window_update(StreamId::CONNECTION, (1 << 31) - 1)
.await?;
conn.verify_connection_error(ErrorC::FlowControlError)
.await?;
Ok(())
}
pub async fn sends_multiple_window_update_frames_increasing_flow_control_window_above_max_on_stream<
IO: IntoHalves,
>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
let stream_id = StreamId(1);
conn.handshake().await?;
conn.encode_and_write_headers(
stream_id,
HeadersFlags::EndHeaders,
&conn.common_headers("POST"),
)
.await?;
conn.write_window_update(stream_id, (1 << 31) - 1).await?;
_ = conn.write_window_update(stream_id, (1 << 31) - 1).await;
conn.verify_stream_error(ErrorC::FlowControlError).await?;
Ok(())
}
pub async fn changes_settings_initial_window_size_after_sending_headers_frame<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
let stream_id = StreamId(1);
conn.handshake().await?;
conn.write_and_ack_settings(&[(Setting::InitialWindowSize, 0)])
.await?;
conn.encode_and_write_headers(
stream_id,
HeadersFlags::EndStream | HeadersFlags::EndHeaders,
&conn.common_headers("POST"),
)
.await?;
conn.write_settings(&[(Setting::InitialWindowSize, 1)])
.await?;
let (frame, _payload) = conn.wait_for_frame(FrameT::Data).await.unwrap();
assert_eq!(frame.len, 1);
Ok(())
}
pub async fn sends_settings_frame_for_window_size_to_be_negative<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
let stream_id = StreamId(1);
conn.handshake().await?;
conn.write_and_ack_settings(&[(Setting::InitialWindowSize, 3)])
.await?;
conn.send_empty_post_to_root(stream_id).await?;
let (_, payload) = conn.wait_for_frame(FrameT::Data).await.unwrap();
assert_eq!(payload.len(), 3);
conn.write_and_ack_settings(&[(Setting::InitialWindowSize, 2)])
.await?;
conn.write_window_update(stream_id, 2).await?;
let (frame, _payload) = conn.wait_for_frame(FrameT::Data).await.unwrap();
assert_eq!(frame.len, 1);
Ok(())
}
pub async fn sends_settings_initial_window_size_with_exceeded_max_window_size_value<
IO: IntoHalves,
>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
conn.write_settings(&[(Setting::InitialWindowSize, 1 << 31)])
.await?;
conn.verify_connection_error(ErrorC::FlowControlError)
.await?;
Ok(())
}
pub async fn sends_multiple_continuation_frames_preceded_by_headers_frame<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
let stream_id = StreamId(1);
conn.handshake().await?;
let headers = conn.common_headers("POST");
let block_fragment = conn.encode_headers(&headers)?;
conn.write_headers(stream_id, HeadersFlags::EndStream, block_fragment)
.await?;
let dummy_headers = conn.dummy_headers(1);
let block_fragment = conn.encode_headers(&dummy_headers)?;
conn.write_continuation(stream_id, BitFlags::empty(), block_fragment)
.await?;
let block_fragment = conn.encode_headers(&dummy_headers)?;
conn.write_continuation(stream_id, ContinuationFlags::EndHeaders, block_fragment)
.await?;
conn.verify_headers_frame(stream_id).await?;
Ok(())
}
pub async fn sends_continuation_frame_followed_by_non_continuation_frame<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
let stream_id = StreamId(1);
conn.handshake().await?;
let block_fragment = conn.encode_headers(&conn.common_headers("POST"))?;
conn.write_headers(stream_id, HeadersFlags::EndStream, block_fragment)
.await?;
let dummy_headers = conn.dummy_headers(1);
let block_fragment = conn.encode_headers(&dummy_headers)?;
conn.write_continuation(stream_id, BitFlags::empty(), block_fragment)
.await?;
conn.write_data(stream_id, true, b"test").await?;
conn.verify_connection_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_continuation_frame_with_zero_stream_id<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
let stream_id = StreamId(1);
conn.handshake().await?;
let block_fragment = conn.encode_headers(&conn.common_headers("POST"))?;
conn.write_headers(stream_id, HeadersFlags::EndStream, block_fragment)
.await?;
let block_fragment = conn.encode_headers(&conn.dummy_headers(1))?;
conn.write_continuation(
StreamId::CONNECTION,
ContinuationFlags::EndHeaders,
block_fragment,
)
.await?;
conn.verify_connection_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_continuation_frame_preceded_by_headers_frame_with_end_headers_flag<
IO: IntoHalves,
>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
let stream_id = StreamId(1);
conn.handshake().await?;
let block_fragment = conn.encode_headers(&conn.common_headers("POST"))?;
conn.write_headers(
stream_id,
HeadersFlags::EndStream | HeadersFlags::EndHeaders,
block_fragment,
)
.await?;
let dummy_headers = conn.dummy_headers(1);
let block_fragment = conn.encode_headers(&dummy_headers)?;
conn.write_continuation(stream_id, ContinuationFlags::EndHeaders, block_fragment)
.await?;
conn.verify_connection_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_continuation_frame_preceded_by_continuation_frame_with_end_headers_flag<
IO: IntoHalves,
>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
let stream_id = StreamId(1);
conn.handshake().await?;
let block_fragment = conn.encode_headers(&conn.common_headers("POST"))?;
conn.write_headers(stream_id, HeadersFlags::EndStream, block_fragment)
.await?;
let dummy_headers = conn.dummy_headers(1);
let block_fragment = conn.encode_headers(&dummy_headers)?;
conn.write_continuation(stream_id, ContinuationFlags::EndHeaders, block_fragment)
.await?;
let block_fragment = conn.encode_headers(&dummy_headers)?;
conn.write_continuation(stream_id, ContinuationFlags::EndHeaders, block_fragment)
.await?;
conn.verify_connection_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_continuation_frame_preceded_by_data_frame<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
let stream_id = StreamId(1);
conn.handshake().await?;
let block_fragment = conn.encode_headers(&conn.common_headers("POST"))?;
conn.write_headers(stream_id, HeadersFlags::EndStream, block_fragment)
.await?;
conn.write_data(stream_id, true, b"test").await?;
let block_fragment = conn.encode_headers(&conn.dummy_headers(1))?;
_ = conn
.write_continuation(stream_id, BitFlags::empty(), block_fragment)
.await;
conn.verify_connection_error(ErrorC::ProtocolError).await?;
Ok(())
}