1use std::collections::hash_map::HashMap;
2
3#[derive(Debug, PartialEq)]
8pub enum Method {
9 GET,
10 POST,
11 PUT,
12 PATCH,
13 DELETE,
14 UNKNOWN(String),
15}
16
17#[derive(Debug, PartialEq)]
19pub struct Request {
20 pub method: Method,
21 pub path: String,
22 pub version: String,
23 pub body: Option<String>,
24 pub headers: HashMap<String, String>,
25}
26
27impl Request {
28 pub fn from_string(s: String) -> Result<Self, &'static str> {
30 let fields = s.split_whitespace().collect::<Vec<_>>();
31 Ok(Request {
32 method: parse_method(&fields)?,
33 path: parse_path(&fields)?,
34 version: parse_version(&fields)?,
35 body: parse_body(&s),
36 headers: parse_headers(&s)?,
37 })
38 }
39}
40
41fn parse_version(fields: &[&str]) -> Result<String, &'static str> {
42 fields
43 .get(2)
44 .map(|&s| String::from(s))
45 .ok_or("Could not parse HTTP version")
46}
47
48fn parse_path(fields: &[&str]) -> Result<String, &'static str> {
49 fields
50 .get(1)
51 .map(|&s| String::from(s))
52 .ok_or("Could not parse HTTP version")
53}
54
55fn parse_method(fields: &[&str]) -> Result<Method, &'static str> {
56 match fields.get(0).cloned() {
57 Some("GET") => Ok(Method::GET),
58 Some("POST") => Ok(Method::POST),
59 Some("PUT") => Ok(Method::PUT),
60 Some("PATCH") => Ok(Method::PATCH),
61 Some("DELETE") => Ok(Method::DELETE),
62 Some(method) => Ok(Method::UNKNOWN(method.to_string())),
64 None => Err("Could not parse HTTP method"),
65 }
66}
67
68fn parse_body(s: &str) -> Option<String> {
70 let text = s.split("\r\n\r\n").skip(1).collect::<String>();
73 if text.is_empty() {
74 None
75 } else {
76 Some(text)
77 }
78}
79
80fn parse_headers(s: &str) -> Result<HashMap<String, String>, &'static str> {
81 let raw_header_section = s.split("\r\n\r\n").next().unwrap_or_default();
84
85 let raw_headers = raw_header_section.split("\r\n").skip(1).collect::<Vec<_>>();
88 let mut map = HashMap::new();
89
90 for header in raw_headers {
91 let sections = header.split(':').collect::<Vec<_>>();
92 let field_name = sections.get(0);
93 let field_value = sections.get(1);
94
95 field_name
98 .and(field_value)
99 .ok_or("Error while parsing request headers")?;
100
101 if let Some(field_name) = field_name {
102 if field_name
105 .chars()
106 .last()
107 .filter(|c| c.is_whitespace())
108 .is_some()
109 {
110 return Err("No whitespace is allowed between the header field-name and colon");
111 }
112
113 if let Some(field_value) = field_value {
114 map.insert(
115 field_name.split_whitespace().collect(),
116 field_value.split_whitespace().collect(),
117 );
118 }
119 }
120 }
121
122 Ok(map)
123}
124
125#[derive(Debug, PartialEq)]
127pub struct Response {
128 pub stream: String,
129 pub headers: Vec<String>,
130 pub(crate) status: u16,
131}
132
133impl Default for Response {
134 fn default() -> Self {
135 Response::new()
136 }
137}
138
139impl Response {
140 pub fn new() -> Self {
141 Self {
142 stream: String::new(),
143 headers: Vec::new(),
144 status: 200,
145 }
146 }
147
148 pub fn send(&mut self, s: String) {
150 self.stream.push_str(&s);
151 }
152
153 pub fn status(&mut self, status: u16) -> &mut Self {
167 self.status = status;
168 self
169 }
170}