blob: 38bfbd788af4ee5b05c55ced8e92ef52093188d5 [file] [log] [blame] [edit]
// Copyright (C) 2024, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//! h3i - low-level HTTP/3 debug and testing
//!
//! HTTP/3 ([RFC 9114]) is the wire format for HTTP semantics ([RFC 9110]). The
//! RFCs contain a range of requirements about how Request or Response messages
//! are generated, serialized, sent, received, parsed, and consumed. QUIC ([RFC
//! 9000]) streams are used for these messages along with other control and
//! QPACK ([RFC 9204]) header compression instructions.
//!
//! h3i provides a highly configurable HTTP/3 client that can bend RFC rules in
//! order to test the behavior of servers. QUIC streams can be opened, fin'd,
//! stopped or reset at any point in time. HTTP/3 frames can be sent on any
//! stream, in any order, containing user-controlled content (both legal and
//! illegal).
//!
//! [RFC 9000]: https://www.rfc-editor.org/rfc/rfc9000.html
//! [RFC 9110]: https://www.rfc-editor.org/rfc/rfc9110.html
//! [RFC 9114]: https://www.rfc-editor.org/rfc/rfc9114.html
//! [RFC 9204]: https://www.rfc-editor.org/rfc/rfc9204.html
use qlog::events::quic::PacketHeader;
use qlog::events::quic::PacketSent;
use qlog::events::quic::PacketType;
use qlog::events::quic::QuicFrame;
use qlog::events::EventData;
pub use quiche;
use quiche::h3::NameValue;
use smallvec::SmallVec;
/// The ID for an HTTP/3 control stream type.
///
/// See https://datatracker.ietf.org/doc/html/rfc9114#name-control-streams.
pub const HTTP3_CONTROL_STREAM_TYPE_ID: u64 = 0x0;
/// The ID for an HTTP/3 push stream type.
///
/// See https://datatracker.ietf.org/doc/html/rfc9114#name-push-streams.
pub const HTTP3_PUSH_STREAM_TYPE_ID: u64 = 0x1;
/// The ID for a QPACK encoder stream type.
///
/// See https://datatracker.ietf.org/doc/html/rfc9204#section-4.2-2.1.
pub const QPACK_ENCODER_STREAM_TYPE_ID: u64 = 0x2;
/// The ID for a QPACK decoder stream type.
///
/// See https://datatracker.ietf.org/doc/html/rfc9204#section-4.2-2.2.
pub const QPACK_DECODER_STREAM_TYPE_ID: u64 = 0x3;
#[derive(Default)]
struct StreamIdAllocator {
id: u64,
}
impl StreamIdAllocator {
pub fn take_next_id(&mut self) -> u64 {
let old = self.id;
self.id += 4;
old
}
pub fn peek_next_id(&mut self) -> u64 {
self.id
}
}
fn encode_header_block(
headers: &[quiche::h3::Header],
) -> std::result::Result<Vec<u8>, String> {
let mut encoder = quiche::h3::qpack::Encoder::new();
let headers_len = headers
.iter()
.fold(0, |acc, h| acc + h.value().len() + h.name().len() + 32);
let mut header_block = vec![0; headers_len];
let len = encoder
.encode(headers, &mut header_block)
.map_err(|_| "Internal Error")?;
header_block.truncate(len);
Ok(header_block)
}
fn fake_packet_header() -> PacketHeader {
PacketHeader {
packet_type: PacketType::OneRtt,
packet_number: None,
flags: None,
token: None,
length: None,
version: None,
scil: None,
dcil: None,
scid: None,
dcid: None,
}
}
fn fake_packet_sent(frames: Option<SmallVec<[QuicFrame; 1]>>) -> EventData {
EventData::PacketSent(PacketSent {
header: fake_packet_header(),
stateless_reset_token: None,
supported_versions: None,
raw: None,
datagram_id: None,
trigger: None,
send_at_time: None,
is_mtu_probe_packet: None,
frames,
})
}
pub mod actions;
pub mod client;
pub mod config;
pub mod frame;
pub mod frame_parser;
pub mod prompts;
pub mod recordreplay;