http_type/request/impl.rs
1use super::error::Error;
2use crate::*;
3use std::{collections::HashMap, str::SplitN};
4
5impl Default for Request {
6 #[inline]
7 fn default() -> Self {
8 Self {
9 method: String::new(),
10 host: String::new(),
11 path: String::new(),
12 query: HashMap::new(),
13 headers: HashMap::new(),
14 body: Vec::new(),
15 }
16 }
17}
18
19impl Request {
20 /// Creates a new `Request` object from a TCP stream.
21 ///
22 /// # Parameters
23 /// - `reader`: A mut reference to a `&mut std::io::BufReader<&std::net::TcpStream>`
24 ///
25 /// # Returns
26 /// - `Ok`: A `Request` object populated with the HTTP request data.
27 /// - `Err`: An `Error` if the request is invalid or cannot be read.
28 #[inline]
29 pub fn from_reader(reader: &mut std::io::BufReader<&std::net::TcpStream>) -> RequestNewResult {
30 let mut request_line: String = String::new();
31 std::io::BufRead::read_line(reader, &mut request_line).map_err(|_| Error::HttpReadError)?;
32 let parts: Vec<&str> = request_line.split_whitespace().collect();
33 if parts.len() < 3 {
34 return Err(Error::InvalidHttpRequest);
35 }
36 let method: RequestMethod = parts[0].to_string();
37 let full_path: String = parts[1].to_string();
38 let hash_index: Option<usize> = full_path.find(HASH_SYMBOL);
39 let query_index: Option<usize> = full_path.find(QUERY_SYMBOL);
40 let query_string: String = query_index.map_or(EMPTY_STR.to_owned(), |i| {
41 let temp: String = full_path[i + 1..].to_string();
42 if hash_index.is_none() || hash_index.unwrap() <= i {
43 return temp.into();
44 }
45 let data: String = temp
46 .split(HASH_SYMBOL)
47 .next()
48 .unwrap_or_default()
49 .to_string();
50 data.into()
51 });
52 let query: RequestQuery = Self::parse_query(&query_string);
53 let path: RequestPath = if let Some(i) = query_index.or(hash_index) {
54 full_path[..i].to_string()
55 } else {
56 full_path
57 };
58 let mut headers: RequestHeaders = HashMap::new();
59 let mut host: RequestHost = EMPTY_STR.to_owned();
60 let mut content_length: usize = 0;
61 loop {
62 let mut header_line: String = String::new();
63 std::io::BufRead::read_line(reader, &mut header_line)
64 .map_err(|_| Error::HttpReadError)?;
65 let header_line: &str = header_line.trim();
66 if header_line.is_empty() {
67 break;
68 }
69 let parts: Vec<&str> = header_line.splitn(2, COLON_SPACE_SYMBOL).collect();
70 if parts.len() != 2 {
71 continue;
72 }
73 let key: String = parts[0].trim().to_string();
74 let value: String = parts[1].trim().to_string();
75 if key.eq_ignore_ascii_case(HOST) {
76 host = value.to_string();
77 }
78 if key.eq_ignore_ascii_case(CONTENT_LENGTH) {
79 content_length = value.parse().unwrap_or(0);
80 }
81 headers.insert(key, value);
82 }
83 let mut body: RequestBody = Vec::new();
84 if content_length > 0 {
85 body.resize(content_length, 0);
86 std::io::Read::read_exact(reader, &mut body).map_err(|_| Error::HttpReadError)?;
87 }
88 Ok(Request {
89 method,
90 host,
91 path,
92 query,
93 headers,
94 body,
95 })
96 }
97
98 /// Creates a new `Request` object from a TCP stream.
99 ///
100 /// # Parameters
101 /// - `reader`: A mut reference to a `&mut tokio::io::BufReader<&mut tokio::net::TcpStream>`
102 ///
103 /// # Returns
104 /// - `Ok`: A `Request` object populated with the HTTP request data.
105 /// - `Err`: An `Error` if the request is invalid or cannot be read.
106 #[inline]
107 pub async fn from_tokio_reader(
108 reader: &mut tokio::io::BufReader<&mut tokio::net::TcpStream>,
109 ) -> RequestNewResult {
110 let mut request_line: String = String::new();
111 let _ = tokio::io::AsyncBufReadExt::read_line(reader, &mut request_line).await;
112 let parts: Vec<&str> = request_line.split_whitespace().collect();
113 if parts.len() < 3 {
114 return Err(Error::InvalidHttpRequest);
115 }
116 let method: RequestMethod = parts[0].to_string();
117 let full_path: String = parts[1].to_string();
118 let hash_index: Option<usize> = full_path.find(HASH_SYMBOL);
119 let query_index: Option<usize> = full_path.find(QUERY_SYMBOL);
120 let query_string: String = query_index.map_or(EMPTY_STR.to_owned(), |i| {
121 let temp: String = full_path[i + 1..].to_string();
122 if hash_index.is_none() || hash_index.unwrap() <= i {
123 return temp.into();
124 }
125 let data: String = temp
126 .split(HASH_SYMBOL)
127 .next()
128 .unwrap_or_default()
129 .to_string();
130 data.into()
131 });
132 let query: RequestQuery = Self::parse_query(&query_string);
133 let path: RequestPath = if let Some(i) = query_index.or(hash_index) {
134 full_path[..i].to_string()
135 } else {
136 full_path
137 };
138 let mut headers: RequestHeaders = HashMap::new();
139 let mut host: RequestHost = EMPTY_STR.to_owned();
140 let mut content_length: usize = 0;
141 loop {
142 let mut header_line: String = String::new();
143 let _ = tokio::io::AsyncBufReadExt::read_line(reader, &mut header_line).await;
144 let header_line: &str = header_line.trim();
145 if header_line.is_empty() {
146 break;
147 }
148 let parts: Vec<&str> = header_line.splitn(2, COLON_SPACE_SYMBOL).collect();
149 if parts.len() != 2 {
150 continue;
151 }
152 let key: String = parts[0].trim().to_string();
153 let value: String = parts[1].trim().to_string();
154 if key.eq_ignore_ascii_case(HOST) {
155 host = value.to_string();
156 }
157 if key.eq_ignore_ascii_case(CONTENT_LENGTH) {
158 content_length = value.parse().unwrap_or(0);
159 }
160 headers.insert(key, value);
161 }
162 let mut body: RequestBody = Vec::new();
163 if content_length > 0 {
164 body.resize(content_length, 0);
165 let _ = tokio::io::AsyncReadExt::read_exact(reader, &mut body);
166 }
167 Ok(Request {
168 method,
169 host,
170 path,
171 query,
172 headers,
173 body,
174 })
175 }
176
177 /// Creates a new `Request` object from a TCP stream.
178 ///
179 /// # Parameters
180 /// - `stream`: A reference to a `&std::net::TcpStream` representing the incoming connection.
181 ///
182 /// # Returns
183 /// - `Ok`: A `Request` object populated with the HTTP request data.
184 /// - `Err`: An `Error` if the request is invalid or cannot be read.
185 #[inline]
186 pub fn from_stream(stream: &std::net::TcpStream) -> RequestNewResult {
187 let mut reader: std::io::BufReader<&std::net::TcpStream> = std::io::BufReader::new(stream);
188 Self::from_reader(&mut reader)
189 }
190
191 /// Creates a new `Request` object from a TCP stream.
192 ///
193 /// # Parameters
194 /// - `stream`: A reference to a `&ArcRwLockStream` representing the incoming connection.
195 ///
196 /// # Returns
197 /// - `Ok`: A `Request` object populated with the HTTP request data.
198 /// - `Err`: An `Error` if the request is invalid or cannot be read.
199 #[inline]
200 pub async fn from_tokio_stream(stream: &ArcRwLockStream) -> RequestNewResult {
201 let mut buf_stream: RwLockWriteGuard<'_, tokio::net::TcpStream> = stream.write().await;
202 let mut reader: tokio::io::BufReader<&mut tokio::net::TcpStream> =
203 tokio::io::BufReader::new(&mut buf_stream);
204 Self::from_tokio_reader(&mut reader).await
205 }
206
207 /// Parse query
208 ///
209 /// # Parameters
210 /// - `query`: &str
211 ///
212 /// # Returns
213 /// - RequestQuery
214 #[inline]
215 fn parse_query(query: &str) -> RequestQuery {
216 let mut query_map: RequestQuery = HashMap::new();
217 for pair in query.split(AND) {
218 let mut parts: SplitN<'_, &str> = pair.splitn(2, EQUAL);
219 let key: String = parts.next().unwrap_or_default().to_string();
220 let value: String = parts.next().unwrap_or_default().to_string();
221 if !key.is_empty() {
222 query_map.insert(key, value);
223 }
224 }
225 query_map
226 }
227
228 /// Adds a header to the request.
229 ///
230 /// This function inserts a key-value pair into the request headers.
231 /// The key and value are converted into `String`, allowing for efficient handling of both owned and borrowed string data.
232 ///
233 /// # Parameters
234 /// - `key`: The header key, which will be converted into a `String`.
235 /// - `value`: The value of the header, which will be converted into a `String`.
236 ///
237 /// # Returns
238 /// - Returns a mutable reference to the current instance (`&mut Self`), allowing for method chaining.
239 #[inline]
240 pub fn set_header<K, V>(&mut self, key: K, value: V) -> &mut Self
241 where
242 K: Into<String>,
243 V: Into<String>,
244 {
245 self.headers.insert(key.into(), value.into());
246 self
247 }
248
249 /// Set the body of the response.
250 ///
251 /// This method allows you to set the body of the response by converting the provided
252 /// value into a `RequestBody` type. The `body` is updated with the converted value,
253 /// and the method returns a mutable reference to the current instance for method chaining.
254 ///
255 /// # Parameters
256 /// - `body`: The body of the response to be set. It can be any type that can be converted
257 /// into a `RequestBody` using the `Into` trait.
258 ///
259 /// # Return Value
260 /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
261 /// Set the body of the response.
262 ///
263 /// This method allows you to set the body of the response by converting the provided
264 /// value into a `RequestBody` type. The `body` is updated with the converted value,
265 /// and the method returns a mutable reference to the current instance for method chaining.
266 ///
267 /// # Parameters
268 /// - `body`: The body of the response to be set. It can be any type that can be converted
269 /// into a `RequestBody` using the `Into` trait.
270 ///
271 /// # Return Value
272 /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
273 #[inline]
274 pub fn set_body<T: Into<RequestBody>>(&mut self, body: T) -> &mut Self {
275 self.body = body.into();
276 self
277 }
278
279 /// Set the HTTP method of the request.
280 ///
281 /// This method allows you to set the HTTP method (e.g., GET, POST) of the request
282 /// by converting the provided value into a `RequestMethod` type. The `method` is updated
283 /// with the converted value, and the method returns a mutable reference to the current
284 /// instance for method chaining.
285 ///
286 /// # Parameters
287 /// - `method`: The HTTP method to be set for the request. It can be any type that can
288 /// be converted into a `RequestMethod` using the `Into` trait.
289 ///
290 /// # Return Value
291 /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
292 #[inline]
293 pub fn set_method<T: Into<RequestMethod>>(&mut self, method: T) -> &mut Self {
294 self.method = method.into();
295 self
296 }
297
298 /// Set the host of the request.
299 ///
300 /// This method allows you to set the host (e.g., www.example.com) for the request
301 /// by converting the provided value into a `RequestHost` type. The `host` is updated
302 /// with the converted value, and the method returns a mutable reference to the current
303 /// instance for method chaining.
304 ///
305 /// # Parameters
306 /// - `host`: The host to be set for the request. It can be any type that can be converted
307 /// into a `RequestHost` using the `Into` trait.
308 ///
309 /// # Return Value
310 /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
311 #[inline]
312 pub fn set_host<T: Into<RequestHost>>(&mut self, host: T) -> &mut Self {
313 self.host = host.into();
314 self
315 }
316
317 /// Set the path of the request.
318 ///
319 /// This method allows you to set the path (e.g., /api/v1/resource) for the request
320 /// by converting the provided value into a `RequestPath` type. The `path` is updated
321 /// with the converted value, and the method returns a mutable reference to the current
322 /// instance for method chaining.
323 ///
324 /// # Parameters
325 /// - `path`: The path to be set for the request. It can be any type that can be converted
326 /// into a `RequestPath` using the `Into` trait.
327 ///
328 /// # Return Value
329 /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
330 #[inline]
331 pub fn set_path<T: Into<RequestPath>>(&mut self, path: T) -> &mut Self {
332 self.path = path.into();
333 self
334 }
335
336 /// Set the query string of the request.
337 ///
338 /// This method allows you to set the query string (e.g., ?key=value) for the request
339 /// by converting the provided value into a `RequestQuery` type. The `query` is updated
340 /// with the converted value, and the method returns a mutable reference to the current
341 /// instance for method chaining.
342 ///
343 /// # Parameters
344 /// - `query`: The query string to be set for the request. It can be any type that can
345 /// be converted into a `RequestQuery` using the `Into` trait.
346 ///
347 /// # Return Value
348 /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
349 #[inline]
350 pub fn set_query<T: Into<RequestQuery>>(&mut self, query: T) -> &mut Self {
351 self.query = query.into();
352 self
353 }
354}