ilmen_http/http/responses/
http_response.rs

1use 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}