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