Skip to content

Commit 9b4c544

Browse files
committed
Port to cap-async-std.
1 parent 20fe435 commit 9b4c544

File tree

3 files changed

+42
-39
lines changed

3 files changed

+42
-39
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ async-session = { version = "3.0", optional = true }
3939
async-sse = { version = "5.1.0", optional = true }
4040
async-std = { version = "1.6.5", features = ["unstable"] }
4141
async-trait = "0.1.41"
42+
cap-async-std = "0.25.0"
4243
femme = { version = "2.1.1", optional = true }
4344
futures-util = "0.3.6"
4445
http-client = { version = "6.1.0", default-features = false }

src/fs/serve_dir.rs

+36-38
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
use crate::log;
22
use crate::{Body, Endpoint, Request, Response, Result, StatusCode};
33

4-
use async_std::path::PathBuf as AsyncPathBuf;
4+
use async_std::io::BufReader;
55

6-
use std::path::{Path, PathBuf};
7-
use std::{ffi::OsStr, io};
6+
use cap_async_std::fs;
87

98
pub(crate) struct ServeDir {
109
prefix: String,
11-
dir: PathBuf,
10+
dir: fs::Dir,
1211
}
1312

1413
impl ServeDir {
1514
/// Create a new instance of `ServeDir`.
16-
pub(crate) fn new(prefix: String, dir: PathBuf) -> Self {
15+
pub(crate) fn new(prefix: String, dir: fs::Dir) -> Self {
1716
Self { prefix, dir }
1817
}
1918
}
@@ -29,57 +28,56 @@ where
2928
.strip_prefix(&self.prefix.trim_end_matches('*'))
3029
.unwrap();
3130
let path = path.trim_start_matches('/');
32-
let mut file_path = self.dir.clone();
33-
for p in Path::new(path) {
34-
if p == OsStr::new(".") {
35-
continue;
36-
} else if p == OsStr::new("..") {
37-
file_path.pop();
38-
} else {
39-
file_path.push(&p);
31+
32+
log::info!("Requested file: {:?}", path);
33+
34+
let file = match self.dir.open(path).await {
35+
Ok(file) => file,
36+
Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => {
37+
log::warn!("Unauthorized attempt to read: {:?}", path);
38+
return Ok(Response::new(StatusCode::Forbidden));
4039
}
41-
}
42-
43-
log::info!("Requested file: {:?}", file_path);
44-
45-
let file_path = AsyncPathBuf::from(file_path);
46-
if !file_path.starts_with(&self.dir) {
47-
log::warn!("Unauthorized attempt to read: {:?}", file_path);
48-
Ok(Response::new(StatusCode::Forbidden))
49-
} else {
50-
match Body::from_file(&file_path).await {
51-
Ok(body) => Ok(Response::builder(StatusCode::Ok).body(body).build()),
52-
Err(e) if e.kind() == io::ErrorKind::NotFound => {
53-
log::warn!("File not found: {:?}", &file_path);
54-
Ok(Response::new(StatusCode::NotFound))
55-
}
56-
Err(e) => Err(e.into()),
40+
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
41+
log::warn!("File not found: {:?}", path);
42+
return Ok(Response::new(StatusCode::NotFound));
5743
}
58-
}
44+
Err(e) => return Err(e.into()),
45+
};
46+
47+
// TODO: This always uses `mime::BYTE_STREAM`; with http-types 3.0
48+
// we'll be able to use `Body::from_open_file` which fixes this.
49+
let body = Body::from_reader(BufReader::new(file), None);
50+
Ok(Response::builder(StatusCode::Ok).body(body).build())
5951
}
6052
}
6153

6254
#[cfg(test)]
6355
mod test {
6456
use super::*;
6557

66-
use std::fs::{self, File};
67-
use std::io::Write;
58+
use async_std::io::WriteExt;
59+
use cap_async_std::ambient_authority;
60+
use cap_async_std::fs::Dir;
6861

6962
fn serve_dir(tempdir: &tempfile::TempDir) -> crate::Result<ServeDir> {
70-
let static_dir = tempdir.path().join("static");
71-
fs::create_dir(&static_dir)?;
72-
73-
let file_path = static_dir.join("foo");
74-
let mut file = File::create(&file_path)?;
75-
write!(file, "Foobar")?;
63+
let static_dir = async_std::task::block_on(async { setup_static_dir(tempdir).await })?;
7664

7765
Ok(ServeDir {
7866
prefix: "/static/".to_string(),
7967
dir: static_dir,
8068
})
8169
}
8270

71+
async fn setup_static_dir(tempdir: &tempfile::TempDir) -> crate::Result<Dir> {
72+
let static_dir = tempdir.path().join("static");
73+
Dir::create_ambient_dir_all(&static_dir, ambient_authority()).await?;
74+
75+
let static_dir = Dir::open_ambient_dir(static_dir, ambient_authority()).await?;
76+
let mut file = static_dir.create("foo").await?;
77+
write!(file, "Foobar").await?;
78+
Ok(static_dir)
79+
}
80+
8381
fn request(path: &str) -> crate::Request<()> {
8482
let request = crate::http::Request::get(
8583
crate::http::Url::parse(&format!("http://localhost/{}", path)).unwrap(),

src/route.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
use async_std::task;
2+
use cap_async_std::ambient_authority;
3+
use cap_async_std::fs::Dir;
14
use std::fmt::Debug;
25
use std::io;
36
use std::path::Path;
@@ -165,7 +168,8 @@ impl<'a, State: Clone + Send + Sync + 'static> Route<'a, State> {
165168
/// ```
166169
pub fn serve_dir(&mut self, dir: impl AsRef<Path>) -> io::Result<()> {
167170
// Verify path exists, return error if it doesn't.
168-
let dir = dir.as_ref().to_owned().canonicalize()?;
171+
let path = dir.as_ref().to_owned().canonicalize()?;
172+
let dir = task::block_on(async { Dir::open_ambient_dir(path, ambient_authority()).await })?;
169173
let prefix = self.path().to_string();
170174
self.get(ServeDir::new(prefix, dir));
171175
Ok(())

0 commit comments

Comments
 (0)