envoy_http 0.0.6

A minimal and pragmatic Rust web application framework built for rapid development
Documentation
use std::{fmt::Debug};

use hyper::{Version, Body, Method, header::{HeaderName, HeaderValue}, Uri};
use routefinder::Captures;
use typemap::Key;

/// ## The context of a request.
///
/// This is a wrapper around a [crate::http::Request] and a [crate::http::Response]
/// that provides access to the request and response
/// as well as some additional information such as the state
/// and parameters.
#[derive(Debug)]
pub struct Context {

    /// The request that was made.
    pub req: crate::Request<Body>,
    ctx: typemap::ShareDebugMap,
    /// Any error captured during the request.
    /// The parsed request parameters
    pub params: Vec<Captures<'static, 'static>>,
}


impl Context {
    /// Create a new [Context] with a [crate::http::Request].
    pub(crate) fn new(

        req: crate::Request<Body>,
        params: Vec<Captures<'static, 'static>>,
    ) -> Self {
        Self {
            req,
            ctx: typemap::ShareDebugMap::custom(),
            params,
        }
    }

    /// Access the request's HTTP method.
    #[must_use]
    pub fn method(&self) -> &Method {
        self.req.method()
    }

    /// Access the request's full URI method.
    #[must_use]
    pub fn uri(&self) -> &Uri {
        self.req.uri()
    }

    /// Access the request's HTTP version.
    #[must_use]
    pub fn version(&self) -> Version {
        self.req.version()
    }

    /// Get the destination host for this request.
    ///
    /// This is determined in the following priority:
    /// 1. `Forwarded` header `host` key
    /// 2. The first `X-Forwarded-Host` header
    /// 3. `Host` header
    /// 4. URL domain, if any
    #[must_use]
    pub fn host(&self) -> Option<&str> {
        self.req.uri().host()
    }

    /// Get an HTTP header.
    /// ```
    #[must_use]
    pub fn header(
        &self,
        key: impl Into<HeaderName>,
    ) -> Option<&HeaderValue> {
        self.req.headers().get(key.into())
    }

    /// Get a mutable reference to a header.
    pub fn header_mut(&mut self, name: impl Into<HeaderName>) -> Option<&mut HeaderValue> {
        self.req.headers_mut().get_mut(name.into())
    }

    /// Set an HTTP header.
    pub fn insert_header(
        &mut self,
        name: impl Into<HeaderName>,
        value: impl Into<HeaderValue>,
    ) -> Option<HeaderValue> {
        self.req.headers_mut().insert(name.into(), value.into())
    }

    /// Remove a header.
    pub fn remove_header(&mut self, name: impl Into<HeaderName>) -> Option<HeaderValue> {
        self.req.headers_mut().remove(name.into())
    }

    /// Get a context value.
    #[must_use]
    pub fn get<T: Key<Value = T> + Debug + Send + Sync>(&self) -> Option<&T> {
        self.ctx.get::<T>()
    }

    /// Get a mutable reference to value stored in context.
    #[must_use]
    pub fn get_mut<T: Key<Value = T> + Debug + Send + Sync>(&mut self) -> Option<&mut T> {
        self.ctx.get_mut::<T>()
    }

    /// Set a context value.
    pub fn set<T: Key<Value = T> + Debug + Send + Sync>(&mut self, val: T) -> Option<T> {
        self.ctx.insert::<T>(val)
    }

    /// Extract and parse a route parameter by name.
    ///
    /// Returns the parameter as a `&str`, borrowed from this `Request`.
    ///
    /// The name should *not* include the leading `:`.
    ///
    /// # Errors
    ///
    /// An error is returned if `key` is not a valid parameter for the route.

    pub fn param(&self, key: &str) -> crate::Result<&str> {
        self.params
            .iter()
            .rev()
            .find_map(|captures| captures.get(key))
            .ok_or_else(|| anyhow::anyhow!("Param \"{}\" not found", key.to_string()).into())
    }

    /// Fetch the wildcard from the route, if it exists
    ///
    /// Returns the parameter as a `&str`, borrowed from this `Request`.

    pub fn wildcard(&self) -> Option<&str> {
        self.params
            .iter()
            .rev()
            .find_map(|captures| captures.wildcard())
    }
}

impl AsRef<crate::Request<Body>> for Context {
    fn as_ref(&self) -> &crate::Request<Body> {
        &self.req
    }
}

impl AsMut<crate::Request<Body>> for Context {
    fn as_mut(&mut self) -> &mut crate::Request<Body> {
        &mut self.req
    }
}