// This is a port of a client from `examples/start_here.rs`. Please see that example first. // Also... maybe brush up on some async tasks since we are going to need them here (there is an // example on async with inferium in `examples/going_async.rs`). // // Features `async`, `tokio-net` and `webpki-roots` dependency must be enabled for this example to // compile. We recommend enabling the `dev` feature when running this example. use std::{collections::HashMap, sync::Arc}; use tokio::net::TcpStream; use tokio_rustls::{ rustls::{ pki_types::ServerName, ClientConfig, RootCertStore }, TlsConnector, TlsStream }; use inferium::{ h1::{ ProtocolVariant, RequestHead, Response, AsyncClient }, HeaderKey, Method, TokioRustls }; async fn run_tls_handshake(raw_stream: TcpStream) -> TlsStream { let mut root_certs = RootCertStore::empty(); root_certs.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned()); let config = ClientConfig::builder() .with_root_certificates(root_certs) .with_no_client_auth(); let connector = TlsConnector::from(Arc::new(config)); let verify_server_name = ServerName::try_from("zumepro.cz").unwrap(); TlsStream::Client(connector.connect(verify_server_name, raw_stream).await.unwrap()) } #[tokio::main] async fn main() { let stream = TcpStream::connect("zumepro.cz:443").await.unwrap(); let stream = run_tls_handshake(stream).await; let conn = TokioRustls::new(stream); let mut client = AsyncClient::::new(conn); let to_send = RequestHead::new( Method::GET, "/".parse().unwrap(), ProtocolVariant::HTTP1_1, HashMap::from([ (HeaderKey::USER_AGENT, "Mozilla/5.0 (inferium)".parse().unwrap()), (HeaderKey::HOST, "zumepro.cz".parse().unwrap()), (HeaderKey::CONNECTION, "close".parse().unwrap()) ]) ); println!("----------> Sending\n\n{to_send}\n"); client.send_request(&to_send).await.unwrap(); let response = client.receive_response().await.unwrap(); let (header, body) = match response { Response::HeadersOnly(h) => (h, None), Response::WithSizedBody((_, _)) => panic!(), Response::WithChunkedBody((h, b)) => (h, Some(b)), }; println!("----------< Received\n\n{header}\n"); if let Some(mut body) = body { // Since our zumepro server sends bodies chunked - we will need to handle it. // This simple loop just collects all the chunks into the res vector. let mut res = Vec::new(); while let Some(mut chunk) = body.get_chunk_async().await.unwrap() { // Now here is a difference between sync and async. // // For easy body manipulation and no redundant trait pollution, a body within an // asynchronous stream can be sent/received using the same methods as a synchronous one, // but with the suffix `_async`. res.append(&mut chunk.recv_all_async().await.unwrap()); } println!( "----------< Body\n\n{:?}\n", std::str::from_utf8(&res).unwrap() ); } }