nucleus_http/
response.rs

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
21/// All types that implent into response already get IntoResponse for free ... does that make this
22/// trait redudant ?
23impl<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        //transform response to array of bytes to be sent
62        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, //FIXME: make this smarter
146            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}