Skip to content

Commit

Permalink
Call ServeDir's fallback on non-uft8 request paths (#310)
Browse files Browse the repository at this point in the history
* Call `ServeDir`'s fallback on non-uft8 request paths

Fixes #308

* changelog link
  • Loading branch information
davidpdrsn authored Dec 2, 2022
1 parent b41401a commit 49fc4d1
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 17 deletions.
4 changes: 3 additions & 1 deletion tower-http/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **trace:** Correctly identify gRPC requests in default `on_response` callback ([#278])
- **cors:** Panic if a wildcard (`*`) is passed to `AllowOrigin::list`. Use
`AllowOrigin::any()` instead ([#285])
- **serve_dir:** Call the fallback on non-uft8 request paths ([#310])

[#275]: https://github.com/tower-rs/tower-http/pull/275
[#278]: https://github.com/tower-rs/tower-http/pull/278
[#285]: https://github.com/tower-rs/tower-http/pull/285
[#275]: https://github.com/tower-rs/tower-http/pull/275
[#289]: https://github.com/tower-rs/tower-http/pull/289
[#299]: https://github.com/tower-rs/tower-http/pull/299
[#303]: https://github.com/tower-rs/tower-http/pull/303
[#310]: https://github.com/tower-rs/tower-http/pull/310

# 0.3.4 (June 06, 2022)

Expand Down
20 changes: 15 additions & 5 deletions tower-http/src/services/fs/serve_dir/future.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@ impl<ReqBody, F> ResponseFuture<ReqBody, F> {
}
}

pub(super) fn invalid_path() -> Self {
pub(super) fn invalid_path(fallback_and_request: Option<(F, Request<ReqBody>)>) -> Self {
Self {
inner: ResponseFutureInner::InvalidPath,
inner: ResponseFutureInner::InvalidPath {
fallback_and_request,
},
}
}

Expand All @@ -67,7 +69,9 @@ pin_project! {
FallbackFuture {
future: BoxFuture<'static, io::Result<Response<ResponseBody>>>,
},
InvalidPath,
InvalidPath {
fallback_and_request: Option<(F, Request<ReqBody>)>,
},
MethodNotAllowed,
}
}
Expand Down Expand Up @@ -138,8 +142,14 @@ where
break Pin::new(future).poll(cx)
}

ResponseFutureInnerProj::InvalidPath => {
break Poll::Ready(Ok(not_found()));
ResponseFutureInnerProj::InvalidPath {
fallback_and_request,
} => {
if let Some((mut fallback, request)) = fallback_and_request.take() {
call_fallback(&mut fallback, request)
} else {
break Poll::Ready(Ok(not_found()));
}
}

ResponseFutureInnerProj::MethodNotAllowed => {
Expand Down
20 changes: 10 additions & 10 deletions tower-http/src/services/fs/serve_dir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,16 +299,6 @@ where
let extensions = std::mem::take(&mut parts.extensions);
let req = Request::from_parts(parts, Empty::<Bytes>::new());

let path_to_file = match self
.variant
.build_and_validate_path(&self.base, req.uri().path())
{
Some(path_to_file) => path_to_file,
None => {
return ResponseFuture::invalid_path();
}
};

let fallback_and_request = self.fallback.as_mut().map(|fallback| {
let mut fallback_req = Request::new(body);
*fallback_req.method_mut() = req.method().clone();
Expand All @@ -323,6 +313,16 @@ where
(fallback, fallback_req)
});

let path_to_file = match self
.variant
.build_and_validate_path(&self.base, req.uri().path())
{
Some(path_to_file) => path_to_file,
None => {
return ResponseFuture::invalid_path(fallback_and_request);
}
};

let buf_chunk_size = self.buf_chunk_size;
let range_header = req
.headers()
Expand Down
25 changes: 24 additions & 1 deletion tower-http/src/services/fs/serve_dir/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ use http::{header, Method, Response};
use http::{Request, StatusCode};
use http_body::Body as HttpBody;
use hyper::Body;
use std::convert::Infallible;
use std::io::{self, Read};
use tower::ServiceExt;
use tower::{service_fn, ServiceExt};

#[tokio::test]
async fn basic() {
Expand Down Expand Up @@ -688,3 +689,25 @@ async fn with_fallback_svc_and_not_append_index_html_on_directories() {
let body = body_into_text(res.into_body()).await;
assert_eq!(body, "from fallback /");
}

// https://github.com/tower-rs/tower-http/issues/308
#[tokio::test]
async fn calls_fallback_on_invalid_paths() {
async fn fallback<T>(_: T) -> Result<Response<Body>, std::io::Error> {
let mut res = Response::new(Body::empty());
res.headers_mut()
.insert("from-fallback", "1".parse().unwrap());
Ok(res)
}

let svc = ServeDir::new("..").fallback(service_fn(fallback));

let req = Request::builder()
.uri("/weird_%c3%28_path")
.body(Body::empty())
.unwrap();

let res = svc.oneshot(req).await.unwrap();

assert_eq!(res.headers()["from-fallback"], "1");
}

0 comments on commit 49fc4d1

Please sign in to comment.