1mod util;
2
3use http::Request;
4use http::Uri;
5
6pub fn request_from_bytes(buffer: &[u8]) -> Result<Request<&[u8]>, String> {
17 let buffer = util::normalize_buffer(buffer);
18 let parts = util::parse_first_line(buffer);
19 let (method, version, path, end) = match parts {
20 (Some(method), Some(version), Some(path), end) => (method, version, path, end),
21 _ => return Err(String::from("Error processing request line"))
22 };
23
24 let (headers, end) = match util::parse_headers(buffer, end) {
25 (Some(headers), end) => (headers, end),
26 _ => return Err(String::from("Error processig headers"))
27 };
28
29 let mut request = Request::builder()
30 .method(method)
31 .version(version);
32
33 let uri = Uri::builder()
34 .scheme("http")
35 .authority(headers.get("Host").unwrap().as_bytes())
36 .path_and_query(path).build();
37
38 let uri = match uri {
39 Ok(u) => u,
40 Err(err) => return Err(err.to_string())
41 };
42
43 for (name, value) in headers {
44 match name {
45 Some(name) => {
46 request = request.header(name, value);
47 },
48 None => return Err(String::from("Error processing header"))
49 }
50 };
51
52 let body = util::parse_body(buffer, end);
53
54 match request.uri(uri).body::<&[u8]>(body) {
55 Ok(req) => Ok(req),
56 Err(_) => Err(String::from("Error building request body"))
57 }
58}
59
60pub fn request_from_str(buffer: &str) -> Result<Request<&[u8]>, String> {
63 request_from_bytes(buffer.as_bytes())
64}
65
66#[cfg(test)]
67mod tests {
68
69 use http::Version;
70
71 #[test]
72 fn parse_request() {
73 let example_request = b"GET /bora/is HTTP/1.1\r\n\
74 Host:www.bora-is-awesome.com\r\n\
75 Content-Type:text/plain\r\n\r\nbora is awesome";
76 let request = super::request_from_bytes(example_request).unwrap();
77
78 assert_eq!(request.method().as_str(), "GET");
79 assert_eq!(request.uri().path(), "/bora/is");
80 assert_eq!(request.version(), Version::HTTP_11);
81 assert_eq!(request.headers().get("host").unwrap(), &"www.bora-is-awesome.com");
82 assert_eq!(request.headers().get("content-type").unwrap(), &"text/plain");
83 assert_eq!(request.body(), b"bora is awesome");
84 }
85
86 #[test]
87 fn parse_null_terminated_request() {
88 let example_request = b"GET / HTTP/1.1\r\n\
89 User-Agent: PostmanRuntime/7.26.1\r\n\
90 Accept: */*\r\n\
91 Postman-Token: 048859cd-7a99-470b-a48f-29004152bd5c\r\n\
92 Host: localhost:7878\r\n\
93 Accept-Encoding: gzip, deflate, br\r\n\
94 Connection: keep-alive\r\n\r\nBora is awesome";
95
96 let mut big_buffer = [0u8; 1024];
97 for (index, byte) in example_request.iter().enumerate() {
98 big_buffer[index] = *byte;
99 }
100
101 let request = super::request_from_bytes(&big_buffer).unwrap();
102
103 assert_eq!(request.method().as_str(), "GET");
104 assert_eq!(request.uri().path(), "/");
105 assert_eq!(request.version(), Version::HTTP_11);
106 assert_eq!(request.headers().get("host").unwrap(), &"localhost:7878");
107 assert_eq!(request.headers().get("Accept-Encoding").unwrap(), &"gzip, deflate, br");
108 assert_eq!(request.body(), b"Bora is awesome");
109 }
110}