1use std::{
2 collections::HashMap,
3 convert::{From, Into},
4 fmt::{self, Display},
5 fs::File,
6 io::Read,
7 path::Path,
8};
9
10use crate::{HttpCode, HttpVersion};
11
12#[derive(Debug, Clone)]
13pub enum Body {
14 Raw(Vec<u8>),
15 S(String),
16}
17
18use Body::*;
19
20impl Body {
21 pub fn unwrap_raw(self) -> Vec<u8> {
22 match self {
23 Raw(v) => v,
24 S(_) => panic!(""),
25 }
26 }
27}
28
29impl Display for Body {
30 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
31 match self {
32 S(s) => write!(f, "{}", s.as_str()),
33 Raw(_) => panic!("Raw body cannot be display!!"),
34 }
35 }
36}
37
38#[allow(dead_code)]
39#[derive(Debug, Clone)]
40pub struct Response {
42 pub response_code: HttpCode,
43 pub http_version: HttpVersion,
44 pub headers: HashMap<String, String>,
45 pub body: Body,
46}
47
48#[allow(clippy::new_without_default)]
49impl Response {
50 pub fn new() -> Self {
51 "".into()
52 }
53
54 #[inline]
55 pub fn header(&self, key: &str) -> std::option::Option<&String> {
56 self.headers.get(&key.to_string())
57 }
58
59 #[inline]
60 pub fn set_header(&mut self, key: &str, value: &str) -> &mut Self {
61 self.headers.insert(key.to_string(), value.to_string());
62 self
63 }
64
65 #[inline]
66 pub fn set_http_code(&mut self, resp_code: HttpCode) -> &mut Self {
67 self.response_code = resp_code;
68 self
69 }
70
71 #[inline]
72 pub fn set_body(&mut self, body: &str) -> &mut Self {
73 self.body = S(body.to_string());
74 self
75 }
76
77 #[inline]
78 pub fn set_raw_body(&mut self, body: Vec<u8>) -> &mut Self {
79 self.body = Raw(body);
80 self
81 }
82}
83
84impl From<&str> for Response {
85 fn from(resp: &str) -> Self {
86 let mut headers: HashMap<String, String> = HashMap::new();
87 headers.insert("Server".into(), "serve".into());
88 headers.insert("X-Powered-By".into(), "serve".into());
89 headers.insert("Connection".into(), "keep-alive".into());
90
91 Response {
92 response_code: HttpCode::_200,
93 http_version: HttpVersion::Ver11,
94 headers,
95 body: S(resp.to_string()),
96 }
97 }
98}
99
100impl From<String> for Response {
101 fn from(resp: String) -> Self {
102 resp.as_str().into()
103 }
104}
105
106impl Into<String> for Response {
107 fn into(self) -> String {
108 self.to_string()
109 }
110}
111
112impl Display for Response {
113 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114 let info = format!(
115 "HTTP/{} {} {}",
116 String::from(self.http_version),
117 get_code(self.response_code),
118 self.response_code
119 );
120
121 let headers = {
122 let mut headers = String::new();
123
124 for (header, value) in self.headers.iter() {
125 headers.push_str(format!("{}: {}\r\n", header, value).as_str());
126 }
127
128 headers.trim_end().to_string()
129 };
130
131 if let S(body) = &self.body {
132 write!(f, "{}\r\n{}\r\n\r\n{}", info, headers, body.to_string())
133 } else {
134 let headers_result = write!(f, "{}\r\n{}\r\n\r\n", info, headers);
135 let body = self.body.clone().unwrap_raw();
136
137 unsafe {
138 f.write_str(std::str::from_utf8_unchecked(&body))
139 .and(headers_result)
140 }
141 }
142 }
143}
144
145impl From<&Path> for Response {
146 fn from(value: &Path) -> Self {
147 if !value.is_file() {
148 println!("File {:?} doesn't exists!", value);
149
150 Response {
151 response_code: HttpCode::_404,
152 ..Response::new()
153 }
154 } else {
155 let mut f = File::open(value.display().to_string()).unwrap();
156 let mut buffer = Vec::new();
157 f.read_to_end(&mut buffer).unwrap();
158
159 Response {
160 body: Raw(buffer),
161 ..Response::new()
162 }
163 }
164 }
165}
166
167fn get_code(code: HttpCode) -> i16 {
168 let code = format!("{:?}", code);
169 let code: Vec<&str> = code.as_str().split('_').collect();
170
171 code[1].parse().unwrap()
172}