bolt_web/
request.rs

1use std::collections::HashMap;
2
3use bytes::Bytes;
4use http_body_util::BodyExt;
5use hyper::header::HeaderName;
6use hyper::{Request, Uri, Version, body::Incoming, header::HeaderValue};
7use serde::de::DeserializeOwned;
8use url::form_urlencoded;
9
10pub struct RequestBody {
11    inner: Request<Incoming>,
12    params: HashMap<String, String>,
13}
14
15impl RequestBody {
16    pub fn new(req: Request<Incoming>) -> Self {
17        Self {
18            inner: req,
19            params: HashMap::new(),
20        }
21    }
22
23    pub fn params(&self) -> &HashMap<String, String> {
24        &self.params
25    }
26
27    pub(crate) fn set_params(&mut self, params: HashMap<String, String>) {
28        self.params = params;
29    }
30
31    pub fn method(&self) -> &hyper::Method {
32        self.inner.method()
33    }
34
35    pub fn path(&self) -> &str {
36        self.inner.uri().path()
37    }
38
39    pub fn headers(&self) -> &hyper::HeaderMap {
40        self.inner.headers()
41    }
42
43    pub fn set_headers(&mut self, key: &str, value: &str) {
44        let key = HeaderName::from_bytes(key.as_bytes()).expect("Invalid header name");
45        let value = HeaderValue::from_str(value).expect("Invalid header value");
46
47        self.inner.headers_mut().insert(key, value);
48    }
49
50    pub fn get_headers(&mut self, key: &str) -> Option<&HeaderValue> {
51        self.inner.headers().get(key)
52    }
53
54    pub fn uri(&self) -> &Uri {
55        self.inner.uri()
56    }
57
58    pub fn version(&self) -> Version {
59        self.inner.version()
60    }
61
62    pub fn query(&self) -> HashMap<String, String> {
63        self.inner
64            .uri()
65            .query()
66            .map(|q| {
67                form_urlencoded::parse(q.as_bytes())
68                    .into_owned()
69                    .collect::<HashMap<String, String>>()
70            })
71            .unwrap_or_default()
72    }
73
74    pub fn query_param(&self, key: &str) -> Option<String> {
75        let query_params = self.query();
76        query_params.get(key).cloned()
77    }
78
79    pub async fn bytes(self) -> Result<Bytes, hyper::Error> {
80        let (_, body) = self.inner.into_parts();
81        let collected = body.collect().await?;
82        Ok(collected.to_bytes())
83    }
84
85    pub async fn text(self) -> Result<String, Box<dyn std::error::Error>> {
86        let bytes = self.bytes().await?;
87        let text = String::from_utf8(bytes.to_vec())?;
88        Ok(text)
89    }
90
91    pub async fn json<T: DeserializeOwned>(self) -> Result<T, Box<dyn std::error::Error>> {
92        let bytes = self.bytes().await?;
93        let value = serde_json::from_slice(&bytes)?;
94        Ok(value)
95    }
96
97    pub fn get_cookie(&self, name: &str) -> Option<String> {
98        self.inner
99            .headers()
100            .get(hyper::header::COOKIE)?
101            .to_str()
102            .ok()
103            .and_then(|cookie_header| {
104                cookie_header.split(';').map(|s| s.trim()).find_map(|pair| {
105                    let mut parts = pair.splitn(2, '=');
106                    let key = parts.next()?;
107                    let value = parts.next()?;
108                    if key == name {
109                        Some(value.to_string())
110                    } else {
111                        None
112                    }
113                })
114            })
115    }
116}