rust_integration_services/http/
http_response.rs

1use std::{collections::HashMap};
2
3use tokio::io::{AsyncBufReadExt, AsyncRead, AsyncReadExt, BufReader};
4
5#[allow(dead_code)]
6#[derive(Debug, Clone)]
7pub struct HttpResponse {
8    pub protocol: String,
9    pub status_code: u16,
10    pub status_text: String,
11    pub headers: HashMap<String, String>,
12    pub body: Vec<u8>,
13}
14
15#[allow(dead_code)]
16impl HttpResponse {
17    pub fn new() -> Self {
18        HttpResponse {
19            protocol: String::from("HTTP/1.1"),
20            status_code: 0,
21            status_text: String::new(),
22            headers: HashMap::new(),
23            body: Vec::new(),
24        }
25    }
26    
27    pub fn ok() -> Self {
28        HttpResponse::new().status(200, "OK")
29    }
30    
31    pub fn found() -> Self {
32        HttpResponse::new().status(302, "Found")
33    }
34    
35    pub fn bad_request() -> Self {
36        HttpResponse::new().status(400, "Bad Request")
37    }
38    
39    pub fn unauthorized() -> Self {
40        HttpResponse::new().status(401, "Unauthorized")
41    }
42    
43    pub fn forbidden() -> Self {
44        HttpResponse::new().status(403, "Forbidden")
45    }
46    
47    pub fn not_found() -> Self {
48        HttpResponse::new().status(404, "Not Found")
49    }
50    
51    pub fn internal_server_error() -> Self {
52        HttpResponse::new().status(500, "Internal Server Error")
53    }
54
55    pub fn status(mut self, code: u16, text: &str) -> Self {
56        self.status_code = code;
57        self.status_text = text.to_string();
58        self
59    }
60    
61    pub fn body_bytes(mut self, body: &[u8]) -> Self {
62        self.body = body.to_vec();
63        self.headers.insert(String::from("Content-Length"), String::from(body.len().to_string()));
64        self
65    }
66
67    pub fn body_string(mut self, body: &str) -> Self {
68        self.body = body.as_bytes().to_vec();
69        self.headers.insert(String::from("Content-Length"), String::from(body.len().to_string()));
70        self
71    }
72
73    pub fn header(mut self, key: &str, value: &str) -> Self {
74        self.headers.insert(key.to_string(), value.to_string());
75        self
76    }
77
78    pub fn body_to_string(&self) -> String {
79        String::from_utf8_lossy(&self.body).to_string()
80    }
81
82    pub fn to_bytes(&self) -> Vec<u8> {
83        let mut bytes: Vec<u8> = Vec::new();
84
85        let first_line_str = format!("{} {} {}", self.protocol, self.status_code, self.status_text);
86
87        let mut headers_str = String::new();
88        for (key, value) in &self.headers {
89            headers_str.push_str(&format!("{}: {}\r\n", key, value));
90        };
91
92        bytes.extend_from_slice(first_line_str.as_bytes());
93        bytes.extend_from_slice("\r\n".as_bytes());
94        bytes.extend_from_slice(headers_str.as_bytes());
95        bytes.extend_from_slice("\r\n".as_bytes());
96        bytes.extend(self.body.clone());
97        bytes
98    }
99
100    pub async fn from_stream<S: AsyncRead + Unpin>(stream: &mut S) -> tokio::io::Result<HttpResponse> {
101        let mut reader = BufReader::new(stream);
102        let mut buffer = String::new();
103
104        reader.read_line(&mut buffer).await?;
105        let first_line: Vec<&str> = buffer.split_whitespace().collect();
106        let protocol = first_line[0].to_string();
107        let status_code = first_line[1].to_string().parse().unwrap();
108        let status_text = first_line[2].to_string();
109
110        let mut header = String::new();
111        let mut headers: HashMap<String, String> = HashMap::new();
112        loop {
113            header.clear();
114            reader.read_line(&mut header).await?;
115    
116            if header.trim().is_empty() {
117                break;
118            }
119    
120            if let Some((key, value)) = header.trim().split_once(":") {
121                headers.insert(key.trim().to_string(), value.trim().to_string());
122            }
123        }
124
125        let mut body = Vec::new();
126        if let Some(content_length) = headers.get("Content-Length") {
127            let length = content_length.parse().unwrap_or(0);
128            let mut bytes = vec![0; length];
129            reader.read_exact(&mut bytes).await?;
130            body = bytes;
131        }
132
133        Ok(HttpResponse {
134            protocol,
135            status_code,
136            status_text,
137            headers,
138            body
139        })
140    }
141}