diff --git a/src/routes.rs b/src/routes.rs index c358c3b..4e9f537 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -1,6 +1,6 @@ use std::{io::{self, Read}, path::PathBuf, path, fs::File}; -use axum::{http::{StatusCode, HeaderMap, HeaderValue}, extract::{Multipart, Path}, body::Bytes, BoxError, Router, routing::{post, get}}; +use axum::{http::{StatusCode, HeaderMap, HeaderValue}, extract::{Multipart, Path}, body::Bytes, BoxError, Router, routing::{post, get}, response::Redirect}; use futures::{Stream, TryStreamExt}; use tokio::io::{BufWriter, AsyncWriteExt}; use tokio_util::io::StreamReader; @@ -11,29 +11,44 @@ use crate::projects::Authed; pub fn router() -> Router { Router::new() .route("/:project", post(upload_project)) + .route("/:project", get(project_redirect)) .route("/:project/*path", get(get_asset)) } +async fn project_redirect(Path(path): Path) -> Redirect { + Redirect::to(&format!("/{}/", path)) +} + async fn get_asset(Path((project, filename)): Path<(String, String)>) -> Result<(HeaderMap, Vec), StatusCode> { let path = path::Path::new("project-archives") .join(format!("{project}.zip")); if path.exists() { - let data = { + let asset = { let filename = filename.clone(); move || { - let zip = ZipArchive::new(File::open(path)?)?; - let asset = find_asset(zip, &filename.clone())?; + let mut zip = ZipArchive::new(File::open(path)?)?; + let asset = find_asset(&mut zip, &filename.clone())?; + let asset = if let Some(asset) = asset { + Some((mime_guess::from_path(filename).first_or_octet_stream(), asset)) + } else if filename.ends_with("/") { + let changed_name = format!("{filename}index.html"); + find_asset(&mut zip, &changed_name)? + .map(|data| (mime_guess::from_path(changed_name).first_or_octet_stream(), data)) + } else { + None + }; Ok::<_, color_eyre::Report>(asset) } }; - let data = tokio::task::spawn_blocking(data).await + + let asset = tokio::task::spawn_blocking(asset).await .unwrap() .map_err(|e| { tracing::error!(%e, "failed to find asset in zip"); StatusCode::INTERNAL_SERVER_ERROR })?; - if let Some(data) = data { - let mime = mime_guess::from_path(filename).first_or_octet_stream(); + + if let Some((mime, data)) = asset { let mut headers = HeaderMap::new(); headers.append("content-type", HeaderValue::from_str(mime.essence_str()).unwrap()); Ok((headers, data)) @@ -45,7 +60,7 @@ async fn get_asset(Path((project, filename)): Path<(String, String)>) -> Result< } } -fn find_asset(mut zip: ZipArchive, filename: &str) -> color_eyre::Result>> { +fn find_asset(zip: &mut ZipArchive, filename: &str) -> color_eyre::Result>> { let filename = if filename.starts_with("/") { &filename[1..] } else {