1use std::collections::HashMap;
2use std::fmt::{Display, Formatter};
3use std::str::FromStr;
4
5#[derive(Default, Debug)]
6pub struct Req {
7 pub body: Option<String>,
8 pub path: String,
9 pub method: ReqMethod,
10 pub queries: HashMap<String, String>,
11 protocol: String,
12 headers: HashMap<String, String>,
13}
14
15#[derive(Default, Debug)]
16pub enum ReqMethod {
17 #[default]
18 Get,
19 Post,
20 Patch,
21 Put,
22 Delete,
23}
24
25impl Display for ReqMethod {
26 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
27 match self {
28 ReqMethod::Get => write!(f, "GET"),
29 ReqMethod::Post => write!(f, "POST"),
30 ReqMethod::Patch => write!(f, "PATCH"),
31 ReqMethod::Put => write!(f, "PUT"),
32 ReqMethod::Delete => write!(f, "DELETE"),
33 }
34 }
35}
36
37impl FromStr for ReqMethod {
38 type Err = ();
39
40 fn from_str(s: &str) -> Result<Self, Self::Err> {
41 match s {
42 "GET" => Ok(ReqMethod::Get),
43 "POST" => Ok(ReqMethod::Post),
44 "PATCH" => Ok(ReqMethod::Patch),
45 "PUT" => Ok(ReqMethod::Put),
46 "DELETE" => Ok(ReqMethod::Delete),
47 _ => Err(()),
48 }
49 }
50}
51
52impl Req {
53 pub fn new(raw_req: &str) -> Option<Req> {
54 let mut lines = raw_req.lines();
55 let mut req = Req::default();
56
57 let main_info = match lines.next() {
58 Some(v) => v,
59 None => {
60 return None;
61 }
62 };
63
64 let (req_method, path, protocol) = Req::parse_first_line(main_info).expect("Wrong format");
65
66 req.method = req_method;
67 req.path = path.parse().unwrap();
68 req.protocol = protocol.parse().unwrap();
69
70 lines.clone().take_while(|l| !l.is_empty()).for_each(|l| {
72 let mut split = l.split(": ");
73 let header_name = split.next().unwrap();
74 let header_value = split.next().unwrap();
75
76 req.headers
77 .insert(header_name.parse().unwrap(), header_value.parse().unwrap());
78 });
79
80 req.derive_queries();
81
82 let body = lines
84 .clone()
85 .skip_while(|l| !l.is_empty())
86 .fold(String::new(), |mut acc, l| {
87 acc += l;
88 acc
89 });
90
91 if !body.is_empty() {
92 req.body = Some(body);
93 };
94
95 Some(req)
96 }
97
98 pub fn get(&self, header_key: &str) -> Option<&str> {
99 let header_value = self.headers.get(header_key)?;
100
101 Some(header_value)
102 }
103
104 fn parse_first_line(line: &str) -> Result<(ReqMethod, &str, &str), ()> {
105 let mut splitted = line.split_whitespace();
106
107 let method = splitted.next().ok_or(())?;
108 let path = splitted.next().ok_or(())?;
109 let protocol = splitted.next().ok_or(())?;
110
111 let req_method = ReqMethod::from_str(method)?;
112
113 Ok((req_method, path, protocol))
114 }
115
116 fn derive_queries(&mut self) {
117 if !self.path.contains('?') {
118 return;
119 }
120
121 let splitted_path = self.path.split('?').collect::<Vec<_>>();
122 let query_string = splitted_path.get(1).unwrap();
123
124 self.queries = Req::parse_query_string(query_string);
125
126 let pure_path = splitted_path.first().unwrap();
127 self.path = pure_path.parse().unwrap();
128 }
129
130 fn parse_query_string(query_string: &str) -> HashMap<String, String> {
131 let mut res = HashMap::new();
132
133 let pairs: Vec<_> = query_string.split('&').collect();
134 pairs.into_iter().for_each(|p| {
135 let mut splitted = p.split('=');
136 let name = splitted.next().unwrap().to_owned();
137 let value = splitted.next().unwrap().to_owned();
138
139 res.insert(name, value);
140 });
141
142 res
143 }
144}