web_server/
response.rs

1use std::{
2    collections::HashMap,
3    convert::{From, Into},
4    fmt::{self, Display},
5    fs::File,
6    io::Read,
7    path::Path,
8};
9
10use crate::{HttpCode, HttpVersion};
11
12#[derive(Debug, Clone)]
13pub enum Body {
14    Raw(Vec<u8>),
15    S(String),
16}
17
18use Body::*;
19
20impl Body {
21    pub fn unwrap_raw(self) -> Vec<u8> {
22        match self {
23            Raw(v) => v,
24            S(_) => panic!(""),
25        }
26    }
27}
28
29impl Display for Body {
30    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
31        match self {
32            S(s) => write!(f, "{}", s.as_str()),
33            Raw(_) => panic!("Raw body cannot be display!!"),
34        }
35    }
36}
37
38#[allow(dead_code)]
39#[derive(Debug, Clone)]
40/// Represents http request
41pub struct Response {
42    pub response_code: HttpCode,
43    pub http_version: HttpVersion,
44    pub headers: HashMap<String, String>,
45    pub body: Body,
46}
47
48#[allow(clippy::new_without_default)]
49impl Response {
50    pub fn new() -> Self {
51        "".into()
52    }
53
54    #[inline]
55    pub fn header(&self, key: &str) -> std::option::Option<&String> {
56        self.headers.get(&key.to_string())
57    }
58
59    #[inline]
60    pub fn set_header(&mut self, key: &str, value: &str) -> &mut Self {
61        self.headers.insert(key.to_string(), value.to_string());
62        self
63    }
64
65    #[inline]
66    pub fn set_http_code(&mut self, resp_code: HttpCode) -> &mut Self {
67        self.response_code = resp_code;
68        self
69    }
70
71    #[inline]
72    pub fn set_body(&mut self, body: &str) -> &mut Self {
73        self.body = S(body.to_string());
74        self
75    }
76
77    #[inline]
78    pub fn set_raw_body(&mut self, body: Vec<u8>) -> &mut Self {
79        self.body = Raw(body);
80        self
81    }
82}
83
84impl From<&str> for Response {
85    fn from(resp: &str) -> Self {
86        let mut headers: HashMap<String, String> = HashMap::new();
87        headers.insert("Server".into(), "serve".into());
88        headers.insert("X-Powered-By".into(), "serve".into());
89        headers.insert("Connection".into(), "keep-alive".into());
90
91        Response {
92            response_code: HttpCode::_200,
93            http_version: HttpVersion::Ver11,
94            headers,
95            body: S(resp.to_string()),
96        }
97    }
98}
99
100impl From<String> for Response {
101    fn from(resp: String) -> Self {
102        resp.as_str().into()
103    }
104}
105
106impl Into<String> for Response {
107    fn into(self) -> String {
108        self.to_string()
109    }
110}
111
112impl Display for Response {
113    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114        let info = format!(
115            "HTTP/{} {} {}",
116            String::from(self.http_version),
117            get_code(self.response_code),
118            self.response_code
119        );
120
121        let headers = {
122            let mut headers = String::new();
123
124            for (header, value) in self.headers.iter() {
125                headers.push_str(format!("{}: {}\r\n", header, value).as_str());
126            }
127
128            headers.trim_end().to_string()
129        };
130
131        if let S(body) = &self.body {
132            write!(f, "{}\r\n{}\r\n\r\n{}", info, headers, body.to_string())
133        } else {
134            let headers_result = write!(f, "{}\r\n{}\r\n\r\n", info, headers);
135            let body = self.body.clone().unwrap_raw();
136
137            unsafe {
138                f.write_str(std::str::from_utf8_unchecked(&body))
139                    .and(headers_result)
140            }
141        }
142    }
143}
144
145impl From<&Path> for Response {
146    fn from(value: &Path) -> Self {
147        if !value.is_file() {
148            println!("File {:?} doesn't exists!", value);
149
150            Response {
151                response_code: HttpCode::_404,
152                ..Response::new()
153            }
154        } else {
155            let mut f = File::open(value.display().to_string()).unwrap();
156            let mut buffer = Vec::new();
157            f.read_to_end(&mut buffer).unwrap();
158
159            Response {
160                body: Raw(buffer),
161                ..Response::new()
162            }
163        }
164    }
165}
166
167fn get_code(code: HttpCode) -> i16 {
168    let code = format!("{:?}", code);
169    let code: Vec<&str> = code.as_str().split('_').collect();
170
171    code[1].parse().unwrap()
172}