Can force file download
This commit is contained in:
		@@ -7,7 +7,7 @@ use crate::models::files::File;
 | 
			
		||||
use crate::services::files_service;
 | 
			
		||||
use crate::utils::time_utils;
 | 
			
		||||
use actix_web::http::header;
 | 
			
		||||
use actix_web::{HttpRequest, HttpResponse};
 | 
			
		||||
use actix_web::{HttpRequest, HttpResponse, web};
 | 
			
		||||
use std::ops::Add;
 | 
			
		||||
use std::time::Duration;
 | 
			
		||||
 | 
			
		||||
@@ -44,40 +44,60 @@ pub async fn get_info(file_extractor: FileIdExtractor) -> HttpResult {
 | 
			
		||||
    Ok(HttpResponse::Ok().json(file_extractor.as_ref()))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Deserialize)]
 | 
			
		||||
pub struct DownloadQuery {
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    download: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Download an uploaded file
 | 
			
		||||
pub async fn download(req: HttpRequest, file_extractor: FileIdExtractor) -> HttpResult {
 | 
			
		||||
    serve_file(req, file_extractor.as_ref()).await
 | 
			
		||||
pub async fn download(
 | 
			
		||||
    req: HttpRequest,
 | 
			
		||||
    file_extractor: FileIdExtractor,
 | 
			
		||||
    query: web::Query<DownloadQuery>,
 | 
			
		||||
) -> HttpResult {
 | 
			
		||||
    serve_file(req, file_extractor.as_ref(), query.download).await
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Serve a file, returning 304 status code if the requested file already exists
 | 
			
		||||
pub async fn serve_file(req: HttpRequest, file: &File) -> HttpResult {
 | 
			
		||||
    // Check if the browser already knows the etag
 | 
			
		||||
    if let Some(c) = req.headers().get(header::IF_NONE_MATCH) {
 | 
			
		||||
        if c.to_str().unwrap_or("") == file.sha512.as_str() {
 | 
			
		||||
            return Ok(HttpResponse::NotModified().finish());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check if the browser already knows the file by date
 | 
			
		||||
    if let Some(c) = req.headers().get(header::IF_MODIFIED_SINCE) {
 | 
			
		||||
        let date_str = c.to_str().unwrap_or("");
 | 
			
		||||
        if let Ok(date) = httpdate::parse_http_date(date_str) {
 | 
			
		||||
            if date.add(Duration::from_secs(1))
 | 
			
		||||
                >= time_utils::unix_to_system_time(file.time_create as u64)
 | 
			
		||||
            {
 | 
			
		||||
pub async fn serve_file(req: HttpRequest, file: &File, download_file: bool) -> HttpResult {
 | 
			
		||||
    if !download_file {
 | 
			
		||||
        // Check if the browser already knows the etag
 | 
			
		||||
        if let Some(c) = req.headers().get(header::IF_NONE_MATCH) {
 | 
			
		||||
            if c.to_str().unwrap_or("") == file.sha512.as_str() {
 | 
			
		||||
                return Ok(HttpResponse::NotModified().finish());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(HttpResponse::Ok()
 | 
			
		||||
        .content_type(file.mime_type.as_str())
 | 
			
		||||
        // Check if the browser already knows the file by date
 | 
			
		||||
        if let Some(c) = req.headers().get(header::IF_MODIFIED_SINCE) {
 | 
			
		||||
            let date_str = c.to_str().unwrap_or("");
 | 
			
		||||
            if let Ok(date) = httpdate::parse_http_date(date_str) {
 | 
			
		||||
                if date.add(Duration::from_secs(1))
 | 
			
		||||
                    >= time_utils::unix_to_system_time(file.time_create as u64)
 | 
			
		||||
                {
 | 
			
		||||
                    return Ok(HttpResponse::NotModified().finish());
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    let mut res = HttpResponse::Ok();
 | 
			
		||||
    res.content_type(file.mime_type.as_str())
 | 
			
		||||
        .insert_header(("etag", file.sha512.as_str()))
 | 
			
		||||
        .insert_header((
 | 
			
		||||
            "last-modified",
 | 
			
		||||
            time_utils::unix_to_http_date(file.time_create as u64),
 | 
			
		||||
        ))
 | 
			
		||||
        .body(files_service::get_file_content(file).await?))
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
    // Add filename to response headers if requested
 | 
			
		||||
    if download_file {
 | 
			
		||||
        res.insert_header((
 | 
			
		||||
            "content-disposition",
 | 
			
		||||
            format!("attachment; filename={}", file.file_name),
 | 
			
		||||
        ));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(res.body(files_service::get_file_content(file).await?))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Delete an uploaded file
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user