diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.rs | 71 |
1 files changed, 38 insertions, 33 deletions
diff --git a/src/main.rs b/src/main.rs index a3da041..6423ad7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ use core::fmt; use std::{ - borrow::{Borrow, Cow}, - clone, + borrow::Cow, collections::HashMap, io::{self, BufRead, BufReader, BufWriter, Write}, net::{IpAddr, SocketAddr}, @@ -34,6 +33,8 @@ fn main() { future::block_on(arxc.run(async move { async_main(moving_arxc, moving_arcdb).await })); } +/// This function is what's run during the lifetime of the program by our +/// [LocalExecutor] async fn async_main(ex: Arc<LocalExecutor<'_>>, db: Arc<RwLock<Database>>) { let addr = SocketAddr::from(([0, 0, 0, 0], 12345)); let listen = TcpListener::bind(addr).await.unwrap(); @@ -47,6 +48,7 @@ async fn async_main(ex: Arc<LocalExecutor<'_>>, db: Arc<RwLock<Database>>) { } } +/// Handles a single connection from a client. async fn handle_request(mut stream: TcpStream, caddr: SocketAddr, db: Arc<RwLock<Database>>) { let mut buffer = vec![0; 1024]; let mut data_end = 0; @@ -102,6 +104,8 @@ async fn handle_request(mut stream: TcpStream, caddr: SocketAddr, db: Arc<RwLock } } +/// Form a simple HTTP/1.1 error response with no body and the specified status +/// code and message. fn error(code: u16, msg: &'static str) -> Vec<u8> { format!( "HTTP/1.1 {code} {msg}\n\ @@ -113,6 +117,12 @@ fn error(code: u16, msg: &'static str) -> Vec<u8> { .to_vec() } +/// Get the request header with the case-insensetive `key`. +/// +/// Returns: +/// - Ok(None) the header was not present +/// - Ok(Some(value)) the header value, interpreted as a utf8 string +/// - Err(Utf8Error) if the header value could not be parsed as a utf8 string fn get_header<'h>( headers: &'h [httparse::Header<'h>], key: &'static str, @@ -124,15 +134,13 @@ fn get_header<'h>( .transpose() } +/// Small struct containing details from the request we might want in the +/// response struct Response { /// IP the request came from. This is very important in our application. client_addr: IpAddr, /// HTTP minor version. Read this from the request so we can respond properly. http_minor: u8, - /// Response status code - status: u16, - /// Response status message - message: &'static str, /// Indicates if this is a GET or a HEAD request is_head: bool, } @@ -154,9 +162,6 @@ async fn form_response<'req>( }; let minor = request.version.unwrap(); - let status = 200; - let message = "Gotcha"; - let requested_type = match get_header(request.headers, "content-type") { Err(e) => return e, Ok(None) | Ok(Some("text/plain")) => ContentType::Plain, @@ -167,8 +172,6 @@ async fn form_response<'req>( let response = Response { client_addr: caddr.ip(), http_minor: minor, - status, - message, is_head, }; @@ -221,12 +224,12 @@ async fn form_response<'req>( } } +/// Form a `200 Gotcha` response containing the client's address and with the +/// correct content-type. fn make_ip_response(requested_type: ContentType, response: Response) -> Vec<u8> { let Response { client_addr, http_minor, - status, - message, is_head, } = response; @@ -238,7 +241,7 @@ fn make_ip_response(requested_type: ContentType, response: Response) -> Vec<u8> let length = body.len(); // And now we form the request :D - let mut response = format!("HTTP/1.{http_minor} {status} {message}\n"); + let mut response = format!("HTTP/1.{http_minor} 200 Gotcha\n"); macro_rules! header { ($content:expr) => { @@ -259,6 +262,7 @@ fn make_ip_response(requested_type: ContentType, response: Response) -> Vec<u8> response.into_bytes() } +/// Possible responses when a client includes an `Authorization` header enum AuthResponse { /// Returned when the key has never been seen before. NewAuth, @@ -305,20 +309,6 @@ async fn handle_auth( } } -enum ContentType { - Plain, - Json, -} - -impl fmt::Display for ContentType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - ContentType::Plain => write!(f, "text/plain"), - ContentType::Json => write!(f, "application/json"), - } - } -} - #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct AuthKey<'a>(Cow<'a, str>); const BASE64: &'static str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890+/="; @@ -434,11 +424,19 @@ impl Database { } } -#[derive(Clone, Copy, Debug)] -enum DatabaseMalformation { - AuthKey, - IpAddr, - Line, +/// Content types we know about +enum ContentType { + Plain, + Json, +} + +impl fmt::Display for ContentType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ContentType::Plain => write!(f, "text/plain"), + ContentType::Json => write!(f, "application/json"), + } + } } #[derive(Debug)] @@ -475,3 +473,10 @@ impl RuntimeError { } } } + +#[derive(Clone, Copy, Debug)] +enum DatabaseMalformation { + AuthKey, + IpAddr, + Line, +} |