gnostr_web/response/
mod.rs1use crate::headers::Headers;
2use crate::request::Request;
3use crate::status::{Status, StatusCode, StatusMethods};
4use std::collections::HashMap;
5use std::io::{BufWriter, Write};
6use std::net::Shutdown;
7
8pub struct Response {
9 pub request: Request,
10 pub headers: Option<Headers>,
12 pub status: Option<usize>,
13 pub fixed_content: Option<String>,
14}
15
16impl Response {
17 pub fn new(request: Request) -> Self {
18 return Self {
19 request,
20 headers: None,
21 status: None,
22 fixed_content: None,
23 };
24 }
25
26 fn init_headers(&mut self) {
27 if !self.headers.is_some() {
28 self.headers = Some(HashMap::new());
29 }
30 }
31
32 pub fn set_content_type(&mut self, text: &str) {
33 self.init_headers();
34
35 if let Some(ref mut headers) = self.headers {
37 if headers.contains_key("Content-Type") {
38 let content_types = headers.get_mut("Content-Type").unwrap();
39
40 content_types[0] = text.to_string();
42 } else {
43 let content_types = vec![text.to_string()];
44 let _ = headers.insert("Content-Type".to_string(), content_types);
45 }
46 }
47 }
48
49 pub fn add_header(&mut self, name: &str, value: &str) -> &mut Self {
51 self.init_headers();
52
53 if let Some(ref mut headers) = self.headers {
55 if headers.contains_key(name) {
56 let values = headers.get_mut(name).unwrap();
57 values.push(value.to_string());
58 } else {
59 let values = vec![value.to_string()];
60 headers.insert(name.to_string(), values);
61 }
62 }
63
64 return self;
65 }
66
67 pub fn html<T: StatusCode>(&mut self, status: T, text: String) -> &mut Self {
68 self.set_content(status.to_usize(), text);
69 self.set_content_type("text/html");
70 return self;
71 }
72
73 pub fn json<T: StatusCode>(&mut self, status: T, text: String) -> &mut Self {
74 self.set_content(status.to_usize(), text);
75 self.set_content_type("application/json");
76 return self;
77 }
78
79 pub fn set_content(&mut self, status: usize, text: String) -> &mut Self {
80 self.status = Some(status);
81 self.fixed_content = Some(text);
82 return self;
83 }
84
85 pub fn send(&mut self) {
86 if self.status.is_some() {
87 let request = &self.request;
88 let access_from: String;
89
90 match request.stream.peer_addr() {
91 Ok(addr) => {
92 access_from = addr.to_string();
93 }
94
95 Err(_) => access_from = "UnKnown".to_string(),
96 }
97
98 println!(
99 "{} - \"{} {} {}\"",
100 access_from,
101 request.method,
102 request.pathname,
103 self.status.unwrap()
104 );
105 self.write_http();
106 }
107 }
108
109 fn write_http(&mut self) {
110 let should_close = self.request.should_close_connection();
111
112 let headers = self.headers.as_mut().expect("Response headers missing.");
113 let content_length = format!(
114 "{}",
115 self.fixed_content
116 .as_ref()
117 .expect("Fixed content is missing.")
118 .len()
119 );
120 headers.insert("Content-Length".to_string(), vec![content_length]);
121
122 if !should_close {
123 headers.insert("Connection".to_string(), vec!["keep-alive".to_string()]);
124 }
125
126 let headers = self.prepare_raw_headers();
128
129 let cloned_stream = self.request.stream.try_clone();
130 if !cloned_stream.is_ok() {
131 println!("Connection closed");
132 self.request.context.dont_wait();
133 return;
134 }
135
136 let mut buf_writer = BufWriter::new(cloned_stream.unwrap());
137 match buf_writer.write_all(headers.as_bytes()) {
138 Ok(_) => {}
139 Err(_) => {
140 println!("Connection closed");
141 self.request.context.dont_wait();
142 return;
143 }
144 }
145
146 if self.request.method != "HEAD" {
148 if let Some(content) = &self.fixed_content {
149 buf_writer.write_all(content.as_bytes()).unwrap();
150 }
151 }
152
153 if !buf_writer.flush().is_ok() {
155 print!("Connection closed");
156 self.request.context.dont_wait();
157 };
158
159 if should_close {
160 let _ = self.request.stream.shutdown(Shutdown::Both);
161 self.request.context.dont_wait();
162 }
163 }
164
165 fn prepare_raw_headers(&mut self) -> String {
166 let status_code = self.status.expect("Status code not set.");
167
168 let mut status_text = Status::status_text(status_code);
169 if !status_text.is_some() {
170 status_text = Some("Custom Status".to_string());
171 }
172
173 let mut raw_headers = format!(
175 "HTTP/1.1 {} {}\r\n",
176 self.status.unwrap(),
177 status_text.unwrap()
178 );
179
180 if let Some(headers) = &self.headers {
181 for header_name in headers.keys() {
182 let values = headers.get(header_name).unwrap();
183
184 for value in values {
185 let header_line = format!("{}: {}\r\n", header_name, value);
186 raw_headers.push_str(&header_line);
187 }
188 }
189 }
190
191 raw_headers.push_str("\r\n");
193 return raw_headers;
194 }
195}