1use crate::header::{self, ContentType};
2pub mod static_files;
3pub mod status_code;
4
5#[derive(Debug, PartialEq, Eq, Clone)]
7pub struct Response {
8 status_code: StatusCode,
10
11 headers: HashMap<Header, String>,
13
14 pub cors: String,
17
18 content: Body,
21}
22
23#[derive(Debug, PartialEq, Eq, Clone)]
24pub enum Body {
25 STRING(String),
26 BYTES(Vec<u8>),
27}
28
29impl std::fmt::Display for Body {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 match self {
32 Body::STRING(string) => write!(f, "{}", string),
33 Body::BYTES(bytes) => {
34 let bytes_str = bytes
35 .iter()
36 .map(|&byte| format!("{:02X}", byte))
37 .collect::<String>();
38 write!(f, "{}", bytes_str)
39 }
40 }
41 }
42}
43
44impl Body {
45 pub fn as_bytes(&self) -> &[u8] {
46 match self {
47 Body::STRING(s) => s.as_bytes(),
48
49 Body::BYTES(b) => b.as_slice(),
50 }
51 }
52}
53
54use std::collections::HashMap;
55
56use chrono;
57use serde_json::Value;
58
59use pillow_templates::Template;
60
61use self::{
62 header::Header,
63 status_code::{AsStr, StatusCode},
64};
65
66impl Response {
67 pub fn new_empty() -> Response {
69 Response {
70 status_code: StatusCode::Successfull(status_code::Successfull::OK),
71
72 headers: HashMap::from([
73 (Header::Server, String::from("Pillow")),
74 ]),
76
77 cors: String::from("*"),
78
79 content: Body::STRING(String::new()),
80 }
81 }
82}
83
84impl Response {
85 pub fn html(page: &'static str) -> Response {
102 let mut response = Self::new_empty();
103
104 let html = Template::Html(page);
105 let contents = html.render();
106
107 let date = crate::get_date_now!();
108
109 response.add_multiple_headers(vec![
110 (Header::AccessControlAllowOrigin, response.cors.to_string()),
111 (Header::Connection, "Keep-Alive".to_string()),
112 (Header::ContentLength, contents.len().to_string()),
113 (Header::ContentType, "text/html; charset=utf-8".to_string()),
114 (Header::Date, date.to_string()),
115 (Header::LastModified, date.to_string()),
116 ]);
117
118 response.insert_string_content(contents);
119
120 response
121 }
122
123 pub fn view(template: Template) -> Response {
145 let mut response = Self::new_empty();
146
147 let contents = template.render();
148
149 let date = crate::get_date_now!();
150
151 response.add_multiple_headers(vec![
152 (Header::AccessControlAllowOrigin, response.cors.to_string()),
153 (Header::Connection, "Keep-Alive".to_string()),
154 (Header::ContentLength, contents.len().to_string()),
155 (Header::ContentType, "text/html; charset=utf-8".to_string()),
156 (Header::Date, date.to_string()),
157 (Header::LastModified, date.to_string()),
158 ]);
159
160 response.insert_string_content(contents);
161
162 response
163 }
164
165 pub fn hbs(page: &'static str, data: Value) -> Response {
188 let mut response = Self::new_empty();
189
190 let hbs = Template::Handlebars(page, data);
191 let contents = hbs.render();
192
193 let date = crate::get_date_now!();
194
195 response.add_multiple_headers(vec![
196 (Header::AccessControlAllowOrigin, response.cors.to_string()),
197 (Header::Connection, "Keep-Alive".to_string()),
198 (Header::ContentLength, contents.len().to_string()),
199 (Header::ContentType, "text/html; charset=utf-8".to_string()),
200 (Header::Date, date.to_string()),
201 (Header::LastModified, date.to_string()),
202 ]);
203
204 response.insert_string_content(contents);
205
206 response
207 }
208
209 pub fn json(js: Value) -> Response {
231 let mut response = Self::new_empty();
232
233 let date = crate::get_date_now!();
234 let json = js.to_string();
235
236 response.add_multiple_headers(vec![
237 (Header::AccessControlAllowOrigin, response.cors.to_string()),
238 (Header::AcceptRanges, "bytes".to_string()),
239 (Header::ContentLength, json.len().to_string()),
240 (
241 Header::ContentType,
242 "application/json; charset=utf-8".to_string(),
243 ),
244 (Header::Date, date.to_string()),
245 (Header::Date, date.to_string()),
246 (Header::Vary, "Accept-Encoding".to_string()),
247 ]);
248
249 response.insert_string_content(json);
250
251 response
252 }
253
254 pub fn json_from_str(json: &str) -> Response {
273 let mut response = Self::new_empty();
274
275 let date = crate::get_date_now!();
276
277 let json_value: Value = serde_json::from_str(json).unwrap();
278 let js = json_value.to_string();
279
280 response.add_multiple_headers(vec![
281 (Header::AccessControlAllowOrigin, response.cors.to_string()),
282 (Header::AcceptRanges, "bytes".to_string()),
283 (Header::ContentLength, js.len().to_string()),
284 (
285 Header::ContentType,
286 "application/json; charset=utf-8".to_string(),
287 ),
288 (Header::Date, date.to_string()),
289 (Header::Date, date.to_string()),
290 (Header::Vary, "Accept-Encoding".to_string()),
291 ]);
292
293 response.insert_string_content(js);
295
296 response
297 }
298
299 pub fn text(txt: &str) -> Response {
312 let mut response = Self::new_empty();
313
314 let length = txt.len();
315
316 response.add_multiple_headers(vec![
317 (Header::AccessControlAllowOrigin, response.cors.to_string()),
318 (Header::ContentType, "text/plain".to_string()),
319 (Header::ContentLength, length.to_string()),
320 ]);
321
322 response.insert_string_content(txt.to_string());
323
324 response
325 }
326
327 pub fn css(&mut self, css: String) -> String {
329 let status_line = self.get_status_line();
330
331 let date = chrono::offset::Local::now();
332
333 self.add_multiple_headers(vec![
334 (Header::AccessControlAllowOrigin, self.cors.to_string()),
335 (Header::ContentLength, css.len().to_string()),
336 (Header::ContentType, "text/css; charset=utf-8".to_string()),
338 (Header::Date, date.to_string()),
339 (Header::LastModified, date.to_string()),
340 ]);
343
344 let headers = self.get_headers();
345 let response = format!("{status_line}{headers}\r\n\r\n{css}");
346
347 response
348 }
349
350 pub fn javascript(&mut self, js: String) -> String {
352 let status_line = self.get_status_line();
353
354 let date = chrono::offset::Local::now();
355
356 self.add_multiple_headers(vec![
357 (Header::AccessControlAllowOrigin, self.cors.to_string()),
358 (Header::ContentLength, js.len().to_string()),
359 (
361 Header::ContentType,
362 "application/javascript; charset=utf-8".to_string(),
363 ),
364 (Header::Date, date.to_string()),
365 (Header::LastModified, date.to_string()),
366 ]);
369
370 let headers = self.get_headers();
371 let response = format!("{status_line}{headers}\r\n\r\n{js}");
372
373 response
374 }
375
376 pub fn file(content_type: ContentType, content: Vec<u8>) -> Response {
377 let mut response = Self::new_empty();
378
379 let date = crate::get_date_now!();
380
381 response.add_multiple_headers(vec![
382 (Header::AccessControlAllowOrigin, response.cors.to_string()),
383 (Header::Connection, "Keep-Alive".to_string()),
384 (Header::ContentLength, content.len().to_string()),
386 (Header::Date, date.to_string()),
387 ]);
388
389 response.content_type(content_type);
390
391 response.insert_bytes_content(content.clone());
392
393 response
394 }
395}
396
397impl Response {
398 pub fn redirect(location: &'static str) -> Response {
399 let mut response = Self::new_empty();
400
401 response.set_status_code(StatusCode::Redirection(status_code::Redirection::Found));
402
403 response.add_multiple_headers(vec![
404 (Header::AccessControlAllowOrigin, response.cors.to_string()),
405 (Header::Location, location.to_string()),
406 ]);
407
408 response
409 }
410}
411
412impl ToString for Response {
413 fn to_string(&self) -> String {
415 let res = format!(
416 "{}{}\r\n\r\n{}",
417 &self.get_status_line(),
418 &self.get_headers(),
419 &self.content
420 );
421
422 res
423 }
424}
425
426impl Response {
427 pub fn insert_string_content(&mut self, content: String) {
429 self.content = Body::STRING(content);
430 }
431
432 pub fn insert_bytes_content(&mut self, content: Vec<u8>) {
433 self.content = Body::BYTES(content);
434 }
435}
436
437impl Response {
438 pub fn content_type(&mut self, content_type: header::ContentType) -> &Response {
440 self.add_header(Header::ContentType, content_type.as_str().to_string());
441 self
442 }
443}
444
445impl Response {
446 pub fn websocket_upgrade_connection() -> Response {
447 let mut response = Response::new_empty();
448
449 response.set_status_code(StatusCode::Information(
450 status_code::Information::SwitchingProtocols,
451 ));
452
453 response.clear_headers();
454
455 response.add_multiple_headers(vec![
456 (Header::Upgrade, "websocket".to_string()),
457 (Header::Connection, "Upgrade".to_string()),
458 (
459 Header::SecWebSocketAccept,
460 "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=".to_string(),
461 ),
462 (Header::SecWebSocketProtocol, "superchat".to_string()),
463 ]);
464
465 println!("Response: {:#?}", &response.to_string());
466
467 response
468 }
469}
470
471impl Response {
472 pub fn add_header(&mut self, header: Header, value: String) {
492 self.headers.insert(header, value);
493 }
494
495 pub fn add_multiple_headers(&mut self, headers: Vec<(Header, String)>) {
515 for (header, value) in headers {
516 self.add_header(header, value);
517 }
518 }
519
520 pub fn get_headers(&self) -> String {
528 let mut res = String::new();
529
530 for (header, value) in &self.headers {
531 let header = &header.as_str();
532 res = format!("{res}\r\n{header}: {value}");
533 }
534
535 res
536 }
537
538 pub fn clear_headers(&mut self) {
540 self.headers = HashMap::new();
541 }
542
543 pub fn get_status_line(&self) -> String {
554 let status_code = &self.status_code;
555 let status_line = format!("HTTP/1.1 {}", status_code.as_str());
556
557 status_line
558 }
559
560 pub fn set_status_code(&mut self, code: StatusCode) {
569 self.status_code = code;
570 }
571
572 pub fn get_body(&self) -> Body {
573 self.content.clone()
574 }
575}
576
577#[macro_export]
578macro_rules! get_date_now {
579 () => {{
580 let date = chrono::offset::Local::now();
581
582 date
583 }};
584}