1use std::fs;
2use std::collections::BTreeMap;
3use std::collections::btree_map::Entry;
4use std::fmt::Display;
5use std::io::Write;
6use std::net::TcpStream;
7
8use super::status_code::StatusCode;
9
10#[derive(Clone)]
12pub struct Response {
13 status: StatusCode,
14 headers: BTreeMap<String, String>,
15 body: String,
16}
17
18impl Response {
19 pub fn builder() -> ResponseWriter {
20 ResponseWriter::default()
21 }
22
23 pub fn write(&self, mut stream: TcpStream) {
25 let mut response = format!("HTTP/1.1 {}\r\n", self.status.get_status());
26
27 for (key, value) in &self.headers {
28 let kv = format!("{}: {}\r\n", key, value);
29 response.push_str(&kv);
30 }
31
32 let body = format!("\r\n{}", self.body);
33 response.push_str(&body);
34
35 stream.write_all(response.as_bytes()).unwrap();
36 stream.flush().unwrap();
37 }
38}
39
40#[derive(Default)]
41pub struct ResponseWriter {
42 status: StatusCode,
43 headers: BTreeMap<String, String>,
44 body: String,
45}
46
47impl ResponseWriter {
48 pub fn set_status(&mut self, status: StatusCode) -> &mut Self {
50 self.status = status;
51 self
52 }
53
54 pub fn header(&mut self, name: &str, value: &str) -> &mut Self {
56 self.headers.insert(name.into(), value.into());
57 self
58 }
59
60 pub fn remove_header(&mut self, name: &str) -> &mut Self {
62 if let Entry::Occupied(header) = self.headers.entry(name.to_string()) {
63 header.remove_entry();
64 }
65 self
66 }
67
68 pub fn set_text(&mut self, body: &str) -> &mut Self {
70 self.body = body.into();
71 self.headers.insert("Content-Length".into(), body.len().to_string());
72 self.headers.insert("Content-Type".into(), "text/plain".into());
73 self
74 }
75
76 pub fn set_html(&mut self, path: &str) -> &mut Self {
79 let path = format!("views/{}", path);
80 let body = fs::read_to_string(path).unwrap();
81
82 self.body = body.clone().into();
83 self.headers.insert("Content-Length".into(), body.len().to_string());
84 self.headers.insert("Content-Type".into(), "text/html".into());
85 self
86 }
87
88 pub fn set_json(&mut self, body: impl Display) -> &mut Self {
91 let body = format!("{}", body);
92
93 self.body = body.clone().into();
94 self.headers.insert("Content-Length".into(), body.len().to_string());
95 self.headers.insert("Content-Type".into(), "application/json".into());
96 self
97 }
98
99 pub fn build(self) -> Response {
101 Response {
102 status: self.status,
103 headers: self.headers,
104 body: self.body,
105 }
106 }
107}