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