diff --git a/src/main.rs b/src/main.rs index ab944f5..6d308ec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,10 +31,11 @@ fn main() { let mut args = env::args(); args.next(); let address = args.next().unwrap_or("127.0.0.1:8080".to_string()); - start_server(path, &address); + let password = args.next(); + start_server(path, &address, password); } -fn start_server(path: PathBuf, address: &str) { +fn start_server(path: PathBuf, address: &str, password: Option) { let listener = TcpListener::bind(address).expect("Invalid bind address!"); eprintln!("Strated server!"); @@ -58,7 +59,8 @@ fn start_server(path: PathBuf, address: &str) { let context = context.clone(); let path = path.clone(); - pool.execute(move || handle_connection(context, path, stream)); + let password = password.clone(); + pool.execute(move || handle_connection(context, path, stream, password.as_deref())); } } @@ -139,7 +141,12 @@ struct Context { infos: HashMap, Arc>>, } -fn handle_connection(context: Arc>, path: PathBuf, mut stream: TcpStream) { +fn handle_connection( + context: Arc>, + path: PathBuf, + mut stream: TcpStream, + password: Option<&str>, +) { let Some(request) = Request::from(&stream) else { eprintln!("Invalid request!"); return; @@ -151,12 +158,86 @@ fn handle_connection(context: Arc>, path: PathBuf, mut stream: Tc eprintln!("- Path: {}", request.path); eprintln!("- Version: {}", request.version); eprintln!("- Headers:"); - for header in request.headers { + for header in &request.headers { eprintln!(" - {header}"); } eprintln!("- Body: {}", request.body); eprintln!(); + #[derive(PartialEq, Eq)] + enum Access { + None, + Full, + } + + let mut access = Access::None; + + let mut cookie = None; + + if let Some(password) = password { + for entry in request.body.split('&') { + let Some((key, input)) = entry.split_once('=') else { + continue; + }; + + if key == "password" && input == password { + access = Access::Full; + cookie = Some(password); + break; + } + } + + if access == Access::None { + for header in request.headers { + let Some((key, values)) = header.split_once(':') else { + continue; + }; + let key = key.trim(); + + if key != "Cookie" { + continue; + } + + for cookie in values.split(',') { + let cookie = cookie.trim(); + let Some((name, state)) = cookie.split_once('=') else { + continue; + }; + if name != "password" { + continue; + } + + if state != password { + continue; + } + + access = Access::Full; + + break; + } + } + } + + if access == Access::None { + let _ = write!(stream, "HTTP/1.1 200 OK\r\n"); + let _ = write!(stream, "Content-Type: text/html; charset=\"utf-8\"\r\n"); + let _ = write!(stream, "\r\n"); + + let html = html! { + h1 { "Authentification required" } + form method="POST" { + input type="password" name="password" placeholder="Password"; + br; + input type="submit" value="Authenticate!"; + } + }; + + let _ = stream.write_all(html.into_string().as_bytes()); + + return; + } + } + let (mut relative_path, _) = request .path .split_once('?') @@ -261,6 +342,7 @@ fn handle_connection(context: Arc>, path: PathBuf, mut stream: Tc file_paths, partial, start_level, + cookie, ) } @@ -301,6 +383,7 @@ fn handle_relative_connection( file_paths: DocumentPaths, partial: Option, start_level: usize, + cookie: Option<&str>, ) { let mut name = None; let mut text = None; @@ -374,6 +457,10 @@ fn handle_relative_connection( let _ = write!(stream, "HTTP/1.1 200 OK\r\n"); let _ = write!(stream, "Content-Type: text/html; charset=\"utf-8\"\r\n"); + if let Some(password) = cookie { + let _ = write!(stream, "Set-Cookie: password={password}\r\n"); + } + let _ = write!(stream, "\r\n"); let parent_path = relative_path