From 7bf68725dbf7cc3bfb6ef904778fc0d50fadf4e2 Mon Sep 17 00:00:00 2001 From: yggverse Date: Sat, 22 Feb 2025 08:21:10 +0200 Subject: [PATCH] update handlers --- src/main.rs | 268 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 155 insertions(+), 113 deletions(-) diff --git a/src/main.rs b/src/main.rs index 6880cab..5ac2040 100644 --- a/src/main.rs +++ b/src/main.rs @@ -55,11 +55,11 @@ fn handle(argument: Arc, peer: SocketAddr, stream: &mut TlsStream println!("[{}] [warning] [{peer}] Connection closed by peer", now()), + Ok(0) => println!("[{}] [warning] [{peer}] Peer closed connection", now()), Ok(s) => match Request::from_bytes(&input[..s]) { Ok(request) => match request { - Request::Gemini(this) => handle_gemini(this, argument, peer, stream), - Request::Titan(this) => handle_titan(this, argument, peer, stream), + Request::Gemini(this) => gemini(this, argument, peer, stream), + Request::Titan(this) => titan(this, argument, peer, stream), }, Err(e) => send( &response::failure::temporary::General { @@ -87,14 +87,14 @@ fn handle(argument: Arc, peer: SocketAddr, stream: &mut TlsStream, peer: SocketAddr, stream: &mut TlsStream, ) { use titanite::*; - match storage::Item::from_url(&gemini.url.as_str(), &argument.directory) { + match storage::Item::from_url(gemini.url.as_str(), &argument.directory) { Ok(item) => send( &response::success::Default { mime: "text/gemini".to_string(), @@ -121,7 +121,7 @@ fn handle_gemini( } } -fn handle_titan( +fn titan( titan: titanite::request::Titan, argument: Arc, peer: SocketAddr, @@ -134,143 +134,185 @@ fn handle_titan( let mut input = vec![0; argument.chunk]; match stream.read(&mut input) { Ok(0) => { - println!("[{}] [warning] [{peer}] Connection closed by peer", now()); + println!("[{}] [warning] [{peer}] Peer closed connection", now()); if let Err(e) = tmp.delete() { println!("[{}] [error] [{peer}] {e}", now()); } break; } - Ok(l) => match tmp.file.write(&input[..l]) { - Ok(s) => { - total += s; - if s != l { - if let Err(e) = tmp.delete() { - println!("[{}] [error] [{peer}] {e}", now()); - } - const MESSAGE: &str = "File sizes mismatch"; - return send( - &response::failure::temporary::General { - message: Some(MESSAGE.to_string()), - } - .into_bytes(), - stream, - |result| match result { - Ok(()) => println!("[{}] [error] [{peer}] {MESSAGE}", now()), - Err(e) => { - println!("[{}] [error] [{peer}] {e}", now()) - } - }, - ); + Ok(read) => { + total += read; + + // validate server-side limits + if argument.size.is_some_and(|limit| total > limit) { + if let Err(e) = tmp.delete() { + println!("[{}] [error] [{peer}] {e}", now()); } - // validate server-side limits - if argument.size.is_some_and(|limit| total > limit) { - if let Err(e) = tmp.delete() { - println!("[{}] [error] [{peer}] {e}", now()); + const MESSAGE: &str = "Allowed max length limit reached"; + return send( + &response::failure::permanent::BadRequest { + message: Some(MESSAGE.to_string()), } - const MESSAGE: &str = "Allowed max length limit reached"; - return send( - &response::failure::permanent::BadRequest { - message: Some(MESSAGE.to_string()), - } - .into_bytes(), - stream, - |result| match result { - Ok(()) => println!("[{}] [warning] [{peer}] {MESSAGE}", now()), - Err(e) => { - println!("[{}] [error] [{peer}] {e}", now()) - } - }, - ); + .into_bytes(), + stream, + |result| match result { + Ok(()) => println!("[{}] [warning] [{peer}] {MESSAGE}", now()), + Err(e) => println!("[{}] [error] [{peer}] {e}", now()), + }, + ); + } + + // validate client-side limits (from header) + if titan.size > total { + if let Err(e) = tmp.delete() { + println!("[{}] [error] [{peer}] {e}", now()); } - // all expected data received - if titan.size >= total { - // validate client-side limits - if titan.size > total { + const MESSAGE: &str = "Data size mismatch header declaration"; + return send( + &response::failure::permanent::BadRequest { + message: Some(MESSAGE.to_string()), + } + .into_bytes(), + stream, + |result| match result { + Ok(()) => println!("[{}] [warning] [{peer}] {MESSAGE}", now()), + Err(e) => println!("[{}] [error] [{peer}] {e}", now()), + }, + ); + } + + // begin chunk recording into the temporary file + match tmp.file.write(&input[..read]) { + Ok(write) => { + // validate file bytes recorded match stream bytes received + if write != read { if let Err(e) = tmp.delete() { println!("[{}] [error] [{peer}] {e}", now()); } - const MESSAGE: &str = "Data size mismatch header declaration"; + const MESSAGE: &str = "File size mismatch"; return send( - &response::failure::permanent::BadRequest { + &response::failure::temporary::General { message: Some(MESSAGE.to_string()), } .into_bytes(), stream, |result| match result { Ok(()) => { - println!("[{}] [warning] [{peer}] {MESSAGE}", now()) + println!("[{}] [error] [{peer}] {MESSAGE}", now()) } Err(e) => println!("[{}] [error] [{peer}] {e}", now()), }, ); } - // @TODO detect/validate/cache mime based on data received - // success - match tmp.commit() { - Ok(pmt) => send( - &response::redirect::Permanent { - target: match argument.redirect { - Some(ref target) => format!( - "{}/{}", - target.trim_end_matches("/"), - pmt.to_uri(&argument.directory) - ), - None => format!( - "gemini://{}/{}", - argument.bind, - pmt.to_uri(&argument.directory) - ), - }, - } - .into_bytes(), - stream, - |result| match result { - Ok(()) => println!( - "[{}] [info] [{peer}] Data saved to {}", - now(), - pmt.path.to_string_lossy() - ), - Err(e) => println!("[{}] [warning] [{peer}] {e}", now()), - }, - ), - Err((tmp, e)) => send( - &response::failure::temporary::General { - message: Some("Internal server error".to_string()), - } - .into_bytes(), - stream, - |result| { - match result { - Ok(()) => { - println!("[{}] [warning] [{peer}] {e}", now()) - } - Err(e) => println!("[{}] [error] [{peer}] {e}", now()), - }; - if let Err(e) = tmp.delete() { - println!("[{}] [error] [{peer}] {e}", now()); + + // all data received + if titan.size >= total { + // @TODO detect/validate/cache mime based on data received + // success + return match tmp.commit() { + Ok(pmt) => send( + &response::redirect::Permanent { + target: match argument.redirect { + Some(ref target) => format!( + "{}/{}", + target.trim_end_matches("/"), + pmt.to_uri(&argument.directory) + ), + None => format!( + "gemini://{}/{}", + argument.bind, + pmt.to_uri(&argument.directory) + ), + }, } - }, - ), + .into_bytes(), + stream, + |result| match result { + Ok(()) => println!( + "[{}] [info] [{peer}] Data saved to {}", + now(), + pmt.path.to_string_lossy() + ), + Err(e) => { + println!("[{}] [error] [{peer}] {e}", now()); + if let Err(e) = pmt.delete() { + println!("[{}] [error] [{peer}] {e}", now()); + } + } + }, + ), + Err((tmp, e)) => send( + &response::failure::temporary::General { + message: Some("Internal server error".to_string()), + } + .into_bytes(), + stream, + |result| { + match result { + Ok(()) => { + println!("[{}] [warning] [{peer}] {e}", now()) + } + Err(e) => { + println!("[{}] [error] [{peer}] {e}", now()) + } + }; + if let Err(e) = tmp.delete() { + println!("[{}] [error] [{peer}] {e}", now()); + } + }, + ), + }; } - break; + } + Err(e) => { + return send( + &response::failure::temporary::General { + message: Some("Internal server error".to_string()), + } + .into_bytes(), + stream, + |result| { + match result { + Ok(()) => println!("[{}] [warning] [{peer}] {e}", now()), + Err(e) => println!("[{}] [error] [{peer}] {e}", now()), + }; + if let Err(e) = tmp.delete() { + println!("[{}] [error] [{peer}] {e}", now()); + } + }, + ) } } - Err(e) => todo!(), - }, - Err(e) => send( - &response::failure::temporary::General { - message: Some("Internal server error".to_string()), + } + Err(e) => { + if let Err(e) = tmp.delete() { + println!("[{}] [error] [{peer}] {e}", now()); } - .into_bytes(), - stream, - |result| match result { - Ok(()) => println!("[{}] [warning] [{peer}] {e}", now()), - Err(e) => println!("[{}] [error] [{peer}] {e}", now()), - }, - ), + return send( + &response::failure::temporary::General { + message: Some("Internal server error".to_string()), + } + .into_bytes(), + stream, + |result| match result { + Ok(()) => println!("[{}] [warning] [{peer}] {e}", now()), + Err(e) => println!("[{}] [error] [{peer}] {e}", now()), + }, + ); + } } }, - Err(e) => todo!(), + Err(e) => send( + &response::failure::temporary::General { + message: Some("Internal server error".to_string()), + } + .into_bytes(), + stream, + |result| match result { + Ok(()) => println!("[{}] [warning] [{peer}] {e}", now()), + Err(e) => println!("[{}] [error] [{peer}] {e}", now()), + }, + ), } }