From 753ecf708d6d943ce8da777044c37f86fb778e09 Mon Sep 17 00:00:00 2001 From: Emi Tatsuo Date: Thu, 19 Nov 2020 02:02:11 -0500 Subject: [PATCH 1/6] Isolate directory serving methods behind feature, incl mime_guess. Remove itertools --- Cargo.toml | 7 +++++-- src/types/document.rs | 2 +- src/util.rs | 16 ++++++++++++---- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dd12927..a2de13d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,10 @@ description = "Gemini server implementation" repository = "https://github.com/panicbit/northstar" documentation = "https://docs.rs/northstar" +[features] +default = ["serve_dir"] +serve_dir = ["mime_guess"] + [dependencies] anyhow = "1.0.33" rustls = { version = "0.18.1", features = ["dangerous_configuration"] } @@ -17,11 +21,10 @@ mime = "0.3.16" uriparse = "0.6.3" percent-encoding = "2.1.0" futures = "0.3.7" -itertools = "0.9.0" log = "0.4.11" webpki = "0.21.0" lazy_static = "1.4.0" -mime_guess = "2.0.3" +mime_guess = { version = "2.0.3", optional = true } [dev-dependencies] env_logger = "0.8.1" diff --git a/src/types/document.rs b/src/types/document.rs index f6fc5aa..e322357 100644 --- a/src/types/document.rs +++ b/src/types/document.rs @@ -39,7 +39,6 @@ use std::convert::TryInto; use std::fmt; -use itertools::Itertools; use crate::types::URIReference; use crate::util::Cowy; @@ -550,5 +549,6 @@ fn strip_newlines(text: impl Cowy) -> String { text.as_ref() .lines() .filter(|part| !part.is_empty()) + .collect::>() .join(" ") } diff --git a/src/util.rs b/src/util.rs index 1ba11af..ac774a2 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,13 +1,18 @@ -use std::path::Path; +#[cfg(feature="serve_dir")] +use std::path::{Path, PathBuf}; +#[cfg(feature="serve_dir")] use mime::Mime; +#[cfg(feature="serve_dir")] use anyhow::*; +#[cfg(feature="serve_dir")] use tokio::{ fs::{self, File}, io, }; +#[cfg(feature="serve_dir")] use crate::types::{Response, Document, document::HeadingLevel::*}; -use itertools::Itertools; +#[cfg(feature="serve_dir")] pub async fn serve_file>(path: P, mime: &Mime) -> Result { let path = path.as_ref(); @@ -22,6 +27,7 @@ pub async fn serve_file>(path: P, mime: &Mime) -> Result, P: AsRef>(dir: D, virtual_path: &[P]) -> Result { debug!("Dir: {}", dir.as_ref().display()); let dir = dir.as_ref().canonicalize() @@ -47,6 +53,7 @@ pub async fn serve_dir, P: AsRef>(dir: D, virtual_path: &[P serve_dir_listing(path, virtual_path).await } +#[cfg(feature="serve_dir")] async fn serve_dir_listing, B: AsRef>(path: P, virtual_path: &[B]) -> Result { let mut dir = match fs::read_dir(path).await { Ok(dir) => dir, @@ -56,10 +63,10 @@ async fn serve_dir_listing, B: AsRef>(path: P, virtual_path } }; - let breadcrumbs = virtual_path.iter().map(|segment| segment.as_ref().display()).join("/"); + let breadcrumbs: PathBuf = virtual_path.iter().collect(); let mut document = Document::new(); - document.add_heading(H1, format!("Index of /{}", breadcrumbs)); + document.add_heading(H1, format!("Index of /{}", breadcrumbs.display())); document.add_blank_line(); if virtual_path.get(0).map(<_>::as_ref) != Some(Path::new("")) { @@ -85,6 +92,7 @@ async fn serve_dir_listing, B: AsRef>(path: P, virtual_path Ok(Response::document(document)) } +#[cfg(feature="serve_dir")] pub fn guess_mime_from_path>(path: P) -> Mime { let path = path.as_ref(); let extension = path.extension().and_then(|s| s.to_str()); From e0abe6344bc9ac93b03898ee8c8f0453e6017c76 Mon Sep 17 00:00:00 2001 From: Emi Tatsuo Date: Thu, 19 Nov 2020 02:54:45 -0500 Subject: [PATCH 2/6] Reduced dependency on futures-rs --- Cargo.toml | 3 ++- examples/certificates.rs | 3 ++- examples/document.rs | 3 ++- examples/serve_dir.rs | 3 ++- src/lib.rs | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a2de13d..1ef35dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,8 @@ tokio = { version = "0.3.1", features = ["full"] } mime = "0.3.16" uriparse = "0.6.3" percent-encoding = "2.1.0" -futures = "0.3.7" +futures-core = "0.3.7" +futures-util = "0.3.7" log = "0.4.11" webpki = "0.21.0" lazy_static = "1.4.0" diff --git a/examples/certificates.rs b/examples/certificates.rs index f0f98b3..541fbe5 100644 --- a/examples/certificates.rs +++ b/examples/certificates.rs @@ -1,5 +1,6 @@ use anyhow::*; -use futures::{future::BoxFuture, FutureExt}; +use futures_core::future::BoxFuture; +use futures_util::FutureExt; use log::LevelFilter; use tokio::sync::RwLock; use northstar::{Certificate, GEMINI_MIME, GEMINI_PORT, Request, Response, Server}; diff --git a/examples/document.rs b/examples/document.rs index 5986896..8ff6bbb 100644 --- a/examples/document.rs +++ b/examples/document.rs @@ -1,5 +1,6 @@ use anyhow::*; -use futures::{future::BoxFuture, FutureExt}; +use futures_core::future::BoxFuture; +use futures_util::FutureExt; use log::LevelFilter; use northstar::{Server, Request, Response, GEMINI_PORT, Document}; use northstar::document::HeadingLevel::*; diff --git a/examples/serve_dir.rs b/examples/serve_dir.rs index 47145e1..fd26ac4 100644 --- a/examples/serve_dir.rs +++ b/examples/serve_dir.rs @@ -1,5 +1,6 @@ use anyhow::*; -use futures::{future::BoxFuture, FutureExt}; +use futures_core::future::BoxFuture; +use futures_util::FutureExt; use log::LevelFilter; use northstar::{Server, Request, Response, GEMINI_PORT}; diff --git a/src/lib.rs b/src/lib.rs index 066ce28..2083e0f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,8 @@ use std::{ sync::Arc, time::Duration, }; -use futures::{future::BoxFuture, FutureExt}; +use futures_core::future::BoxFuture; +use futures_util::future::FutureExt; use tokio::{ prelude::*, io::{self, BufStream}, From 3da18ca5306241c54a269b2806d3735d810b992a Mon Sep 17 00:00:00 2001 From: Emi Tatsuo Date: Thu, 19 Nov 2020 10:21:32 -0500 Subject: [PATCH 3/6] Reduced tokio featureset --- Cargo.toml | 4 ++-- src/types/body.rs | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1ef35dc..ae965a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,13 +10,13 @@ documentation = "https://docs.rs/northstar" [features] default = ["serve_dir"] -serve_dir = ["mime_guess"] +serve_dir = ["mime_guess", "tokio/fs"] [dependencies] anyhow = "1.0.33" rustls = { version = "0.18.1", features = ["dangerous_configuration"] } tokio-rustls = "0.20.0" -tokio = { version = "0.3.1", features = ["full"] } +tokio = { version = "0.3.1", features = ["io-util","net","time", "rt"] } mime = "0.3.16" uriparse = "0.6.3" percent-encoding = "2.1.0" diff --git a/src/types/body.rs b/src/types/body.rs index dfeb8ca..d1356cc 100644 --- a/src/types/body.rs +++ b/src/types/body.rs @@ -1,4 +1,6 @@ -use tokio::{io::AsyncRead, fs::File}; +use tokio::io::AsyncRead; +#[cfg(feature="serve_dir")] +use tokio::fs::File; use crate::types::Document; @@ -37,6 +39,7 @@ impl<'a> From<&'a str> for Body { } } +#[cfg(feature="serve_dir")] impl From for Body { fn from(file: File) -> Self { Self::Reader(Box::new(file)) From 87d71cb207d8bd669b5125c5b58c9de57076b797 Mon Sep 17 00:00:00 2001 From: Emi Tatsuo Date: Thu, 19 Nov 2020 11:08:20 -0500 Subject: [PATCH 4/6] Fixed examples --- Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index ae965a5..62743e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,3 +29,5 @@ mime_guess = { version = "2.0.3", optional = true } [dev-dependencies] env_logger = "0.8.1" +futures-util = "0.3.7" +tokio = { version = "0.3.1", features = ["macros", "rt-multi-thread", "sync"] } From 475db6af797fa80996fe2a8f50ce006c95c3b2a2 Mon Sep 17 00:00:00 2001 From: Emi Tatsuo Date: Thu, 19 Nov 2020 11:09:53 -0500 Subject: [PATCH 5/6] Adapted a type from futures-util allowing us to drop the dep and remove a big chunk of the dep tree --- Cargo.toml | 1 - src/lib.rs | 5 ++--- src/util.rs | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 62743e8..9ad991d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,6 @@ mime = "0.3.16" uriparse = "0.6.3" percent-encoding = "2.1.0" futures-core = "0.3.7" -futures-util = "0.3.7" log = "0.4.11" webpki = "0.21.0" lazy_static = "1.4.0" diff --git a/src/lib.rs b/src/lib.rs index 2083e0f..9b1ad5c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,6 @@ use std::{ time::Duration, }; use futures_core::future::BoxFuture; -use futures_util::future::FutureExt; use tokio::{ prelude::*, io::{self, BufStream}, @@ -33,7 +32,7 @@ pub const REQUEST_URI_MAX_LEN: usize = 1024; pub const GEMINI_PORT: u16 = 1965; type Handler = Arc HandlerResponse + Send + Sync>; -type HandlerResponse = BoxFuture<'static, Result>; +pub (crate) type HandlerResponse = BoxFuture<'static, Result>; #[derive(Clone)] pub struct Server { @@ -94,7 +93,7 @@ impl Server { let handler = (self.handler)(request); let handler = AssertUnwindSafe(handler); - let response = handler.catch_unwind().await + let response = util::HandlerCatchUnwind::new(handler).await .unwrap_or_else(|_| Response::server_error("")) .or_else(|err| { error!("Handler failed: {:?}", err); diff --git a/src/util.rs b/src/util.rs index ac774a2..628b018 100644 --- a/src/util.rs +++ b/src/util.rs @@ -11,6 +11,9 @@ use tokio::{ }; #[cfg(feature="serve_dir")] use crate::types::{Response, Document, document::HeadingLevel::*}; +use std::panic::{catch_unwind, AssertUnwindSafe}; +use std::task::Poll; +use futures_core::future::Future; #[cfg(feature="serve_dir")] pub async fn serve_file>(path: P, mime: &Mime) -> Result { @@ -123,3 +126,32 @@ where C: AsRef + Into, T: ToOwned + ?Sized, {} + +/// A utility for catching unwinds on Futures. +/// +/// This is adapted from the futures-rs CatchUnwind, in an effort to reduce the large +/// amount of dependencies tied into the feature that provides this simple struct. +#[must_use = "futures do nothing unless polled"] +pub (crate) struct HandlerCatchUnwind { + future: AssertUnwindSafe, +} + +impl HandlerCatchUnwind { + pub(super) fn new(future: AssertUnwindSafe) -> Self { + Self { future } + } +} + +impl Future for HandlerCatchUnwind { + type Output = Result, Box>; + + fn poll( + mut self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context + ) -> Poll { + match catch_unwind(AssertUnwindSafe(|| self.future.as_mut().poll(cx))) { + Ok(res) => res.map(Ok), + Err(e) => Poll::Ready(Err(e)) + } + } +} From c69cf49d995a2c341fe0e68e0fc8cd83f14640d0 Mon Sep 17 00:00:00 2001 From: Emi Tatsuo Date: Thu, 19 Nov 2020 11:29:11 -0500 Subject: [PATCH 6/6] Removed over-zeleous feature gating --- src/util.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util.rs b/src/util.rs index 628b018..c48b8bf 100644 --- a/src/util.rs +++ b/src/util.rs @@ -2,7 +2,6 @@ use std::path::{Path, PathBuf}; #[cfg(feature="serve_dir")] use mime::Mime; -#[cfg(feature="serve_dir")] use anyhow::*; #[cfg(feature="serve_dir")] use tokio::{ @@ -10,7 +9,8 @@ use tokio::{ io, }; #[cfg(feature="serve_dir")] -use crate::types::{Response, Document, document::HeadingLevel::*}; +use crate::types::{Document, document::HeadingLevel::*}; +use crate::types::Response; use std::panic::{catch_unwind, AssertUnwindSafe}; use std::task::Poll; use futures_core::future::Future;