HTTP/2

Implementation of RFC7541 and RFC9113. In other words, a low-level HTTP.

Passes the hpack-test-case and the h2spec test suites. Due to official deprecation, server push and prioritization are not supported.

Activation feature is called http2.

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, NoStdRng, Uri},
};

#[tokio::main]
async fn main() -> wtx::Result<()> {
  let uri = Uri::new("http://www.example.com");
  let (frame_reader, mut http2) = Http2Tokio::connect(
    Http2Buffer::new(NoStdRng::default()),
    Http2Params::default(),
    TcpStream::connect(uri.hostname_with_implied_port()).await?.into_split(),
  )
  .await?;
  let _jh = tokio::spawn(frame_reader);
  let rrb = ReqResBuffer::default();
  let mut stream = http2.stream().await?;
  stream.send_req(Request::http2(Method::Get, b"Hello!"), &uri.to_ref()).await?;
  let (res_rrb, opt) = stream.recv_res(rrb).await?;
  let _status_code = opt.unwrap();
  println!("{}", from_utf8_basic(&res_rrb.data)?);
  http2.send_go_away(Http2ErrorCode::NoError).await;
  Ok(())
}

Server Example

//! Serves requests using low-level HTTP/2 resources along side self-made certificates.

extern crate tokio;
extern crate wtx;
extern crate wtx_instances;

use wtx::{
  http::{LowLevelServer, ReqResBuffer, Request, Response, StatusCode},
  http2::{Http2Buffer, Http2Params},
  misc::{StdRng, TokioRustlsAcceptor},
};

#[tokio::main]
async fn main() -> wtx::Result<()> {
  LowLevelServer::tokio_http2(
    &wtx_instances::host_from_args(),
    || Ok(((), Http2Buffer::new(StdRng::default()), Http2Params::default())),
    |error| eprintln!("{error}"),
    handle,
    || Ok(((), ReqResBuffer::default())),
    (
      || {
        TokioRustlsAcceptor::without_client_auth()
          .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 handle(
  _: (),
  _: (),
  mut req: Request<ReqResBuffer>,
) -> Result<Response<ReqResBuffer>, wtx::Error> {
  req.rrd.clear();
  Ok(req.into_response(StatusCode::Ok))
}