agate

Simple gemini server for static files
git clone https://github.com/mbrubeck/agate.git
Log | Files | Refs | README

commit 70b28a65e1ee03507d544db66436072985014c30
parent 968314685113fc34b68b47f85e662b21444071ab
Author: Matt Brubeck <mbrubeck@limpet.net>
Date:   Wed, 30 Dec 2020 21:16:12 -0800

Encode spaces in filenames

Diffstat:
MCargo.lock | 1+
MCargo.toml | 1+
Msrc/main.rs | 13+++++++++++--
3 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -11,6 +11,7 @@ dependencies = [ "log", "mime_guess", "once_cell", + "percent-encoding", "rustls", "url", ] diff --git a/Cargo.toml b/Cargo.toml @@ -18,6 +18,7 @@ getopts = "0.2.21" log = "0.4" mime_guess = "2.0" once_cell = "1.4" +percent-encoding = "2.1" rustls = "0.19.0" url = "2.1" diff --git a/src/main.rs b/src/main.rs @@ -6,6 +6,7 @@ use async_std::{ }; use async_tls::TlsAcceptor; use once_cell::sync::Lazy; +use percent_encoding::{AsciiSet, CONTROLS, percent_decode_str, percent_encode}; use rustls::{ internal::pemfile::{certs, pkcs8_private_keys}, NoClientAuth, ServerConfig, @@ -181,7 +182,9 @@ async fn parse_request<R: Read + Unpin>( async fn send_response<W: Write + Unpin>(url: Url, stream: &mut W) -> Result { let mut path = std::path::PathBuf::from(&ARGS.content_dir); if let Some(segments) = url.path_segments() { - path.extend(segments); + for segment in segments { + path.push(&*percent_decode_str(segment).decode_utf8()?); + } } if async_std::fs::metadata(&path).await?.is_dir() { if url.path().ends_with('/') || url.path().is_empty() { @@ -226,6 +229,7 @@ async fn send_header<W: Write + Unpin>(stream: &mut W, status: &str, meta: &[&st } async fn list_directory<W: Write + Unpin>(stream: &mut W, path: &Path) -> Result { + const WHITESPACE: AsciiSet = CONTROLS.add(b' '); log::info!("Listing directory {:?}", path); send_text_gemini_header(stream).await?; let mut entries = async_std::fs::read_dir(path).await?; @@ -239,7 +243,12 @@ async fn list_directory<W: Write + Unpin>(stream: &mut W, path: &Path) -> Result if entry.file_type().await?.is_dir() { name += "/"; } - lines.push(format!("=> {}\n", name)); + if name.contains(char::is_whitespace) { + let url = percent_encode(name.as_bytes(), &WHITESPACE); + lines.push(format!("=> {} {}\n", url, name)); + } else { + lines.push(format!("=> {}\n", name)); + } } lines.sort(); for line in lines {