Skip to main content

feather_runtime/http/
request.rs

1use std::io;
2use std::net::SocketAddr;
3/// Simple alias for error results in this module.
4/// We use a boxed std error to avoid depending on the removed crate error type.
5pub type Error = Box<dyn std::error::Error>;
6use bytes::Bytes;
7use http::{Extensions, HeaderMap, Method, Uri, Version};
8use std::str::FromStr;
9use std::{borrow::Cow, collections::HashMap, fmt};
10use urlencoding::decode;
11// TODO : Add remote_addr()
12/// Contains a incoming Http Request
13#[derive(Debug)]
14pub struct Request {
15    /// The HTTP method of the request.<br>
16    /// For example, GET, POST, PUT, DELETE, etc.
17    pub method: Method,
18    /// The URI of the request.
19    pub uri: Uri,
20    /// The HTTP version of the request.
21    pub version: Version,
22    /// The headers of the request.
23    pub headers: HeaderMap,
24    /// The body of the request.
25    pub body: Bytes,
26    /// The extensions of the request.
27    pub extensions: Extensions,
28    /// The Address of the request
29    addr: SocketAddr,
30    /// The route parameters of the request.
31    params: HashMap<String, String>,
32}
33
34impl Request {
35    /// Parses a Request from raw bytes if parsing fails returns a error
36    pub fn parse(headers_raw: &[u8], body: Bytes, incoming_addr: SocketAddr) -> Result<Request, Error> {
37        let mut headers = [httparse::EMPTY_HEADER; 64];
38        let mut request = httparse::Request::new(&mut headers);
39
40        request.parse(headers_raw).map_err(|e| -> Error { Box::new(io::Error::new(io::ErrorKind::InvalidData, format!("Failed to parse request: {}", e))) })?;
41
42        // Get the method string, ensuring it exists
43        let method_str = request.method.ok_or_else(|| -> Error { Box::new(io::Error::new(io::ErrorKind::InvalidData, "Missing HTTP method")) })?;
44
45        // Validate method against known HTTP methods
46        let method = Method::from_str(method_str).map_err(|_| -> Error { Box::new(io::Error::new(io::ErrorKind::InvalidData, format!("Invalid HTTP method: {}", method_str))) })?;
47        let path = request.path.ok_or_else(|| -> Error { Box::new(io::Error::new(io::ErrorKind::InvalidData, "Failed to parse URI")) })?;
48        let uri: Uri = path.parse().map_err(|e| -> Error { Box::new(io::Error::new(io::ErrorKind::InvalidData, format!("Failed to parse URI: {}", e))) })?;
49
50        let version = match request.version {
51            Some(0) => Version::HTTP_10,
52            Some(1) => Version::HTTP_11,
53            _ => Version::HTTP_11,
54        };
55        let mut header_map = HeaderMap::new();
56        for header in request.headers.iter() {
57            let name = http::header::HeaderName::from_bytes(header.name.as_bytes()).map_err(|e| -> Error { Box::new(io::Error::new(io::ErrorKind::InvalidData, format!("Failed to parse header name: {}", e))) })?;
58            let value = http::header::HeaderValue::from_bytes(header.value).map_err(|e| -> Error { Box::new(io::Error::new(io::ErrorKind::InvalidData, format!("Failed to parse header value: {}", e))) })?;
59
60            header_map.insert(name, value);
61        }
62
63        let extensions = Extensions::new();
64        Ok(Request {
65            method,
66            uri,
67            version,
68            headers: header_map,
69            body,
70            addr: incoming_addr,
71            extensions,
72            params: HashMap::new(),
73        })
74    }
75
76    /// Parses the body of the request as Serde JSON Value. Returns an error if the body is not valid JSON.  
77    /// This method is useful for parsing JSON payloads in requests.  
78    #[cfg(feature = "json")]
79    pub fn json(&self) -> Result<serde_json::Value, Error> {
80        serde_json::from_slice(&self.body).map_err(|e| -> Error { Box::new(io::Error::new(io::ErrorKind::InvalidData, format!("Failed to parse JSON body: {}", e))) })
81    }
82    /// Returns a Hashmap of the query parameters of the Request.  
83    /// Returns a Error if parsing fails
84    pub fn query(&self) -> Result<HashMap<String, String>, Error> {
85        if let Some(query) = self.uri.query() {
86            serde_urlencoded::from_str(query).map_err(|e| -> Error { Box::new(io::Error::new(io::ErrorKind::InvalidData, format!("Failed to Parse Query parameters {}", e))) })
87        } else {
88            Ok(HashMap::new())
89        }
90    }
91
92    pub fn set_params(&mut self, params: HashMap<String, String>) {
93        self.params = params;
94    }
95
96    pub fn param(&self, key: &str) -> Option<&str> {
97        self.params.get(key).map(|v| &**v)
98    }
99
100    /// Returns the path of the Request
101    pub fn path(&self) -> Cow<'_, str> {
102        decode(self.uri.path()).unwrap()
103    }
104    pub fn remote_addr(&self) -> SocketAddr {
105        self.addr
106    }
107}
108
109impl fmt::Display for Request {
110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111        write!(f, "{} {}", self.method, self.uri.path())
112    }
113}