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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
use std::cell::{Ref, RefMut};

use requiem_codec::Framed;
use requiem_http::http::{HeaderMap, Method, Uri, Version};
use requiem_http::{h1::Codec, Extensions, Request, RequestHead};
use requiem_router::{Path, Url};

use crate::state::State;

pub struct FramedRequest<Io, S = ()> {
    req: Request,
    framed: Framed<Io, Codec>,
    state: State<S>,
    pub(crate) path: Path<Url>,
}

impl<Io, S> FramedRequest<Io, S> {
    pub fn new(
        req: Request,
        framed: Framed<Io, Codec>,
        path: Path<Url>,
        state: State<S>,
    ) -> Self {
        Self {
            req,
            framed,
            state,
            path,
        }
    }
}

impl<Io, S> FramedRequest<Io, S> {
    /// Split request into a parts
    pub fn into_parts(self) -> (Request, Framed<Io, Codec>, State<S>) {
        (self.req, self.framed, self.state)
    }

    /// This method returns reference to the request head
    #[inline]
    pub fn head(&self) -> &RequestHead {
        self.req.head()
    }

    /// This method returns muttable reference to the request head.
    /// panics if multiple references of http request exists.
    #[inline]
    pub fn head_mut(&mut self) -> &mut RequestHead {
        self.req.head_mut()
    }

    /// Shared application state
    #[inline]
    pub fn state(&self) -> &S {
        self.state.get_ref()
    }

    /// Request's uri.
    #[inline]
    pub fn uri(&self) -> &Uri {
        &self.head().uri
    }

    /// Read the Request method.
    #[inline]
    pub fn method(&self) -> &Method {
        &self.head().method
    }

    /// Read the Request Version.
    #[inline]
    pub fn version(&self) -> Version {
        self.head().version
    }

    #[inline]
    /// Returns request's headers.
    pub fn headers(&self) -> &HeaderMap {
        &self.head().headers
    }

    /// The target path of this Request.
    #[inline]
    pub fn path(&self) -> &str {
        self.head().uri.path()
    }

    /// The query string in the URL.
    ///
    /// E.g., id=10
    #[inline]
    pub fn query_string(&self) -> &str {
        if let Some(query) = self.uri().query().as_ref() {
            query
        } else {
            ""
        }
    }

    /// Get a reference to the Path parameters.
    ///
    /// Params is a container for url parameters.
    /// A variable segment is specified in the form `{identifier}`,
    /// where the identifier can be used later in a request handler to
    /// access the matched value for that segment.
    #[inline]
    pub fn match_info(&self) -> &Path<Url> {
        &self.path
    }

    /// Request extensions
    #[inline]
    pub fn extensions(&self) -> Ref<Extensions> {
        self.head().extensions()
    }

    /// Mutable reference to a the request's extensions
    #[inline]
    pub fn extensions_mut(&self) -> RefMut<Extensions> {
        self.head().extensions_mut()
    }
}

#[cfg(test)]
mod tests {
    use std::convert::TryFrom;

    use requiem_http::http::{HeaderName, HeaderValue};
    use requiem_http::test::{TestBuffer, TestRequest};

    use super::*;

    #[test]
    fn test_reqest() {
        let buf = TestBuffer::empty();
        let framed = Framed::new(buf, Codec::default());
        let req = TestRequest::with_uri("/index.html?q=1")
            .header("content-type", "test")
            .finish();
        let path = Path::new(Url::new(req.uri().clone()));

        let mut freq = FramedRequest::new(req, framed, path, State::new(10u8));
        assert_eq!(*freq.state(), 10);
        assert_eq!(freq.version(), Version::HTTP_11);
        assert_eq!(freq.method(), Method::GET);
        assert_eq!(freq.path(), "/index.html");
        assert_eq!(freq.query_string(), "q=1");
        assert_eq!(
            freq.headers()
                .get("content-type")
                .unwrap()
                .to_str()
                .unwrap(),
            "test"
        );

        freq.head_mut().headers.insert(
            HeaderName::try_from("x-hdr").unwrap(),
            HeaderValue::from_static("test"),
        );
        assert_eq!(
            freq.headers().get("x-hdr").unwrap().to_str().unwrap(),
            "test"
        );

        freq.extensions_mut().insert(100usize);
        assert_eq!(*freq.extensions().get::<usize>().unwrap(), 100usize);

        let (_, _, state) = freq.into_parts();
        assert_eq!(*state, 10);
    }
}