agate

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

commit 2ed6d2886e0dc40ffcf1b7af3ea18b32902345a7
parent afd30c386c1b8762e21c6880e32563a518047c3d
Author: Johann150 <johann.galle@protonmail.com>
Date:   Tue,  9 Mar 2021 21:11:34 +0100

Merge branch 'master' into multi-certs
Diffstat:
MCHANGELOG.md | 4++++
MCargo.lock | 16++++++++--------
MREADME.md | 10++++++++++
Msrc/main.rs | 37+++++++++++++++++++++++++------------
4 files changed, 47 insertions(+), 20 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md @@ -14,6 +14,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed * Agate now requires the use of SNI by any connecting client. +* All log lines are in the same format now: + `<local ip>:<local port> <remote ip or dash> "<request>" <response status> "<response meta>" [error:<error>]` + If the connection could not be established correctly (e.g. because of TLS errors), the status code `00` is used. +* Messages from modules other than Agate itself are not logged by default. ## [2.5.3] - 2021-02-27 Thank you to @littleli and @06kellyjac for contributing to this release. diff --git a/Cargo.lock b/Cargo.lock @@ -178,9 +178,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.86" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" +checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a" [[package]] name = "log" @@ -263,9 +263,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.7.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10acf907b94fc1b1a152d08ef97e7759650268cf986bf127f387e602b02c7e5a" +checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" [[package]] name = "percent-encoding" @@ -275,9 +275,9 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pin-project-lite" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" +checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" [[package]] name = "proc-macro2" @@ -354,9 +354,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "syn" -version = "1.0.60" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +checksum = "123a78a3596b24fee53a6464ce52d8ecbf62241e6294c7e7fe12086cd161f512" dependencies = [ "proc-macro2", "quote", diff --git a/README.md b/README.md @@ -170,6 +170,16 @@ Using a directory named just `.` causes undefined behaviour as this would have t The files for a certificate/key pair have to be named `cert.pem` and `key.rsa` respectively. The certificate has to be a X.509 certificate in a PEM file and has to include a subject alt name of the domain name. The private key has to be in PKCS#8 format. For an example of how to create such certificates see Installation and Setup, step 2. +## Logging + +All requests will be logged using this format: +``` +<local ip>:<local port> <remote ip or dash> "<request>" <response status> "<response meta>"[ error:<error>] +``` +The "error:" part will only be logged if an error occurred. This should only be used for informative purposes as the status code should provide the information that an error occurred. If the error consisted in the connection not being established (e.g. because of TLS errors), the status code `00` will be used. + +There are some lines apart from these that might occur in logs depending on the selected log level. For example the initial "Listening on..." line or information about listing a particular directory. + [Gemini]: https://gemini.circumlunar.space/ [Rust]: https://www.rust-lang.org/ [home]: gemini://qwertqwefsday.eu/agate.gmi diff --git a/src/main.rs b/src/main.rs @@ -30,7 +30,10 @@ use { fn main() -> Result { if !ARGS.silent { env_logger::Builder::new() - .filter_level(log::LevelFilter::Info) + // turn off logging for other modules + .filter_level(log::LevelFilter::Off) + // turn on logging for agate + .filter_module("agate", log::LevelFilter::Info) .parse_default_env() .init(); } @@ -230,7 +233,8 @@ impl RequestHandle { log_line, metadata, }), - Err(e) => Err(format!("{} error:{}", log_line, e)), + // use nonexistent status code 00 if connection was not established + Err(e) => Err(format!("{} \"\" 00 \"TLS error\" error:{}", log_line, e)), } } @@ -263,22 +267,31 @@ impl RequestHandle { let mut len = 0; // Read until CRLF, end-of-stream, or there's no buffer space left. - loop { - let bytes_read = self - .stream - .read(buf) - .await - .or(Err((59, "Request ended unexpectedly")))?; + // + // Since neither CR nor LF can be part of a URI according to + // ISOC-RFC 3986, we could use BufRead::read_line here, but that does + // not allow us to cap the number of read bytes at 1024+2. + let result = loop { + let bytes_read = if let Ok(read) = self.stream.read(buf).await { + read + } else { + break Err((59, "Request ended unexpectedly")); + }; len += bytes_read; if request[..len].ends_with(b"\r\n") { - break; + break Ok(()); } else if bytes_read == 0 { - return Err((59, "Request ended unexpectedly")); + break Err((59, "Request ended unexpectedly")); } buf = &mut request[len..]; } - let request = - std::str::from_utf8(&request[..len - 2]).or(Err((59, "Non-UTF-8 request")))?; + .and_then(|()| std::str::from_utf8(&request[..len - 2]).or(Err((59, "Non-UTF-8 request")))); + + let request = result.map_err(|e| { + // write empty request to log line for uniformity + write!(self.log_line, " \"\"").unwrap(); + e + })?; // log literal request (might be different from or not an actual URL) write!(self.log_line, " \"{}\"", request).unwrap();