1
2use std::rc::Rc;
3use std::collections::HashMap;
4use std::cell::RefCell;
5use std::sync::Arc;
6
7use crate::session::SessionManager;
8use crate::request::Request;
9use crate::cookie::Cookie;
10
11use debug_print::debug_eprintln;
12use lazy_static::lazy_static;
13use chrono::{DateTime, Utc};
14use uuid::Uuid;
15
16lazy_static! {
17 static ref STATUSES: HashMap<String, String> = HashMap::from([
18 ( "200".to_string(), "OK".to_string() ),
19 ( "301".to_string(), "MOVED PERMANENTLY".to_string() ),
20 ( "302".to_string(), "FOUND".to_string() ),
21 ( "308".to_string(), "PERMANENT REDIRECT".to_string() ),
22 ( "400".to_string(), "BAD REQUEST".to_string() ),
23 ( "401".to_string(), "UNAUTHORIZED".to_string() ),
24 ( "403".to_string(), "FORBIDDEN".to_string() ),
25 ( "404".to_string(), "NOT FOUND".to_string() ),
26 ( "411".to_string(), "LENGTH REQUIRED".to_string() ),
27 ( "413".to_string(), "PAYLOAD TOO LARGE".to_string() ),
28 ( "414".to_string(), "URI TOO LONG".to_string() ),
29 ( "418".to_string(), "I AM A TEAPOT".to_string() ),
30 ( "426".to_string(), "UPGRADE REQUIRED".to_string() ),
31 ( "451".to_string(), "UNAVAILABLE FOR LEGAL REASONS".to_string() ),
32 ( "500".to_string(), "INTERNAL SERVER ERROR".to_string() ),
33 ( "501".to_string(), "NOT IMPLEMENTED".to_string() ),
34 ( "505".to_string(), "HTTP VERSION NOT SUPPORTED".to_string() ),
35 ]);
36}
37
38#[derive(Debug)]
39pub struct Response<'req> {
40 pub body: Vec<u8>,
41 pub code: &'req str,
42 pub status: &'req str,
43 pub protocol: &'req str,
44 pub method: &'req str,
45 pub headers: HashMap<&'req str, String>,
46 pub cookies: Vec<Cookie<'req>>,
47}
48
49impl<'req> Response<'req> {
50 pub fn new(
52 req: Rc<RefCell<Request<'req>>>,
53 session_manager: Arc<SessionManager>,
54 session_id: &mut Uuid
55 ) -> Self {
56 let mut headers: HashMap<&str, String> = HashMap::new();
57
58 headers.insert("Connection", "close".to_string());
60 headers.insert("Content-Type", "text/html".to_string());
61
62 let sm_is_enabled = session_manager.is_enabled();
63 if sm_is_enabled {
64 if let Some(cookie) = req.borrow_mut().cookie("id") {
65 if let Ok(id) = cookie.value.parse::<Uuid>() {
66 *session_id = id;
67 }
68 }
69 }
70
71 let sm_should_gen_id = session_manager.is_enabled()
72 && !session_manager.add_session(*session_id)
73 && !session_manager.session_exists(*session_id);
74
75 let mut should_add_cookie = false;
76 if sm_should_gen_id {
77 *session_id = SessionManager::generate_id();
78 should_add_cookie = true;
79 }
80
81 let mut cookies: Vec<Cookie> = Vec::new();
82 let sm_is_enabled = session_manager.is_enabled();
83 if sm_is_enabled && should_add_cookie && !session_id.is_nil() {
84 let cookie = Cookie::builder()
85 .name("id")
86 .value(session_id.to_string().as_str())
87 .http_only(true)
88 .build();
89 cookies.push(cookie);
90 }
91
92 Self {
93 body: vec![],
94 code: "200",
95 status: "OK",
96 protocol: "HTTP/1.1",
97 method: req.borrow_mut().method,
98 headers,
99 cookies,
100 }
101 }
102
103 pub fn bad() -> Self {
105 let mut headers: HashMap<&str, String> = HashMap::new();
106
107 headers.insert("Connection", "close".to_string());
109 headers.insert("Content-Type", "text/html".to_string());
110
111 Self {
112 body: vec![],
113 code: "400",
114 status: "BAD REQUEST",
115 protocol: "HTTP/1.1",
116 method: "GET",
117 headers,
118 cookies: Vec::new(),
119 }
120 }
121
122 pub fn serialize(&mut self) -> Vec<u8> {
124 let mut serialized = vec![];
125
126 let mut status = match STATUSES.get(self.code) {
127 None => self.status,
128 Some(thing) => thing,
129 };
130
131 if status.is_empty() {
132 debug_eprintln!("ERROR: No default status string for HTTP {}, sending 500", self.code);
133 self.code = "500";
134 status = match STATUSES.get(self.code) {
135 None => "INTERNAL SERVER ERROR",
136 Some(thing) => thing,
137 };
138 self.headers.insert("Content-Type", "text/html".to_string());
139 self.body = format!("<h1>500: {}</h1>", status).into_bytes();
140 }
141
142 if !self.cookies.is_empty() {
143 self.headers.insert("Set-Cookie", self.cookies.iter()
144 .map(|c| c.to_string())
145 .intersperse("; ".to_string())
146 .reduce(|acc, c| acc + &c).unwrap());
147 }
148
149 serialized.append(&mut format!("{} {} {}\r\n", &self.protocol, &self.code, &status).into_bytes());
151
152 let now: DateTime<Utc> = Utc::now();
153 self.headers.insert("Date", now.format("%a, %d %b %Y %H:%M:%S").to_string());
154
155 for (key, value) in self.headers.iter() {
157 if !key.is_empty() {
158 serialized.append(&mut format!("{}: {}\r\n", &key, &value).into_bytes());
159 }
160 }
161
162 if self.method != "HEAD" {
164 serialized.append(&mut format!("Content-Length: {}\r\n\r\n", &self.body.len()).into_bytes());
165 serialized.append(&mut self.body);
166 } else {
167 serialized.append(&mut "Content-Length: 0\r\n\r\n".to_string().into_bytes());
168 }
169
170 serialized
171 }
172
173 pub fn header(&self, key: &str) -> Option<&str> {
175 match self.headers.get(key) {
176 None => None,
177 Some(thing) => Some(thing.as_str()),
178 }
179 }
180
181 pub fn is_redirect(&self) -> bool {
182 let mut cases = 0;
183 if self.code.starts_with('3') {
184 cases += 1;
185 }
186 if self.header("Location").is_some() {
187 cases += 1;
188 }
189 cases == 2
190 }
191}
192