update handlers

This commit is contained in:
yggverse 2025-02-22 08:21:10 +02:00
parent 71d75bc22f
commit 7bf68725db

View file

@ -55,11 +55,11 @@ fn handle(argument: Arc<Argument>, peer: SocketAddr, stream: &mut TlsStream<TcpS
println!("[{}] [info] [{peer}] New connection", now()); println!("[{}] [info] [{peer}] New connection", now());
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}] Connection closed by peer", 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) => handle_gemini(this, argument, peer, stream), Request::Gemini(this) => gemini(this, argument, peer, stream),
Request::Titan(this) => handle_titan(this, argument, peer, stream), Request::Titan(this) => titan(this, argument, peer, stream),
}, },
Err(e) => send( Err(e) => send(
&response::failure::temporary::General { &response::failure::temporary::General {
@ -87,14 +87,14 @@ fn handle(argument: Arc<Argument>, peer: SocketAddr, stream: &mut TlsStream<TcpS
} }
} }
fn handle_gemini( fn gemini(
gemini: titanite::request::Gemini, gemini: titanite::request::Gemini,
argument: Arc<Argument>, argument: Arc<Argument>,
peer: SocketAddr, peer: SocketAddr,
stream: &mut TlsStream<TcpStream>, stream: &mut TlsStream<TcpStream>,
) { ) {
use titanite::*; 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( Ok(item) => send(
&response::success::Default { &response::success::Default {
mime: "text/gemini".to_string(), mime: "text/gemini".to_string(),
@ -121,7 +121,7 @@ fn handle_gemini(
} }
} }
fn handle_titan( fn titan(
titan: titanite::request::Titan, titan: titanite::request::Titan,
argument: Arc<Argument>, argument: Arc<Argument>,
peer: SocketAddr, peer: SocketAddr,
@ -134,143 +134,185 @@ fn handle_titan(
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) => { Ok(0) => {
println!("[{}] [warning] [{peer}] Connection closed by peer", now()); println!("[{}] [warning] [{peer}] Peer closed connection", now());
if let Err(e) = tmp.delete() { if let Err(e) = tmp.delete() {
println!("[{}] [error] [{peer}] {e}", now()); println!("[{}] [error] [{peer}] {e}", now());
} }
break; break;
} }
Ok(l) => match tmp.file.write(&input[..l]) { Ok(read) => {
Ok(s) => { total += read;
total += s;
if s != l { // validate server-side limits
if let Err(e) = tmp.delete() { if argument.size.is_some_and(|limit| total > limit) {
println!("[{}] [error] [{peer}] {e}", now()); 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())
}
},
);
} }
// validate server-side limits const MESSAGE: &str = "Allowed max length limit reached";
if argument.size.is_some_and(|limit| total > limit) { return send(
if let Err(e) = tmp.delete() { &response::failure::permanent::BadRequest {
println!("[{}] [error] [{peer}] {e}", now()); message: Some(MESSAGE.to_string()),
} }
const MESSAGE: &str = "Allowed max length limit reached"; .into_bytes(),
return send( stream,
&response::failure::permanent::BadRequest { |result| match result {
message: Some(MESSAGE.to_string()), 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) => { // validate client-side limits (from header)
println!("[{}] [error] [{peer}] {e}", now()) if titan.size > total {
} if let Err(e) = tmp.delete() {
}, println!("[{}] [error] [{peer}] {e}", now());
);
} }
// all expected data received const MESSAGE: &str = "Data size mismatch header declaration";
if titan.size >= total { return send(
// validate client-side limits &response::failure::permanent::BadRequest {
if titan.size > total { 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() { if let Err(e) = tmp.delete() {
println!("[{}] [error] [{peer}] {e}", now()); println!("[{}] [error] [{peer}] {e}", now());
} }
const MESSAGE: &str = "Data size mismatch header declaration"; const MESSAGE: &str = "File size mismatch";
return send( return send(
&response::failure::permanent::BadRequest { &response::failure::temporary::General {
message: Some(MESSAGE.to_string()), message: Some(MESSAGE.to_string()),
} }
.into_bytes(), .into_bytes(),
stream, stream,
|result| match result { |result| match result {
Ok(()) => { Ok(()) => {
println!("[{}] [warning] [{peer}] {MESSAGE}", now()) println!("[{}] [error] [{peer}] {MESSAGE}", now())
} }
Err(e) => println!("[{}] [error] [{peer}] {e}", now()), Err(e) => println!("[{}] [error] [{peer}] {e}", now()),
}, },
); );
} }
// @TODO detect/validate/cache mime based on data received
// success // all data received
match tmp.commit() { if titan.size >= total {
Ok(pmt) => send( // @TODO detect/validate/cache mime based on data received
&response::redirect::Permanent { // success
target: match argument.redirect { return match tmp.commit() {
Some(ref target) => format!( Ok(pmt) => send(
"{}/{}", &response::redirect::Permanent {
target.trim_end_matches("/"), target: match argument.redirect {
pmt.to_uri(&argument.directory) Some(ref target) => format!(
), "{}/{}",
None => format!( target.trim_end_matches("/"),
"gemini://{}/{}", pmt.to_uri(&argument.directory)
argument.bind, ),
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());
} }
}, .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) => {
Err(e) => send( if let Err(e) = tmp.delete() {
&response::failure::temporary::General { println!("[{}] [error] [{peer}] {e}", now());
message: Some("Internal server error".to_string()),
} }
.into_bytes(), return send(
stream, &response::failure::temporary::General {
|result| match result { message: Some("Internal server error".to_string()),
Ok(()) => println!("[{}] [warning] [{peer}] {e}", now()), }
Err(e) => println!("[{}] [error] [{peer}] {e}", now()), .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()),
},
),
} }
} }