HTTP/2
Implementation of RFC7541 and RFC9113. HTTP/2 is the second major version of the Hypertext Transfer Protocol, introduced in 2015 to improve web performance, it addresses limitations of HTTP/1.1 while maintaining backwards compatibility.
Passes the hpack-test-case
and the h2spec
test suites. Due to official deprecation, prioritization is not supported and due to the lack of third-party support, server-push is also not supported.
To use this functionality, it is necessary to activate the http2
feature.
Client Example
//! Fetches an URI using low-level HTTP/2 resources. //! //! This snippet requires ~25 dependencies and has an optimized binary size of ~700K. extern crate tokio; extern crate wtx; extern crate wtx_instances; use tokio::net::TcpStream; use wtx::{ http::{Method, ReqResBuffer, Request}, http2::{Http2Buffer, Http2ErrorCode, Http2Params, Http2Tokio}, misc::{from_utf8_basic, simple_seed, Uri, Xorshift64}, }; #[tokio::main] async fn main() -> wtx::Result<()> { let uri = Uri::new("http://www.example.com"); let (frame_reader, mut http2) = Http2Tokio::connect( Http2Buffer::new(Xorshift64::from(simple_seed())), Http2Params::default(), TcpStream::connect(uri.hostname_with_implied_port()).await?.into_split(), ) .await?; let _jh = tokio::spawn(frame_reader); let rrb = ReqResBuffer::empty(); let mut stream = http2.stream().await?; stream.send_req(Request::http2(Method::Get, b"Hello!"), &uri.to_ref()).await?; let (_, res_rrb) = stream.recv_res(rrb).await?; stream.common().clear(false).await?; println!("{}", from_utf8_basic(&res_rrb.body)?); http2.send_go_away(Http2ErrorCode::NoError).await; Ok(()) }
Server Example
//! HTTP/2 server that uses optioned parameters. extern crate tokio; extern crate tokio_rustls; extern crate wtx; extern crate wtx_instances; use tokio::{io::WriteHalf, net::TcpStream}; use tokio_rustls::server::TlsStream; use wtx::{ http::{ is_web_socket_handshake, AutoStream, ManualServerStreamTokio, OperationMode, OptionedServer, ReqResBuffer, Response, StatusCode, }, http2::{Http2Buffer, Http2Params, WebSocketOverStream}, misc::{simple_seed, TokioRustlsAcceptor, Vector, Xorshift64}, web_socket::{Frame, OpCode}, }; #[tokio::main] async fn main() -> wtx::Result<()> { OptionedServer::http2_tokio( &wtx_instances::host_from_args(), auto, || { Ok(( (), Http2Buffer::new(Xorshift64::from(simple_seed())), Http2Params::default() .set_enable_connect_protocol(true) .set_max_hpack_len((128 * 1024, 128 * 1024)), )) }, |error| eprintln!("{error}"), manual, |_, protocol, req, _| { Ok(( (), if is_web_socket_handshake(&mut req.rrd.headers, req.method, protocol) { OperationMode::Manual } else { OperationMode::Auto }, )) }, || Ok((Vector::new(), ReqResBuffer::empty())), ( || { TokioRustlsAcceptor::without_client_auth() .http2() .build_with_cert_chain_and_priv_key(wtx_instances::CERT, wtx_instances::KEY) }, |acceptor| acceptor.clone(), |acceptor, stream| async move { Ok(tokio::io::split(acceptor.accept(stream).await?)) }, ), ) .await } async fn auto( _: (), mut ha: AutoStream<(), Vector<u8>>, ) -> Result<Response<ReqResBuffer>, wtx::Error> { ha.req.rrd.clear(); Ok(ha.req.into_response(StatusCode::Ok)) } async fn manual( _: (), mut hm: ManualServerStreamTokio<(), Http2Buffer, Vector<u8>, WriteHalf<TlsStream<TcpStream>>>, ) -> Result<(), wtx::Error> { let rng = Xorshift64::from(simple_seed()); hm.req.rrd.headers.clear(); let mut wos = WebSocketOverStream::new(&hm.req.rrd.headers, false, rng, hm.stream).await?; loop { let mut frame = wos.read_frame(&mut hm.stream_aux).await?; match (frame.op_code(), frame.text_payload()) { (_, Some(elem)) => println!("{elem}"), (OpCode::Close, _) => break, _ => {} } wos.write_frame(&mut Frame::new_fin(OpCode::Text, frame.payload_mut())).await?; } wos.close().await?; Ok(()) }