Handle requested path being a directory correctly
This commit is contained in:
parent
6a611c371c
commit
6dd53f96d8
@ -39,6 +39,9 @@ pub enum GetFileError {
|
||||
#[error("file not found")]
|
||||
FileNotFound,
|
||||
|
||||
#[error("path is directory")]
|
||||
PathIsDirectory,
|
||||
|
||||
#[error(transparent)]
|
||||
Unexpected(#[from] unexpected::Error),
|
||||
}
|
||||
|
@ -330,10 +330,20 @@ impl super::Store for FSStore {
|
||||
.object()
|
||||
.or_unexpected()?;
|
||||
|
||||
// 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) })))
|
||||
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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()),
|
||||
};
|
||||
|
||||
|
@ -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())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user