Handle requested path being a directory correctly

This commit is contained in:
Brian Picciano 2024-01-16 14:31:32 +01:00
parent 6a611c371c
commit 6dd53f96d8
4 changed files with 52 additions and 10 deletions

View File

@ -39,6 +39,9 @@ pub enum GetFileError {
#[error("file not found")]
FileNotFound,
#[error("path is directory")]
PathIsDirectory,
#[error(transparent)]
Unexpected(#[from] unexpected::Error),
}

View File

@ -330,11 +330,21 @@ impl super::Store for FSStore {
.object()
.or_unexpected()?;
use gix::object::Kind;
match file_object.kind {
Kind::Tree => Err(origin::GetFileError::PathIsDirectory),
Kind::Blob => {
// TODO this is very not ideal, the whole file is first read totally into memory, and then
// that is cloned.
let data = bytes::Bytes::copy_from_slice(file_object.data.as_slice());
Ok(Box::pin(stream::once(async move { Ok(data) })))
}
Kind::Commit | Kind::Tag => Err(unexpected::Error::from(
format!("found object of kind {} in tree", file_object.kind).as_str(),
)
.into()),
}
}
}
#[cfg(test)]

View File

@ -113,6 +113,13 @@ impl Service {
)
.into())
}
Err(GetFileError::PathIsDirectory) => {
// redirect so that the path has '/' appended to it, which will cause the server to
// check index.gmi within the path on the new page load.
let mut path = path.into_owned();
path.push_str("/");
return Ok(self.respond_conn(w, "30", path.as_str(), None).await?);
}
Err(GetFileError::Unexpected(e)) => return Err(e.into()),
};

View File

@ -153,6 +153,19 @@ impl Service {
)
}
fn render_redirect(&self, status_code: u16, target_uri: &str) -> Response<Body> {
Response::builder()
.status(status_code)
.header("Location", target_uri.to_string())
.body(Body::empty())
.unwrap_or_else(|err| {
self.internal_error(
format!("failed to render {status_code} redirect to {target_uri}: {err}",)
.as_str(),
)
})
}
fn https_redirect(&self, domain: domain::Name, req: Request<Body>) -> Response<Body> {
let https_addr = self.config.http.https_addr.unwrap();
@ -173,13 +186,12 @@ impl Service {
.try_into()
.or_unexpected_while("constructing new URI")?;
Response::builder()
.status(http::status::StatusCode::PERMANENT_REDIRECT)
.header("Location", uri.to_string())
.body(Body::empty())
.or_unexpected_while("building redirect")
Ok(self.render_redirect(
http::status::StatusCode::PERMANENT_REDIRECT.into(),
uri.to_string().as_str(),
))
})()
.unwrap_or_else(|err| {
.unwrap_or_else(|err: unexpected::Error| {
self.internal_error(
format!("failed to redirect from {} to https: {}", req.uri(), err).as_str(),
)
@ -216,6 +228,16 @@ impl Service {
)
.as_str(),
),
Err(GetFileError::PathIsDirectory) => {
// redirect so that the path has '/' appended to it, which will cause the server to
// check index.html within the path on the new page load.
let mut path = path.into_owned();
path.push_str("/");
self.render_redirect(
http::status::StatusCode::TEMPORARY_REDIRECT.into(),
path.as_str(),
)
}
Err(GetFileError::Unexpected(e)) => {
self.internal_error(format!("failed to fetch file {path}: {e}").as_str())
}