1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-01-18 13:51:50 +01:00

added ConnectionInfo

This commit is contained in:
Nikolay Kim 2017-12-05 17:09:15 -08:00
parent d8b880e167
commit c3de32c3b3
6 changed files with 180 additions and 31 deletions

View File

@ -42,8 +42,8 @@ fn main() {
.header("LOCATION", "/index.html") .header("LOCATION", "/index.html")
.body(Body::Empty) .body(Body::Empty)
}))) })))
.serve_tls::<_, ()>("127.0.0.1:8080", pkcs12).unwrap(); .serve_tls::<_, ()>("127.0.0.1:8443", pkcs12).unwrap();
println!("Started http server: 127.0.0.1:8080"); println!("Started http server: 127.0.0.1:8443");
let _ = sys.run(); let _ = sys.run();
} }

View File

@ -9,12 +9,14 @@ use url::form_urlencoded;
use http::{header, Uri, Method, Version, HeaderMap, Extensions}; use http::{header, Uri, Method, Version, HeaderMap, Extensions};
use {Cookie, HttpRange}; use {Cookie, HttpRange};
use info::ConnectionInfo;
use recognizer::Params; use recognizer::Params;
use payload::Payload; use payload::Payload;
use multipart::Multipart; use multipart::Multipart;
use error::{ParseError, PayloadError, use error::{ParseError, PayloadError,
MultipartError, CookieParseError, HttpRangeError, UrlencodedError}; MultipartError, CookieParseError, HttpRangeError, UrlencodedError};
struct HttpMessage { struct HttpMessage {
version: Version, version: Version,
method: Method, method: Method,
@ -27,6 +29,7 @@ struct HttpMessage {
cookies_loaded: bool, cookies_loaded: bool,
addr: Option<SocketAddr>, addr: Option<SocketAddr>,
payload: Payload, payload: Payload,
info: Option<ConnectionInfo<'static>>,
} }
impl Default for HttpMessage { impl Default for HttpMessage {
@ -44,6 +47,7 @@ impl Default for HttpMessage {
addr: None, addr: None,
payload: Payload::empty(), payload: Payload::empty(),
extensions: Extensions::new(), extensions: Extensions::new(),
info: None,
} }
} }
} }
@ -70,6 +74,7 @@ impl HttpRequest<()> {
addr: None, addr: None,
payload: payload, payload: payload,
extensions: Extensions::new(), extensions: Extensions::new(),
info: None,
}), }),
Rc::new(()) Rc::new(())
) )
@ -106,6 +111,15 @@ impl<S> HttpRequest<S> {
&mut self.as_mut().extensions &mut self.as_mut().extensions
} }
pub(crate) fn set_prefix(&mut self, idx: usize) {
self.as_mut().prefix = idx;
}
#[doc(hidden)]
pub fn prefix_len(&self) -> usize {
self.0.prefix
}
/// Read the Request Uri. /// Read the Request Uri.
#[inline] #[inline]
pub fn uri(&self) -> &Uri { &self.0.uri } pub fn uri(&self) -> &Uri { &self.0.uri }
@ -132,13 +146,15 @@ impl<S> HttpRequest<S> {
self.0.uri.path() self.0.uri.path()
} }
pub(crate) fn set_prefix(&mut self, idx: usize) { /// Load *ConnectionInfo* for currect request.
self.as_mut().prefix = idx; #[inline]
pub fn load_connection_info(&mut self) -> &ConnectionInfo {
if self.0.info.is_none() {
let info: ConnectionInfo<'static> = unsafe{
mem::transmute(ConnectionInfo::new(self))};
self.as_mut().info = Some(info);
} }
self.0.info.as_ref().unwrap()
#[doc(hidden)]
pub fn prefix_len(&self) -> usize {
self.0.prefix
} }
/// Remote IP of client initiated HTTP request. /// Remote IP of client initiated HTTP request.

148
src/info.rs Normal file
View File

@ -0,0 +1,148 @@
use std::str::FromStr;
use http::header::{self, HeaderName};
use httprequest::HttpRequest;
const X_FORWARDED_HOST: &str = "X-FORWARDED-HOST";
const X_FORWARDED_PROTO: &str = "X-FORWARDED-PROTO";
/// `HttpRequest` connection information
///
/// While it is possible to create `ConnectionInfo` directly,
/// consider using `HttpRequest::load_connection_info()` which cache result.
pub struct ConnectionInfo<'a> {
scheme: &'a str,
host: &'a str,
remote: String,
forwarded_for: Vec<&'a str>,
forwarded_by: Vec<&'a str>,
}
impl<'a> ConnectionInfo<'a> {
/// Create *ConnectionInfo* instance for a request.
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();
// 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, '=');
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()),
"proto" => if scheme.is_none() {
scheme = Some(val.trim());
},
"host" => if host.is_none() {
host = Some(val.trim());
},
_ => (),
}
}
}
}
}
}
}
// scheme
if scheme.is_none() {
if let Some(h) = req.headers().get(
HeaderName::from_str(X_FORWARDED_PROTO).unwrap()) {
if let Ok(h) = h.to_str() {
scheme = h.split(',').next().map(|v| v.trim());
}
}
if scheme.is_none() {
if let Some(a) = req.uri().scheme_part() {
scheme = Some(a.as_str())
}
}
}
// host
if host.is_none() {
if let Some(h) = req.headers().get(HeaderName::from_str(X_FORWARDED_HOST).unwrap()) {
if let Ok(h) = h.to_str() {
host = h.split(',').next().map(|v| v.trim());
}
}
if host.is_none() {
if let Some(h) = req.headers().get(header::HOST) {
if let Ok(h) = h.to_str() {
host = Some(h);
}
}
if host.is_none() {
if let Some(a) = req.uri().authority_part() {
host = Some(a.as_str())
}
}
}
}
ConnectionInfo {
scheme: scheme.unwrap_or("http"),
host: host.unwrap_or("localhost"),
remote: String::new(),
forwarded_for: forwarded_for,
forwarded_by: forwarded_by,
}
}
/// Scheme of the request.
///
/// Scheme is resolved through the following headers, in this order:
///
/// - Forwarded
/// - X-Forwarded-Proto
/// - Uri
#[inline]
pub fn scheme(&self) -> &str {
self.scheme
}
/// Hostname of the request.
///
/// Hostname is resolved through the following headers, in this order:
///
/// - Forwarded
/// - X-Forwarded-Host
/// - Host
/// - Uri
pub fn host(&self) -> &str {
self.host
}
/// 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) -> &str {
&self.remote
}
/// List of the nodes making the request to the proxy.
#[inline]
pub fn forwarded_for(&self) -> &Vec<&str> {
&self.forwarded_for
}
/// List of the user-agent facing interface of the proxies
#[inline]
pub fn forwarded_by(&self) -> &Vec<&str> {
&self.forwarded_by
}
}

View File

@ -55,6 +55,7 @@ mod encoding;
mod httprequest; mod httprequest;
mod httpresponse; mod httpresponse;
mod payload; mod payload;
mod info;
mod route; mod route;
mod resource; mod resource;
mod recognizer; mod recognizer;
@ -81,6 +82,7 @@ pub use error::{Error, Result};
pub use encoding::ContentEncoding; pub use encoding::ContentEncoding;
pub use body::{Body, Binary}; pub use body::{Body, Binary};
pub use application::Application; pub use application::Application;
pub use info::ConnectionInfo;
pub use httprequest::{HttpRequest, UrlEncoded}; pub use httprequest::{HttpRequest, UrlEncoded};
pub use httpresponse::HttpResponse; pub use httpresponse::HttpResponse;
pub use payload::{Payload, PayloadItem}; pub use payload::{Payload, PayloadItem};

View File

@ -209,28 +209,17 @@ pub struct RouteRecognizer<T> {
patterns: HashMap<String, Pattern>, patterns: HashMap<String, Pattern>,
} }
impl<T> Default for RouteRecognizer<T> {
fn default() -> Self {
RouteRecognizer {
prefix: 0,
re: RegexSet::new([""].iter()).unwrap(),
routes: Vec::new(),
patterns: HashMap::new(),
}
}
}
impl<T> RouteRecognizer<T> { impl<T> RouteRecognizer<T> {
pub fn new<P: Into<String>, U>(prefix: P, routes: U) -> Self pub fn new<P: Into<String>, U, K>(prefix: P, routes: U) -> Self
where U: IntoIterator<Item=(String, Option<String>, T)> where U: IntoIterator<Item=(K, Option<String>, T)>,
K: Into<String>,
{ {
let mut paths = Vec::new(); let mut paths = Vec::new();
let mut handlers = Vec::new(); let mut handlers = Vec::new();
let mut patterns = HashMap::new(); let mut patterns = HashMap::new();
for item in routes { for item in routes {
let (pat, elements) = parse(&item.0); let (pat, elements) = parse(&item.0.into());
let pattern = Pattern::new(&pat, elements); let pattern = Pattern::new(&pat, elements);
if let Some(ref name) = item.1 { if let Some(ref name) = item.1 {
let _ = patterns.insert(name.clone(), pattern.clone()); let _ = patterns.insert(name.clone(), pattern.clone());
@ -399,8 +388,6 @@ mod tests {
#[test] #[test]
fn test_recognizer() { fn test_recognizer() {
let mut rec = RouteRecognizer::<usize>::default();
let routes = vec![ let routes = vec![
("/name", None, 1), ("/name", None, 1),
("/name/{val}", None, 2), ("/name/{val}", None, 2),
@ -408,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),
]; ];
rec.set_routes(routes); let mut 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);

View File

@ -66,13 +66,9 @@ use wsframe;
use wsproto::*; use wsproto::*;
pub use wsproto::CloseCode; pub use wsproto::CloseCode;
#[doc(hidden)]
const SEC_WEBSOCKET_ACCEPT: &str = "SEC-WEBSOCKET-ACCEPT"; const SEC_WEBSOCKET_ACCEPT: &str = "SEC-WEBSOCKET-ACCEPT";
#[doc(hidden)]
const SEC_WEBSOCKET_KEY: &str = "SEC-WEBSOCKET-KEY"; const SEC_WEBSOCKET_KEY: &str = "SEC-WEBSOCKET-KEY";
#[doc(hidden)]
const SEC_WEBSOCKET_VERSION: &str = "SEC-WEBSOCKET-VERSION"; const SEC_WEBSOCKET_VERSION: &str = "SEC-WEBSOCKET-VERSION";
// #[doc(hidden)]
// const SEC_WEBSOCKET_PROTOCOL: &'static str = "SEC-WEBSOCKET-PROTOCOL"; // const SEC_WEBSOCKET_PROTOCOL: &'static str = "SEC-WEBSOCKET-PROTOCOL";