pub(crate) mod fragment;
mod remote;
use self::fragment::{Fragment, FragmentSelect};
pub use self::remote::RemoteAddress;
use crate::HttpEntity;
use std::convert::TryFrom;
use std::str::FromStr;
macro_rules! forward {
() => {};
(
$(#[$m:meta])* $v:vis fn $name:ident(&self $(, $pn:ident: $pt:ty)*) -> $ret:ty;
$($tail:tt)*
) => {
$(#[$m])* $v fn $name(&self $(, $pn: $pt)*) -> $ret {
(self.0).$name($($pn),*)
}
forward! { $($tail)* }
};
(
$(#[$m:meta])* $v:vis fn $name:ident(&mut self $(, $pn:ident: $pt:ty)*) -> $ret:ty;
$($tail:tt)*
) => {
$(#[$m])* $v fn $name(&mut self $(, $pn: $pt)*) -> $ret {
(self.0).$name($($pn),*)
}
forward! { $($tail)* }
}
}
macro_rules! construct {
() => {};
($($(#[$m:meta])* $v:vis fn $method:ident = $action:expr;)+) => {
$($(#[$m])* $v fn $method<U>(uri: U) -> Result<Self, http::Error>
where
http::Uri: TryFrom<U>,
<http::Uri as TryFrom<U>>::Error: Into<http::Error>
{
http::request::Builder::new()
.method($action)
.uri(uri)
.body(hyper::Body::empty())
.map(Request)
})+
};
}
#[derive(Debug)]
pub struct Request(http::Request<hyper::Body>);
impl Request {
construct! {
pub fn get = http::Method::GET;
pub fn post = http::Method::POST;
pub fn options = http::Method::OPTIONS;
pub fn put = http::Method::PUT;
pub fn delete = http::Method::DELETE;
pub fn head = http::Method::HEAD;
pub fn trace = http::Method::TRACE;
pub fn connect = http::Method::CONNECT;
pub fn patch = http::Method::PATCH;
}
pub fn from_method<U>(uri: U, method: http::Method) -> Result<Self, http::Error>
where
http::Uri: TryFrom<U>,
<http::Uri as TryFrom<U>>::Error: Into<http::Error>,
{
http::request::Builder::new()
.method(method)
.uri(uri)
.body(hyper::Body::empty())
.map(Request)
}
pub fn fragment<I: FromStr, K: FragmentSelect>(&self, key: K) -> Option<I> {
self.fragment_str(key).and_then(|s| s.parse().ok())
}
pub fn fragment_str<K: FragmentSelect>(&self, key: K) -> Option<&str> {
self.fragment_ext()?.select(key)
}
fn fragment_ext(&self) -> Option<&Fragment> {
self.extensions().get::<Fragment>()
}
#[cfg(feature = "serde")]
#[cfg_attr(nightly, doc(cfg(feature = "serde")))]
pub fn query<'q, S: serde::Deserialize<'q>>(&'q self) -> Option<S> {
self.uri()
.query()
.and_then(|s| serde_qs::from_str::<S>(s).ok())
}
pub fn peer_addr(&self) -> Option<std::net::SocketAddr> {
Some(self.ext::<crate::middleware::PeerAddress>()?.0)
}
#[must_use]
pub fn with_local_addr(mut self) -> Self {
self.extensions_mut()
.insert(crate::middleware::PeerAddress(std::net::SocketAddr::from(
([127, 0, 0, 1], 0),
)));
self
}
#[deprecated(note = "use remote_address instead")]
pub fn remote(&self) -> Option<std::net::IpAddr> {
use std::net::IpAddr;
fn forwarded_header(request: &Request) -> Option<IpAddr> {
request
.header("Forwarded")
.and_then(|s| s.to_str().ok())?
.split(';')
.find_map(|s| {
s.trim()
.strip_prefix("for=")
.and_then(|s| s.trim_matches('"').parse::<IpAddr>().ok())
})
}
fn x_forwarded_for_header(request: &Request) -> Option<IpAddr> {
request
.header("X-Forwarded-For")
.and_then(|s| s.to_str().ok())?
.split(',')
.next()
.and_then(|s| s.trim().parse::<IpAddr>().ok())
}
forwarded_header(self)
.or_else(|| x_forwarded_for_header(self))
.or_else(|| self.peer_addr().map(|addr| addr.ip()))
}
pub fn remote_address(&self) -> RemoteAddress<'_> {
RemoteAddress::new(self)
}
pub fn state<T: Send + Sync + 'static>(&self) -> Option<&T> {
self.ext::<crate::middleware::State<T>>().map(|v| &v.0)
}
pub fn ext<T: Send + Sync + 'static>(&self) -> Option<&T> {
self.extensions().get::<T>()
}
pub fn ext_mut<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
self.extensions_mut().get_mut::<T>()
}
pub fn set_ext<T: Send + Sync + 'static>(&mut self, value: T) -> &mut Self {
self.extensions_mut().insert(value);
self
}
#[must_use]
pub fn with_ext<T: Send + Sync + 'static>(mut self, value: T) -> Self {
self.set_ext(value);
self
}
pub fn remove_ext<T: Send + Sync + 'static>(&mut self) -> Option<T> {
self.extensions_mut().remove::<T>()
}
#[must_use]
pub fn without_ext<T: Send + Sync + 'static>(mut self) -> Self {
self.remove_ext::<T>();
self
}
forward! {
#[inline]
pub fn uri(&self) -> &http::Uri;
#[inline]
pub fn method(&self) -> &http::Method;
#[inline]
pub fn extensions(&self) -> &http::Extensions;
#[inline]
pub fn extensions_mut(&mut self) -> &mut http::Extensions;
}
}
impl crate::HttpEntity for Request {
#[inline]
fn body_mut(&mut self) -> &mut hyper::Body {
self.0.body_mut()
}
#[inline]
fn headers(&self) -> &http::HeaderMap {
self.0.headers()
}
#[inline]
fn headers_mut(&mut self) -> &mut http::HeaderMap {
self.0.headers_mut()
}
}
impl From<http::Request<hyper::Body>> for Request {
fn from(r: http::Request<hyper::Body>) -> Self {
Request(r)
}
}
impl From<Request> for http::Request<hyper::Body> {
fn from(r: Request) -> Self {
r.0
}
}
impl std::borrow::Borrow<http::Request<hyper::Body>> for Request {
fn borrow(&self) -> &http::Request<hyper::Body> {
&self.0
}
}
impl std::borrow::BorrowMut<http::Request<hyper::Body>> for Request {
fn borrow_mut(&mut self) -> &mut http::Request<hyper::Body> {
&mut self.0
}
}