ilmen_http/http/responses/
http_response.rs1use std::fmt;
2
3use crate::http::{errors::http_errors::HttpError, header::{HeaderKey, HeaderValue, Headers}};
4
5const PROTOCOL : &str= "HTTP/1.1";
6
7pub struct HTTPResponse {
8 code: i32,
9 body: Option<String>,
10 headers: Headers
11}
12
13impl HTTPResponse {
14 pub fn code(&self) -> i32 {
15 self.code
16 }
17}
18
19impl Default for HTTPResponse {
20 fn default() -> Self {
21 Self {
22 code: 404,
23 body: Default::default(),
24 headers: Default::default() }
25 }
26}
27
28
29
30fn construct_status_line(code : i32) -> String {
31 format!("{} {} {}", PROTOCOL, code, message_from_code(code))
32}
33
34fn message_from_code(code : i32) -> String {
35 match code {
36 200 => String::from("OK"),
37 500 => "INTERNAL".to_string(),
38 404 => "NOT FOUND".to_string(),
39 400 => "BAD REQUEST".to_string(),
40 _ => "".to_string()
41 }
42}
43
44impl fmt::Display for HTTPResponse {
45 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
46 let headers= self.headers.iter().map(|(key, value)| key.to_string() + ": " + value).collect::<Vec<String>>().join("\r\n");
47 let body ="\r\n".to_string() + &self.body.to_owned().unwrap_or_default();
48 write!(f,
49 "{}\r\n{}{}",
50 construct_status_line(self.code),
51 headers,
52 body
53 )
54 }
55}
56
57
58
59impl From<HttpError> for HTTPResponse {
60 fn from(value: HttpError) -> Self {
61 match value {
62 HttpError::DefaultError => ResponseBuilder::new(0, None).build(),
63 HttpError::NotFoundError(_) => ResponseBuilder::new(404, Some("Not found".to_string())).build(),
64 HttpError::UnauthorizedError(_) => ResponseBuilder::new(401, None).build(),
65 HttpError::BadRequest(_) => ResponseBuilder::new(400, None).build(),
66 }
67 }
68}
69
70
71#[derive(Default)]
72pub struct ResponseBuilder {
73 code: i32,
74 body: Option<String>,
75 headers: Headers
76}
77
78
79impl ResponseBuilder {
80 pub fn new(code: i32, body: Option<String>) -> Self {
81 ResponseBuilder {
82 code,
83 body,
84 ..Default::default()
85 }
86 }
87
88 pub fn content_type(mut self, content_type: String) -> Self {
89 self.headers.push(("Content-Type".to_string(), content_type));
90 self
91 }
92
93 pub fn build(&self) -> HTTPResponse{
94 let headers = vec![];
95 HTTPResponse {
96 body: self.body.clone(),
97 code: self.code,
98 headers
99 }
100 }
101
102 pub fn put_header(mut self, key: HeaderKey, value: HeaderValue) -> ResponseBuilder {
103 self.headers.push((key, value));
104 self
105 }
106
107 pub fn body(mut self, body: String) -> ResponseBuilder {
108 self.body = Some(body);
109 self
110 }
111}