// Hello, and welcome to inferium. A performance-oriented small HTTP library written in Rust that // keeps you (the user) in charge. // Let's first import some necessary things. // In inferium - HashMaps are used to store uri parameters and headers. use std::collections::HashMap; // TcpStream is needed if we want to connect to the internet. use std::net::TcpStream; use inferium::{ // The h1 module contains all the protocol specific things for HTTP/1.(0/1). h1::{ // ProtocolVariant contains variants with the protocol versions supported in this module: // - HTTP/1.1 // - HTTP/1.0 ProtocolVariant, // RequestHead contains headers and the HTTP request headline (method, path, protocol). RequestHead, // Response here is a wrapper for a response that can have the following: // - Headers only // - Headers and body (with a known length or chunked) // // ! The body in the response is not yet collected. It is up to you if you wish to discard // the connection or receive and collect the response body into some structure. // // The same things here go for the Request object which is nearly the same except that the // headline contains protocol and status instead. Response, // Sync client is a stream wrapper that helps us keep track of the open connection and // perform request/response operations. // // The server equivalent is SyncServer. SyncClient }, // Header key contains various known header keys, but can also store arbitrary (unknown) header // key in the OTHER variant. HeaderKey, Method, // StdInet here is a stream wrapper that allows the TcpStream to be used by inferium. There is // also a unix socket equivalent and some asynchronous io wrappers. StdInet }; fn main() { // Let's first create a connection... nothing weird here. let conn = StdInet::new(TcpStream::connect("zumepro.cz:80").unwrap()); // And a client... let mut client = SyncClient::::new(conn); // Now let's create a request to send let to_send = RequestHead::new( // The path here is parsed into an HTTP path object (which also supports parameters) // I'm using HTTP/1.0 in this example as HTTP/1.1 automatically infers a compatibility with // chunked encoding (which I'm not even trying to handle here). Method::GET, "/".parse().unwrap(), ProtocolVariant::HTTP1_0, HashMap::from([ // All headers are HeaderKey - HeaderValue pairs. We can parse the header value into // the desired object. // // Constructing arbitrary header key is supported using the OTHER variant - however // it's not recommended as a violation of the HTTP protocol can happen. // // If you really want to construct an arbitrary header key - please carefully check // that all of the symbols are valid. (HeaderKey::USER_AGENT, "Mozilla/5.0 (inferium)".parse().unwrap()), (HeaderKey::HOST, "zumepro.cz".parse().unwrap()), ]) ); println!("----------> Sending\n\n{to_send}\n"); // Let's send the request - this is pretty straightforward. client.send_request(&to_send).unwrap(); // As is receiving a response. let response = client.receive_response().unwrap(); // Now (as we discussed earlier) - the response can have a body. // In this example we'll try to handle a basic body with a known size. let (header, body) = match response { // Extracting the headers if no body is present. Response::HeadersOnly(h) => (h, None), // Extracting both the headers and the body if body is present. Response::WithSizedBody((h, b)) => (h, Some(b)), // We will not handle chunked responses in this example. Response::WithChunkedBody((_, _)) => panic!(), }; // inferium kindly provides a simple way to print the head of a request/response. // It will be formatted pretty close to the actual protocol plaintext representation. println!("----------< Received\n\n{header}\n"); // And finally... if we have a body, we'll print it. if let Some(mut body) = body { println!( "----------< Body\n\n{:?}\n", // A body is always returned in bytes. It's up to you to decode it however you see fit. std::str::from_utf8(&mut body.recv_all().unwrap()).unwrap() ); } // And you're done. Come on... try to run it. }