simplified http_log internal routine
This commit is contained in:
parent
ba06d8d4eb
commit
42464d1d49
2 changed files with 94 additions and 28 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
use super::canonical_address::ToCanonical;
|
use super::canonical_address::ToCanonical;
|
||||||
use crate::log::*;
|
use crate::{log::*, message_handler::utils_headers};
|
||||||
use http::header;
|
use http::header;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
|
|
@ -12,10 +12,11 @@ pub struct HttpMessageLog {
|
||||||
pub host: String,
|
pub host: String,
|
||||||
pub p_and_q: String,
|
pub p_and_q: String,
|
||||||
pub version: http::Version,
|
pub version: http::Version,
|
||||||
pub uri_scheme: String,
|
pub scheme: String,
|
||||||
pub uri_host: String,
|
pub path: String,
|
||||||
pub ua: String,
|
pub ua: String,
|
||||||
pub xff: String,
|
pub xff: String,
|
||||||
|
pub forwarded: String,
|
||||||
pub status: String,
|
pub status: String,
|
||||||
pub upstream: String,
|
pub upstream: String,
|
||||||
}
|
}
|
||||||
|
|
@ -29,17 +30,21 @@ impl<T> From<&http::Request<T>> for HttpMessageLog {
|
||||||
.map_or_else(|| "", |s| s.to_str().unwrap_or(""))
|
.map_or_else(|| "", |s| s.to_str().unwrap_or(""))
|
||||||
.to_string()
|
.to_string()
|
||||||
};
|
};
|
||||||
|
let host =
|
||||||
|
utils_headers::host_from_uri_or_host_header(req.uri(), req.headers().get(header::HOST).cloned()).unwrap_or_default();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
// tls_server_name: "".to_string(),
|
// tls_server_name: "".to_string(),
|
||||||
client_addr: "".to_string(),
|
client_addr: "".to_string(),
|
||||||
method: req.method().to_string(),
|
method: req.method().to_string(),
|
||||||
host: header_mapper(header::HOST),
|
host,
|
||||||
p_and_q: req.uri().path_and_query().map_or_else(|| "", |v| v.as_str()).to_string(),
|
p_and_q: req.uri().path_and_query().map_or_else(|| "", |v| v.as_str()).to_string(),
|
||||||
version: req.version(),
|
version: req.version(),
|
||||||
uri_scheme: req.uri().scheme_str().unwrap_or("").to_string(),
|
scheme: req.uri().scheme_str().unwrap_or("").to_string(),
|
||||||
uri_host: req.uri().host().unwrap_or("").to_string(),
|
path: req.uri().path().to_string(),
|
||||||
ua: header_mapper(header::USER_AGENT),
|
ua: header_mapper(header::USER_AGENT),
|
||||||
xff: header_mapper(header::HeaderName::from_static("x-forwarded-for")),
|
xff: header_mapper(header::HeaderName::from_static("x-forwarded-for")),
|
||||||
|
forwarded: header_mapper(header::FORWARDED),
|
||||||
status: "".to_string(),
|
status: "".to_string(),
|
||||||
upstream: "".to_string(),
|
upstream: "".to_string(),
|
||||||
}
|
}
|
||||||
|
|
@ -48,26 +53,29 @@ impl<T> From<&http::Request<T>> for HttpMessageLog {
|
||||||
|
|
||||||
impl std::fmt::Display for HttpMessageLog {
|
impl std::fmt::Display for HttpMessageLog {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let forwarded_part = if !self.forwarded.is_empty() {
|
||||||
|
format!(" \"{}\"", self.forwarded)
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{} <- {} -- {} {} {:?} -- {} -- {} \"{}\", \"{}\" \"{}\"",
|
"{} <- {} -- {} {} {:?} -- {} -- {} \"{}\", \"{}\"{} \"{}\"",
|
||||||
if !self.host.is_empty() {
|
self.host,
|
||||||
self.host.as_str()
|
|
||||||
} else {
|
|
||||||
self.uri_host.as_str()
|
|
||||||
},
|
|
||||||
self.client_addr,
|
self.client_addr,
|
||||||
self.method,
|
self.method,
|
||||||
self.p_and_q,
|
self.p_and_q,
|
||||||
self.version,
|
self.version,
|
||||||
self.status,
|
self.status,
|
||||||
if !self.uri_scheme.is_empty() && !self.uri_host.is_empty() {
|
if !self.scheme.is_empty() && !self.host.is_empty() {
|
||||||
format!("{}://{}", self.uri_scheme, self.uri_host)
|
format!("{}://{}{}", self.scheme, self.host, self.path)
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
self.path.clone()
|
||||||
},
|
},
|
||||||
self.ua,
|
self.ua,
|
||||||
self.xff,
|
self.xff,
|
||||||
|
forwarded_part,
|
||||||
self.upstream
|
self.upstream
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -102,3 +110,56 @@ impl HttpMessageLog {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use http::{Method, Version};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_log_format_without_forwarded() {
|
||||||
|
let log = HttpMessageLog {
|
||||||
|
client_addr: "192.168.1.1:8080".to_string(),
|
||||||
|
method: Method::GET.to_string(),
|
||||||
|
host: "example.com".to_string(),
|
||||||
|
p_and_q: "/path?query=value".to_string(),
|
||||||
|
version: Version::HTTP_11,
|
||||||
|
scheme: "https".to_string(),
|
||||||
|
path: "/path".to_string(),
|
||||||
|
ua: "Mozilla/5.0".to_string(),
|
||||||
|
xff: "10.0.0.1".to_string(),
|
||||||
|
forwarded: "".to_string(),
|
||||||
|
status: "200".to_string(),
|
||||||
|
upstream: "https://backend.example.com".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let formatted = format!("{}", log);
|
||||||
|
assert!(!formatted.contains(" \"\""));
|
||||||
|
assert!(formatted.contains("\"Mozilla/5.0\", \"10.0.0.1\" \"https://backend.example.com\""));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_log_format_with_forwarded() {
|
||||||
|
let log = HttpMessageLog {
|
||||||
|
client_addr: "192.168.1.1:8080".to_string(),
|
||||||
|
method: Method::GET.to_string(),
|
||||||
|
host: "example.com".to_string(),
|
||||||
|
p_and_q: "/path?query=value".to_string(),
|
||||||
|
version: Version::HTTP_11,
|
||||||
|
scheme: "https".to_string(),
|
||||||
|
path: "/path".to_string(),
|
||||||
|
ua: "Mozilla/5.0".to_string(),
|
||||||
|
xff: "10.0.0.1".to_string(),
|
||||||
|
forwarded: "for=192.0.2.60;proto=http;by=203.0.113.43".to_string(),
|
||||||
|
status: "200".to_string(),
|
||||||
|
upstream: "https://backend.example.com".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let formatted = format!("{}", log);
|
||||||
|
assert!(formatted.contains(" \"for=192.0.2.60;proto=http;by=203.0.113.43\""));
|
||||||
|
assert!(
|
||||||
|
formatted
|
||||||
|
.contains("\"Mozilla/5.0\", \"10.0.0.1\" \"for=192.0.2.60;proto=http;by=203.0.113.43\" \"https://backend.example.com\"")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -360,25 +360,30 @@ fn generate_forwarded_header(headers: &HeaderMap, tls: bool, original_uri: &Uri)
|
||||||
"for={};proto={};host={}",
|
"for={};proto={};host={}",
|
||||||
for_values,
|
for_values,
|
||||||
if tls { "https" } else { "http" },
|
if tls { "https" } else { "http" },
|
||||||
host_from_uri(original_uri)?
|
host_from_uri_or_host_header(original_uri, headers.get(header::HOST).cloned())?
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(forwarded_value)
|
Ok(forwarded_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Extract host from URI
|
/// Extract host from URI
|
||||||
fn host_from_uri(uri: &Uri) -> Result<String> {
|
pub(super) fn host_from_uri_or_host_header(uri: &Uri, host_header_value: Option<header::HeaderValue>) -> Result<String> {
|
||||||
uri
|
// Prioritize uri host over host header
|
||||||
.host()
|
let uri_host = uri.host().map(|host| {
|
||||||
.map(|host| {
|
if let Some(port) = uri.port_u16() {
|
||||||
if let Some(port) = uri.port_u16() {
|
format!("{}:{}", host, port)
|
||||||
format!("{}:{}", host, port)
|
} else {
|
||||||
} else {
|
host.to_string()
|
||||||
host.to_string()
|
}
|
||||||
}
|
});
|
||||||
})
|
if let Some(host) = uri_host {
|
||||||
.ok_or_else(|| anyhow!("No host found in URI"))
|
return Ok(host);
|
||||||
|
}
|
||||||
|
// If uri host is not available, use host header
|
||||||
|
host_header_value
|
||||||
|
.map(|h| h.to_str().map(|s| s.to_string()))
|
||||||
|
.transpose()?
|
||||||
|
.ok_or_else(|| anyhow!("No host found in URI or Host header"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove connection header
|
/// Remove connection header
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue