agate

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

commit ce570fc8c43e2fe68964f1f9f15fc890ee682cf3
parent db5665b783c3f136f6005960fb1359ec824bebc2
Author: Matt Brubeck <mbrubeck@limpet.net>
Date:   Thu, 21 May 2020 15:28:07 -0700

Auto-detect MIME types

Diffstat:
MCargo.lock | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
MCargo.toml | 3++-
MREADME.md | 2+-
Msrc/main.rs | 15++++++++-------
4 files changed, 125 insertions(+), 12 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -2,12 +2,13 @@ # It is not intended for manual editing. [[package]] name = "agate" -version = "1.0.1" +version = "1.1.0" dependencies = [ "async-std", "async-tls", "lazy_static", "rustls", + "tree_magic", "url", ] @@ -26,7 +27,7 @@ dependencies = [ "futures-timer", "kv-log-macro", "log", - "memchr", + "memchr 2.3.3", "mio", "mio-uds", "num_cpus", @@ -95,6 +96,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] name = "crossbeam-channel" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -142,6 +152,18 @@ dependencies = [ ] [[package]] +name = "fixedbitset" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] name = "fuchsia-zircon" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -250,7 +272,7 @@ dependencies = [ "futures-macro", "futures-sink", "futures-task", - "memchr", + "memchr 2.3.3", "pin-project", "pin-utils", "proc-macro-hack", @@ -279,6 +301,15 @@ dependencies = [ ] [[package]] +name = "indexmap" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292" +dependencies = [ + "autocfg", +] + +[[package]] name = "iovec" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -328,6 +359,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f" [[package]] +name = "lock_api" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" +dependencies = [ + "scopeguard", +] + +[[package]] name = "log" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -350,6 +390,15 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" @@ -417,6 +466,15 @@ dependencies = [ ] [[package]] +name = "nom" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b" +dependencies = [ + "memchr 1.0.2", +] + +[[package]] name = "num_cpus" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -433,12 +491,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" [[package]] +name = "parking_lot" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" +dependencies = [ + "cfg-if", + "cloudabi", + "libc", + "redox_syscall", + "smallvec", + "winapi 0.3.8", +] + +[[package]] name = "percent-encoding" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] +name = "petgraph" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c127eea4a29ec6c85d153c59dc1213f33ec74cead30fe4730aecc88cc1fd92" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] name = "pin-project" version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -501,6 +593,12 @@ dependencies = [ ] [[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" + +[[package]] name = "ring" version = "0.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -574,6 +672,19 @@ dependencies = [ ] [[package]] +name = "tree_magic" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d99367ce3e553a84738f73bd626ccca541ef90ae757fdcdc4cbe728e6cb629" +dependencies = [ + "fnv", + "lazy_static", + "nom", + "parking_lot", + "petgraph", +] + +[[package]] name = "unicode-bidi" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "agate" -version = "1.0.1" +version = "1.1.0" authors = ["Matt Brubeck <mbrubeck@limpet.net>"] description = "Very simple server for the Gemini hypertext protocol" keywords = ["server", "gemini", "hypertext", "internet", "protocol"] @@ -15,6 +15,7 @@ async-tls = "0.7.0" async-std = "1.5" lazy_static = "1.4" rustls = "0.17.0" +tree_magic = "0.2.3" url = "2.1" [profile.release] diff --git a/README.md b/README.md @@ -29,7 +29,7 @@ openssl req -x509 -newkey rsa:4096 -keyout key.rsa -out cert.pem \ agate localhost:1965 path/to/content/ cert.pem key.rsa ``` -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.gemini` inside that directory. Currently, Agate sends all responses with the `text/gemini` MIME type. (Support for other MIME types may be added in the future.) +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.gemini` inside that directory. [Gemini]: https://gemini.circumlunar.space/ [Rust]: https://www.rust-lang.org/ diff --git a/src/main.rs b/src/main.rs @@ -8,12 +8,7 @@ use { }, async_tls::{TlsAcceptor, server::TlsStream}, lazy_static::lazy_static, - std::{ - error::Error, - fs::File, - io::BufReader, - sync::Arc, - }, + std::{error::Error, ffi::OsStr, fs::File, io::BufReader, sync::Arc}, url::Url, }; @@ -118,7 +113,13 @@ async fn get(url: &Url, stream: &mut TlsStream<TcpStream>) -> Result { } match async_std::fs::read(&path).await { Ok(body) => { - stream.write_all(b"20 text/gemini\r\n").await?; + if path.extension() == Some(OsStr::new("gemini")) { + stream.write_all(b"20 text/gemini\r\n").await?; + } else { + let mime = tree_magic::from_u8(&body); + let header = format!("20 {}\r\n", mime); + stream.write_all(header.as_bytes()).await?; + } stream.write_all(&body).await?; } Err(e) => {