milstian_http/
response.rs

1//! # Handles everything related to HTTP responses.
2
3use std::collections::HashMap;
4use std::str;
5
6/// # A request message
7pub struct Message {
8    pub protocol: String,
9    pub status: String,
10    pub headers: HashMap<String, String>,
11    pub body: Vec<u8>,
12}
13
14impl Message {
15    /// # Create a new HTTP Message
16    pub fn new(
17        protocol: String,
18        status: String,
19        headers: HashMap<String, String>,
20        body: Vec<u8>,
21    ) -> Message {
22        Message {
23            protocol,
24            status,
25            headers,
26            body,
27        }
28    }
29
30    /// # Get the HTTP header as a new string
31    /// ```rust
32    /// use milstian_http::response::Message;
33    /// use std::collections::HashMap;
34    /// assert_eq!(
35    ///     Message::new(
36    ///         "HTTP/1.0".to_string(),
37    ///         "200 OK".to_string(),
38    ///         HashMap::new(),
39    ///         b"<html><body>Nothing here</body></html>".to_vec()
40    ///     ).header_to_string(),
41    ///     "HTTP/1.0 200 OK\r\n\r\n".to_string()
42    /// );    
43    /// ```
44    pub fn header_to_string(&self) -> String {
45        let mut response = format!("{} {}\r\n", &self.protocol, &self.status);
46
47        if !&self.headers.is_empty() {
48            let mut headers: Vec<(&String, &String)> = self.headers.iter().collect();
49            headers.sort_by(|a, b| a.cmp(b));
50            for (key, value) in headers {
51                response.push_str(&format!("{}: {}\r\n", &key, &value));
52            }
53        }
54        response.push_str("\r\n");
55
56        response
57    }
58
59    /// # Convert response message into a string
60    /// ```rust
61    /// use milstian_http::response::Message;
62    /// use std::collections::HashMap;
63    /// assert_eq!(
64    ///     Message::new(
65    ///         "HTTP/1.0".to_string(),
66    ///         "200 OK".to_string(),
67    ///         HashMap::new(),
68    ///         b"<html><body>Nothing here</body></html>".to_vec()
69    ///     ).to_string(),
70    ///     "HTTP/1.0 200 OK\r\n\r\n<html><body>Nothing here</body></html>".to_string()
71    /// );
72    /// ```
73    pub fn to_string(&mut self) -> String {
74        let mut response = format!("{} {}\r\n", &self.protocol, &self.status);
75
76        if !&self.headers.is_empty() {
77            let mut headers: Vec<(&String, &String)> = self.headers.iter().collect();
78            headers.sort_by(|a, b| a.cmp(b));
79            for (key, value) in headers {
80                response.push_str(&format!("{}: {}\r\n", &key, &value));
81            }
82        }
83        response.push_str("\r\n");
84
85        if !&self.body.is_empty() {
86            if let Ok(body_string) = str::from_utf8(&self.body) {
87                response.push_str(body_string);
88            }
89        }
90
91        response
92    }
93
94    /// # Convert message into bytes
95    /// ```rust
96    /// use milstian_http::response::Message;
97    /// use std::collections::HashMap;
98    /// assert_eq!(
99    ///     Message::new(
100    ///         "HTTP/1.0".to_string(),
101    ///         "200 OK".to_string(),
102    ///         HashMap::new(),
103    ///         b"<html><body>Nothing here</body></html>".to_vec()
104    ///     ).to_bytes(),
105    ///     b"HTTP/1.0 200 OK\r\n\r\n<html><body>Nothing here</body></html>".to_vec()
106    /// );
107    /// ```
108    pub fn to_bytes(&mut self) -> Vec<u8> {
109        let mut response = format!("{} {}\r\n", &self.protocol, &self.status).into_bytes();
110
111        if !&self.headers.is_empty() {
112            let mut headers: Vec<(&String, &String)> = self.headers.iter().collect();
113            headers.sort_by(|a, b| a.cmp(b));
114            for (key, value) in headers {
115                response.append(&mut format!("{}: {}\r\n", &key, &value).into_bytes());
116            }
117        }
118        response.append(&mut "\r\n".to_string().into_bytes());
119
120        if !&self.body.is_empty() {
121            response.append(&mut self.body);
122        }
123
124        response
125    }
126}
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131
132    #[test]
133    fn test_to_string() {
134        let mut message = Message::new(
135            "HTTP/1.0".to_string(),
136            "200 OK".to_string(),
137            HashMap::new(),
138            b"<html><body>Nothing here</body></html>".to_vec(),
139        );
140        assert_eq!(
141            message.to_string(),
142            "HTTP/1.0 200 OK\r\n\r\n<html><body>Nothing here</body></html>".to_string()
143        );
144    }
145
146    #[test]
147    fn test_to_bytes() {
148        let mut message = Message::new(
149            "HTTP/1.0".to_string(),
150            "200 OK".to_string(),
151            HashMap::new(),
152            b"<html><body>Nothing here</body></html>".to_vec(),
153        );
154        assert_eq!(
155            message.to_bytes(),
156            b"HTTP/1.0 200 OK\r\n\r\n<html><body>Nothing here</body></html>".to_vec()
157        );
158    }
159
160}