record stream directly to file

This commit is contained in:
yggverse 2025-02-22 06:48:13 +02:00
parent f62153ac91
commit 69b0186d01

View file

@ -51,7 +51,8 @@ fn main() -> Result<()> {
fn handle(argument: Arc<Argument>, peer: SocketAddr, stream: &mut TlsStream<TcpStream>) { fn handle(argument: Arc<Argument>, peer: SocketAddr, stream: &mut TlsStream<TcpStream>) {
use titanite::*; use titanite::*;
println!("[{}] [info] [{peer}] New connection", now()); println!("[{}] [info] [{peer}] New connection", now());
// validate totals
let mut total = 0;
// read header bytes // read header bytes
let mut input = vec![0; 1024]; let mut input = vec![0; 1024];
match stream.read(&mut input) { match stream.read(&mut input) {
@ -92,48 +93,24 @@ fn handle(argument: Arc<Argument>, peer: SocketAddr, stream: &mut TlsStream<TcpS
), ),
} }
} }
Request::Titan(titan) => { Request::Titan(titan) => match storage::Item::create(&argument.directory) {
// init memory pool Ok(mut tmp) => loop {
let mut data: Vec<u8> = Vec::with_capacity(titan.size);
loop {
// read data bytes
let mut input = vec![0; argument.chunk]; let mut input = vec![0; argument.chunk];
match stream.read(&mut input) { match stream.read(&mut input) {
Ok(0) => println!( Ok(0) => println!(
"[{}] [warning] [{peer}] Connection closed by peer", "[{}] [warning] [{peer}] Connection closed by peer",
now() now()
), ),
Ok(l) => { Ok(l) => match tmp.file.write(&input[..l]) {
data.extend(&input[..l]); Ok(s) => {
// calculate once total += s;
let total = data.len(); if s != l {
// validate server-side limits todo!()
if argument.size.is_some_and(|limit| total > limit) { }
const MESSAGE: &str = // validate server-side limits
"Allowed max length limit reached"; if argument.size.is_some_and(|limit| total > limit) {
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())
}
},
);
}
// all expected data received
if titan.size >= total {
// validate client-side limits
if titan.size > total {
const MESSAGE: &str = const MESSAGE: &str =
"Data size mismatch header declaration"; "Allowed max length limit reached";
return send( return send(
&response::failure::permanent::BadRequest { &response::failure::permanent::BadRequest {
message: Some(MESSAGE.to_string()), message: Some(MESSAGE.to_string()),
@ -141,117 +118,112 @@ fn handle(argument: Arc<Argument>, peer: SocketAddr, stream: &mut TlsStream<TcpS
.into_bytes(), .into_bytes(),
stream, stream,
|result| match result { |result| match result {
Ok(()) => { Ok(()) => println!(
"[{}] [warning] [{peer}] {MESSAGE}",
now()
),
Err(e) => {
println!( println!(
"[{}] [warning] [{peer}] {MESSAGE}", "[{}] [error] [{peer}] {e}",
now() now()
) )
} }
Err(e) => println!(
"[{}] [error] [{peer}] {e}",
now()
),
}, },
); );
} }
// @TODO detect/validate/cache mime based on data received // all expected data received
// success if titan.size >= total {
match storage::Item::create(&argument.directory) { // validate client-side limits
Ok(mut tmp) => match tmp.file.write(&data) { if titan.size > total {
Ok(_) => match tmp.commit() { const MESSAGE: &str =
Ok(pmt) => send( "Data size mismatch header declaration";
&response::redirect::Permanent { return send(
target: match argument.redirect { &response::failure::permanent::BadRequest {
Some(ref target) => format!( message: Some(MESSAGE.to_string()),
"{}/{}", }
target.trim_end_matches("/"), .into_bytes(),
pmt.to_uri(&argument.directory) stream,
), |result| match result {
None => format!( Ok(()) => {
"gemini://{}/{}", println!(
argument.bind, "[{}] [warning] [{peer}] {MESSAGE}",
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() now()
), )
},
),
Err((tmp, e)) => send(
&response::failure::temporary::General {
message: Some(
"Internal server error".to_string(),
),
} }
.into_bytes(), Err(e) => println!(
stream, "[{}] [error] [{peer}] {e}",
|result| { now()
match result { ),
Ok(()) => println!( },
"[{}] [error] [{peer}] {e}", );
now() }
), // @TODO detect/validate/cache mime based on data received
Err(e) => println!( // success
"[{}] [error] [{peer}] {e}", match tmp.commit() {
now() Ok(pmt) => send(
), &response::redirect::Permanent {
}; target: match argument.redirect {
if let Err(e) = tmp.delete() { Some(ref target) => format!(
println!( "{}/{}",
"[{}] [error] [{peer}] {e}", target.trim_end_matches("/"),
now() pmt.to_uri(&argument.directory)
); ),
} None => format!(
"gemini://{}/{}",
argument.bind,
pmt.to_uri(&argument.directory)
),
}, },
),
},
Err(e) => send(
&response::failure::temporary::General {
message: Some("Internal server error".to_string()),
} }
.into_bytes(), .into_bytes(),
stream, stream,
|result| { |result| {
match result { match result {
Ok(()) => { Ok(()) => println!(
println!("[{}] [error] [{peer}] {e}", now()) "[{}] [info] [{peer}] Data saved to {}",
} now(),
Err(e) => { pmt.path.to_string_lossy()
println!("[{}] [error] [{peer}] {e}", now()) ),
} 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!(
"[{}] [error] [{peer}] {e}",
now()
),
Err(e) => println!(
"[{}] [error] [{peer}] {e}",
now()
),
}; };
if let Err(e) = tmp.delete() { if let Err(e) = tmp.delete() {
println!("[{}] [error] [{peer}] {e}", now()); println!(
"[{}] [error] [{peer}] {e}",
now()
);
} }
}, },
), ),
}, }
Err(e) => send( break;
&response::failure::temporary::General {
message: Some("Internal server error".to_string()),
}
.into_bytes(),
stream,
|result| match result {
Ok(()) => println!("[{}] [error] [{peer}] {e}", now()),
Err(e) => println!("[{}] [error] [{peer}] {e}", now()),
},
),
} }
break;
} }
} Err(e) => todo!(),
},
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()),
@ -259,13 +231,19 @@ fn handle(argument: Arc<Argument>, peer: SocketAddr, stream: &mut TlsStream<TcpS
.into_bytes(), .into_bytes(),
stream, stream,
|result| match result { |result| match result {
Ok(()) => println!("[{}] [error] [{peer}] {e}", now()), Ok(()) => {
Err(e) => println!("[{}] [error] [{peer}] {e}", now()), println!("[{}] [error] [{peer}] {e}", now())
}
Err(e) => {
println!("[{}] [error] [{peer}] {e}", now())
}
}, },
), ),
} }
} },
}
Err(e) => todo!(),
},
} }
} }
Err(e) => send( Err(e) => send(