performance improvements
This commit is contained in:
@@ -4,7 +4,8 @@ use axum::{
|
||||
http::{HeaderMap, StatusCode},
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use std::{fs, sync::Arc};
|
||||
use std::sync::Arc;
|
||||
use tokio::fs;
|
||||
use tracing::{error, info, warn};
|
||||
|
||||
use crate::{
|
||||
@@ -76,15 +77,15 @@ pub async fn delete_upload(
|
||||
let uploads_dir = state.data_dir.join("uploads");
|
||||
let file_path = uploads_dir.join(&filename);
|
||||
|
||||
let canonical_dir = uploads_dir.canonicalize().map_err(|e| {
|
||||
let canonical_dir = fs::canonicalize(&uploads_dir).await.map_err(|e| {
|
||||
AppError::Internal("Path resolution".to_string(), Some(e.to_string()))
|
||||
})?;
|
||||
if let Ok(canonical_file) = file_path.canonicalize() {
|
||||
if let Ok(canonical_file) = fs::canonicalize(&file_path).await {
|
||||
if !canonical_file.starts_with(&canonical_dir) {
|
||||
warn!("Refused delete outside uploads dir: {}", filename);
|
||||
return Err(AppError::BadRequest("Invalid filename".to_string()));
|
||||
}
|
||||
fs::remove_file(canonical_file).map_err(|e| {
|
||||
fs::remove_file(canonical_file).await.map_err(|e| {
|
||||
error!("Delete error for file {}: {}", filename, e);
|
||||
AppError::Internal("Delete error".to_string(), Some(e.to_string()))
|
||||
})?;
|
||||
@@ -104,15 +105,30 @@ pub async fn list_uploads(
|
||||
let uploads_dir = state.data_dir.join("uploads");
|
||||
let mut files = Vec::new();
|
||||
|
||||
if let Ok(entries) = fs::read_dir(uploads_dir) {
|
||||
for entry in entries.flatten() {
|
||||
let path = entry.path();
|
||||
if path.is_file() {
|
||||
if let Some(name) = path.file_name().and_then(|n| n.to_str()) {
|
||||
files.push(FileInfo {
|
||||
name: name.to_string(),
|
||||
url: format!("/uploads/{}", name),
|
||||
});
|
||||
if let Ok(mut rd) = fs::read_dir(&uploads_dir).await {
|
||||
loop {
|
||||
match rd.next_entry().await {
|
||||
Ok(Some(entry)) => {
|
||||
let path = entry.path();
|
||||
let is_file = entry
|
||||
.file_type()
|
||||
.await
|
||||
.map(|t| t.is_file())
|
||||
.unwrap_or(false);
|
||||
if !is_file {
|
||||
continue;
|
||||
}
|
||||
if let Some(name) = path.file_name().and_then(|n| n.to_str()) {
|
||||
files.push(FileInfo {
|
||||
name: name.to_string(),
|
||||
url: format!("/uploads/{}", name),
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(None) => break,
|
||||
Err(e) => {
|
||||
warn!("Error iterating uploads dir: {}", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,7 +194,9 @@ pub async fn upload_file(
|
||||
let uploads_dir = state.data_dir.join("uploads");
|
||||
let target_path = uploads_dir.join(&final_name);
|
||||
|
||||
let final_path = if target_path.exists() && !query.replace.unwrap_or(false) {
|
||||
let final_path = if fs::try_exists(&target_path).await.unwrap_or(false)
|
||||
&& !query.replace.unwrap_or(false)
|
||||
{
|
||||
let timestamp = chrono::Utc::now().timestamp();
|
||||
uploads_dir.join(format!("{}_{}", timestamp, final_name))
|
||||
} else {
|
||||
@@ -186,11 +204,11 @@ pub async fn upload_file(
|
||||
};
|
||||
|
||||
// Final containment check.
|
||||
let canonical_dir = uploads_dir.canonicalize().map_err(|e| {
|
||||
let canonical_dir = fs::canonicalize(&uploads_dir).await.map_err(|e| {
|
||||
AppError::Internal("Path resolution".to_string(), Some(e.to_string()))
|
||||
})?;
|
||||
if let Some(parent) = final_path.parent() {
|
||||
let canonical_parent = parent.canonicalize().map_err(|e| {
|
||||
let canonical_parent = fs::canonicalize(parent).await.map_err(|e| {
|
||||
AppError::Internal("Path resolution".to_string(), Some(e.to_string()))
|
||||
})?;
|
||||
if canonical_parent != canonical_dir {
|
||||
@@ -204,7 +222,7 @@ pub async fn upload_file(
|
||||
.unwrap_or(&final_name)
|
||||
.to_string();
|
||||
|
||||
fs::write(&final_path, &data).map_err(|e| {
|
||||
fs::write(&final_path, &data).await.map_err(|e| {
|
||||
error!("Failed to write file to {:?}: {}", final_path, e);
|
||||
AppError::Internal("Write error".to_string(), Some(e.to_string()))
|
||||
})?;
|
||||
|
||||
Reference in New Issue
Block a user