1use std::convert::Infallible;
2
3use crate::http::{Header, IntoHeader, MimeType, StatusCode, Version};
4use anyhow;
5
6pub type ResponseBody = Vec<u8>;
7
8#[derive(Debug, PartialEq)]
9pub struct Response {
10 version: Version,
11 status: StatusCode,
12 body: ResponseBody,
13 mime: MimeType,
14 headers: Vec<Header>,
15}
16
17pub trait IntoResponse {
18 fn into_response(self) -> Response;
19}
20
21impl<T> IntoResponse for T
24where
25 T: Into<Response>,
26{
27 fn into_response(self) -> Response {
28 self.into()
29 }
30}
31
32impl Response {
33 pub fn new(status: StatusCode, body: ResponseBody, mime: MimeType) -> Response {
34 let version = Version::V1_1;
35 Response {
36 status,
37 mime,
38 body,
39 version,
40 headers: vec![],
41 }
42 }
43
44 pub fn error(status: StatusCode, body: ResponseBody) -> Response {
45 let version = Version::V1_1;
46 let mime = MimeType::PlainText;
47 Response {
48 status,
49 body,
50 version,
51 mime,
52 headers: vec![],
53 }
54 }
55
56 pub fn set_mime(&mut self, mime: MimeType) {
57 self.mime = mime;
58 }
59
60 pub fn to_send_buffer(&self) -> Vec<u8> {
61 let status: &str = &self.status.to_string();
63 let length = self.body.len();
64 let version: &str = self.version.into();
65 let content_type: String = String::from(&self.mime);
66 let mut headers_string = "".to_string();
67 for header in &self.headers {
68 let header_string: String = String::from(header);
69 headers_string.push_str(&header_string);
70 headers_string.push_str("\r\n");
71 }
72 let mut buffer: Vec<u8> = Vec::new();
73 let response = format!(
74 "{version} {status}\r\n\
75 Content-Length: {length}\r\n\
76 Content-Type: {content_type}\r\n\
77 {headers_string}\r\n"
78 );
79 buffer.append(&mut response.into_bytes());
80 for byte in &self.body {
81 buffer.push(*byte);
82 }
83 buffer
84 }
85
86 pub fn add_header(&mut self, value: impl IntoHeader) {
87 let header = value.into_header();
88 self.headers.push(header);
89 }
90
91 pub fn version(&self) -> Version {
92 self.version
93 }
94
95 pub fn status(&self) -> StatusCode {
96 self.status
97 }
98
99 pub fn mime(&self) -> MimeType {
100 self.mime
101 }
102}
103
104impl From<Vec<u8>> for Response {
105 fn from(bytes: Vec<u8>) -> Self {
106 Response {
107 status: StatusCode::OK,
108 body: bytes,
109 mime: MimeType::Binary,
110 version: Version::V1_1,
111 headers: vec![],
112 }
113 }
114}
115
116impl From<String> for Response {
117 fn from(string: String) -> Self {
118 Response {
119 status: StatusCode::OK,
120 body: string.into(),
121 mime: MimeType::HTML,
122 version: Version::V1_1,
123 headers: vec![],
124 }
125 }
126}
127
128impl From<&str> for Response {
129 fn from(string: &str) -> Self {
130 Response {
131 status: StatusCode::OK,
132 body: string.into(),
133 mime: MimeType::HTML,
134 version: Version::V1_1,
135 headers: vec![],
136 }
137 }
138}
139
140impl From<anyhow::Error> for Response {
141 fn from(value: anyhow::Error) -> Self {
142 tracing::error!(?value);
143 let message = "<h1>Error 500 Internal Server Error</h1>\r\n".to_string();
144 Response {
145 status: StatusCode::INTERNAL_SERVER_ERROR, body: message.into(),
147 mime: MimeType::HTML,
148 version: Version::V1_1,
149 headers: vec![],
150 }
151 }
152}
153
154impl From<Infallible> for Response {
155 fn from(_: Infallible) -> Self {
156 panic!("tried to conver from infalliable");
157 }
158}
159
160impl From<Response> for String {
161 fn from(response: Response) -> String {
162 let status: &str = response.status.as_str();
163 let length = response.body.len();
164 let version: &str = response.version.into();
165 let body: &str = &String::from_utf8_lossy(&response.body);
166 let content_type: String = response.mime.into();
167 let mut headers_string = "".to_string();
168 for header in response.headers {
169 let header_string: String = header.into();
170 headers_string.push_str(&header_string);
171 headers_string.push_str("\r\n");
172 }
173 let response = format!(
174 "{version} {status}\r\n\
175 Content-Length: {length}\r\n\
176 Content-Type: {content_type}\r\n\
177 {headers_string}\r\n\
178 {body}"
179 );
180 response
181 }
182}
183
184impl From<std::io::Error> for Response {
185 fn from(error: std::io::Error) -> Self {
186 Response {
187 status: StatusCode::INTERNAL_SERVER_ERROR,
188 body: error.to_string().into(),
189 mime: MimeType::HTML,
190 version: Version::V1_1,
191 headers: vec![],
192 }
193 }
194}
195
196impl From<StatusCode> for Response {
197 fn from(value: StatusCode) -> Self {
198 let body = if let Some(reason) = value.canonical_reason() {
199 reason
200 } else {
201 "Invalid Status Code"
202 };
203 let body = body.as_bytes().to_vec();
204 Response {
205 version: Version::V1_1,
206 status: value,
207 body,
208 mime: MimeType::HTML,
209 headers: vec![],
210 }
211 }
212}