Merge pull request #25 from Alch-Emi/trim-deps

Trim dependencies & move directory serving utils to feature
This commit is contained in:
panicbit 2020-11-19 18:29:52 +01:00 committed by GitHub
commit 4e251d0cb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 68 additions and 17 deletions

View File

@ -8,20 +8,25 @@ description = "Gemini server implementation"
repository = "https://github.com/panicbit/northstar"
documentation = "https://docs.rs/northstar"
[features]
default = ["serve_dir"]
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"
futures = "0.3.7"
itertools = "0.9.0"
futures-core = "0.3.7"
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"
futures-util = "0.3.7"
tokio = { version = "0.3.1", features = ["macros", "rt-multi-thread", "sync"] }

View File

@ -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};

View File

@ -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::*;

View File

@ -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};

View File

@ -8,7 +8,7 @@ use std::{
path::PathBuf,
time::Duration,
};
use futures::{future::BoxFuture, FutureExt};
use futures_core::future::BoxFuture;
use tokio::{
prelude::*,
io::{self, BufStream},
@ -33,7 +33,7 @@ pub const REQUEST_URI_MAX_LEN: usize = 1024;
pub const GEMINI_PORT: u16 = 1965;
type Handler = Arc<dyn Fn(Request) -> HandlerResponse + Send + Sync>;
type HandlerResponse = BoxFuture<'static, Result<Response>>;
pub (crate) type HandlerResponse = BoxFuture<'static, Result<Response>>;
#[derive(Clone)]
pub struct Server {
@ -94,7 +94,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);

View File

@ -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<File> for Body {
fn from(file: File) -> Self {
Self::Reader(Box::new(file))

View File

@ -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<str>) -> String {
text.as_ref()
.lines()
.filter(|part| !part.is_empty())
.collect::<Vec<_>>()
.join(" ")
}

View File

@ -1,13 +1,21 @@
use std::path::Path;
#[cfg(feature="serve_dir")]
use std::path::{Path, PathBuf};
#[cfg(feature="serve_dir")]
use mime::Mime;
use anyhow::*;
#[cfg(feature="serve_dir")]
use tokio::{
fs::{self, File},
io,
};
use crate::types::{Response, Document, document::HeadingLevel::*};
use itertools::Itertools;
#[cfg(feature="serve_dir")]
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;
#[cfg(feature="serve_dir")]
pub async fn serve_file<P: AsRef<Path>>(path: P, mime: &Mime) -> Result<Response> {
let path = path.as_ref();
@ -22,6 +30,7 @@ pub async fn serve_file<P: AsRef<Path>>(path: P, mime: &Mime) -> Result<Response
Ok(Response::success_with_body(mime, file))
}
#[cfg(feature="serve_dir")]
pub async fn serve_dir<D: AsRef<Path>, P: AsRef<Path>>(dir: D, virtual_path: &[P]) -> Result<Response> {
debug!("Dir: {}", dir.as_ref().display());
let dir = dir.as_ref().canonicalize()
@ -47,6 +56,7 @@ pub async fn serve_dir<D: AsRef<Path>, P: AsRef<Path>>(dir: D, virtual_path: &[P
serve_dir_listing(path, virtual_path).await
}
#[cfg(feature="serve_dir")]
async fn serve_dir_listing<P: AsRef<Path>, B: AsRef<Path>>(path: P, virtual_path: &[B]) -> Result<Response> {
let mut dir = match fs::read_dir(path).await {
Ok(dir) => dir,
@ -56,10 +66,10 @@ async fn serve_dir_listing<P: AsRef<Path>, B: AsRef<Path>>(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 +95,7 @@ async fn serve_dir_listing<P: AsRef<Path>, B: AsRef<Path>>(path: P, virtual_path
Ok(Response::document(document))
}
#[cfg(feature="serve_dir")]
pub fn guess_mime_from_path<P: AsRef<Path>>(path: P) -> Mime {
let path = path.as_ref();
let extension = path.extension().and_then(|s| s.to_str());
@ -115,3 +126,32 @@ where
C: AsRef<T> + Into<T::Owned>,
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<crate::HandlerResponse>,
}
impl HandlerCatchUnwind {
pub(super) fn new(future: AssertUnwindSafe<crate::HandlerResponse>) -> Self {
Self { future }
}
}
impl Future for HandlerCatchUnwind {
type Output = Result<Result<Response>, Box<dyn std::any::Any + Send>>;
fn poll(
mut self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context
) -> Poll<Self::Output> {
match catch_unwind(AssertUnwindSafe(|| self.future.as_mut().poll(cx))) {
Ok(res) => res.map(Ok),
Err(e) => Poll::Ready(Err(e))
}
}
}