use std::{ net::IpAddr, collections::HashMap, }; use axum::http::{header::FORWARDED, HeaderMap}; use forwarded_header_value::{ForwardedHeaderValue, Identifier}; use crate::defs::{ Config, AppConnectInfo, AUTHORIZATION, REFERER, BEARER, USER_AGENT, ACCEPT_LANGUAGE, X_FORWARDED_FOR, X_REAL_IP, X_INTERNAL, }; pub struct ReqHeaderMap { pub header: HeaderMap, pub req_path: Vec, pub app_connect_info: AppConnectInfo, } impl ReqHeaderMap { pub fn new(header: HeaderMap, request_path: &str, app_connect_info: &AppConnectInfo) -> Self { let req_path = Self::req_end_path(request_path) .split(",").map(|s| s.to_string()) .collect(); ReqHeaderMap { header, req_path, app_connect_info: app_connect_info.to_owned(), } } pub fn req_end_path(req_path: &str) -> String { let arr_req_path: Vec = req_path.split("/").map(|s| s.to_string()).collect(); format!("{}",arr_req_path[arr_req_path.len()-1]) } pub fn auth(&self) -> String { if let Some(auth) = self.header.get(AUTHORIZATION) { format!("{}",auth.to_str().unwrap_or("").replace(&format!("{} ", BEARER),"")) } else { String::from("") } } pub fn referer(&self) -> String { if let Some(referer) = self.header.get(REFERER) { format!("{}",referer.to_str().unwrap_or("")) } else { String::from("") } } pub fn internal(&self) -> String { if let Some(internal) = self.header.get(X_INTERNAL) { format!("{}",internal.to_str().unwrap_or("")) } else { String::from("") } } pub fn is_browser(&self) -> bool { if let Some(user_agent) = self.header.get(USER_AGENT) { let agent = user_agent.to_str().unwrap_or(""); if agent.contains("Mozilla") { true } else if agent.contains("WebKit") { true } else if agent.contains("Chrome") { true } else { false } } else { false } } #[allow(dead_code)] pub fn is_curl(&self) -> bool { if let Some(user_agent) = self.header.get(USER_AGENT) { let agent = user_agent.to_str().unwrap_or(""); if agent.contains("curl") { true } else { false } } else { false } } pub fn is_wget(&self) -> bool { if let Some(user_agent) = self.header.get(USER_AGENT) { let agent = user_agent.to_str().unwrap_or("").to_lowercase(); if agent.contains("wget") { true } else { false } } else { false } } #[allow(dead_code)] pub fn response_user_agent_html(&self) -> bool { if let Some(user_agent) = self.header.get(USER_AGENT) { let agent = user_agent.to_str().unwrap_or("").to_lowercase(); agent.contains("curl") || agent.contains("wget") } else { false } } pub fn agent(&self) -> String { if let Some(user_agent) = self.header.get(USER_AGENT) { user_agent.to_str().unwrap_or("").to_owned() } else { String::from("") } } pub fn lang(&self, config: &Config) -> String { if let Some(langs) = self.header.get(ACCEPT_LANGUAGE) { let langs_data = langs.to_str().unwrap_or(""); if langs_data.is_empty() { format!("{}",config.dflt_lang) } else { let arr_langs: Vec = langs_data.split(",").map(|s| s.to_string()).collect(); let arr_lang: Vec = arr_langs[0].split("-").map(|s| s.to_string()).collect(); format!("{}",arr_lang[0]) } } else { format!("{}",config.dflt_lang) } } /// Tries to parse the `x-real-ip` header fn maybe_x_forwarded_for(&self) -> Option { self.header .get(X_FORWARDED_FOR) .and_then(|hv| hv.to_str().ok()) .and_then(|s| s.split(',').find_map(|s| s.trim().parse::().ok())) } /// Tries to parse the `x-real-ip` header fn maybe_x_real_ip(&self) -> Option { self.header .get(X_REAL_IP) .and_then(|hv| hv.to_str().ok()) .and_then(|s| s.parse::().ok()) } /// Tries to parse `forwarded` headers fn maybe_forwarded(&self) -> Option { self.header .get_all(FORWARDED).iter().find_map(|hv| { hv.to_str() .ok() .and_then(|s| ForwardedHeaderValue::from_forwarded(s).ok()) .and_then(|f| { f.iter() .filter_map(|fs| fs.forwarded_for.as_ref()) .find_map(|ff| match ff { Identifier::SocketAddr(a) => Some(a.ip()), Identifier::IpAddr(ip) => Some(*ip), _ => None, }) }) }) } pub fn ip(&self) -> String { if let Some(ip) = self.maybe_x_real_ip() .or_else(||self.maybe_x_forwarded_for()) .or_else(|| self.maybe_forwarded()) .or_else(|| None ) { format!("{}",ip) } else { format!("{}", self.app_connect_info.remote_addr) } } pub fn req_info(&self) -> HashMap { let mut req_data: HashMap = HashMap::new(); req_data.insert(String::from("agent"), self.agent()); req_data.insert(String::from("ip"), self.ip()); req_data.insert(String::from("auth"), self.auth()); req_data.insert(String::from("ref"), self.referer()); req_data.insert(String::from("int"), self.internal()); req_data } }