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