1use std::collections::HashMap;
2use std::error::Error;
3use std::io::{BufRead, BufReader, Read};
4
5pub fn handle_stream<T>(stream: &T) -> Result<Request, Box<dyn Error + Send + Sync + 'static>>
6where
7 for<'a> &'a T: std::io::Read,
8{
9 let mut buf_reader = BufReader::new(stream);
10
11 let mut line_buf = String::new();
12
13 if let Err(_) = buf_reader.read_line(&mut line_buf) {
14 panic!("Bad Request");
15 }
16
17 let mut request_parts: Vec<&str> = line_buf.split_whitespace().collect();
18
19 let method = match request_parts.get(0) {
22 Some(method) => method.to_string(),
23 None => panic!("No request method"),
24 };
25
26 let mut headers = HashMap::new();
27
28 loop {
29 let mut line_buf = String::new();
30
31 if let Err(_) = buf_reader.read_line(&mut line_buf) {
32 panic!("Bad Request");
33 }
34
35 if line_buf.is_empty() || line_buf == "\n" || line_buf == "\r\n" {
36 break;
37 }
38
39 let mut comps = line_buf.split(":");
40 let key = comps.next().unwrap_or("None");
41 let value = comps.next().unwrap_or("None").trim();
42
43 headers.insert(key.to_string(), value.to_string());
44 }
45
46 let body;
47
48 if let Some(length) = headers.get("Content-Length") {
49 let mut bytes = vec![0_u8; length.parse().expect("Bad Content Length Header")];
50
51 buf_reader
52 .read_exact(&mut bytes)
53 .expect("Failed to read content!");
54
55 body = Some(String::from_utf8(bytes).expect("Invalid String!"));
56 } else {
57 body = None;
58 }
59
60 Ok(Request {
61 method: method,
62 route: request_parts.swap_remove(1).to_string(),
63 version: request_parts.pop().unwrap().to_string(),
64 headers: headers,
65 body: body,
66 })
67}
68
69pub struct Request {
70 pub method: String,
71 pub route: String,
72 pub version: String,
73 pub headers: HashMap<String, String>,
74 pub body: Option<String>,
75}
76
77impl Request {
78 pub fn as_text(&self) -> String{
80 match &self.body {
81 Some(body) => {
82 let mut r = String::new();
83 r.push_str(&format!("{} {} {}\r\n", self.method, self.route, self.version));
84 for (k , v) in &self.headers {
85 r.push_str(&format!("{}: {}\r\n", k, v));
86 }
87
88 r.push_str("\r\n");
89 r.push_str(&body);
90
91 r
92 }
93 None => {
94 let mut r = String::new();
95 r.push_str(&format!("{} {} {}\r\n", self.method, self.route, self.version));
96 for (k , v) in &self.headers {
97 r.push_str(&format!("{}: {}\r\n", k, v));
98 }
99
100 r.push_str("\r\n");
101
102 r
103 }
104 }
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn test_as_text_body() {
114 let mut headers = HashMap::new();
115 headers.insert("Test".into(), "Value".into());
116
117 let req = Request {
118 method: "POST".to_string(),
119 route: "/".to_string(),
120 version: "HTTP/1".to_string(),
121 headers: headers,
122 body: Some("My body".into()),
123 };
124
125 assert_eq!(req.as_text(), "POST / HTTP/1\r\nTest: Value\r\n\r\nMy body");
126 }
127
128 #[test]
129 fn test_as_text() {
130 let mut headers = HashMap::new();
131 headers.insert("Test".into(), "Value".into());
132
133 let req = Request {
134 method: "POST".to_string(),
135 route: "/".to_string(),
136 version: "HTTP/1".to_string(),
137 headers: headers,
138 body: None,
139 };
140
141 assert_eq!(req.as_text(), "POST / HTTP/1\r\nTest: Value\r\n\r\n");
142
143 }
144}