improve file streams

This commit is contained in:
2025-09-06 18:00:58 +02:00
parent 1c4aaa7040
commit 5c09120c23
4 changed files with 55 additions and 14 deletions

View File

@@ -116,11 +116,19 @@ pub enum FileType {
pub struct FileMimeType(String);
impl FileMimeType {
pub fn new_raw(raw: &str) -> Self {
Self(raw.to_owned())
}
pub fn from_name(name: &str) -> Option<Self> {
mime_guess::from_path(name)
.first_raw()
.map(|s| Self(s.to_owned()))
}
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
/// A valid file path that might start with a slash
@@ -289,27 +297,39 @@ impl From<AbsoluteFilePath> for FilePath {
pub type FileStreamInner =
Box<dyn Stream<Item = Result<Bytes, std::io::Error>> + Send + Sync + Unpin + 'static>;
pub struct FileStream(FileType, FileStreamInner);
pub struct FileStream {
file_type: FileType,
mime_type: Option<FileMimeType>,
stream: FileStreamInner,
}
impl FileStream {
pub fn new<S>(file_type: FileType, stream: S) -> Self
pub fn new<S>(file_type: FileType, mime_type: Option<FileMimeType>, stream: S) -> Self
where
S: Stream<Item = Result<Bytes, std::io::Error>> + Send + Sync + Unpin + 'static,
{
Self(file_type, Box::new(stream))
Self {
file_type,
mime_type,
stream: Box::new(stream),
}
}
pub fn file_type(&self) -> FileType {
self.0
self.file_type
}
pub fn mime_type(&self) -> Option<&FileMimeType> {
self.mime_type.as_ref()
}
pub fn stream(&self) -> &FileStreamInner {
&self.1
&self.stream
}
}
impl From<FileStream> for FileStreamInner {
fn from(value: FileStream) -> Self {
value.1
value.stream
}
}

View File

@@ -76,18 +76,22 @@ impl IntoResponse for FileStream {
let mut builder = Response::builder().header(http::header::TRANSFER_ENCODING, "chunked");
if let Some(headers) = builder.headers_mut() {
if self.file_type() == FileType::Directory {
if let Some(mime_type) = self.mime_type() {
headers.insert(
http::header::CONTENT_TYPE,
HeaderValue::from_str("application/zip").unwrap(),
HeaderValue::from_str(mime_type.as_str()).unwrap(),
);
}
headers.remove(http::header::CONTENT_LENGTH);
headers.insert(
http::header::TRANSFER_ENCODING,
HeaderValue::from_str("chunked").unwrap(),
);
}
let inner: FileStreamInner = self.into();
builder.body(axum::body::Body::from_stream(inner)).unwrap()
builder
.body(axum::body::Body::from_stream(FileStreamInner::from(self)))
.unwrap()
}
}

View File

@@ -265,7 +265,11 @@ impl FileSystem {
}
});
FileStream::new(FileType::Directory, ReceiverStream::new(rx))
FileStream::new(
FileType::Directory,
Some(FileMimeType::new_raw("application/zip")),
ReceiverStream::new(rx),
)
}
match path_request {
@@ -293,7 +297,20 @@ impl FileSystem {
bail!("File size exceeds configured limit");
}
let stream = FileStream::new(FileType::File, ReaderStream::new(file));
let mime_type = {
let file_name = {
let path = file_path.as_str();
if let Some(last_slash_index) = path.rfind("/") {
&path[last_slash_index + 1..]
} else {
path
}
};
FileMimeType::from_name(file_name)
};
let stream = FileStream::new(FileType::File, mime_type, ReaderStream::new(file));
Ok(stream)
}