102 lines
4.5 KiB
Rust
102 lines
4.5 KiB
Rust
// 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::<StdInet>::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.
|
|
}
|