prevent server fault on handshake issues, fix size conditions, begin response implementation

This commit is contained in:
yggverse 2025-02-23 01:37:34 +02:00
parent 5e2b90a39e
commit 61f5e22da3

View file

@ -4,11 +4,12 @@ mod storage;
use anyhow::Result; use anyhow::Result;
use argument::Argument; use argument::Argument;
use native_tls::{Identity, TlsAcceptor, TlsStream}; use native_tls::{HandshakeError, Identity, TlsAcceptor, TlsStream};
use std::{ use std::{
fs::File, fs::File,
io::{Read, Write}, io::{Read, Write},
net::{SocketAddr, TcpListener, TcpStream}, net::{SocketAddr, TcpListener, TcpStream},
os::unix::fs::FileExt,
sync::Arc, sync::Arc,
thread, thread,
time::{SystemTime, UNIX_EPOCH}, time::{SystemTime, UNIX_EPOCH},
@ -40,8 +41,8 @@ fn main() -> Result<()> {
thread::spawn({ thread::spawn({
let argument = argument.clone(); let argument = argument.clone();
let peer = stream.peer_addr()?; let peer = stream.peer_addr()?;
let mut stream = acceptor.accept(stream)?; let connection = acceptor.accept(stream);
move || handle(argument, peer, &mut stream) move || handle(argument, peer, connection)
}); });
} }
Err(e) => println!("[{}] [error] {e}", now()), Err(e) => println!("[{}] [error] {e}", now()),
@ -50,23 +51,29 @@ fn main() -> Result<()> {
Ok(()) Ok(())
} }
fn handle(argument: Arc<Argument>, peer: SocketAddr, stream: &mut TlsStream<TcpStream>) { fn handle(
argument: Arc<Argument>,
peer: SocketAddr,
connection: Result<TlsStream<TcpStream>, HandshakeError<TcpStream>>,
) {
use titanite::*; use titanite::*;
//println!("[{}] [info] [{peer}] New connection", now()); //println!("[{}] [info] [{peer}] New connection", now());
match connection {
Ok(mut stream) => {
let mut input = vec![0; titanite::HEADER_MAX_LEN]; let mut input = vec![0; titanite::HEADER_MAX_LEN];
match stream.read(&mut input) { match stream.read(&mut input) {
Ok(0) => println!("[{}] [warning] [{peer}] Peer closed connection", now()), Ok(0) => println!("[{}] [warning] [{peer}] Peer closed connection", now()),
Ok(s) => match Request::from_bytes(&input[..s]) { Ok(s) => match Request::from_bytes(&input[..s]) {
Ok(request) => match request { Ok(request) => match request {
Request::Gemini(this) => gemini(this, argument, peer, stream), Request::Gemini(this) => gemini(this, argument, peer, &mut stream),
Request::Titan(this) => titan(this, argument, peer, stream), Request::Titan(this) => titan(this, argument, peer, &mut stream),
}, },
Err(e) => send( Err(e) => send(
&response::failure::temporary::General { &response::failure::temporary::General {
message: Some("Internal server error".to_string()), message: Some("Internal server error".to_string()),
} }
.into_bytes(), .into_bytes(),
stream, &mut stream,
|result| match result { |result| match result {
Ok(()) => println!("[{}] [warning] [{peer}] {e}", now()), Ok(()) => println!("[{}] [warning] [{peer}] {e}", now()),
Err(e) => println!("[{}] [error] [{peer}] {e}", now()), Err(e) => println!("[{}] [error] [{peer}] {e}", now()),
@ -78,13 +85,16 @@ fn handle(argument: Arc<Argument>, peer: SocketAddr, stream: &mut TlsStream<TcpS
message: Some("Internal server error".to_string()), message: Some("Internal server error".to_string()),
} }
.into_bytes(), .into_bytes(),
stream, &mut stream,
|result| match result { |result| match result {
Ok(()) => println!("[{}] [warning] [{peer}] {e}", now()), Ok(()) => println!("[{}] [warning] [{peer}] {e}", now()),
Err(e) => println!("[{}] [error] [{peer}] {e}", now()), Err(e) => println!("[{}] [error] [{peer}] {e}", now()),
}, },
), ),
} }
}
Err(e) => println!("[{}] [warning] [{peer}] Handshake issue: {e}", now()),
}
} }
fn gemini( fn gemini(
@ -94,19 +104,34 @@ fn gemini(
stream: &mut TlsStream<TcpStream>, stream: &mut TlsStream<TcpStream>,
) { ) {
use titanite::*; use titanite::*;
println!("[{}] [info] [{peer}] Request: {}", now(), gemini.url);
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( Ok(item) => {
let mut read: usize = 0;
match stream.write_all(
&response::success::Default { &response::success::Default {
mime: item.mime, mime: item.mime,
//data: item.file.read(vec![1000]), data: &[], // init empty
} }
.into_bytes(), .into_bytes(),
stream, ) {
|result| match result { Ok(()) => loop {
Ok(()) => println!("[{}] [info] [{peer}] Request: {}", now(), gemini.url), let mut data = vec![0; argument.chunk];
Err(e) => println!("[{}] [error] [{peer}] {e}", now()), let l = item.file.read_at(&mut data, read as u64).unwrap();
stream.write_all(&data[..l]).unwrap();
read += l;
println!("[{}] [info] [{peer}] Chunk sent: {l} ({read} total)", now());
// EOF
if l == 0 {
stream.flush().unwrap();
stream.shutdown().unwrap();
println!("[{}] [info] [{peer}] Response: {read} bytes", now());
break;
}
}, },
), Err(e) => println!("[{}] [error] [{peer}] {e}", now()),
}
}
Err(e) => send( Err(e) => send(
&response::failure::permanent::NotFound { &response::failure::permanent::NotFound {
message: Some("Not found".to_string()), message: Some("Not found".to_string()),
@ -184,7 +209,7 @@ fn titan(
} }
// validate client-side limits (from header) // validate client-side limits (from header)
if titan.size > total { if total > titan.size {
if let Err(e) = tmp.delete() { if let Err(e) = tmp.delete() {
println!("[{}] [error] [{peer}] {e}", now()); println!("[{}] [error] [{peer}] {e}", now());
} }
@ -227,7 +252,7 @@ fn titan(
} }
// just to make sure // just to make sure
if titan.size > total { if total > titan.size {
panic!() panic!()
} }