ilmen_http/http/responses/
http_response.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use std::fmt;

use crate::http::{errors::http_errors::HttpError, header::{HeaderKey, HeaderValue, Headers}};

const PROTOCOL : &str= "HTTP/1.1";

pub struct HTTPResponse {
    code: i32,
    body: Option<String>,
    headers: Headers
}

impl HTTPResponse {
    pub fn code(&self) -> i32 {
        self.code
    }    
}

impl Default for HTTPResponse {
    fn default() -> Self {
        Self { 
            code: 404,  
            body: Default::default(), 
            headers: Default::default() }
    }
}



fn construct_status_line(code : i32) -> String {
    format!("{} {} {}", PROTOCOL, code, message_from_code(code))
}

fn message_from_code(code : i32) -> String {
    match code {
        200 =>  String::from("OK"),
        500 => "INTERNAL".to_string(),
        404 => "NOT FOUND".to_string(),
        400 => "BAD REQUEST".to_string(),
        _  => "".to_string()
    }
}

impl fmt::Display for HTTPResponse {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let headers= self.headers.iter().map(|(key, value)| key.to_string() + ": " + value).collect::<Vec<String>>().join("\r\n");
        let body = match &self.body {
            Some(body) =>  "\r\n\r\n".to_string() + body,
            None => "\r\n".to_string(),
        };
        write!(f,
            "{}\r\n{}{}",
            construct_status_line(self.code),
            headers,
            body
        )
    }
}



impl From<HttpError> for HTTPResponse {
    fn from(value: HttpError) -> Self {
        match value {
            HttpError::DefaultError => ResponseBuilder::new(0, None).build(),
            HttpError::NotFoundError(_) => ResponseBuilder::new(404, Some("Not found".to_string())).build(),
            HttpError::UnauthorizedError(_) => ResponseBuilder::new(401, None).build(),
            HttpError::BadRequest(_) => ResponseBuilder::new(400, None).build(),
        }
    }
}


#[derive(Default)]
pub struct ResponseBuilder {
    code: i32,
    body: Option<String>,
    headers: Headers
}


impl ResponseBuilder {
    pub fn new(code: i32, body: Option<String>) -> Self {
        ResponseBuilder {
            code,
            body,
            ..Default::default()
        }
    }

    pub fn content_type(mut self, content_type: String) -> Self {
        self.headers.push(("Content-Type".to_string(), content_type)); 
        self
    }

    pub fn build(&self) -> HTTPResponse{
        let headers = vec![];
        HTTPResponse {
            body: self.body.clone(),
            code: self.code,
            headers
        }   
    }

    pub fn put_header(mut self, key: HeaderKey, value: HeaderValue) -> ResponseBuilder {
        self.headers.push((key, value));
        self
    }

    pub fn body(mut self, body: String) -> ResponseBuilder {
        self.body = Some(body);
        self
    }
}