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