Skip to content

Commit

Permalink
Add static file serving
Browse files Browse the repository at this point in the history
This depends on #414
  • Loading branch information
yoshuawuyts committed Apr 20, 2020
1 parent 2003a99 commit 2f43286
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 1 deletion.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ serde = { version = "1.0.102", features = ["derive"] }
structopt = "0.3.3"
surf = "2.0.0-alpha.1"
futures = "0.3.1"
femme = "1.3.0"

[[test]]
name = "nested"
Expand Down
68 changes: 68 additions & 0 deletions examples/static_file.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use async_std::fs::File;
use async_std::io::BufReader;
use async_std::task;
use http_types::StatusCode;

use std::io;
use tide::{Endpoint, Request, Response};

use std::path::{Path, PathBuf};

type BoxFuture<'a, T> = std::pin::Pin<Box<dyn std::future::Future<Output = T> + 'a + Send>>;

fn main() -> Result<(), std::io::Error> {
femme::start(log::LevelFilter::Info).unwrap();
task::block_on(async {
let mut app = tide::new();
app.at("/").get(|_| async move { "Hello, world!" });
serve_dir(&mut app.at("/foo"), "src/")?;
app.listen("127.0.0.1:8080").await?;
Ok(())
})
}

fn serve_dir<State: 'static>(
route: &mut tide::Route<State>,
dir: impl AsRef<Path>,
) -> io::Result<()> {
// Verify path exists, return error if it doesn't.
let dir = dir.as_ref().to_owned().canonicalize()?;
let serve = ServeDir {
prefix: route.path().to_string(),
dir,
};
route.at("*").get(serve);
Ok(())
}

pub struct ServeDir {
prefix: String,
dir: PathBuf,
}

impl<State> Endpoint<State> for ServeDir {
fn call<'a>(&'a self, req: Request<State>) -> BoxFuture<'a, Response> {
let path = req.uri().path();
let path = path.replace(&self.prefix, "");
let path = path.trim_start_matches('/');
let dir = self.dir.clone();
let dir = dir.join(&path);
log::info!("Requested file: {:?}", dir);

Box::pin(async move {
let file = match async_std::fs::canonicalize(&dir).await {
Err(_) => {
log::info!("File not found: {:?}", dir);
return Response::new(StatusCode::NotFound);
}
Ok(file) => {
log::info!("Serving file: {:?}", file);
File::open(file).await.unwrap() // TODO: remove unwrap
}
};

// TODO: fix related bug where async-h1 crashes on large files
Response::new(StatusCode::Ok).body(BufReader::new(file))
})
}
}
1 change: 0 additions & 1 deletion src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use async_std::io;
use async_std::net::ToSocketAddrs;
use async_std::sync::Arc;
use async_std::task::{Context, Poll};

use http_service::HttpService;

use std::pin::Pin;
Expand Down
18 changes: 18 additions & 0 deletions src/server/route.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,24 @@ impl<'a, State: 'static> Route<'a, State> {
}
}

/// Get the current path.
pub fn path(&self) -> &str {
&self.path
}

// /// Serve up a static directory.
// pub fn dir(&mut self, dir: &Path) -> http_types::Result<()> {
// for entry in WalkDir::new(dir) {
// let entry = entry?;
// if !entry.file_type().is_dir() {
// let p = entry.into_path();
// continue;
// }
// // self.at(entry.name()).get(/* serve file */)
// }
// todo!();
// }

/// Treat the current path as a prefix, and strip prefixes from requests.
///
/// This method is marked unstable as its name might change in the near future.
Expand Down

0 comments on commit 2f43286

Please sign in to comment.