1use std::collections::HashMap;
2#[derive(PartialEq, Debug)]
3pub enum Resource{
4 Path(String)
5}
6
7#[derive(PartialEq, Debug)]
8pub struct HttpRequest{
9 pub method: Method,
10 pub version: Version,
11 pub resource: Resource,
12 pub headers: HashMap<String, String>,
13 pub msg_body: String,
14}
15impl From<String> for HttpRequest{
16 fn from(req:String) -> Self
17 {
18 let mut parsed_method = Method::Uninitialized;
19 let mut parsed_version = Version::V1_1;
20 let mut parsed_resource = Resource::Path("".to_string());
21 let mut parsed_headers = HashMap::new();
22 let mut parsed_msg_body = "";
23
24 for line in req.lines()
25 {
26 if line.contains("HTTP")
27 {
28 let (method, resource, version) = process_req_line(line);
29 parsed_method = method;
30 parsed_resource = resource;
31 parsed_version = version;
32 }
33 else if line.contains(":")
34 {
35 let (key, value) = process_req_header(line);
36 parsed_headers.insert(key, value);
37 }
38 else if line.len() == 0
39 {
40
41 }
42 else{
43 parsed_msg_body = line;
44 }
45
46 }
47 HttpRequest{
48 method: parsed_method,
49 version: parsed_version,
50 resource: parsed_resource,
51 headers: parsed_headers,
52 msg_body: parsed_msg_body.to_string(),
53 }
54 }
55}
56
57fn process_req_line(s: &str) ->(Method, Resource, Version)
58{
59 let mut word = s.split_whitespace();
60 let method = word.next().unwrap();
61 let resource = word.next().unwrap();
62 let version = word.next().unwrap();
63 (
64 method.into(),
65 Resource::Path(resource.to_string()),
66 version.into()
67 )
68}
69
70fn process_req_header(s: &str) -> (String, String)
71{
72 let mut header_items = s.split(":");
73 let mut key = String::from("");
74 let mut value = String::from("");
75
76 if let Some(k) = header_items.next(){
77 key = k.to_string();
78 }
79
80 if let Some(v) = header_items.next()
81 {
82 value = v.to_string();
83 }
84 (key, value)
85}
86
87#[derive(PartialEq)]
88#[derive(Debug)]
89pub enum Method{
90 Get,
91 Post,
92 Uninitialized
93}
94impl From<&str> for Method{
95 fn from(s: &str) -> Method{
96 match s {
97 "GET" => Method::Get,
98 "POST" => Method::Post,
99 _ => Method::Uninitialized,
100 }
101 }
102}
103
104
105#[derive(PartialEq, Debug)]
106pub enum Version{
107 V1_1,
108 V2_0,
109 Uninitialized,
110}
111impl From<&str> for Version{
112 fn from(s: &str) -> Version{
113 match s{
114 "HTTP/1.1" => Version::V1_1,
115 _ => Version::Uninitialized,
116 }
117 }
118}
119
120
121#[cfg(test)]
122
123mod tests{
124 use super::*;
125 #[test]
126 fn test_method_into()
127 {
128 let m: Method = "GET".into();
129 assert_eq!(m, Method::Get);
130 }
131 #[test]
132 fn test_version_into()
133 {
134 let m:Version = "HTTP/1.1".into();
135 assert_eq!(m, Version::V1_1);
136 }
137 #[test]
138 fn test_incoming_http_request()
139 {
140 let s: String = String::from("GET /greeting HTTP/1.1\r\nHost: localhost:3000\r\nUser-Agent: curl/7.64.1\r\nAccept: */*\r\n\r\n");
141 let mut headers_expected = HashMap::new();
142 headers_expected.insert("Host".into(), " localhost".into());
143 headers_expected.insert("Accept".into(), " */*".into());
144 headers_expected.insert("User-Agent".into(), " curl/7.64.1".into());
145 let req: HttpRequest = s.into();
146 assert_eq!(Method::Get, req.method);
147 assert_eq!(Version::V1_1, req.version);
148 assert_eq!(Resource::Path("/greeting".to_string()), req.resource);
149 assert_eq!(headers_expected, req.headers);
150 }
151}