Merge pull request #277 from dvdsk/streaming_file_up_down

Awnser Range requests and stream files downloads
This commit is contained in:
Dániel Szabó 2024-10-24 13:48:41 +09:00 committed by GitHub
commit d3a7eaf072
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 23 additions and 24 deletions

View file

@ -70,6 +70,10 @@ pub fn expiration_to_timestamp(expiration: &str, timenow: i64) -> i64 {
} }
} }
/// receives a file through http Post on url /upload/a-b-c with a, b and c
/// different animals. The client sends the post in response to a form.
// TODO: form field order might need to be changed. In my testing the attachment
// data is nestled between password encryption key etc <21-10-24, dvdsk>
pub async fn create( pub async fn create(
data: web::Data<AppState>, data: web::Data<AppState>,
mut payload: Multipart, mut payload: Multipart,

View file

@ -1,4 +1,4 @@
use std::fs::{self, File}; use std::fs::File;
use std::path::PathBuf; use std::path::PathBuf;
use crate::args::ARGS; use crate::args::ARGS;
@ -8,6 +8,7 @@ use crate::util::misc::remove_expired;
use crate::util::{animalnumbers::to_u64, misc::decrypt_file}; use crate::util::{animalnumbers::to_u64, misc::decrypt_file};
use crate::AppState; use crate::AppState;
use actix_multipart::Multipart; use actix_multipart::Multipart;
use actix_web::http::header;
use actix_web::{get, post, web, Error, HttpResponse}; use actix_web::{get, post, web, Error, HttpResponse};
#[post("/secure_file/{id}")] #[post("/secure_file/{id}")]
@ -49,6 +50,8 @@ pub async fn post_secure_file(
pastas[index].id_as_animals() pastas[index].id_as_animals()
))?; ))?;
// Not compatible with NamedFile from actix_files (it needs a File
// to work therefore secure files do not support streaming
let decrypted_data: Vec<u8> = decrypt_file(&password, &file)?; let decrypted_data: Vec<u8> = decrypt_file(&password, &file)?;
// Set the content type based on the file extension // Set the content type based on the file extension
@ -63,6 +66,7 @@ pub async fn post_secure_file(
"Content-Disposition", "Content-Disposition",
format!("attachment; filename=\"{}\"", pasta_file.name()), format!("attachment; filename=\"{}\"", pasta_file.name()),
)) ))
// TODO: make streaming <21-10-24, dvdsk>
.body(decrypted_data); .body(decrypted_data);
return Ok(response); return Ok(response);
} }
@ -72,8 +76,9 @@ pub async fn post_secure_file(
#[get("/file/{id}")] #[get("/file/{id}")]
pub async fn get_file( pub async fn get_file(
data: web::Data<AppState>, request: actix_web::HttpRequest,
id: web::Path<String>, id: web::Path<String>,
data: web::Data<AppState>,
) -> Result<HttpResponse, Error> { ) -> Result<HttpResponse, Error> {
// get access to the pasta collection // get access to the pasta collection
let mut pastas = data.pastas.lock().unwrap(); let mut pastas = data.pastas.lock().unwrap();
@ -118,28 +123,18 @@ pub async fn get_file(
); );
let file_path = PathBuf::from(file_path); let file_path = PathBuf::from(file_path);
// Read the contents of the file into memory // This will stream the file and set the content type based on the
// let mut file_content = Vec::new(); // file path
// let mut file = File::open(&file_path)?; let file_reponse = actix_files::NamedFile::open(file_path)?;
// file.read_exact(&mut file_content)?; let file_reponse = file_reponse.set_content_disposition(header::ContentDisposition {
disposition: header::DispositionType::Attachment,
let file_contents = fs::read(&file_path)?; parameters: vec![header::DispositionParam::Filename(
pasta_file.name().to_string(),
// Set the content type based on the file extension )],
let content_type = mime_guess::from_path(&file_path) });
.first_or_octet_stream() // This takes care of streaming/seeking using the Range
.to_string(); // header in the request.
return Ok(file_reponse.into_response(&request));
// Create an HttpResponse object with the file contents as the response body
let response = HttpResponse::Ok()
.content_type(content_type)
.append_header((
"Content-Disposition",
format!("attachment; filename=\"{}\"", pasta_file.name()),
))
.body(file_contents);
return Ok(response);
} }
} }