192 lines
6.1 KiB
Rust
192 lines
6.1 KiB
Rust
|
|
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<String>,
|
|
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<String> = 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<String> = langs_data.split(",").map(|s| s.to_string()).collect();
|
|
let arr_lang: Vec<String> = 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<IpAddr> {
|
|
self.header
|
|
.get(X_FORWARDED_FOR)
|
|
.and_then(|hv| hv.to_str().ok())
|
|
.and_then(|s| s.split(',').find_map(|s| s.trim().parse::<IpAddr>().ok()))
|
|
}
|
|
|
|
/// Tries to parse the `x-real-ip` header
|
|
fn maybe_x_real_ip(&self) -> Option<IpAddr> {
|
|
self.header
|
|
.get(X_REAL_IP)
|
|
.and_then(|hv| hv.to_str().ok())
|
|
.and_then(|s| s.parse::<IpAddr>().ok())
|
|
}
|
|
|
|
/// Tries to parse `forwarded` headers
|
|
fn maybe_forwarded(&self) -> Option<IpAddr> {
|
|
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<String,String> {
|
|
let mut req_data: HashMap<String,String> = 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
|
|
}
|
|
}
|