1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
use crate::http_types::*;
use std::collections::HashMap;
pub struct Response {
version: String,
status: StatusCode,
headers: Option<Headers>,
body: Option<Vec<u8>>,
}
impl Response {
pub fn new(
version: String,
status: StatusCode,
headers: Option<Headers>,
body: Option<Vec<u8>>,
) -> Self {
Response {
version,
headers,
status,
body,
}
}
}
impl Into<Vec<u8>> for Response {
fn into(self) -> Vec<u8> {
let status_line = format!("HTTP/{} {}", self.version, String::from(self.status))
.as_bytes()
.to_owned();
let headers = self
.headers
.unwrap_or(Headers(HashMap::new()))
.0
.iter()
.map(|(key, value)| format!("{key}: {value}\r\n"))
.collect::<String>()
.as_bytes()
.to_owned();
let body = self.body.unwrap_or(vec![]);
let crlf = "\r\n".as_bytes().to_owned();
vec![status_line, crlf.clone(), headers, crlf.clone(), body]
.concat()
.to_owned()
}
}
impl Into<Response> for &str {
fn into(self) -> Response {
let mut lines = self.lines();
// Parse the status line
let status_line = lines.next().unwrap_or_default();
let mut status_line_parts = status_line.split_whitespace();
let version = status_line_parts.next().unwrap_or_default().to_string();
let status_code = status_line_parts.next().unwrap_or_default();
let status = match status_code {
"200" => StatusCode::Ok,
"404" => StatusCode::NotFound,
_ => StatusCode::Ok,
};
// Parse headers
let mut headers_map = HashMap::new();
while let Some(line) = lines.next() {
if line.is_empty() {
break;
}
let mut parts = line.splitn(2, ':');
let key = parts.next().unwrap_or_default().trim();
let value = parts.next().unwrap_or_default().trim();
headers_map.insert(key.to_string(), value.to_string());
}
let headers = if headers_map.is_empty() {
None
} else {
Some(Headers(headers_map))
};
// Parse body
let body: Option<Vec<u8>> = {
let remaining_lines: Vec<&str> = lines.collect();
if remaining_lines.is_empty() {
None
} else {
Some(remaining_lines.join("\n").as_bytes().to_owned())
}
};
Response {
version,
status,
headers,
body,
}
}
}
|