rust_express/utils/
request.rs1use crate::utils::helpers::{parse_body, parse_query_params};
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4use tokio::io::AsyncReadExt;
5
6#[derive(Deserialize, Serialize, Clone)]
7pub struct Request {
8 pub method: String,
9 pub route: String,
10 pub host: String,
11 pub user_agent: String,
12 pub accept: String,
13 pub connection: String,
14 pub raw: String,
15 pub content_length: usize,
16 pub body: HashMap<String, String>,
17 pub query: HashMap<String, String>,
18}
19
20impl Request {
21 fn new() -> Self {
22 Self {
23 method: "GET".to_owned(),
24 route: "/".to_owned(),
25 host: "".to_owned(),
26 user_agent: "".to_owned(),
27 accept: "".to_owned(),
28 connection: "keep-alive".to_owned(),
29 content_length: 0,
30 raw: "".to_owned(),
31 body: HashMap::new(),
32 query: HashMap::new(),
33 }
34 }
35}
36
37pub async fn parse_request_data(stream: &mut tokio::net::TcpStream) -> Request {
38 stream
39 .readable()
40 .await
41 .expect("stream failed to be readable");
42 let mut buffer = [0u8; 4096];
43 let n = stream
44 .read(&mut buffer)
45 .await
46 .expect("Failed to read request buffer");
47 let request_data = String::from_utf8_lossy(&buffer[..n]).to_string();
48 let mut request = Request::new();
49 request.raw = request_data.clone();
50 let mut lines = request_data.split("\r\n");
51
52 if let Some(first_line) = lines.next() {
53 let mut parts = first_line.split_whitespace();
54 request.method = parts.next().unwrap_or("GET").to_string();
55 let full_route = parts.next().unwrap_or("/");
56 let mut route_parts = full_route.splitn(2, '?');
57 request.route = route_parts.next().unwrap_or("/").to_string();
58 let query_string = route_parts.next().unwrap_or("");
59 request.query = parse_query_params(query_string);
60 }
61
62 for line in lines.by_ref() {
63 if line.is_empty() {
64 break;
65 }
66
67 let mut header_parts = line.splitn(2, ": ");
68 let header_key = header_parts.next().unwrap_or("").to_lowercase();
69 let header_value = header_parts.next().unwrap_or("").to_string();
70
71 match header_key.as_str() {
72 "host" => request.host = header_value,
73 "user-agent" => request.user_agent = header_value,
74 "accept" => request.accept = header_value,
75 "connection" => request.connection = header_value,
76 "content-length" => request.content_length = header_value.parse().unwrap_or(0),
77 _ => {}
78 }
79 }
80
81 let body = lines.collect::<Vec<&str>>().join("\r\n");
82 let parsed_body = parse_body(&body);
83 request.body = parsed_body;
84 request
85}