#![allow(dead_code)]
pub mod reference;
use http_net::{
BodyFraming, ClientConn, ClientEvent, HttpError, Limits, Request, Response, ServerConn,
ServerEvent, Version,
};
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Ev {
Head {
method: String,
target: String,
version: Version,
headers: Vec<(String, Vec<u8>)>,
framing: BodyFraming,
keep_alive: bool,
upgrade: bool,
},
Status {
status: u16,
headers: Vec<(String, Vec<u8>)>,
framing: BodyFraming,
},
Body(Vec<u8>),
Trailers(Vec<(String, Vec<u8>)>),
Informational {
status: u16,
headers: Vec<(String, Vec<u8>)>,
},
Continue,
End,
Upgraded(Vec<u8>),
Closed,
Err(HttpError),
}
#[derive(Clone, Copy, Debug, Default)]
pub struct Opts {
pub report_trailers: bool,
pub report_informational: bool,
}
fn fields_of<'a>(it: impl Iterator<Item = (&'a str, &'a [u8])>) -> Vec<(String, Vec<u8>)> {
it.map(|(n, v)| (n.to_string(), v.to_vec())).collect()
}
fn push_body(events: &mut Vec<Ev>, chunk: &[u8]) {
if let Some(Ev::Body(b)) = events.last_mut() {
b.extend_from_slice(chunk);
} else {
events.push(Ev::Body(chunk.to_vec()));
}
}
pub fn split<'a>(input: &'a [u8], cuts: &[usize]) -> Vec<&'a [u8]> {
if input.is_empty() {
return vec![input];
}
let mut points: Vec<usize> = cuts.iter().map(|c| c % input.len()).collect();
points.sort_unstable();
points.dedup();
let mut pieces = Vec::new();
let mut last = 0;
for p in points {
pieces.push(&input[last..p]);
last = p;
}
pieces.push(&input[last..]);
pieces
}
pub fn first_offered(r: &http_net::RequestHead<'_>) -> Option<String> {
r.header_all("upgrade")
.flat_map(|v| v.split(|&b| b == b','))
.map(|e| e.trim_ascii())
.find(|e| !e.is_empty() && !e.eq_ignore_ascii_case(b"h2c") && !e.starts_with(b"h2c/"))
.and_then(|e| std::str::from_utf8(e).ok())
.map(str::to_string)
}
pub fn drive_server(pieces: &[&[u8]], limits: Limits) -> Vec<Ev> {
drive_server_opts(pieces, limits, Opts::default())
}
pub fn drive_server_opts(pieces: &[&[u8]], limits: Limits, opts: Opts) -> Vec<Ev> {
let mut conn = ServerConn::with_limits(limits);
conn.set_report_trailers(opts.report_trailers);
let mut out = Vec::new();
let mut events = Vec::new();
let mut next = 0;
let mut pending: &[u8] = &[];
let mut eof = false;
let mut upgrade_to: Option<String> = None;
for _ in 0..10_000_000 {
match conn.poll() {
Ok(ServerEvent::Request(r)) => {
upgrade_to = r.is_upgrade().then(|| first_offered(&r)).flatten();
events.push(Ev::Head {
method: r.method_str().to_string(),
target: r.target().to_string(),
version: r.version(),
headers: r
.headers()
.map(|(n, v)| (n.to_string(), v.to_vec()))
.collect(),
framing: r.framing(),
keep_alive: r.keep_alive(),
upgrade: r.is_upgrade(),
});
}
Ok(ServerEvent::Body(b)) => push_body(&mut events, b),
Ok(ServerEvent::Trailers(t)) => events.push(Ev::Trailers(fields_of(t))),
Ok(ServerEvent::RequestEnd) => {
events.push(Ev::End);
let response = match &upgrade_to {
Some(protocol) => Response::switching_protocols(protocol),
None => Response::new(200),
};
conn.respond(&response, &mut out).expect("respond");
}
Ok(ServerEvent::NeedInput) => {
assert!(!eof, "NeedInput after EOF");
while pending.is_empty() && next < pieces.len() {
pending = pieces[next];
next += 1;
}
if pending.is_empty() {
conn.feed_eof();
eof = true;
} else {
let n = conn.feed(pending);
assert!(n > 0, "buffer full while the parser waits for input");
pending = &pending[n..];
}
}
Ok(ServerEvent::AwaitingResponse) => panic!("driver always responds"),
Ok(ServerEvent::Upgraded) => {
let mut rest = conn.remaining_input().to_vec();
rest.extend_from_slice(pending);
for p in &pieces[next..] {
rest.extend_from_slice(p);
}
events.push(Ev::Upgraded(rest));
return events;
}
Ok(ServerEvent::Closed) => {
events.push(Ev::Closed);
return events;
}
Ok(other) => panic!("unknown event {other:?}"),
Err(e) => {
events.push(Ev::Err(e));
return events;
}
}
}
panic!("driver did not terminate");
}
pub fn drive_client(request: &Request, pieces: &[&[u8]], limits: Limits) -> Vec<Ev> {
drive_client_opts(request, pieces, limits, Opts::default())
}
pub fn drive_client_opts(
request: &Request,
pieces: &[&[u8]],
limits: Limits,
opts: Opts,
) -> Vec<Ev> {
let mut conn = ClientConn::with_limits(limits);
conn.set_report_trailers(opts.report_trailers);
conn.set_report_informational(opts.report_informational);
let mut out = Vec::new();
conn.send_request(request, &mut out).expect("send");
let mut events = Vec::new();
let mut next = 0;
let mut pending: &[u8] = &[];
let mut eof = false;
for _ in 0..10_000_000 {
match conn.poll() {
Ok(ClientEvent::Response(r)) => events.push(Ev::Status {
status: r.status(),
headers: r
.headers()
.map(|(n, v)| (n.to_string(), v.to_vec()))
.collect(),
framing: r.framing(),
}),
Ok(ClientEvent::Body(b)) => push_body(&mut events, b),
Ok(ClientEvent::Trailers(t)) => events.push(Ev::Trailers(fields_of(t))),
Ok(ClientEvent::Informational(r)) => events.push(Ev::Informational {
status: r.status(),
headers: fields_of(r.headers()),
}),
Ok(ClientEvent::Continue) => events.push(Ev::Continue),
Ok(ClientEvent::ResponseEnd) => events.push(Ev::End),
Ok(ClientEvent::NeedInput) => {
assert!(!eof, "NeedInput after EOF");
while pending.is_empty() && next < pieces.len() {
pending = pieces[next];
next += 1;
}
if pending.is_empty() {
conn.feed_eof();
eof = true;
} else {
let n = conn.feed(pending);
assert!(n > 0, "buffer full while the parser waits for input");
pending = &pending[n..];
}
}
Ok(ClientEvent::Idle) => {
while pending.is_empty() && next < pieces.len() {
pending = pieces[next];
next += 1;
}
if pending.is_empty() {
return events;
}
let n = conn.feed(pending);
assert!(n > 0, "buffer full while idle");
pending = &pending[n..];
}
Ok(ClientEvent::Upgraded) => {
let mut rest = conn.remaining_input().to_vec();
rest.extend_from_slice(pending);
for p in &pieces[next..] {
rest.extend_from_slice(p);
}
events.push(Ev::Upgraded(rest));
return events;
}
Ok(ClientEvent::Closed) => {
events.push(Ev::Closed);
return events;
}
Ok(other) => panic!("unknown event {other:?}"),
Err(e) => {
events.push(Ev::Err(e));
return events;
}
}
}
panic!("driver did not terminate");
}
pub fn server_error(input: &[u8]) -> Option<HttpError> {
drive_server(&[input], Limits::new())
.into_iter()
.find_map(|e| match e {
Ev::Err(e) => Some(e),
_ => None,
})
}