feather_runtime/http/
request.rs

1use super::ConnectionState;
2use crate::utils::error::Error;
3use bytes::Bytes;
4use http::{Extensions, HeaderMap, Method, Uri, Version};
5use std::str::FromStr;
6use std::{borrow::Cow, collections::HashMap, fmt};
7use std::net::TcpStream;
8use urlencoding::decode;
9
10/// Contains a incoming Http Request
11#[derive(Debug)]
12pub struct Request {
13    stream: Option<TcpStream>,
14    /// The HTTP method of the request.<br>
15    /// For example, GET, POST, PUT, DELETE, etc.
16    pub method: Method,
17    /// The URI of the request.
18    pub uri: Uri,
19    /// The HTTP version of the request.
20    pub version: Version,
21    /// The headers of the request.
22    pub headers: HeaderMap,
23    /// The body of the request.
24    pub body: Bytes,
25    /// The extensions of the request.
26    pub extensions: Extensions,
27    /// The route parameters of the request.
28    params: HashMap<String, String>,
29    // Connection State(Keep-Alive OR Close) of the Request
30    pub(crate) connection: Option<ConnectionState>,
31}
32
33
34impl Request {
35    /// Parses a Request from raw bytes if parsing fails returns a error
36    /// #### Puts a None to as stream of the request!
37    pub fn parse(raw: &[u8]) -> Result<Request, Error> {
38        let mut headers = [httparse::EMPTY_HEADER; 16];
39        let mut request = httparse::Request::new(&mut headers);
40        let mut connection = None;
41        request.parse(raw).map_err(|e| Error::ParseError(format!("Failed to parse request: {}", e)))?;
42        let method = match Method::from_str(request.method.unwrap_or("nil")) {
43            Ok(m) => m,
44            Err(e) => return Err(Error::ParseError(format!("Failed to parse method: {}", e))),
45        };
46        let uri: Uri = request.path.ok_or_else(|| Error::ParseError("Failed to parse URI".to_string()))?.parse().map_err(|e| Error::ParseError(format!("Failed to parse URI: {}", e)))?;
47
48        let version = match request.version {
49            Some(0) => Version::HTTP_10,
50            Some(1) => Version::HTTP_11,
51            _ => Version::HTTP_11,
52        };
53        let mut header_map = HeaderMap::new();
54        for header in request.headers.iter() {
55            let name = http::header::HeaderName::from_bytes(header.name.as_bytes()).map_err(|e| Error::ParseError(format!("Failed to parse header name: {}", e)))?;
56            let value = http::header::HeaderValue::from_bytes(header.value).map_err(|e| Error::ParseError(format!("Failed to parse header value: {}", e)))?;
57
58            if name.as_str().eq_ignore_ascii_case("connection") {
59                connection = ConnectionState::parse(value.to_str().unwrap_or(""));
60            }
61
62            header_map.insert(name, value);
63        }
64        let body_start = raw.windows(4).position(|w| w == b"\r\n\r\n").map(|pos| pos + 4).unwrap_or(raw.len());
65        let body = Bytes::copy_from_slice(&raw[body_start..]);
66        let extensions = Extensions::new();
67        Ok(Request {
68            stream: None,
69            method,
70            uri,
71            version,
72            headers: header_map,
73            body,
74            extensions,
75            connection,
76            params: HashMap::new(),
77        })
78    }
79
80    pub(crate) fn set_stream(&mut self, stream: TcpStream) {
81        self.stream = Some(stream);
82    }
83    /// Takes the stream of the request
84    /// This medhod takes ownership of the Request!  
85    /// And also gives you to responsiblity give answer to the socket connection
86    /// This method is only intented to used by Power Users use **it at your own risk.**  
87    /// ## Usage:
88    /// Takes the stream out but you have to clone the request to do so.  
89    /// ```rust,ignore
90    /// if let Some(stream) = request.clone().take_stream(){
91    ///     
92    /// }
93    /// ```
94    /// The Reason of this is in the middlewares don't allow you to have ownership of the request and response objects so to get ownership you have to clone it
95    pub fn take_stream(mut self) -> Option<TcpStream> {
96        self.stream.take()
97    }
98    /// Returns true if the Request has a Stream false if stream is taken
99    pub fn has_stream(&self) -> bool {
100        self.stream.is_some()
101    }
102
103    /// Parses the body of the request as Serde JSON Value. Returns an error if the body is not valid JSON.  
104    /// This method is useful for parsing JSON payloads in requests.  
105    #[cfg(feature = "json")]
106    pub fn json(&self) -> Result<serde_json::Value, Error> {
107        serde_json::from_slice(&self.body).map_err(|e| Error::ParseError(format!("Failed to parse JSON body: {}", e)))
108    }
109    /// Returns a Hashmap of the query parameters of the Request.  
110    /// Returns a Error if parsing fails
111    pub fn query(&self) -> Result<HashMap<String, String>, Error> {
112        if let Some(query) = self.uri.query() {
113            serde_urlencoded::from_str(query).map_err(|e| Error::ParseError(format!("Failed to Parse Query parameters {}", e)))
114        } else {
115            Ok(HashMap::new())
116        }
117    }
118
119    pub fn set_params(&mut self, params: HashMap<String, String>) {
120        self.params = params;
121    }
122
123    pub fn param(&self, key: &str) -> Option<&str> {
124        self.params.get(key).map(|v| &**v)
125    }
126
127    /// Returns the path of the Request
128    pub fn path(&self) -> Cow<'_, str> {
129        decode(self.uri.path()).unwrap()
130    }
131}
132
133impl fmt::Display for Request {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135        write!(f, "{} for {}: Body Data: {} ", self.method, self.uri.path(), String::from_utf8_lossy(&self.body))
136    }
137}