It lives!

This commit is contained in:
Elf M. Sternberg 2026-06-06 12:30:13 -07:00
parent 5245420073
commit 8a3dc6995c
3 changed files with 87 additions and 6 deletions

View File

@ -1,3 +1,4 @@
use rc_zip_tokio::ReadZip;
use std::convert::Infallible;
use std::sync::Arc;
@ -5,6 +6,7 @@ use axum::body::Body;
use http::{Method, Request, Response, StatusCode};
use crate::index::Entries;
use crate::read_zip_for_arc::ArcBytes;
use crate::serve_zip::ZipServeConfig;
pub async fn serve<B>(
@ -57,13 +59,65 @@ fn not_found() -> Response<Body> {
}
async fn serve_entry(
_data: Arc<[u8]>,
_config: ZipServeConfig,
_entry_name: String,
_method: Method,
data: Arc<[u8]>,
config: ZipServeConfig,
entry_name: String,
method: Method,
) -> Result<Response<Body>, Infallible> {
Ok(Response::builder()
.status(StatusCode::NOT_IMPLEMENTED)
let data = ArcBytes(data);
let archive = match data.read_zip().await {
Ok(a) => a,
Err(e) => {
eprintln!("Failed to open archive: {}", e);
return Ok(internal_error("Failed to open archive"));
}
};
let entry = match archive.by_name(&entry_name) {
Some(e) => e,
None => return Ok(not_found()),
};
let content_type = mime_for(&entry_name, &config);
let content_length = entry.uncompressed_size;
if method == Method::HEAD {
return Ok(Response::builder()
.status(StatusCode::OK)
.header("content-type", content_type)
.header("content-length", content_length.to_string())
.body(Body::empty())
.unwrap());
}
let mut reader = entry.reader();
let mut buffer = Vec::with_capacity(content_length as usize);
if let Err(e) = tokio::io::AsyncReadExt::read_to_end(&mut reader, &mut buffer).await {
eprintln!("Failed to read entry: {}", e);
return Ok(internal_error("Failed to read entry"));
}
let body = Body::from(buffer);
Ok(Response::builder()
.status(StatusCode::OK)
.header("content-type", content_type)
.header("content-length", content_length.to_string())
.body(body)
.unwrap())
}
fn mime_for(entry_name: &str, config: &ZipServeConfig) -> String {
mime_guess::from_path(entry_name)
.first_raw()
.unwrap_or(&config.fallback_content_type)
.to_string()
}
fn internal_error(msg: &str) -> Response<Body> {
Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.header("content-type", "text/plain; charset=utf-8")
.body(Body::from(msg.to_string()))
.unwrap()
}

View File

@ -1,5 +1,6 @@
pub mod handler;
pub mod index;
pub mod read_zip_for_arc;
pub mod serve_zip;
pub mod service;
pub mod source;

View File

@ -0,0 +1,26 @@
use rc_zip::Error;
use rc_zip_tokio::{ArchiveHandle, HasCursor, ReadZip, ReadZipWithSize};
use std::io::Cursor;
use std::sync::Arc;
pub struct ArcBytes(pub Arc<[u8]>);
impl HasCursor for ArcBytes {
type Cursor<'a>
= Cursor<Arc<[u8]>>
where
Self: 'a;
fn cursor_at(&self, offset: u64) -> Self::Cursor<'_> {
let mut c = Cursor::new(Arc::clone(&self.0));
c.set_position(offset);
c
}
}
impl ReadZip for ArcBytes {
type File = Self;
async fn read_zip(&self) -> Result<ArchiveHandle<'_, Self>, Error> {
self.read_zip_with_size(self.0.len() as u64).await
}
}