proxy_server/http/
headers.rs

1///! Module [`Header`]
2use crate::http::CRLF;
3#[cfg(feature = "napi")]
4use napi_derive::napi;
5use regex::Regex;
6use serde::{Deserialize, Serialize};
7use std::{
8    fmt,
9    io::{Error, ErrorKind, Result},
10    str,
11};
12
13use super::status::Status;
14
15/// HTTP header
16#[cfg_attr(feature = "napi", napi(object))]
17#[derive(Debug, Serialize, Clone, Deserialize)]
18pub struct Header {
19    pub name: String,
20    pub value: String,
21}
22
23/// HTTP headers
24#[cfg_attr(feature = "napi", napi(object))]
25#[derive(Debug, Serialize, Clone, Deserialize)]
26pub struct Headers {
27    pub raw: String,
28    pub list: Vec<Header>,
29}
30
31impl fmt::Display for Header {
32    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
33        write!(f, "{}: {}", self.name, self.value)
34    }
35}
36
37impl Headers {
38    pub fn new() -> Self {
39        Headers::from_string("".to_string())
40    }
41
42    // Create request headers
43    pub fn new_request(prefix: &str, list: Vec<Header>) -> Self {
44        let postfix = Headers::to_string(list);
45        let raw = format!(
46            "{}{CRLF}{postfix}",
47            Regex::new(r"\s*$")
48                .unwrap()
49                .replace_all(prefix, "")
50                .to_string()
51        );
52        Headers::from_string(raw)
53    }
54
55    /// Create response headers
56    pub fn new_response(status: &Status, list: Vec<Header>) -> Self {
57        let postfix = Headers::to_string(list);
58        let prefix = status.to_full_string();
59        let raw = format!("{prefix}{CRLF}{postfix}");
60        Headers::from_string(raw)
61    }
62
63    /// Parse headers
64    pub fn from_string(raw: String) -> Self {
65        let mut res: Headers = Headers {
66            raw: raw.clone(),
67            list: vec![],
68        };
69        let heads = raw.split(CRLF);
70        for h in heads {
71            let reg_name = Regex::new(r"^.+: ").unwrap();
72            let capts_name = reg_name.captures(h);
73            if let None = capts_name {
74                continue;
75            }
76            let capts_name = capts_name.unwrap();
77            let name = capts_name
78                .get(0)
79                .unwrap()
80                .as_str()
81                .to_string()
82                .replace(": ", "");
83
84            let reg_value = Regex::new(r": *.*$").unwrap();
85            let capts_value = reg_value.captures(h);
86            if let None = capts_value {
87                res.list.push(Header {
88                    name,
89                    value: "".to_string(),
90                });
91                continue;
92            }
93            let capts_value = capts_value.unwrap();
94            let value = capts_value
95                .get(0)
96                .unwrap()
97                .as_str()
98                .to_string()
99                .replace(": ", "");
100            res.list.push(Header { name, value });
101        }
102        res
103    }
104
105    /// Create string of headers from list
106    pub fn to_string(list: Vec<Header>) -> String {
107        let mut result = "".to_string();
108        for h in list {
109            result = format!("{result}{}: {}{CRLF}", h.name, h.value);
110        }
111        result = format!("{result}{CRLF}");
112        result
113    }
114
115    /// Create headers from bytes
116    pub fn from_bytes(heads: &Vec<u8>) -> Result<Self> {
117        let res = str::from_utf8(heads);
118        if let Err(err) = res {
119            return Err(Error::new(ErrorKind::InvalidInput, err));
120        }
121        let res = res.unwrap().to_string();
122        Ok(Headers::from_string(res))
123    }
124
125    fn change_header(&self, name: &str, value: &str) -> (Vec<Header>, bool) {
126        let mut check = false;
127        let mut new_list: Vec<Header> = vec![];
128        for h in self.list.clone() {
129            if name.to_lowercase() == h.name.as_str().to_lowercase() {
130                new_list.push(Header {
131                    name: name.to_string(),
132                    value: value.to_string(),
133                });
134                check = true;
135            } else {
136                new_list.push(Header {
137                    name: h.name.to_string(),
138                    value: h.value.to_string(),
139                });
140            }
141        }
142        (new_list, check)
143    }
144
145    /// Set new header or change old one
146    pub fn set_header(&self, name: &str, value: &str) -> Result<Self> {
147        let (mut new_list, check) = self.change_header(name, value);
148        if !check {
149            new_list.push(Header {
150                name: name.to_string(),
151                value: value.to_string(),
152            });
153        }
154
155        let new_h = match self.is_response() {
156            true => {
157                let status = Headers::get_status(&self.raw)?;
158                Headers::new_response(&status, new_list)
159            }
160            false => {
161                let prefix = Headers::get_headers_prefix(&self.raw)?;
162                Headers::new_request(prefix.as_str(), new_list)
163            }
164        };
165
166        Ok(Headers {
167            list: new_h.list,
168            raw: new_h.raw,
169        })
170    }
171
172    /// Parse content length from request headers
173    pub fn get_content_length(raw: &String) -> Option<u32> {
174        let raw = raw.to_lowercase();
175        let low = Regex::new(r"content-length: *\d+").unwrap().captures(&raw);
176
177        let mut check: Option<&str> = None;
178        if let Some(v) = low {
179            let low = v.get(0).unwrap();
180            check = Some(low.as_str());
181        }
182
183        if let None = check {
184            return None;
185        }
186
187        let cont_len = check.unwrap();
188
189        let num = Regex::new(r"\d+").unwrap().captures(cont_len);
190        if let None = num {
191            return None;
192        }
193        let capts = num.unwrap();
194        let num = capts.get(0);
195        let num_str = num.unwrap().as_str();
196        let num = num_str.parse::<u32>();
197        if let Err(e) = num {
198            println!("Failed parse content lenght from str: {}: {}", num_str, e);
199            return None;
200        }
201        Some(num.unwrap())
202    }
203
204    /// Get url from raw headers
205    pub fn get_url(raw: &String) -> String {
206        let reg = Regex::new(r"\/[a-zA-Z0-9_\-\/]*").unwrap();
207        let capts = reg.captures(raw.as_str());
208        if let None = capts {
209            return "/".to_string();
210        }
211        let capts = capts.unwrap();
212        let res = capts.get(0).unwrap().as_str();
213        res.to_string()
214    }
215
216    /// Get query string from raw headers
217    pub fn get_query(raw: &String) -> String {
218        let reg = Regex::new(r"\?[a-zA-Z0-9_\-&=\.]*").unwrap();
219        let capts = reg.captures(raw.as_str());
220        if let None = capts {
221            return "".to_string();
222        }
223        let capts = capts.unwrap();
224        let res = capts.get(0).unwrap().as_str();
225        res.to_string()
226    }
227
228    /// Get request chunked
229    pub fn get_chunked(raw: &String) -> bool {
230        let reg = Regex::new(r"transfer-encoding: *chunked").unwrap();
231        let raw = raw.to_lowercase();
232        let capts = reg.captures(raw.as_str());
233
234        if let None = capts {
235            return false;
236        }
237        return true;
238    }
239
240    // Get protocol from raw headers
241    pub fn get_protocol(raw: &String) -> String {
242        let reg = Regex::new(r"HTTPS?\/\d+\.\d+").unwrap();
243        let capts = reg.captures(raw.as_str());
244        if let None = capts {
245            return "OPTIONS".to_string();
246        }
247        let capts = capts.unwrap();
248        let protocol = capts.get(0).unwrap().as_str();
249        protocol.to_string()
250    }
251
252    // Get request prefix
253    fn get_status(raw: &String) -> Result<Status> {
254        let reg = Regex::new(format!(r".+{CRLF}").as_str()).unwrap();
255        let capts = reg.captures(raw.as_str());
256        if let None = capts {
257            return Err(Error::new(
258                ErrorKind::InvalidInput,
259                "Headers prefix didn't find",
260            ));
261        }
262        let capts = capts.unwrap();
263        let result = capts.get(0).unwrap().as_str();
264
265        let result = Regex::new(format!(r"^HTTPS?\/\d+\.\d+ ").as_str())
266            .unwrap()
267            .replace_all(result, "")
268            .to_string();
269
270        let reg = Regex::new(format!(r"^\d+").as_str()).unwrap();
271        let capts = reg.captures(result.as_str());
272        if let None = capts {
273            return Err(Error::new(
274                ErrorKind::InvalidInput,
275                "Headers prefix didn't find",
276            ));
277        }
278        let capts = capts.unwrap();
279        let code = capts.get(0).unwrap().as_str().parse::<u16>();
280        if let Err(err) = code {
281            return Err(Error::new(
282                ErrorKind::InvalidInput,
283                format!("Failed parse status code {:?}", err),
284            ));
285        }
286        let code = code.unwrap();
287
288        let text = Regex::new(format!(r"^\d+ ").as_str())
289            .unwrap()
290            .replace_all(result.as_str(), "")
291            .to_string();
292
293        Ok(Status { code, text })
294    }
295
296    /// Get method from raw headers
297    pub fn get_method(raw: &String) -> String {
298        let reg = Regex::new(r"\w+").unwrap();
299        let capts = reg.captures(raw.as_str());
300        if let None = capts {
301            return "OPTIONS".to_string();
302        }
303        let capts = capts.unwrap();
304        let method = capts.get(0).unwrap().as_str();
305        method.to_string()
306    }
307
308    // Get request prefix
309    fn get_headers_prefix(raw: &String) -> Result<String> {
310        let reg = Regex::new(format!(r".+{CRLF}").as_str()).unwrap();
311        let capts = reg.captures(raw.as_str());
312        if let None = capts {
313            return Err(Error::new(
314                ErrorKind::InvalidInput,
315                "Headers prefix didn't find",
316            ));
317        }
318        let capts = capts.unwrap();
319        let result = capts.get(0).unwrap().as_str();
320        let result = Regex::new(format!(r"{CRLF}+$").as_str())
321            .unwrap()
322            .replace_all(result, "");
323        Ok(result.to_string())
324    }
325
326    fn is_response(&self) -> bool {
327        let reg = Regex::new(r"^HTTPS?/\d+\.\d+").unwrap();
328        let capts = reg.captures(self.raw.as_str());
329        if let None = capts {
330            return false;
331        }
332        true
333    }
334}