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 neqo_common::{event::Provider as _, header::HeadersExt as _};
use neqo_http3::{Error, Header, Http3ClientEvent, Http3ServerEvent, Priority};
use test_fixture::{default_http3_client, default_http3_server, exchange_packets, now};
const AUTHORITY: &str = "something.com";
#[test]
fn classic_connect() {
// Connect a client and a server.
let mut client = default_http3_client();
let mut server = default_http3_server();
let out = test_fixture::connect_peers(&mut client, &mut server);
assert_eq!(server.process(out, now()).dgram(), None);
// Ignore all events so far.
drop(server.events());
client.events();
// Have client send a CONNECT request.
let stream_id = client
.connect(now(), AUTHORITY, &[], Priority::default())
.unwrap();
client.send_data(stream_id, b"ping").unwrap();
exchange_packets(&mut client, &mut server, false, None);
let Some(Http3ServerEvent::Headers { headers, .. }) = server.next_event() else {
panic!("Expected Headers event");
};
assert_eq!(
headers.find_header(":method").map(Header::value),
Some("CONNECT")
);
assert_eq!(
headers.find_header(":authority").map(Header::value),
Some(AUTHORITY)
);
// > The :scheme and :path pseudo-header fields are omitted
//
assert_eq!(headers.find_header(":scheme"), None);
assert_eq!(headers.find_header(":path"), None);
let Some(Http3ServerEvent::Data { stream, data, .. }) = server.next_event() else {
panic!("Expected Data event");
};
assert_eq!(stream.stream_id(), stream_id);
assert_eq!(data, b"ping");
// Have server respond.
stream
.send_headers(&[Header::new(":status", "200")])
.unwrap();
stream.send_data(b"pong").unwrap();
exchange_packets(&mut client, &mut server, false, None);
// Ignore some client events.
let mut next_event = None;
while let Some(event) = client.next_event() {
match event {
Http3ClientEvent::StateChange { .. }
| Http3ClientEvent::RequestsCreatable
| Http3ClientEvent::ResumptionToken { .. }
| Http3ClientEvent::DataWritable { .. } => {}
e => {
next_event = Some(e);
break;
}
}
}
let Http3ClientEvent::HeaderReady {
stream_id, headers, ..
} = next_event.unwrap()
else {
unreachable!()
};
assert_eq!(stream_id, stream.stream_id());
assert_eq!(
headers.find_header(":status").map(Header::value),
Some("200")
);
let Some(Http3ClientEvent::DataReadable { stream_id }) = client.next_event() else {
unreachable!()
};
assert_eq!(stream_id, stream.stream_id());
let mut data = vec![0; 4];
let (amount, _fin) = client.read_data(now(), stream_id, &mut data).unwrap();
assert_eq!(&data[..amount], b"pong");
}
#[test]
fn classic_connect_via_fetch_panics_in_debug() {
let mut client = default_http3_client();
let mut server = default_http3_server();
let out = test_fixture::connect_peers(&mut client, &mut server);
assert_eq!(server.process(out, now()).dgram(), None);
let res = client.fetch(
now(),
"CONNECT",
("https", AUTHORITY, "/"),
&[],
Priority::default(),
);
assert_eq!(res, Err(Error::InvalidInput));
}