diff --git a/examples/serve_dir.rs b/examples/serve_dir.rs index bb81add..b79c08d 100644 --- a/examples/serve_dir.rs +++ b/examples/serve_dir.rs @@ -1,6 +1,8 @@ +use std::path::PathBuf; + use anyhow::*; use log::LevelFilter; -use northstar::{Server, Request, Response, GEMINI_PORT}; +use northstar::{Server, GEMINI_PORT}; #[tokio::main] async fn main() -> Result<()> { @@ -9,14 +11,7 @@ async fn main() -> Result<()> { .init(); Server::bind(("localhost", GEMINI_PORT)) - .add_route("/", handle_request) + .add_route("/", PathBuf::from("public")) .serve() .await } - -async fn handle_request(request: Request) -> Result { - let path = request.path_segments(); - let response = northstar::util::serve_dir("public", &path).await?; - - Ok(response) -} diff --git a/src/handling.rs b/src/handling.rs index b8bb811..de2d750 100644 --- a/src/handling.rs +++ b/src/handling.rs @@ -14,6 +14,8 @@ use std::{ task::Poll, panic::{catch_unwind, AssertUnwindSafe}, }; +#[cfg(feature = "serve_dir")] +use std::path::PathBuf; use crate::{Document, types::{Body, Response, Request}}; @@ -30,6 +32,8 @@ use crate::{Document, types::{Body, Response, Request}}; pub enum Handler { FnHandler(HandlerInner), StaticHandler(Response), + #[cfg(feature = "serve_dir")] + FilesHandler(PathBuf), } /// Since we can't store train objects, we need to wrap fn handlers in a box @@ -77,7 +81,15 @@ impl Handler { ).unwrap() } } - } + }, + #[cfg(feature = "serve_dir")] + Self::FilesHandler(path) => { + let resp = crate::util::serve_dir(path, request.trailing_segments()).await; + resp.unwrap_or_else(|e| { + warn!("Unexpected error serving from dir {}: {:?}", path.display(), e); + Response::server_error("").unwrap() + }) + }, } } } @@ -140,6 +152,24 @@ impl From<&Document> for Handler { } } +#[cfg(feature = "serve_dir")] +impl From for Handler { + /// Serve files from a directory + /// + /// Any requests directed to this handler will be served from this path. For example, + /// if a handler serving files from the path `./public/` and bound to `/serve` + /// receives a request for `/serve/file.txt`, it will respond with the contents of the + /// file at `./public/file.txt`. + /// + /// This is equivilent to serving files using [`util::serve_dir()`], and as such will + /// include directory listings. + /// + /// [`util::serve_dir()`]: crate::util::serve_dir() + fn from(path: PathBuf) -> Self { + Self::FilesHandler(path) + } +} + /// A utility for catching unwinds on Futures. /// /// This is adapted from the futures-rs CatchUnwind, in an effort to reduce the large