use base64::prelude::*; use neqo_bin::server::{HttpServer, ServerRunner}; use neqo_common::{event::Provider, qdebug, qtrace, Datagram, Header}; use neqo_crypto::{generate_ech_keys, init_db, AllowZeroRtt, AntiReplay}; use neqo_http3::{
Error, Http3OrWebTransportStream, Http3Parameters, Http3Server, Http3ServerEvent,
WebTransportRequest, WebTransportServerEvent, WebTransportSessionAcceptAction,
}; use neqo_transport::server::ConnectionRef; use neqo_transport::{
ConnectionEvent, ConnectionParameters, Output, RandomConnectionIdGenerator, StreamType,
}; use std::env;
use std::cell::RefCell; use std::io; use std::path::PathBuf; use std::process::exit; use std::rc::Rc; use std::thread; use std::time::{Duration, Instant};
use cfg_if::cfg_if;
cfg_if! { if#[cfg(not(target_os = "android"))] { use std::sync::mpsc::{channel, Receiver, TryRecvError}; use hyper::body::HttpBody; use hyper::header::{HeaderName, HeaderValue}; use hyper::{Body, Client, Method, Request};
}
}
use std::cmp::min; use std::collections::hash_map::DefaultHasher; use std::collections::HashMap; use std::collections::HashSet; use std::hash::{Hash, Hasher}; use std::mem; use std::net::SocketAddr;
const HTTP_RESPONSE_WITH_WRONG_FRAME: &[u8] = &[ 0x01, 0x06, 0x00, 0x00, 0xd9, 0x54, 0x01, 0x37, // headers 0x0, 0x3, 0x61, 0x62, 0x63, // the first data frame 0x3, 0x1, 0x5, // a cancel push frame that is not allowed
]; struct Http3TestServer {
server: Http3Server, // This a map from a post request to amount of data ithas been received on the request. // The respons will carry the amount of data received.
posts: HashMap<Http3OrWebTransportStream, usize>,
responses: HashMap<Http3OrWebTransportStream, Vec<u8>>,
current_connection_hash: u64,
sessions_to_close: HashMap<Instant, Vec<WebTransportRequest>>,
sessions_to_create_stream: Vec<(WebTransportRequest, StreamType, Option<Vec<u8>>)>,
webtransport_bidi_stream: HashSet<Http3OrWebTransportStream>,
wt_unidi_conn_to_stream: HashMap<ConnectionRef, Http3OrWebTransportStream>,
wt_unidi_echo_back: HashMap<Http3OrWebTransportStream, Http3OrWebTransportStream>,
received_datagram: Option<Vec<u8>>,
}
fn maybe_close_session(&mutself) { let now = Instant::now(); for (expires, sessions) inself.sessions_to_close.iter_mut() { if *expires <= now { for s in sessions.iter_mut() {
mem::drop(s.close_session(0, ""));
}
}
} self.sessions_to_close.retain(|expires, _| *expires >= now);
}
fn maybe_create_wt_stream(&mutself) { ifself.sessions_to_create_stream.is_empty() { return;
} let tuple = self.sessions_to_create_stream.pop().unwrap(); let session = tuple.0; let wt_server_stream = session.create_stream(tuple.1).unwrap(); if tuple.1 == StreamType::UniDi { iflet Some(data) = tuple.2 { self.new_response(wt_server_stream, data);
} else { // relaying Http3ServerEvent::Data to uni streams // slows down netwerk/test/unit/test_webtransport_simple.js // to the point of failure. Only do so when necessary. self.wt_unidi_conn_to_stream
.insert(wt_server_stream.conn.clone(), wt_server_stream);
}
} else { iflet Some(data) = tuple.2 { self.new_response(wt_server_stream, data);
} else { self.webtransport_bidi_stream.insert(wt_server_stream);
}
}
}
}
impl HttpServer for Http3TestServer { fn process(&mutself, dgram: Option<Datagram<&[u8]>>, now: Instant) -> Output { let output = self.server.process(dgram, now);
let output = ifself.sessions_to_close.is_empty() {
output
} else { // In case there are pending sessions to close, use a shorter // timeout to make process_events() to be called earlier. const MIN_INTERVAL: Duration = Duration::from_millis(100);
match output {
Output::None => Output::Callback(MIN_INTERVAL),
o @ Output::Datagram(_) => o,
Output::Callback(d) => Output::Callback(min(d, MIN_INTERVAL)),
}
};
// Some responses do not have content-type. This is on purpose to exercise // UnknownDecoder code. let default_ret = b"Hello World".to_vec(); let default_headers = vec![
Header::new(":status", "200"),
Header::new("cache-control", "no-cache"),
Header::new("content-length", default_ret.len().to_string()),
Header::new( "x-http3-conn-hash", self.current_connection_hash.to_string(),
),
];
// echo unidirectional input to back to client // need to close or we hang ifself.wt_unidi_echo_back.contains_key(&stream) { let echo_back = self.wt_unidi_echo_back.remove(&stream).unwrap();
echo_back.send_data(&data).unwrap();
echo_back.stream_close_send().unwrap(); break;
}
impl HttpServer for Http3ProxyServer { fn process(&mutself, dgram: Option<Datagram<&[u8]>>, now: Instant) -> Output { let output = self.server.process(dgram, now);
#[cfg(not(target_os = "android"))] let output = ifself.response_to_send.is_empty() {
output
} else { // In case there are pending responses to send, make sure a reasonable // callback is returned. const MIN_INTERVAL: Duration = Duration::from_millis(100);
match output {
Output::None => Output::Callback(MIN_INTERVAL),
o @ Output::Datagram(_) => o,
Output::Callback(d) => Output::Callback(min(d, MIN_INTERVAL)),
}
};
let socket = match neqo_bin::udp::Socket::bind(&addr) {
Err(err) => {
eprintln!("Unable to bind UDP socket: {}", err);
exit(1)
}
Ok(s) => s,
};
let local_addr = match socket.local_addr() {
Err(err) => {
eprintln!("Socket local address not bound: {}", err);
exit(1)
}
Ok(s) => s,
};
let anti_replay = AntiReplay::new(Instant::now(), Duration::from_secs(10), 7, 14)
.expect("unable to setup anti-replay"); let cid_mgr = Rc::new(RefCell::new(RandomConnectionIdGenerator::new(10)));
let server: Box<dyn HttpServer> = match server_type {
ServerType::Http3 => Box::new(Http3TestServer::new(
neqo_http3::Http3Server::new(
Instant::now(),
&[" HTTP2 Test Cert"],
PROTOCOLS,
anti_replay,
cid_mgr,
Http3Parameters::default()
.max_table_size_encoder(MAX_TABLE_SIZE)
.max_table_size_decoder(MAX_TABLE_SIZE)
.max_blocked_streams(MAX_BLOCKED_STREAMS)
.webtransport(true)
.connection_parameters(ConnectionParameters::default().datagram_size(1200)),
None,
)
.expect("We cannot make a server!"),
)),
ServerType::Http3Fail => Box::new(Server(
neqo_transport::server::Server::new(
Instant::now(),
&[" HTTP2 Test Cert"],
PROTOCOLS,
anti_replay, Box::new(AllowZeroRtt {}),
cid_mgr,
ConnectionParameters::default(),
)
.expect("We cannot make a server!"),
)),
ServerType::Http3NoResponse => Box::new(NonRespondingServer::default()),
ServerType::Http3Ech => { letmut server = Box::new(Http3TestServer::new(
neqo_http3::Http3Server::new(
Instant::now(),
&[" HTTP2 Test Cert"],
PROTOCOLS,
anti_replay,
cid_mgr,
Http3Parameters::default()
.max_table_size_encoder(MAX_TABLE_SIZE)
.max_table_size_decoder(MAX_TABLE_SIZE)
.max_blocked_streams(MAX_BLOCKED_STREAMS),
None,
)
.expect("We cannot make a server!"),
)); letrefmut unboxed_server = (*server).server; let (sk, pk) = generate_ech_keys().unwrap();
unboxed_server
.enable_ech(ECH_CONFIG_ID, ECH_PUBLIC_NAME, &sk, &pk)
.expect("unable to enable ech");
ech_config = Some(Vec::from(unboxed_server.ech_config()));
server
}
ServerType::Http3Proxy => { let server_config = if env::var("MOZ_HTTP3_MOCHITEST").is_ok() {
("mochitest-cert", 8888)
} else {
(" HTTP2 Test Cert", -1)
}; let server = Box::new(Http3ProxyServer::new(
neqo_http3::Http3Server::new(
Instant::now(),
&[server_config.0],
PROTOCOLS,
anti_replay,
cid_mgr,
Http3Parameters::default()
.max_table_size_encoder(MAX_TABLE_SIZE)
.max_table_size_decoder(MAX_TABLE_SIZE)
.max_blocked_streams(MAX_BLOCKED_STREAMS)
.webtransport(true)
.connection_parameters(ConnectionParameters::default().datagram_size(1200)),
None,
)
.expect("We cannot make a server!"),
server_config.1,
));
server
}
};
let args: Vec<String> = env::args().collect(); if args.len() < 2 {
eprintln!("Wrong arguments.");
exit(1)
}
// Read data from stdin and terminate the server if EOF is detected, which // means that runxpcshelltests.py ended without shutting down the server.
thread::spawn(|| loop { letmut buffer = String::new(); match io::stdin().read_line(&mut buffer) {
Ok(n) => { if n == 0 {
exit(0);
}
}
Err(_) => {
exit(0);
}
}
});
init_db(PathBuf::from(args[1].clone())).unwrap();
let local = tokio::task::LocalSet::new(); letmut hosts = vec![]; letmut ech_config = None;
let proxy_port = match env::var("MOZ_HTTP3_PROXY_PORT") {
Ok(val) => val.parse::<u16>().unwrap(),
_ => 0,
};
// Work around until we can use raw-dylibs. #[cfg_attr(target_os = "windows", link(name = "runtimeobject"))] extern"C" {} #[cfg_attr(target_os = "windows", link(name = "propsys"))] extern"C" {}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.28 Sekunden
(vorverarbeitet am 2026-06-19)
¤
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.