1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//! Context

use std::fmt;

use crate::{http, Extract, Result, VecMiddleware};

/// The `Context` of an HTTP `request - response`.
pub struct Context {
    /// The request's URI
    uri: http::Uri,

    /// The request's method
    method: http::Method,

    /// The request's version
    version: http::Version,

    /// The request's headers
    headers: http::HeaderMap,

    /// The request's extensions
    extensions: http::Extensions,

    /// The request's body
    body: Option<http::Body>,

    /// The request's middleware
    middleware: VecMiddleware,
}

impl Context {
    /// Consumes the request to Context
    pub fn new(req: http::Request) -> Self {
        req.into()
    }

    /// Returns a reference to the associated HTTP method.
    pub fn method(&self) -> &http::Method {
        &self.method
    }

    /// Returns the associated version.
    pub fn version(&self) -> http::Version {
        self.version
    }

    /// Returns a reference to the associated URI.
    pub fn uri(&self) -> &http::Uri {
        &self.uri
    }

    /// Returns a reference to the associated path portion of the URL.
    pub fn path(&self) -> &str {
        self.uri.path()
    }

    /// Returns a reference to the associated query portion of the URL.
    pub fn query_str(&self) -> &str {
        if let Some(query) = self.uri().query().as_ref() { query } else { "" }
    }

    /// Returns a reference to the associated host portion of the URL.
    pub fn host(&self) -> Option<&str> {
        self.uri.host()
    }

    /// Gets content type
    pub fn mime(&self) -> Option<mime::Mime> {
        self.header(http::header::CONTENT_TYPE)
    }

    /// Gets content length
    pub fn size(&self) -> Option<u64> {
        self.header(http::header::CONTENT_LENGTH)
    }

    /// Returns a reference to the associated header by key.
    pub fn header_value(&self, key: impl AsRef<str>) -> Option<&http::HeaderValue> {
        self.headers.get(key.as_ref())
    }

    /// Returns a value by header key.
    pub fn header<T: std::str::FromStr>(&self, key: impl AsRef<str>) -> Option<T> {
        self.header_value(key.as_ref())
            .and_then(|v| v.to_str().ok())
            .and_then(|v| v.parse::<T>().ok())
    }

    /// Returns a reference to the associated header field map.
    pub fn headers(&self) -> &http::HeaderMap {
        &self.headers
    }

    /// Returns a reference to the associated extensions.
    pub fn extensions(&self) -> &http::Extensions {
        &self.extensions
    }

    /// Returns a mutable reference to the associated extensions.
    pub fn extensions_mut(&mut self) -> &mut http::Extensions {
        &mut self.extensions
    }

    /// Consumes the request, returning just the body.
    pub fn take_body(&mut self) -> Option<http::Body> {
        self.body.take()
    }

    /// Returns a reference to the associated middleware.
    pub fn middleware(&self) -> &VecMiddleware {
        &self.middleware
    }

    /// Returns a mutable reference to the associated middleware.
    pub fn middleware_mut(&mut self) -> &mut VecMiddleware {
        &mut self.middleware
    }

    /// Returns a data from the `Context` with a Extractor.
    pub async fn extract<T: Extract>(&mut self) -> Result<T, T::Error> {
        T::extract(self).await
    }

    /// Invokes the next middleware.
    pub async fn next(&mut self) -> Result {
        if let Some(m) = self.middleware.pop() {
            return m.call(self).await;
        }
        Ok(http::StatusCode::NOT_FOUND.into())
    }
}

impl From<http::Request> for Context {
    fn from(req: http::Request) -> Self {
        let (::http::request::Parts { uri, method, headers, version, extensions, .. }, body) =
            req.into_parts();
        Self { uri, method, headers, version, extensions, body: Some(body), middleware: Vec::new() }
    }
}

impl fmt::Debug for Context {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt.debug_struct("Context")
            .field("version", &self.version)
            .field("method", &self.method)
            .field("uri", &self.uri)
            .field("headers", &self.headers)
            .field("extensions", &self.extensions)
            .field("body", &self.body.is_some())
            .field("middleware", &self.middleware.len())
            .finish()
    }
}