rust_express/utils/
request.rs

1use 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}