use ntex::http::header::{CONTENT_LENGTH, CONTENT_TYPE}; use ntex::{ http::Response, web::{self, HttpRequest, error}, }; use crate::util::requester::Requester; fn normalize_image_url(endpoint: &str) -> String { let endpoint = endpoint.trim_start_matches('/'); if endpoint.starts_with("http://") || endpoint.starts_with("https://") { endpoint.to_string() } else if endpoint.starts_with("hanime-cdn.com/") || endpoint == "hanime-cdn.com" { format!("https://{endpoint}") } else { format!("https://hanime-cdn.com/{endpoint}") } } pub async fn get_image( req: HttpRequest, requester: web::types::State, ) -> Result { let endpoint = req.match_info().query("endpoint").to_string(); let image_url = normalize_image_url(&endpoint); let upstream = match requester .get_ref() .clone() .get_raw_with_headers( image_url.as_str(), vec![("Referer".to_string(), "https://hanime.tv/".to_string())], ) .await { Ok(response) => response, Err(_) => return Ok(web::HttpResponse::NotFound().finish()), }; let status = upstream.status(); let headers = upstream.headers().clone(); // Read body from upstream let bytes = upstream.bytes().await.map_err(error::ErrorBadGateway)?; // Build response and forward headers let mut resp = Response::build(status); if let Some(ct) = headers.get(CONTENT_TYPE) { if let Ok(ct_str) = ct.to_str() { resp.set_header(CONTENT_TYPE, ct_str); } } if let Some(cl) = headers.get(CONTENT_LENGTH) { if let Ok(cl_str) = cl.to_str() { resp.set_header(CONTENT_LENGTH, cl_str); } } // Either zero-copy to ntex Bytes... // Ok(resp.body(NtexBytes::from(bytes))) // ...or simple & compatible: Ok(resp.body(bytes.to_vec())) } #[cfg(test)] mod tests { use super::normalize_image_url; #[test] fn keeps_full_hanime_cdn_host_path_without_duplication() { assert_eq!( normalize_image_url("hanime-cdn.com/images/covers/natsu-zuma-2-cv1.png"), "https://hanime-cdn.com/images/covers/natsu-zuma-2-cv1.png" ); } #[test] fn prefixes_relative_paths_with_hanime_cdn_host() { assert_eq!( normalize_image_url("/images/covers/natsu-zuma-2-cv1.png"), "https://hanime-cdn.com/images/covers/natsu-zuma-2-cv1.png" ); } }