diff --git a/actix-framed/src/app.rs b/actix-framed/src/app.rs index d8a273d72..cce618bb9 100644 --- a/actix-framed/src/app.rs +++ b/actix-framed/src/app.rs @@ -206,7 +206,7 @@ where let mut path = Path::new(Url::new(req.uri().clone())); if let Some((srv, _info)) = self.router.recognize_mut(&mut path) { - return srv.call(FramedRequest::new(req, framed, self.state.clone())); + return srv.call(FramedRequest::new(req, framed, path, self.state.clone())); } Box::new( SendResponse::new(framed, Response::NotFound().finish()).then(|_| Ok(())), diff --git a/actix-framed/src/request.rs b/actix-framed/src/request.rs index 4bc2932cd..eab28a9ef 100644 --- a/actix-framed/src/request.rs +++ b/actix-framed/src/request.rs @@ -1,5 +1,9 @@ +use std::cell::{Ref, RefMut}; + use actix_codec::Framed; -use actix_http::{h1::Codec, Request}; +use actix_http::http::{HeaderMap, Method, Uri, Version}; +use actix_http::{h1::Codec, Extensions, Request, RequestHead}; +use actix_router::{Path, Url}; use crate::state::State; @@ -7,24 +11,150 @@ pub struct FramedRequest { req: Request, framed: Framed, state: State, + pub(crate) path: Path, } impl FramedRequest { - pub fn new(req: Request, framed: Framed, state: State) -> Self { - Self { req, framed, state } + pub fn new( + req: Request, + framed: Framed, + path: Path, + state: State, + ) -> Self { + Self { + req, + framed, + state, + path, + } } } impl FramedRequest { - pub fn request(&self) -> &Request { - &self.req - } - - pub fn request_mut(&mut self) -> &mut Request { - &mut self.req - } - + /// Split request into a parts pub fn into_parts(self) -> (Request, Framed, State) { (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 { + &self.path + } + + /// Request extensions + #[inline] + pub fn extensions(&self) -> Ref { + self.head().extensions() + } + + /// Mutable reference to a the request's extensions + #[inline] + pub fn extensions_mut(&self) -> RefMut { + self.head().extensions_mut() + } +} + +#[cfg(test)] +mod tests { + use actix_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 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.extensions_mut().insert(100usize); + assert_eq!(*freq.extensions().get::().unwrap(), 100usize); + + let (_, _, state) = freq.into_parts(); + assert_eq!(*state, 10); + } } diff --git a/actix-http/src/test.rs b/actix-http/src/test.rs index 3d948ebd4..ce55912f7 100644 --- a/actix-http/src/test.rs +++ b/actix-http/src/test.rs @@ -205,6 +205,11 @@ impl TestBuffer { } } + /// Create new empty TestBuffer instance + pub fn empty() -> TestBuffer { + TestBuffer::new("") + } + /// Add extra data to read buffer. pub fn extend_read_buf>(&mut self, data: T) { self.read_buf.extend_from_slice(data.as_ref())