use neqo_common::{event::Provider as _, header::HeadersExt as _}; use neqo_http3::{
Http3Client, Http3ClientEvent, Http3OrWebTransportStream, Http3Parameters, Http3Server,
Http3ServerEvent, Http3State, SessionAcceptAction, WebTransportEvent, WebTransportRequest,
WebTransportServerEvent,
}; use neqo_transport::{ConnectionParameters, StreamId, StreamType}; use nss::AuthenticationStatus; use test_fixture::{
CountingConnectionIdGenerator, DEFAULT_ADDR, DEFAULT_ALPN_H3, DEFAULT_KEYS,
DEFAULT_SERVER_NAME, anti_replay, exchange_packets, fixture_init, now,
};
fn connect() -> (Http3Client, Http3Server) {
fixture_init(); letmut client = Http3Client::new(
DEFAULT_SERVER_NAME,
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
DEFAULT_ADDR,
DEFAULT_ADDR,
Http3Parameters::default().webtransport(true),
now(),
)
.expect("create a default client"); letmut server = Http3Server::new(
now(),
DEFAULT_KEYS,
DEFAULT_ALPN_H3,
anti_replay(),
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
Http3Parameters::default().webtransport(true),
None,
)
.expect("create a server");
assert_eq!(client.state(), Http3State::Initializing); let out = client.process_output(now()); let out2 = client.process_output(now());
assert_eq!(client.state(), Http3State::Initializing);
_ = server.process(out.dgram(), now()); let out = server.process(out2.dgram(), now()); let out = client.process(out.dgram(), now()); let out = server.process(out.dgram(), now()); let out = client.process(out.dgram(), now()); let out = server.process(out.dgram(), now());
assert!(out.as_dgram_ref().is_none());
let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded);
assert!(client.events().any(authentication_needed));
client.authenticated(AuthenticationStatus::Ok, now());
letmut out = client.process(out.dgram(), now()).dgram(); let connected = |e| matches!(e, Http3ClientEvent::StateChange(Http3State::Connected));
assert!(client.events().any(connected));
#[test] fn wt_keepalive() { let (mut client, mut server) = connect(); let _wt_session = create_wt_session(&mut client, &mut server); // Expect client and server to send PING after half of the idle timeout in order to keep // connection alive.
assert_eq!(
client.process_output(now()).callback(),
ConnectionParameters::DEFAULT_IDLE_TIMEOUT / 2
);
assert_eq!(
server.process_output(now()).callback(),
ConnectionParameters::DEFAULT_IDLE_TIMEOUT / 2
);
}
// Server accepts the session, but hold back the UDP datagram. let wt_server_session = server
.events()
.find_map(|event| { iflet Http3ServerEvent::WebTransport(WebTransportServerEvent::NewSession {
session,
..
}) = event
{
Some(session)
} else {
None
}
})
.expect("Should receive WebTransport session request");
wt_server_session
.response(&SessionAcceptAction::Accept, now)
.unwrap(); let server_accept_dgram = server
.process_output(now)
.dgram()
.expect("Expected server to produce session acceptance datagram");
assert_eq!(server.process_output(now).dgram(), None);
// Server creates a stream, but hold back the UDP datagram. let wt_server_stream = wt_server_session.create_stream(StreamType::UniDi).unwrap();
assert_eq!(wt_server_stream.send_data(&[42], now).unwrap(), 1); let server_stream_dgram = server
.process_output(now)
.dgram()
.expect("Expected server to produce a datagram with stream data");
if in_order { // Client processes the server UDP datagrams in order, i.e. the // session acceptance before the stream data.
client.process_input(server_accept_dgram, now);
assert!(
matches!(
client.events().next(),
Some(Http3ClientEvent::WebTransport(
WebTransportEvent::NewSession { .. }
))
), "Should receive session acceptance event"
);
client.process_input(server_stream_dgram, now);
} else { // Client processes the server UDP datagrams out-of-order, i.e. the // stream data before the session acceptance.
client.process_input(server_stream_dgram, now);
client.process_input(server_accept_dgram, now);
assert!(
matches!(
client.events().next(),
Some(Http3ClientEvent::WebTransport(
WebTransportEvent::NewSession { .. }
))
), "Should receive session acceptance event"
);
}
// Server accepts the session, and sends a WebTransport datagram, all in the same UDP datagram. let wt_server_session = server
.events()
.find_map(|event| { iflet Http3ServerEvent::WebTransport(WebTransportServerEvent::NewSession {
session,
..
}) = event
{
Some(session)
} else {
None
}
})
.expect("Should receive WebTransport session request");
wt_server_session
.response(&SessionAcceptAction::Accept, now)
.unwrap();
wt_server_session.send_datagram(b"PING", None, now).unwrap(); let accept_and_wt_datagram = server
.process_output(now)
.dgram()
.expect("Expected server to produce session acceptance datagram");
assert_eq!(server.process_output(now).dgram(), None);
// Client processes the server's UDP datagram, first the session acceptance, // then the WebTransport datagram.
client.process_input(accept_and_wt_datagram, now);
assert!(
matches!(
client.events().next(),
Some(Http3ClientEvent::WebTransport(
WebTransportEvent::NewSession { .. }
))
), "Should receive session acceptance event"
);
assert!(
matches!(
client.events().next(),
Some(Http3ClientEvent::WebTransport(
WebTransportEvent::Datagram{ session_id, datagram }
)) if session_id == wt_server_session.stream_id() && &datagram == b"PING",
), "Should receive datagram"
);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.