1use std::collections::HashMap;
2use serde_json::Value;
3
4#[derive(PartialEq, Eq, Hash, Debug, Clone)]
5pub enum ContentType {
6 ApplicationJson,
7 TextPlain,
8 TextHtml,
9}
10
11#[derive(PartialEq, Eq, Hash, Debug, Clone)]
12pub enum QueryArg {
13 Single(String),
14 Multiple(Vec<String>),
15}
16
17#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
18pub enum Method {
19 GET,
20 POST,
21 PUT,
22 DELETE,
23 OPTIONS,
24 NONE,
25}
26
27#[derive(PartialEq, Eq, Debug, Clone)]
28pub struct Request {
29 pub method: Method,
30 pub uri: String,
31 pub path: String,
32 pub query: Option<String>,
33 pub headers: HashMap<String, String>,
34 pub body: Vec<u8>,
35 pub params: HashMap<String, String>,
36}
37
38impl Request {
39
40 pub fn new() -> Request {
51 Request {
52 method: Method::NONE,
53 uri: String::new(),
54 path: String::new(),
55 query: None,
56 headers: HashMap::new(),
57 body: Vec::new(),
58 params: HashMap::new(),
59 }
60 }
61
62 pub fn with_params(mut self, params: HashMap<String, String>) -> Self {
65 self.params = params;
66 self
67 }
68
69 pub fn get_var<T: FromUri>(&self, name: &str) -> T {
84 if !self.params.contains_key(name) {
85 panic!("Invalid route parameter {:?}", name);
86 }
87
88 FromUri::from_uri(&self.params[name])
89 }
90
91 pub fn json(&self) -> Option<Value> { let binding = self.body.clone();
102 let data = std::str::from_utf8(&binding).ok();
103
104 match data {
105 Some(data) =>{ let v: Option<Value> = serde_json::from_str(data).ok(); return v; },
106 None => { let v: Option<Value> = serde_json::from_str("").ok(); return v; },
107 }
108 }
109
110 pub fn get_string(&self) -> String {
113 return String::from_utf8(self.body.clone()).expect("Bytes should be valid utf8");
114 }
115
116 pub fn parse(&mut self, rqstr: &str) -> std::result::Result<(), RequestError> {
117 let mut lines = rqstr.split("\r\n");
118
119 if let Some(request_line) = lines.next() {
120 let parts: Vec<&str> = request_line.splitn(3, ' ').collect();
121 if parts.len() != 3 {
122 return Err(RequestError::InvalidRequestLine);
123 }
124 self.method = match_method(parts[0]);
125 self.uri = parts[1].to_string();
126 self.parse_uri(parts[1]);
127 } else {
128 return Err(RequestError::InvalidRequestLine);
129 }
130
131 for line in lines.by_ref() {
132 if line.is_empty() {
133 break;
134 }
135
136 if let Some((name, value)) = line.split_once(": ") {
137 self.headers.insert(name.to_lowercase(), value.to_string());
138 }
139 }
140
141 self.body = lines.collect::<Vec<&str>>().join("\r\n").into_bytes();
142
143 Ok(())
144 }
145
146 fn parse_uri(&mut self, uri: &str) {
147 if let Some((path, query)) = uri.split_once('?') {
148 self.path = path.to_string();
149 self.query = Some(query.to_string());
150 } else {
151 self.path = uri.to_string();
152 self.query = None;
153 }
154 }
155}
156
157pub fn match_method(method: &str) -> Method {
158 match method {
159 "GET" => Method::GET,
160 "POST" => Method::POST,
161 "PUT" => Method::PUT,
162 "DELETE" => Method::DELETE,
163 "OPTIONS" => Method::OPTIONS,
164 _ => { Method::NONE },
165 }
166}
167
168#[derive(Debug)]
169pub enum RequestError {
170 JsonStrError(serde_json::Error),
171 StrCopyError(std::string::FromUtf8Error),
172 InvalidRequestLine,
173}
174
175impl std::str::FromStr for Request {
176 type Err = RequestError;
177
178 fn from_str(rqstr: &str) -> std::result::Result<Request, RequestError> {
179 let mut req = Request::new();
180 req.parse(rqstr).unwrap();
181 Ok(req)
182 }
183}
184
185pub trait FromUri {
186 fn from_uri(data: &str) -> Self;
187}
188
189impl FromUri for String {
190 fn from_uri(data: &str) -> String {
191 String::from(data)
192 }
193}
194
195impl FromUri for i32 {
196 fn from_uri(data: &str) -> i32 {
197 data.parse::<i32>().expect("matched integer can't be parsed")
198 }
199}
200
201impl FromUri for u32 {
202 fn from_uri(data: &str) -> u32 {
203 data.parse::<u32>().expect("matched integer can't be parsed")
204 }
205}
206
207impl FromUri for f32 {
208 fn from_uri(data: &str) -> f32 {
209 data.parse::<f32>().expect("matched float can't be parsed")
210 }
211}