agate

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

commit e4dacd1315dec45a51db57525aa85d3c1637a326
parent 7998fafcc7d52c85ce74fced2bc62f28f0c99de8
Author: Johann150 <johann.galle@protonmail.com>
Date:   Sat, 26 Dec 2020 15:51:58 +0100

implement basic directory listing

Diffstat:
MREADME.md | 2+-
Msrc/main.rs | 28++++++++++++++++++++++++++++
2 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md @@ -40,7 +40,7 @@ agate --content path/to/content/ \ All of the command-line arguments are optional. Run `agate --help` to see the default values used when arguments are omitted. -When a client requests the URL `gemini://example.com/foo/bar`, Agate will respond with the file at `path/to/content/foo/bar`. If there is a directory at that path, Agate will look for a file named `index.gmi` inside that directory. +When a client requests the URL `gemini://example.com/foo/bar`, Agate will respond with the file at `path/to/content/foo/bar`. If there is a directory at that path, Agate will look for a file named `index.gmi` inside that directory. If there is no such file, but a file named `.directory-listing-ok` exists inside that directory, a basic directory listing is displayed. Files whose name starts with a dot (e.g. `.hidden`) are omitted from the list. [Gemini]: https://gemini.circumlunar.space/ [Rust]: https://www.rust-lang.org/ diff --git a/src/main.rs b/src/main.rs @@ -188,6 +188,34 @@ async fn send_response<W: Write + Unpin>(url: Url, stream: &mut W) -> Result { // if the path ends with a slash or the path is empty, the links will work the same // without a redirect path.push("index.gmi"); + if path.exists() { + // index file exists + } else if path.with_file_name(".directory-listing-ok").exists() { + // no index file, but directory listing allowed + path.pop(); + log::info!("Listing directory {:?}", path); + let entries = std::fs::read_dir(path)?; + let listing = entries + .filter(Result::is_ok) + .map(Result::unwrap) + .map(|entry| { + // transform filenames into gemini link lines + let mut name = String::from("=> "); + name += &entry.file_name().to_string_lossy(); + if entry.path().is_dir() { + // to avoid redirects link to directories with a trailing slash + name += "/"; + } + name + "\n" + }) + // filter out files starting with a dot + .filter(|entry| !entry.starts_with("=> .")) + .collect::<String>(); + + respond(stream, "20", &["text/gemini"]).await?; + stream.write_all(listing.as_bytes()).await?; + return Ok(()); + } } else { // if client is not redirected, links may not work as expected without trailing slash return respond(stream, "31", &[url.as_str(), "/"]).await;