Skip to content

Commit d5189ec

Browse files
committed
refactor: drop root arc-path on static files module
1 parent 084c4e6 commit d5189ec

File tree

1 file changed

+27
-47
lines changed

1 file changed

+27
-47
lines changed

src/static_files.rs

Lines changed: 27 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use std::io;
1717
use std::ops::Bound;
1818
use std::path::PathBuf;
1919
use std::pin::Pin;
20-
use std::sync::Arc;
2120
use std::task::Poll;
2221
use std::time::{SystemTime, UNIX_EPOCH};
2322
use std::{cmp, path::Path};
@@ -27,16 +26,6 @@ use tokio_util::io::poll_read_buf;
2726

2827
use crate::error::Result;
2928

30-
/// A small Arch `PathBuf` wrapper since Arc<PathBuf> doesn't implement AsRef<Path>.
31-
#[derive(Clone, Debug)]
32-
pub struct ArcPath(pub Arc<PathBuf>);
33-
34-
impl AsRef<Path> for ArcPath {
35-
fn as_ref(&self) -> &Path {
36-
(*self.0).as_ref()
37-
}
38-
}
39-
4029
/// Entry point to handle web server requests which map to specific files
4130
/// on file system and return a file response.
4231
pub async fn handle_request(
@@ -51,14 +40,13 @@ pub async fn handle_request(
5140
return Err(StatusCode::METHOD_NOT_ALLOWED);
5241
}
5342

54-
let base = Arc::new(base.into());
55-
let (path, meta, auto_index) = path_from_tail(base, uri_path).await?;
43+
let (path, meta, auto_index) = path_from_tail(base.into(), uri_path).await?;
5644

5745
// Directory listing
5846
// 1. Check if "directory listing" feature is enabled,
5947
// if current path is a valid directory and
6048
// if it does not contain an `index.html` file
61-
if dir_listing && auto_index && !path.as_ref().exists() {
49+
if dir_listing && auto_index && !path.exists() {
6250
// Redirect if current path does not end with a slash
6351
let current_path = uri_path;
6452
if !current_path.ends_with('/') {
@@ -79,10 +67,10 @@ pub async fn handle_request(
7967
}
8068

8169
fn path_from_tail(
82-
base: Arc<PathBuf>,
70+
base: PathBuf,
8371
tail: &str,
84-
) -> impl Future<Output = Result<(ArcPath, Metadata, bool), StatusCode>> + Send {
85-
future::ready(sanitize_path(base.as_ref(), tail)).and_then(|mut buf| async {
72+
) -> impl Future<Output = Result<(PathBuf, Metadata, bool), StatusCode>> + Send {
73+
future::ready(sanitize_path(base, tail)).and_then(|mut buf| async {
8674
match tokio::fs::metadata(&buf).await {
8775
Ok(meta) => {
8876
let mut auto_index = false;
@@ -92,7 +80,7 @@ fn path_from_tail(
9280
auto_index = true;
9381
}
9482
tracing::trace!("dir: {:?}", buf);
95-
Ok((ArcPath(Arc::new(buf)), meta, auto_index))
83+
Ok((buf, meta, auto_index))
9684
}
9785
Err(err) => {
9886
tracing::debug!("file not found: {:?}", err);
@@ -104,11 +92,11 @@ fn path_from_tail(
10492

10593
fn directory_listing(
10694
method: &Method,
107-
res: (String, ArcPath),
95+
res: (String, PathBuf),
10896
) -> impl Future<Output = Result<Response<Body>, StatusCode>> + Send {
10997
let (current_path, path) = res;
11098
let is_head = method == Method::HEAD;
111-
let parent = path.as_ref().parent().unwrap();
99+
let parent = path.parent().unwrap();
112100
let parent = PathBuf::from(parent);
113101

114102
tokio::fs::read_dir(parent).then(move |res| match res {
@@ -118,7 +106,7 @@ fn directory_listing(
118106
Err(err) => {
119107
tracing::error!(
120108
"error during directory entries reading (path={:?}): {} ",
121-
path.as_ref().parent().unwrap().display(),
109+
path.parent().unwrap().display(),
122110
err
123111
);
124112
Err(StatusCode::INTERNAL_SERVER_ERROR)
@@ -128,20 +116,17 @@ fn directory_listing(
128116
Err(err) => {
129117
let status = match err.kind() {
130118
io::ErrorKind::NotFound => {
131-
tracing::debug!("entry file not found: {:?}", path.as_ref().display());
119+
tracing::debug!("entry file not found: {:?}", path.display());
132120
StatusCode::NOT_FOUND
133121
}
134122
io::ErrorKind::PermissionDenied => {
135-
tracing::warn!(
136-
"entry file permission denied: {:?}",
137-
path.as_ref().display()
138-
);
123+
tracing::warn!("entry file permission denied: {:?}", path.display());
139124
StatusCode::FORBIDDEN
140125
}
141126
_ => {
142127
tracing::error!(
143128
"directory entries error (path={:?}): {} ",
144-
path.as_ref().display(),
129+
path.display(),
145130
err
146131
);
147132
StatusCode::INTERNAL_SERVER_ERROR
@@ -249,7 +234,7 @@ fn parse_last_modified(modified: SystemTime) -> Result<time::Tm, Box<dyn std::er
249234
/// Reply with a file content.
250235
fn file_reply(
251236
headers: &HeaderMap<HeaderValue>,
252-
res: (ArcPath, Metadata, bool),
237+
res: (PathBuf, Metadata, bool),
253238
) -> impl Future<Output = Result<Response<Body>, StatusCode>> + Send {
254239
let (path, meta, auto_index) = res;
255240
let conditionals = get_conditional_headers(headers);
@@ -258,19 +243,15 @@ fn file_reply(
258243
Err(err) => {
259244
let status = match err.kind() {
260245
io::ErrorKind::NotFound => {
261-
tracing::debug!("file not found: {:?}", path.as_ref().display());
246+
tracing::debug!("file not found: {:?}", path.display());
262247
StatusCode::NOT_FOUND
263248
}
264249
io::ErrorKind::PermissionDenied => {
265-
tracing::warn!("file permission denied: {:?}", path.as_ref().display());
250+
tracing::warn!("file permission denied: {:?}", path.display());
266251
StatusCode::FORBIDDEN
267252
}
268253
_ => {
269-
tracing::error!(
270-
"file open error (path={:?}): {} ",
271-
path.as_ref().display(),
272-
err
273-
);
254+
tracing::error!("file open error (path={:?}): {} ", path.display(), err);
274255
StatusCode::INTERNAL_SERVER_ERROR
275256
}
276257
};
@@ -293,16 +274,15 @@ fn get_conditional_headers(header_list: &HeaderMap<HeaderValue>) -> Conditionals
293274
}
294275
}
295276

296-
fn sanitize_path(base: impl AsRef<Path>, tail: &str) -> Result<PathBuf, StatusCode> {
297-
let mut buf = PathBuf::from(base.as_ref());
277+
fn sanitize_path(mut buf: PathBuf, tail: &str) -> Result<PathBuf, StatusCode> {
298278
let p = match percent_decode_str(tail).decode_utf8() {
299279
Ok(p) => p,
300280
Err(err) => {
301281
tracing::debug!("dir: failed to decode route={:?}: {:?}", tail, err);
302282
return Err(StatusCode::UNSUPPORTED_MEDIA_TYPE);
303283
}
304284
};
305-
tracing::trace!("dir? base={:?}, route={:?}", base.as_ref(), p);
285+
tracing::trace!("dir? base={:?}, route={:?}", buf, p);
306286
for seg in p.split('/') {
307287
if seg.starts_with("..") {
308288
tracing::warn!("dir: rejecting segment starting with '..'");
@@ -381,13 +361,13 @@ impl Conditionals {
381361

382362
fn file_conditional(
383363
f: TkFile,
384-
path: ArcPath,
364+
path: PathBuf,
385365
meta: Metadata,
386366
auto_index: bool,
387367
conditionals: Conditionals,
388368
) -> impl Future<Output = Result<Response<Body>, StatusCode>> + Send {
389369
file_metadata(f, meta, auto_index)
390-
.map_ok(|(file, meta)| response_body(file, meta, path, conditionals))
370+
.map_ok(|(file, meta)| response_body(file, &meta, path, conditionals))
391371
}
392372

393373
async fn file_metadata(
@@ -409,8 +389,8 @@ async fn file_metadata(
409389

410390
fn response_body(
411391
file: TkFile,
412-
meta: Metadata,
413-
path: ArcPath,
392+
meta: &Metadata,
393+
path: PathBuf,
414394
conditionals: Conditionals,
415395
) -> Response<Body> {
416396
let mut len = meta.len();
@@ -421,7 +401,7 @@ fn response_body(
421401
bytes_range(range, len)
422402
.map(|(start, end)| {
423403
let sub_len = end - start;
424-
let buf_size = optimal_buf_size(&meta);
404+
let buf_size = optimal_buf_size(meta);
425405
let stream = file_stream(file, buf_size, (start, end));
426406
let body = Body::wrap_stream(stream);
427407

@@ -436,7 +416,7 @@ fn response_body(
436416
len = sub_len;
437417
}
438418

439-
let mime = mime_guess::from_path(path.as_ref()).first_or_octet_stream();
419+
let mime = mime_guess::from_path(path).first_or_octet_stream();
440420

441421
resp.headers_mut().typed_insert(ContentLength(len));
442422
resp.headers_mut().typed_insert(ContentType::from(mime));
@@ -602,14 +582,14 @@ mod tests {
602582
}
603583

604584
assert_eq!(
605-
sanitize_path(base, "/foo.html").unwrap(),
585+
sanitize_path(base.into(), "/foo.html").unwrap(),
606586
p("/var/www/foo.html")
607587
);
608588

609589
// bad paths
610-
sanitize_path(base, "/../foo.html").expect_err("dot dot");
590+
sanitize_path(base.into(), "/../foo.html").expect_err("dot dot");
611591

612-
sanitize_path(base, "/C:\\/foo.html").expect_err("C:\\");
592+
sanitize_path(base.into(), "/C:\\/foo.html").expect_err("C:\\");
613593
}
614594

615595
#[test]

0 commit comments

Comments
 (0)