aboutsummaryrefslogtreecommitdiff
path: root/src/response.rs
blob: c3540d2230ba45d1ea9dec9a3f7a196a9177bc1f (plain)
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
use crate::http_types::*;
use std::collections::HashMap;

pub struct Response {
    version: String,
    status: StatusCode,
    headers: Option<Headers>,
    body: Option<String>,
}

impl Response {
    pub fn new(
        version: String,
        status: StatusCode,
        headers: Option<Headers>,
        body: Option<String>,
    ) -> Self {
        Response {
            version,
            headers,
            status,
            body,
        }
    }
}

impl Into<String> for Response {
    fn into(self) -> String {
        let status_line = format!("HTTP/{} {}", self.version, String::from(self.status));
        let headers = self
            .headers
            .unwrap_or(Headers(HashMap::new()))
            .0
            .iter()
            .map(|(key, value)| format!("{key}: {value}\r\n"))
            .collect::<String>();
        let body = self.body.unwrap_or("".to_string());
        format!("{status_line}\r\n{headers}\r\n{body}")
    }
}

impl Into<Response> for &str {
    fn into(self) -> Response {
        let mut lines = self.lines();

        // Parse the status line
        let status_line = lines.next().unwrap_or_default();
        let mut status_line_parts = status_line.split_whitespace();

        let version = status_line_parts.next().unwrap_or_default().to_string();
        let status_code = status_line_parts.next().unwrap_or_default();

        let status = match status_code {
            "200" => StatusCode::Ok,
            "404" => StatusCode::NotFound,
            _ => StatusCode::Ok,
        };

        // Parse headers
        let mut headers_map = HashMap::new();
        while let Some(line) = lines.next() {
            if line.is_empty() {
                break;
            }
            let mut parts = line.splitn(2, ':');
            let key = parts.next().unwrap_or_default().trim();
            let value = parts.next().unwrap_or_default().trim();
            headers_map.insert(key.to_string(), value.to_string());
        }
        let headers = if headers_map.is_empty() {
            None
        } else {
            Some(Headers(headers_map))
        };

        // Parse body
        let body: Option<String> = {
            let remaining_lines: Vec<&str> = lines.collect();
            if remaining_lines.is_empty() {
                None
            } else {
                Some(remaining_lines.join("\n"))
            }
        };

        Response {
            version,
            status,
            headers,
            body,
        }
    }
}