Source code

Revision control

Copy as Markdown

Other Tools

// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::sync::OnceLock;
use neqo_common::event::Provider;
use neqo_crypto::AuthenticationStatus;
use neqo_http3::{
Error, Header, Http3Client, Http3ClientEvent, Http3OrWebTransportStream, Http3Server,
Http3ServerEvent, Priority,
};
use test_fixture::*;
const RESPONSE_DATA: &[u8] = &[0x61, 0x62, 0x63];
fn response_header_no_data() -> &'static Vec<Header> {
static HEADERS: OnceLock<Vec<Header>> = OnceLock::new();
HEADERS.get_or_init(|| vec![Header::new(":status", "200"), Header::new("something", "3")])
}
fn response_header_103() -> &'static Vec<Header> {
static HEADERS: OnceLock<Vec<Header>> = OnceLock::new();
HEADERS.get_or_init(|| vec![Header::new(":status", "103"), Header::new("link", "...")])
}
fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) {
let mut out = None;
loop {
out = client.process(out.as_ref(), now()).dgram();
out = server.process(out.as_ref(), now()).dgram();
if out.is_none() {
break;
}
}
}
fn receive_request(server: &mut Http3Server) -> Option<Http3OrWebTransportStream> {
while let Some(event) = server.next_event() {
if let Http3ServerEvent::Headers {
stream,
headers,
fin,
} = event
{
assert_eq!(
&headers,
&[
Header::new(":method", "GET"),
Header::new(":scheme", "https"),
Header::new(":authority", "something.com"),
Header::new(":path", "/")
]
);
assert!(fin);
return Some(stream);
}
}
None
}
fn send_trailers(request: &mut Http3OrWebTransportStream) -> Result<(), Error> {
request.send_headers(&[
Header::new("something1", "something"),
Header::new("something2", "3"),
])
}
fn send_informational_headers(request: &mut Http3OrWebTransportStream) -> Result<(), Error> {
request.send_headers(response_header_103())
}
fn send_headers(request: &mut Http3OrWebTransportStream) -> Result<(), Error> {
request.send_headers(&[
Header::new(":status", "200"),
Header::new("content-length", "3"),
])
}
fn process_client_events(conn: &mut Http3Client) {
let mut response_header_found = false;
let mut response_data_found = false;
while let Some(event) = conn.next_event() {
match event {
Http3ClientEvent::HeaderReady { headers, fin, .. } => {
assert!(
(headers.as_ref()
== [
Header::new(":status", "200"),
Header::new("content-length", "3"),
])
|| (headers.as_ref() == *response_header_103())
);
assert!(!fin);
response_header_found = true;
}
Http3ClientEvent::DataReadable { stream_id } => {
let mut buf = [0u8; 100];
let (amount, fin) = conn.read_data(now(), stream_id, &mut buf).unwrap();
assert!(fin);
assert_eq!(amount, RESPONSE_DATA.len());
assert_eq!(&buf[..RESPONSE_DATA.len()], RESPONSE_DATA);
response_data_found = true;
}
_ => {}
}
}
assert!(response_header_found);
assert!(response_data_found);
}
fn process_client_events_no_data(conn: &mut Http3Client) {
let mut response_header_found = false;
let mut fin_received = false;
while let Some(event) = conn.next_event() {
match event {
Http3ClientEvent::HeaderReady { headers, fin, .. } => {
assert_eq!(headers.as_ref(), *response_header_no_data());
fin_received = fin;
response_header_found = true;
}
Http3ClientEvent::DataReadable { stream_id } => {
let mut buf = [0u8; 100];
let (amount, fin) = conn.read_data(now(), stream_id, &mut buf).unwrap();
assert!(fin);
fin_received = true;
assert_eq!(amount, 0);
}
_ => {}
}
}
assert!(response_header_found);
assert!(fin_received);
}
fn connect_send_and_receive_request() -> (Http3Client, Http3Server, Http3OrWebTransportStream) {
let mut hconn_c = default_http3_client();
let mut hconn_s = default_http3_server();
exchange_packets(&mut hconn_c, &mut hconn_s);
let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded);
assert!(hconn_c.events().any(authentication_needed));
hconn_c.authenticated(AuthenticationStatus::Ok, now());
exchange_packets(&mut hconn_c, &mut hconn_s);
let req = hconn_c
.fetch(
now(),
"GET",
&("https", "something.com", "/"),
&[],
Priority::default(),
)
.unwrap();
assert_eq!(req, 0);
hconn_c.stream_close_send(req).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
let request = receive_request(&mut hconn_s).unwrap();
(hconn_c, hconn_s, request)
}
#[test]
fn response_trailers1() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
send_headers(&mut request).unwrap();
request.send_data(RESPONSE_DATA).unwrap();
send_trailers(&mut request).unwrap();
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events(&mut hconn_c);
}
#[test]
fn response_trailers2() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
send_headers(&mut request).unwrap();
request.send_data(RESPONSE_DATA).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
send_trailers(&mut request).unwrap();
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events(&mut hconn_c);
}
#[test]
fn response_trailers3() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
send_headers(&mut request).unwrap();
request.send_data(RESPONSE_DATA).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
send_trailers(&mut request).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events(&mut hconn_c);
}
#[test]
fn response_trailers_no_data() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
request.send_headers(response_header_no_data()).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
send_trailers(&mut request).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events_no_data(&mut hconn_c);
}
#[test]
fn multiple_response_trailers() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
send_headers(&mut request).unwrap();
request.send_data(RESPONSE_DATA).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
send_trailers(&mut request).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
assert_eq!(send_trailers(&mut request), Err(Error::InvalidInput));
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events(&mut hconn_c);
}
#[test]
fn data_after_trailer() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
send_headers(&mut request).unwrap();
request.send_data(RESPONSE_DATA).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
send_trailers(&mut request).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
assert_eq!(request.send_data(RESPONSE_DATA), Err(Error::InvalidInput));
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events(&mut hconn_c);
}
#[test]
fn trailers_after_close() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
send_headers(&mut request).unwrap();
request.send_data(RESPONSE_DATA).unwrap();
request.stream_close_send().unwrap();
assert_eq!(send_trailers(&mut request), Err(Error::InvalidStreamId));
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events(&mut hconn_c);
}
#[test]
fn multiple_response_headers() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
request.send_headers(response_header_no_data()).unwrap();
assert_eq!(
request.send_headers(response_header_no_data()),
Err(Error::InvalidHeader)
);
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events_no_data(&mut hconn_c);
}
#[test]
fn informational_after_response_headers() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
request.send_headers(response_header_no_data()).unwrap();
assert_eq!(
send_informational_headers(&mut request),
Err(Error::InvalidHeader)
);
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events_no_data(&mut hconn_c);
}
#[test]
fn data_after_informational() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
send_informational_headers(&mut request).unwrap();
assert_eq!(request.send_data(RESPONSE_DATA), Err(Error::InvalidInput));
send_headers(&mut request).unwrap();
request.send_data(RESPONSE_DATA).unwrap();
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events(&mut hconn_c);
}
#[test]
fn non_trailers_headers_after_data() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
send_headers(&mut request).unwrap();
request.send_data(RESPONSE_DATA).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
assert_eq!(
request.send_headers(response_header_no_data()),
Err(Error::InvalidHeader)
);
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events(&mut hconn_c);
}
#[test]
fn data_before_headers() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
assert_eq!(request.send_data(RESPONSE_DATA), Err(Error::InvalidInput));
send_headers(&mut request).unwrap();
request.send_data(RESPONSE_DATA).unwrap();
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events(&mut hconn_c);
}