forked from neri/datatrash
don't reread file to perform mime guess
This commit is contained in:
parent
7983557c5a
commit
7664ba3ec9
|
@ -416,7 +416,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "datatrash"
|
name = "datatrash"
|
||||||
version = "2.0.0"
|
version = "2.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-files",
|
"actix-files",
|
||||||
"actix-governor",
|
"actix-governor",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "datatrash"
|
name = "datatrash"
|
||||||
version = "2.0.0"
|
version = "2.0.1"
|
||||||
authors = ["neri"]
|
authors = ["neri"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,10 @@ use actix_multipart::{Field, Multipart};
|
||||||
use actix_web::{error, http::header::DispositionParam, Error};
|
use actix_web::{error, http::header::DispositionParam, Error};
|
||||||
use futures_util::{StreamExt, TryStreamExt};
|
use futures_util::{StreamExt, TryStreamExt};
|
||||||
use mime::{Mime, APPLICATION_OCTET_STREAM, TEXT_PLAIN};
|
use mime::{Mime, APPLICATION_OCTET_STREAM, TEXT_PLAIN};
|
||||||
use std::path::Path;
|
use std::{
|
||||||
|
cmp::{max, min},
|
||||||
|
path::Path,
|
||||||
|
};
|
||||||
use time::{Duration, OffsetDateTime};
|
use time::{Duration, OffsetDateTime};
|
||||||
use tokio::{fs::File, io::AsyncWriteExt};
|
use tokio::{fs::File, io::AsyncWriteExt};
|
||||||
|
|
||||||
|
@ -42,10 +45,10 @@ pub(crate) async fn parse_multipart(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
original_name = uploaded_name;
|
original_name = uploaded_name;
|
||||||
size = create_file(file_path, field, config.max_file_size).await?;
|
let first_bytes;
|
||||||
println!("mime: {}", mime);
|
(size, first_bytes) = create_file(file_path, field, config.max_file_size).await?;
|
||||||
content_type = Some(if mime == APPLICATION_OCTET_STREAM {
|
content_type = Some(if mime == APPLICATION_OCTET_STREAM {
|
||||||
get_content_type(file_path)
|
get_content_type(&first_bytes)
|
||||||
} else {
|
} else {
|
||||||
mime_relations::get_alias(mime)
|
mime_relations::get_alias(mime)
|
||||||
});
|
});
|
||||||
|
@ -54,8 +57,9 @@ pub(crate) async fn parse_multipart(
|
||||||
if original_name.is_some() {
|
if original_name.is_some() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
size = create_file(file_path, field, config.max_file_size).await?;
|
let first_bytes;
|
||||||
content_type = Some(get_content_type(file_path));
|
(size, first_bytes) = create_file(file_path, field, config.max_file_size).await?;
|
||||||
|
content_type = Some(get_content_type(&first_bytes));
|
||||||
}
|
}
|
||||||
"delete_on_download" => {
|
"delete_on_download" => {
|
||||||
delete_on_download = parse_string(name, field).await? != "false";
|
delete_on_download = parse_string(name, field).await? != "false";
|
||||||
|
@ -149,23 +153,25 @@ async fn create_file(
|
||||||
filename: &Path,
|
filename: &Path,
|
||||||
field: Field,
|
field: Field,
|
||||||
max_file_size: Option<u64>,
|
max_file_size: Option<u64>,
|
||||||
) -> Result<u64, Error> {
|
) -> Result<(u64, Vec<u8>), Error> {
|
||||||
let mut file = File::create(&filename).await.map_err(|file_err| {
|
let mut file = File::create(&filename).await.map_err(|file_err| {
|
||||||
log::error!("could not create file {:?}", file_err);
|
log::error!("could not create file {:?}", file_err);
|
||||||
error::ErrorInternalServerError("could not create file")
|
error::ErrorInternalServerError("could not create file")
|
||||||
})?;
|
})?;
|
||||||
let written_bytes = write_to_file(&mut file, field, max_file_size).await?;
|
write_to_file(&mut file, field, max_file_size).await
|
||||||
Ok(written_bytes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn write_to_file(
|
async fn write_to_file(
|
||||||
file: &mut File,
|
file: &mut File,
|
||||||
mut field: Field,
|
mut field: Field,
|
||||||
max_size: Option<u64>,
|
max_size: Option<u64>,
|
||||||
) -> Result<u64, error::Error> {
|
) -> Result<(u64, Vec<u8>), error::Error> {
|
||||||
|
let mut first_bytes = Vec::with_capacity(2048);
|
||||||
let mut written_bytes: u64 = 0;
|
let mut written_bytes: u64 = 0;
|
||||||
while let Some(chunk) = field.next().await {
|
while let Some(chunk) = field.next().await {
|
||||||
let chunk = chunk.map_err(error::ErrorBadRequest)?;
|
let chunk = chunk.map_err(error::ErrorBadRequest)?;
|
||||||
|
let remaining_first_bytes = min(max(0, 2048 - written_bytes) as usize, chunk.len());
|
||||||
|
first_bytes.extend_from_slice(&chunk[0..remaining_first_bytes]);
|
||||||
written_bytes += chunk.len() as u64;
|
written_bytes += chunk.len() as u64;
|
||||||
if let Some(max_size) = max_size {
|
if let Some(max_size) = max_size {
|
||||||
if written_bytes > max_size {
|
if written_bytes > max_size {
|
||||||
|
@ -179,7 +185,7 @@ async fn write_to_file(
|
||||||
error::ErrorInternalServerError("could not write file")
|
error::ErrorInternalServerError("could not write file")
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
Ok(written_bytes)
|
Ok((written_bytes, first_bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_file_metadata(field: &actix_multipart::Field) -> (Mime, Option<String>) {
|
fn get_file_metadata(field: &actix_multipart::Field) -> (Mime, Option<String>) {
|
||||||
|
@ -195,9 +201,9 @@ fn get_file_metadata(field: &actix_multipart::Field) -> (Mime, Option<String>) {
|
||||||
(mime, filename)
|
(mime, filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_content_type(path: &Path) -> Mime {
|
fn get_content_type(bytes: &[u8]) -> Mime {
|
||||||
let std_path = std::path::Path::new(path.as_os_str());
|
tree_magic_mini::from_u8(bytes)
|
||||||
tree_magic_mini::from_filepath(std_path)
|
.parse()
|
||||||
.and_then(|mime| mime.parse().ok())
|
.ok()
|
||||||
.unwrap_or(TEXT_PLAIN)
|
.unwrap_or(TEXT_PLAIN)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue