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