mirror of
https://github.com/fafhrd91/actix-web
synced 2024-11-24 08:22:59 +01:00
add ConnectionInfo tests
This commit is contained in:
parent
c3de32c3b3
commit
d7e65b6212
@ -175,7 +175,7 @@ impl<T, H> Http1<T, H>
|
||||
not_ready = false;
|
||||
|
||||
// set remote addr
|
||||
req.set_remove_addr(self.addr);
|
||||
req.set_peer_addr(self.addr);
|
||||
|
||||
// stop keepalive timer
|
||||
self.keepalive_timer.take();
|
||||
|
@ -223,7 +223,7 @@ impl Entry {
|
||||
parts.method, parts.uri, parts.version, parts.headers, payload);
|
||||
|
||||
// set remote addr
|
||||
req.set_remove_addr(addr);
|
||||
req.set_peer_addr(addr);
|
||||
|
||||
// Payload sender
|
||||
let psender = PayloadType::new(req.headers(), psender);
|
||||
|
@ -140,12 +140,27 @@ impl<S> HttpRequest<S> {
|
||||
&self.0.headers
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn headers_mut(&mut self) -> &mut HeaderMap {
|
||||
&mut self.as_mut().headers
|
||||
}
|
||||
|
||||
/// The target path of this Request.
|
||||
#[inline]
|
||||
pub fn path(&self) -> &str {
|
||||
self.0.uri.path()
|
||||
}
|
||||
|
||||
/// Get previously loaded *ConnectionInfo*.
|
||||
#[inline]
|
||||
pub fn connection_info(&self) -> Option<&ConnectionInfo> {
|
||||
if self.0.info.is_none() {
|
||||
None
|
||||
} else {
|
||||
self.0.info.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// Load *ConnectionInfo* for currect request.
|
||||
#[inline]
|
||||
pub fn load_connection_info(&mut self) -> &ConnectionInfo {
|
||||
@ -157,19 +172,12 @@ impl<S> HttpRequest<S> {
|
||||
self.0.info.as_ref().unwrap()
|
||||
}
|
||||
|
||||
/// Remote IP of client initiated HTTP request.
|
||||
///
|
||||
/// The IP is resolved through the following headers, in this order:
|
||||
///
|
||||
/// - Forwarded
|
||||
/// - X-Forwarded-For
|
||||
/// - peername of opened socket
|
||||
#[inline]
|
||||
pub fn remote(&self) -> Option<&SocketAddr> {
|
||||
pub fn peer_addr(&self) -> Option<&SocketAddr> {
|
||||
self.0.addr.as_ref()
|
||||
}
|
||||
|
||||
pub(crate) fn set_remove_addr(&mut self, addr: Option<SocketAddr>) {
|
||||
pub(crate) fn set_peer_addr(&mut self, addr: Option<SocketAddr>) {
|
||||
self.as_mut().addr = addr
|
||||
}
|
||||
|
||||
|
107
src/info.rs
107
src/info.rs
@ -2,6 +2,7 @@ use std::str::FromStr;
|
||||
use http::header::{self, HeaderName};
|
||||
use httprequest::HttpRequest;
|
||||
|
||||
const X_FORWARDED_FOR: &str = "X-FORWARDED-FOR";
|
||||
const X_FORWARDED_HOST: &str = "X-FORWARDED-HOST";
|
||||
const X_FORWARDED_PROTO: &str = "X-FORWARDED-PROTO";
|
||||
|
||||
@ -13,9 +14,8 @@ const X_FORWARDED_PROTO: &str = "X-FORWARDED-PROTO";
|
||||
pub struct ConnectionInfo<'a> {
|
||||
scheme: &'a str,
|
||||
host: &'a str,
|
||||
remote: String,
|
||||
forwarded_for: Vec<&'a str>,
|
||||
forwarded_by: Vec<&'a str>,
|
||||
remote: Option<&'a str>,
|
||||
peer: Option<String>,
|
||||
}
|
||||
|
||||
impl<'a> ConnectionInfo<'a> {
|
||||
@ -24,20 +24,21 @@ impl<'a> ConnectionInfo<'a> {
|
||||
pub fn new<S>(req: &'a HttpRequest<S>) -> ConnectionInfo<'a> {
|
||||
let mut host = None;
|
||||
let mut scheme = None;
|
||||
let mut forwarded_for = Vec::new();
|
||||
let mut forwarded_by = Vec::new();
|
||||
let mut remote = None;
|
||||
let mut peer = None;
|
||||
|
||||
// load forwarded header
|
||||
for hdr in req.headers().get_all(header::FORWARDED) {
|
||||
if let Ok(val) = hdr.to_str() {
|
||||
for pair in val.split(';') {
|
||||
for el in pair.split(',') {
|
||||
let mut items = el.splitn(1, '=');
|
||||
let mut items = el.trim().splitn(2, '=');
|
||||
if let Some(name) = items.next() {
|
||||
if let Some(val) = items.next() {
|
||||
match &name.to_lowercase() as &str {
|
||||
"for" => forwarded_for.push(val.trim()),
|
||||
"by" => forwarded_by.push(val.trim()),
|
||||
"for" => if remote.is_none() {
|
||||
remote = Some(val.trim());
|
||||
},
|
||||
"proto" => if scheme.is_none() {
|
||||
scheme = Some(val.trim());
|
||||
},
|
||||
@ -89,12 +90,27 @@ impl<'a> ConnectionInfo<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// remote addr
|
||||
if remote.is_none() {
|
||||
if let Some(h) = req.headers().get(
|
||||
HeaderName::from_str(X_FORWARDED_FOR).unwrap()) {
|
||||
if let Ok(h) = h.to_str() {
|
||||
remote = h.split(',').next().map(|v| v.trim());
|
||||
}
|
||||
}
|
||||
if remote.is_none() {
|
||||
if let Some(addr) = req.peer_addr() {
|
||||
// get peeraddr from socketaddr
|
||||
peer = Some(format!("{}", addr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConnectionInfo {
|
||||
scheme: scheme.unwrap_or("http"),
|
||||
host: host.unwrap_or("localhost"),
|
||||
remote: String::new(),
|
||||
forwarded_for: forwarded_for,
|
||||
forwarded_by: forwarded_by,
|
||||
remote: remote,
|
||||
peer: peer,
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,19 +146,66 @@ impl<'a> ConnectionInfo<'a> {
|
||||
/// - X-Forwarded-For
|
||||
/// - peername of opened socket
|
||||
#[inline]
|
||||
pub fn remote(&self) -> &str {
|
||||
&self.remote
|
||||
pub fn remote(&self) -> Option<&str> {
|
||||
if let Some(r) = self.remote {
|
||||
Some(r)
|
||||
} else if let Some(ref peer) = self.peer {
|
||||
Some(peer)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// List of the nodes making the request to the proxy.
|
||||
#[inline]
|
||||
pub fn forwarded_for(&self) -> &Vec<&str> {
|
||||
&self.forwarded_for
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use http::header::HeaderValue;
|
||||
|
||||
/// List of the user-agent facing interface of the proxies
|
||||
#[inline]
|
||||
pub fn forwarded_by(&self) -> &Vec<&str> {
|
||||
&self.forwarded_by
|
||||
#[test]
|
||||
fn test_forwarded() {
|
||||
let req = HttpRequest::default();
|
||||
let info = ConnectionInfo::new(&req);
|
||||
assert_eq!(info.scheme(), "http");
|
||||
assert_eq!(info.host(), "localhost");
|
||||
|
||||
let mut req = HttpRequest::default();
|
||||
req.headers_mut().insert(
|
||||
header::FORWARDED,
|
||||
HeaderValue::from_static(
|
||||
"for=192.0.2.60; proto=https; by=203.0.113.43; host=rust-lang.org"));
|
||||
|
||||
let info = ConnectionInfo::new(&req);
|
||||
assert_eq!(info.scheme(), "https");
|
||||
assert_eq!(info.host(), "rust-lang.org");
|
||||
assert_eq!(info.remote(), Some("192.0.2.60"));
|
||||
|
||||
let mut req = HttpRequest::default();
|
||||
req.headers_mut().insert(
|
||||
header::HOST, HeaderValue::from_static("rust-lang.org"));
|
||||
|
||||
let info = ConnectionInfo::new(&req);
|
||||
assert_eq!(info.scheme(), "http");
|
||||
assert_eq!(info.host(), "rust-lang.org");
|
||||
assert_eq!(info.remote(), None);
|
||||
|
||||
let mut req = HttpRequest::default();
|
||||
req.headers_mut().insert(
|
||||
HeaderName::from_str(X_FORWARDED_FOR).unwrap(), HeaderValue::from_static("192.0.2.60"));
|
||||
let info = ConnectionInfo::new(&req);
|
||||
assert_eq!(info.remote(), Some("192.0.2.60"));
|
||||
|
||||
let mut req = HttpRequest::default();
|
||||
req.headers_mut().insert(
|
||||
HeaderName::from_str(X_FORWARDED_HOST).unwrap(), HeaderValue::from_static("192.0.2.60"));
|
||||
let info = ConnectionInfo::new(&req);
|
||||
assert_eq!(info.host(), "192.0.2.60");
|
||||
assert_eq!(info.remote(), None);
|
||||
|
||||
let mut req = HttpRequest::default();
|
||||
req.headers_mut().insert(
|
||||
HeaderName::from_str(X_FORWARDED_PROTO).unwrap(), HeaderValue::from_static("https"));
|
||||
let info = ConnectionInfo::new(&req);
|
||||
assert_eq!(info.scheme(), "https");
|
||||
}
|
||||
}
|
||||
|
@ -102,6 +102,7 @@ impl Logger {
|
||||
impl Middleware for Logger {
|
||||
|
||||
fn start(&self, req: &mut HttpRequest) -> Started {
|
||||
req.load_connection_info();
|
||||
req.extensions().insert(StartTime(time::now()));
|
||||
Started::Done
|
||||
}
|
||||
@ -112,7 +113,6 @@ impl Middleware for Logger {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A formatting style for the `Logger`, consisting of multiple
|
||||
/// `FormatText`s concatenated into one line.
|
||||
#[derive(Clone)]
|
||||
@ -237,12 +237,13 @@ impl FormatText {
|
||||
fmt.write_fmt(format_args!("{:.6}", response_time_ms))
|
||||
},
|
||||
FormatText::RemoteAddr => {
|
||||
if let Some(addr) = req.remote() {
|
||||
addr.fmt(fmt)
|
||||
} else {
|
||||
"-".fmt(fmt)
|
||||
if let Some(addr) = req.connection_info() {
|
||||
if let Some(remote) = addr.remote() {
|
||||
return remote.fmt(fmt);
|
||||
}
|
||||
}
|
||||
"-".fmt(fmt)
|
||||
}
|
||||
FormatText::RequestTime => {
|
||||
entry_time.strftime("[%d/%b/%Y:%H:%M:%S %z]")
|
||||
.unwrap()
|
||||
|
@ -395,7 +395,7 @@ mod tests {
|
||||
("/v{val}/{val2}/index.html", None, 4),
|
||||
("/v/{tail:.*}", None, 5),
|
||||
];
|
||||
let mut rec = RouteRecognizer::new("/", routes);
|
||||
let rec = RouteRecognizer::new("/", routes);
|
||||
|
||||
let (params, val) = rec.recognize("/name").unwrap();
|
||||
assert_eq!(*val, 1);
|
||||
|
Loading…
Reference in New Issue
Block a user