use std::io::Write;
use buffet::IntoHalves;
use loona_h2::{pack_bit_and_u31, FrameType, HeadersFlags, StreamId};
use crate::{Conn, ErrorC, FrameT, Headers};
pub async fn sends_second_headers_frame_without_end_stream<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
let stream_id = StreamId(1);
conn.handshake().await?;
let headers_fragment = conn.encode_headers(&conn.common_headers("POST"))?;
conn.write_headers(stream_id, HeadersFlags::EndHeaders, headers_fragment)
.await?;
conn.write_data(stream_id, false, b"test").await?;
let mut trailers = Headers::default();
trailers.append("x-test", "ok");
let trailers_fragment = conn.encode_headers(&trailers)?;
conn.write_headers(stream_id, HeadersFlags::EndHeaders, trailers_fragment)
.await?;
conn.verify_stream_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_headers_frame_with_incorrect_content_length_single_data_frame<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", "10");
let block_fragment = conn.encode_headers(&headers);
conn.write_headers(stream_id, HeadersFlags::EndHeaders, block_fragment?)
.await?;
conn.write_data(stream_id, true, b"test").await?;
conn.verify_stream_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_headers_frame_with_incorrect_content_length_multiple_data_frames<
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", "10");
let block_fragment = conn.encode_headers(&headers);
conn.write_headers(stream_id, HeadersFlags::EndHeaders, block_fragment?)
.await?;
conn.write_data(stream_id, false, b"te").await?;
conn.write_data(stream_id, false, b"st").await?;
conn.write_data(stream_id, true, b"ing").await?;
conn.verify_stream_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_headers_frame_with_uppercase_field_name<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append("UPPERCASE", "oh no");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_space_in_field_name<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append("space force", "oh no");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_non_visible_ascii<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append("\x01invalid", "oh no");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_del_character<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append("\x7Finvalid", "oh no");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_non_ascii_character<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append("inválid", "oh no");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_colon_in_field_name<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append("invalid:field", "oh no");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_lf_in_field_value<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append("invalid-value", "oh\nno");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_cr_in_field_value<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append("invalid-value", "oh\rno");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_nul_in_field_value<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append("invalid-value", "oh\0no");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_leading_space_in_field_value<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append("invalid-value", " oh no");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_trailing_tab_in_field_value<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append("invalid-value", "oh no\t");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_connection_header<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append("connection", "keep-alive");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_proxy_connection_header<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append("proxy-connection", "keep-alive");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_keep_alive_header<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append("keep-alive", "timeout=5");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_transfer_encoding_header<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append("transfer-encoding", "chunked");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_upgrade_header<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append("upgrade", "h2c");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_te_trailers<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append("te", "trailers");
conn.send_req_and_expect_status(StreamId(1), &headers, 200)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_te_not_trailers<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append("te", "not-trailers");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_response_pseudo_header<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.append(":status", "200");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_pseudo_header_in_trailer<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
let stream_id = StreamId(1);
conn.handshake().await?;
let headers_fragment = conn.encode_headers(&conn.common_headers("POST"))?;
conn.write_headers(stream_id, HeadersFlags::EndHeaders, headers_fragment)
.await?;
conn.write_data(stream_id, false, b"test").await?;
let mut trailers = Headers::default();
trailers.append(":method", "POST");
let trailers_fragment = conn.encode_headers(&trailers)?;
conn.write_headers(
stream_id,
HeadersFlags::EndHeaders | HeadersFlags::EndStream,
trailers_fragment,
)
.await?;
conn.verify_stream_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_headers_frame_with_duplicate_pseudo_headers<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.prepend(":method", "POST");
headers.prepend(":method", "POST");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_mismatched_host_authority<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.replace(":authority", conn.config.host.clone().into_bytes());
headers.append(
"host",
format!("{}.different", conn.config.host).into_bytes(),
);
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_empty_path_component<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.replace(":path", "");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
tracing::debug!("empty path component test passed!");
Ok(())
}
pub async fn sends_headers_frame_without_method<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.remove(&":method".into());
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_without_scheme<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.remove(&":scheme".into());
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_without_path<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = conn.common_headers("POST");
headers.remove(&":path".into());
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_without_status<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let block_fragment = conn.encode_headers(&conn.common_headers("POST"))?;
conn.write_frame(
FrameType::Headers(HeadersFlags::EndStream | HeadersFlags::EndHeaders)
.into_frame(StreamId(1)),
block_fragment,
)
.await?;
let (frame, payload) = conn.wait_for_frame(FrameT::Headers).await.unwrap();
assert!(frame.is_end_headers(), "the test makes that assumption");
let headers = conn.decode_headers(payload.into())?;
let mut found_status = false;
for (name, _) in headers.iter() {
if name == b":status" {
found_status = true;
} else {
assert!(
!name.starts_with(b":"),
"no header name should start with ':'"
);
}
}
assert!(found_status, "the :status pseudo-header must be present");
Ok(())
}
pub async fn client_sends_push_promise_frame<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let stream_id = StreamId(1);
let promised_stream_id = StreamId(2);
let mut headers = Headers::default();
headers.append(":status", "200");
let block_fragment = conn.encode_headers(&headers)?;
let payload = conn
.scratch
.put_to_roll(block_fragment.len() + 4, |mut s| {
s.write_all(&pack_bit_and_u31(0, promised_stream_id.0))?;
s.write_all(&block_fragment)?;
Ok(())
})?;
conn.write_frame(FrameType::PushPromise.into_frame(stream_id), payload)
.await?;
conn.verify_connection_error(ErrorC::ProtocolError).await?;
Ok(())
}
pub async fn sends_connect_with_scheme<IO: IntoHalves>(mut conn: Conn<IO>) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = Headers::default();
headers.append(":method", "CONNECT");
headers.append(":scheme", "https");
headers.append(":authority", "example.com:443");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_connect_with_path<IO: IntoHalves>(mut conn: Conn<IO>) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = Headers::default();
headers.append(":method", "CONNECT");
headers.append(":path", "/");
headers.append(":authority", "example.com:443");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_connect_without_authority<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = Headers::default();
headers.append(":method", "CONNECT");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}
pub async fn sends_headers_frame_with_pseudo_headers_after_regular_headers<IO: IntoHalves>(
mut conn: Conn<IO>,
) -> eyre::Result<()> {
conn.handshake().await?;
let mut headers = Headers::default();
headers.append(":method", "POST");
headers.append(":path", "/");
headers.append("content-type", "application/json");
headers.append(":authority", "example.com");
conn.send_req_and_expect_stream_rst(StreamId(1), &headers)
.await?;
Ok(())
}