add custom welcome pages support

This commit is contained in:
yggverse 2025-02-24 02:21:54 +02:00
parent 31e33bca28
commit d5883d977e
4 changed files with 66 additions and 6 deletions

View file

@ -39,6 +39,7 @@ openssl pkcs12 -export -out server.pfx -inkey server.pem -in server.crt
* `--mime`, `-m` optional, uploads MIME type whitelist (comma separated, all by default) * `--mime`, `-m` optional, uploads MIME type whitelist (comma separated, all by default)
* `--directory`, `-d` optional, uploads target directory (`public` by default) * `--directory`, `-d` optional, uploads target directory (`public` by default)
* `--redirect`, `-r` optional, redirection URL on request handle complete (e.g. `gemini://localhost`) * `--redirect`, `-r` optional, redirection URL on request handle complete (e.g. `gemini://localhost`)
* `--welcome`, `-w` optional, filepath to welcome page template (in gemtext format)
### Start ### Start

View file

@ -35,4 +35,8 @@ pub struct Argument {
/// Redirection URL on request handle complete (e.g. `gemini://localhost`) /// Redirection URL on request handle complete (e.g. `gemini://localhost`)
#[arg(short, long)] #[arg(short, long)]
pub redirect: Option<String>, pub redirect: Option<String>,
/// Welcome page filename (in gemtext format)
#[arg(short, long)]
pub welcome: Option<String>,
} }

View file

@ -139,16 +139,44 @@ fn handle(
} }
fn gemini( fn gemini(
gemini: titanite::request::Gemini, request: titanite::request::Gemini,
argument: &Argument, argument: &Argument,
peer: &SocketAddr, peer: &SocketAddr,
stream: &mut TlsStream<TcpStream>, stream: &mut TlsStream<TcpStream>,
) { ) {
use titanite::*; use titanite::*;
println!("[{}] [info] [{peer}] Request: {}", now(), gemini.url);
// file could be large, println!("[{}] [info] [{peer}] Request: {}", now(), request.url);
// to not overflow the memory pool, build the response using chunks
match storage::Item::from_url(gemini.url.as_str(), &argument.directory) { // try welcome page
if request.url.path().trim_end_matches("/").is_empty() {
return send(
&match welcome(argument, request.url.host_str(), request.url.port()) {
Ok(welcome) => response::success::Default {
data: welcome.as_bytes(),
meta: response::success::default::Meta {
mime: "text/gemini".to_string(),
},
}
.into_bytes(),
Err(e) => {
println!("[{}] [error] [{peer}] {e}", now());
response::failure::temporary::General {
message: Some("Internal server error".to_string()),
}
.into_bytes()
}
},
stream,
|result| match result {
Ok(()) => println!("[{}] [info] [{peer}] /", now()),
Err(e) => println!("[{}] [error] [{peer}] {e}", now()),
},
);
}
// try file resource
// * it could be large, to not overflow the memory pool, use chunked read
match storage::Item::from_url(request.url.as_str(), &argument.directory) {
Ok(item) => { Ok(item) => {
let mut read: usize = 0; let mut read: usize = 0;
// create header packet // create header packet
@ -185,7 +213,7 @@ fn gemini(
} }
Err(e) => send( Err(e) => send(
&response::failure::permanent::NotFound { &response::failure::permanent::NotFound {
message: Some("Not found".to_string()), message: Some("Resource not found".to_string()),
} }
.into_bytes(), .into_bytes(),
stream, stream,
@ -431,6 +459,24 @@ fn send(data: &[u8], stream: &mut TlsStream<TcpStream>, callback: impl FnOnce(Re
})()); })());
} }
fn welcome(argument: &Argument, host: Option<&str>, port: Option<u16>) -> Result<String> {
let mut file = File::open(argument.welcome.as_deref().unwrap_or("welcome.gmi"))?;
let mut data = String::new();
file.read_to_string(&mut data)?;
Ok(data.replace(
"{UPLOAD_URL}",
&if let Some(host) = host {
let mut url = format!("titan://{host}");
if let Some(port) = port {
url = format!("{url}:{port}")
}
url
} else {
argument.bind.to_string()
},
))
}
fn now() -> u128 { fn now() -> u128 {
SystemTime::now() SystemTime::now()
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)

9
welcome.gmi Normal file
View file

@ -0,0 +1,9 @@
# Titan it!
File Share Server for Gemini & Titan protocols
=> {UPLOAD_URL} Upload..
## About
=> https://github.com/YGGverse/titanit GitHub