rust_integration_services/http/
http_request.rs

1use std::{collections::HashMap};
2
3use tokio::io::{AsyncBufReadExt, AsyncRead, AsyncReadExt, AsyncWrite, BufReader};
4
5#[allow(dead_code)]
6#[derive(Debug, Clone)]
7pub struct HttpRequest {
8    pub method: String,
9    pub path: String,
10    pub protocol: String,
11    pub headers: HashMap<String, String>,
12    pub body: Vec<u8>,
13    pub ip: Option<String>,
14}
15
16#[allow(dead_code)]
17impl HttpRequest {
18    pub fn new() -> Self {
19        HttpRequest {
20            method: String::new(),
21            path: String::new(),
22            protocol: String::from("HTTP/1.1"),
23            headers: HashMap::new(),
24            body: Vec::new(),
25            ip: None,
26        }
27    }
28
29    /// Builds a default GET request equal to:
30    /// 
31    /// HttpRequest::new().method("GET").path("/")
32    pub fn get() -> Self {
33        HttpRequest::new().method("GET").path("/")
34    }
35
36    /// Builds a default POST request equal to:
37    /// 
38    /// HttpRequest::new().method("POST").path("/")
39    pub fn post() -> Self {
40        HttpRequest::new().method("POST").path("/")
41    }
42
43    /// Builds a default PUT request equal to:
44    /// 
45    /// HttpRequest::new().method("PUT").path("/")
46    pub fn put() -> Self {
47        HttpRequest::new().method("PUT").path("/")
48    }
49
50    /// Builds a default DELETE request equal to:
51    /// 
52    /// HttpRequest::new().method("DELETE").path("/")
53    pub fn delete() -> Self {
54        HttpRequest::new().method("DELETE").path("/")
55    }
56
57    pub fn header(mut self, key: &str, value: &str) -> Self {
58        self.headers.insert(key.to_string(), value.to_string());
59        self
60    }
61
62    pub fn body_bytes(mut self, body: &[u8]) -> Self {
63        self.body = body.to_vec();
64        self.headers.insert(String::from("Content-Length"), String::from(body.len().to_string()));
65        self
66    }
67
68    pub fn body_string(mut self, body: &str) -> Self {
69        self.body = body.as_bytes().to_vec();
70        self.headers.insert(String::from("Content-Length"), String::from(body.len().to_string()));
71        self
72    }
73
74    pub fn method(mut self, method: &str) -> Self {
75        self.method = method.to_uppercase();
76        self
77    }
78
79    pub fn path(mut self, path: &str) -> Self {
80        self.path = path.to_string();
81        self
82    }
83
84    pub fn ip(mut self, ip: String) -> Self {
85        self.ip = Some(ip);
86        self
87    }
88
89    pub fn body_to_string(&self) -> String {
90        String::from_utf8_lossy(&self.body).to_string()
91    }
92
93    pub fn to_bytes(&self) -> Vec<u8> {
94        let mut bytes: Vec<u8> = Vec::new();
95        let first_line_str = format!("{} {} {}", self.method, self.path, self.protocol);
96
97        let mut headers_str = String::new();
98        for (key, value) in &self.headers {
99            headers_str.push_str(&format!("{}: {}\r\n", key, value));
100        };
101
102        bytes.extend_from_slice(first_line_str.as_bytes());
103        bytes.extend_from_slice("\r\n".as_bytes());
104        bytes.extend_from_slice(headers_str.as_bytes());
105        bytes.extend_from_slice("\r\n".as_bytes());
106        bytes.extend(self.body.clone());
107        bytes
108    }
109
110    pub async fn from_stream<S: AsyncRead + AsyncWrite + Unpin>(stream: &mut S) -> tokio::io::Result<HttpRequest> {
111        let mut reader = BufReader::new(stream);
112        let mut buffer = String::new();
113    
114        reader.read_line(&mut buffer).await?;
115        let first_line: Vec<&str> = buffer.split_whitespace().collect();
116        let method = first_line[0];
117        let path = first_line[1];
118        let protocol = first_line[2];
119    
120        let mut header = String::new();
121        let mut headers: HashMap<String, String> = HashMap::new();
122        loop {
123            header.clear();
124            reader.read_line(&mut header).await?;
125    
126            if header.trim().is_empty() {
127                break;
128            }
129    
130            if let Some((key, value)) = header.trim().split_once(":") {
131                headers.insert(key.trim().to_string(), value.trim().to_string());
132            }
133        }
134    
135        let mut body = Vec::new();
136        if let Some(content_length) = headers.get("Content-Length") {
137            let length = content_length.parse().unwrap_or(0);
138            let mut bytes = vec![0; length];
139            reader.read_exact(&mut bytes).await?;
140            body = bytes;
141        }
142    
143        Ok(HttpRequest {
144            method: String::from(method),
145            path: String::from(path),
146            protocol: String::from(protocol),
147            headers: headers,
148            body: body,
149            ip: None,
150        })
151    }
152}