diff --git a/src/handlers/common.rs b/src/handlers/common.rs index 09df221..05aa8c8 100644 --- a/src/handlers/common.rs +++ b/src/handlers/common.rs @@ -233,3 +233,38 @@ pub fn create_error_response(status: actix_web::http::StatusCode, message: &str) /// Константы для безопасности pub const MAX_TOKEN_LENGTH: usize = 2048; pub const MIN_TOKEN_LENGTH: usize = 100; + +/// Проверяет, является ли файл системным файлом и возвращает соответствующий ответ +pub fn handle_system_file(filename: &str) -> Option { + match filename.to_lowercase().as_str() { + "robots.txt" => { + info!("Serving robots.txt for static image server"); + Some(HttpResponse::Ok() + .content_type("text/plain") + .insert_header(("access-control-allow-origin", "*")) + .body("User-agent: *\nDisallow: /\n")) + } + "favicon.ico" => { + info!("Serving favicon.ico (empty)"); + Some(HttpResponse::Ok() + .content_type("image/x-icon") + .insert_header(("access-control-allow-origin", "*")) + .body("")) + } + "sitemap.xml" => { + info!("Serving sitemap.xml (empty)"); + Some(HttpResponse::Ok() + .content_type("application/xml") + .insert_header(("access-control-allow-origin", "*")) + .body("\n\n")) + } + "humans.txt" => { + info!("Serving humans.txt"); + Some(HttpResponse::Ok() + .content_type("text/plain") + .insert_header(("access-control-allow-origin", "*")) + .body("# Static Image Server\n# Powered by Quoter\n")) + } + _ => None + } +} diff --git a/src/handlers/proxy.rs b/src/handlers/proxy.rs index a25dc8c..92ed9e8 100644 --- a/src/handlers/proxy.rs +++ b/src/handlers/proxy.rs @@ -3,7 +3,7 @@ use actix_web::{HttpRequest, HttpResponse, Result, error::ErrorInternalServerErr use log::{error, info, warn}; use super::common::{ - create_file_response_with_analytics, create_vercel_compatible_response, is_vercel_request, + create_file_response_with_analytics, create_vercel_compatible_response, is_vercel_request, handle_system_file, }; use crate::app_state::AppState; use crate::handlers::serve_file::serve_file; @@ -24,7 +24,12 @@ pub async fn proxy_handler( state: web::Data, ) -> Result { let start_time = std::time::Instant::now(); - info!("GET {} [START]", requested_res); + info!("GET {} [START] - Static image server request", requested_res); + + // Проверяем системные файлы (robots.txt, favicon.ico, etc.) + if let Some(response) = handle_system_file(&requested_res) { + return Ok(response); + } let normalized_path = if requested_res.ends_with("/webp") { info!("Converting to WebP format: {}", requested_res); @@ -38,10 +43,17 @@ pub async fn proxy_handler( let ext = extension.as_str().to_lowercase(); let filekey = format!("{}.{}", base_filename, &ext); - info!( - "Parsed request - base: {}, width: {}, ext: {}", - base_filename, requested_width, ext - ); + if requested_width > 0 { + info!( + "Parsed thumbnail request - base: {}, width: {}, ext: {} (full path: {})", + base_filename, requested_width, ext, requested_res + ); + } else { + info!( + "Parsed image request - base: {}, ext: {} (full path: {})", + base_filename, ext, requested_res + ); + } // Caching handled by Vercel Edge - focus on fast file serving let content_type = match get_mime_type(&ext) { @@ -57,7 +69,7 @@ pub async fn proxy_handler( } } _ => { - error!("Unsupported file format for: {}", base_filename); + error!("Unsupported file format for: {} (full path: {})", base_filename, requested_res); return Err(ErrorInternalServerError("Unsupported file format")); } },