Skip to content

Commit

Permalink
Port to cap-async-std.
Browse files Browse the repository at this point in the history
  • Loading branch information
sunfishcode committed Nov 17, 2021
1 parent 4be9062 commit d1980a7
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 33 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -38,6 +38,7 @@ async-session = { version = "3.0", optional = true }
async-sse = "4.0.1"
async-std = { version = "1.6.5", features = ["unstable"] }
async-trait = "0.1.41"
cap-async-std = "0.21.1"
femme = { version = "2.1.1", optional = true }
futures-util = "0.3.6"
http-client = { version = "6.1.0", default-features = false }
Expand Down
44 changes: 12 additions & 32 deletions src/fs/serve_dir.rs
@@ -1,19 +1,18 @@
use crate::log;
use crate::{Body, Endpoint, Request, Response, Result, StatusCode};

use async_std::path::PathBuf as AsyncPathBuf;
use async_std::io::BufReader;

use std::path::{Path, PathBuf};
use std::{ffi::OsStr, io};
use cap_async_std::fs;

pub(crate) struct ServeDir {
prefix: String,
dir: PathBuf,
dir: fs::Dir,
}

impl ServeDir {
/// Create a new instance of `ServeDir`.
pub(crate) fn new(prefix: String, dir: PathBuf) -> Self {
pub(crate) fn new(prefix: String, dir: fs::Dir) -> Self {
Self { prefix, dir }
}
}
Expand All @@ -29,33 +28,14 @@ where
.strip_prefix(&self.prefix.trim_end_matches('*'))
.unwrap();
let path = path.trim_start_matches('/');
let mut file_path = self.dir.clone();
for p in Path::new(path) {
if p == OsStr::new(".") {
continue;
} else if p == OsStr::new("..") {
file_path.pop();
} else {
file_path.push(&p);
}
}

log::info!("Requested file: {:?}", file_path);

let file_path = AsyncPathBuf::from(file_path);
if !file_path.starts_with(&self.dir) {
log::warn!("Unauthorized attempt to read: {:?}", file_path);
Ok(Response::new(StatusCode::Forbidden))
} else {
match Body::from_file(&file_path).await {
Ok(body) => Ok(Response::builder(StatusCode::Ok).body(body).build()),
Err(e) if e.kind() == io::ErrorKind::NotFound => {
log::warn!("File not found: {:?}", &file_path);
Ok(Response::new(StatusCode::NotFound))
}
Err(e) => Err(e.into()),
}
}

log::info!("Requested file: {:?}", path);

let file = self.dir.open(path).await?;
// TODO: This always uses `mime::BYTE_STREAM`; with http-types 3.0
// we'll be able to use `Body::from_open_file` which fixes this.
let body = Body::from_reader(BufReader::new(file), None);
Ok(Response::builder(StatusCode::Ok).body(body).build())
}
}

Expand Down
8 changes: 7 additions & 1 deletion src/route.rs
Expand Up @@ -2,6 +2,9 @@ use std::fmt::Debug;
use std::io;
use std::path::Path;
use std::sync::Arc;
use async_std::task;
use cap_async_std::ambient_authority;
use cap_async_std::fs::Dir;

use crate::endpoint::MiddlewareEndpoint;
use crate::fs::{ServeDir, ServeFile};
Expand Down Expand Up @@ -165,7 +168,10 @@ impl<'a, State: Clone + Send + Sync + 'static> Route<'a, State> {
/// ```
pub fn serve_dir(&mut self, dir: impl AsRef<Path>) -> io::Result<()> {
// Verify path exists, return error if it doesn't.
let dir = dir.as_ref().to_owned().canonicalize()?;
let path = dir.as_ref().to_owned().canonicalize()?;
let dir = task::block_on(async {
Dir::open_ambient_dir(path, ambient_authority()).await
})?;
let prefix = self.path().to_string();
self.get(ServeDir::new(prefix, dir));
Ok(())
Expand Down

0 comments on commit d1980a7

Please sign in to comment.