stream_httparse/
request.rs1use crate::{general::StringContainer, header::HeaderValue, Headers, Method};
2
3#[derive(Debug)]
4enum BodyData<'a> {
5 Ref(&'a [u8]),
6 Owned(Vec<u8>),
7}
8
9impl<'a> AsRef<[u8]> for BodyData<'a> {
10 fn as_ref(&self) -> &[u8] {
11 match self {
12 Self::Ref(tmp) => tmp,
13 Self::Owned(tmp) => tmp.as_ref(),
14 }
15 }
16}
17
18impl<'a> PartialEq for BodyData<'a> {
19 fn eq(&self, other: &Self) -> bool {
20 self.as_ref().eq(other.as_ref())
21 }
22}
23
24#[derive(Debug, PartialEq)]
26pub struct Request<'a> {
27 method: Method,
28 path: StringContainer<'a>,
29 protocol: &'a str,
30 headers: Headers<'a>,
31 body: BodyData<'a>,
32}
33
34impl<'a> Request<'a> {
35 pub fn new(
38 protocol: &'a str,
39 method: Method,
40 path: &'a str,
41 headers: Headers<'a>,
42 body: &'a [u8],
43 ) -> Self {
44 Self {
45 method,
46 path: StringContainer::Ref(path),
47 protocol,
48 headers,
49 body: BodyData::Ref(body),
50 }
51 }
52
53 pub fn serialize(&self) -> (Vec<u8>, &[u8]) {
56 let method = self.method.serialize();
57 let path = self.path.as_ref();
58 let capacity = method.len() + 1 + path.len() + 1 + self.protocol.len() + 4;
59 let mut result = Vec::with_capacity(capacity);
60
61 result.extend_from_slice(method.as_bytes());
63 result.push(b' ');
64 result.extend_from_slice(path.as_bytes());
65 result.push(b' ');
66 result.extend_from_slice(self.protocol.as_bytes());
67 result.extend_from_slice("\r\n".as_bytes());
68
69 self.headers.serialize(&mut result);
71
72 result.extend_from_slice("\r\n".as_bytes());
74
75 (result, self.body.as_ref())
76 }
77
78 pub fn protocol(&self) -> &'a str {
80 &self.protocol
81 }
82 pub fn method(&self) -> &Method {
84 &self.method
85 }
86 pub fn path(&'a self) -> &'a str {
88 self.path.as_ref()
89 }
90 pub fn headers(&self) -> &Headers<'a> {
92 &self.headers
93 }
94 pub fn header_mut(&mut self) -> &mut Headers<'a> {
96 &mut self.headers
97 }
98 pub fn body(&self) -> &[u8] {
100 self.body.as_ref()
101 }
102
103 pub fn is_keep_alive(&self) -> bool {
106 match self.headers.get("Connection") {
107 None => false,
108 Some(value) => value.eq_ignore_case(&HeaderValue::StrRef("Keep-Alive")),
109 }
110 }
111
112 pub fn set_path_ref<'b>(&mut self, n_path: &'b str)
114 where
115 'b: 'a,
116 {
117 self.path = StringContainer::Ref(n_path);
118 }
119 pub fn set_path_owned(&mut self, n_path: String) {
122 self.path = StringContainer::Owned(n_path);
123 }
124
125 pub fn set_body(&mut self, data: Vec<u8>) {
127 self.body = BodyData::Owned(data);
128 }
129}
130
131impl std::fmt::Display for Request<'_> {
132 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133 write!(f, "[{}] Path: '{}'", self.method, self.path.as_ref())
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn update_path_to_own() {
143 let mut req = Request::new("HTTP/1.1", Method::GET, "/test/path", Headers::new(), &[]);
144
145 let path = req.path().to_owned();
146 req.set_path_ref(&path[1..]);
147
148 assert_eq!("test/path", req.path());
149 }
150
151 #[test]
152 fn serialize_valid() {
153 let mut headers = Headers::new();
154 headers.set("test-1", "value-1");
155
156 let req = Request::new("HTTP/1.1", Method::GET, "/test", headers, "body".as_bytes());
157 let raw_header = "GET /test HTTP/1.1\r\ntest-1: value-1\r\n\r\n";
158 let header_resp = raw_header.as_bytes().to_vec();
159 let body_resp = "body".as_bytes();
160
161 assert_eq!(req.serialize(), (header_resp, body_resp));
162 }
163 #[test]
164 fn serialize_valid_no_body() {
165 let mut headers = Headers::new();
166 headers.set("test-1", "value-1");
167
168 let req = Request::new("HTTP/1.1", Method::GET, "/test", headers, "".as_bytes());
169 let raw_header = "GET /test HTTP/1.1\r\ntest-1: value-1\r\n\r\n";
170 let resp_header = raw_header.as_bytes().to_vec();
171 let resp_body = "".as_bytes();
172
173 assert_eq!(req.serialize(), (resp_header, resp_body));
174 }
175
176 #[test]
177 fn is_keep_alive_not_set() {
178 let mut headers = Headers::new();
179 headers.set("test-1", "value-1");
180
181 let req = Request::new("HTTP/1.1", Method::GET, "/test", headers, "".as_bytes());
182
183 assert_eq!(false, req.is_keep_alive());
184 }
185 #[test]
186 fn is_keep_alive_is_set() {
187 let mut headers = Headers::new();
188 headers.set("Connection", "Keep-Alive");
189
190 let req = Request::new("HTTP/1.1", Method::GET, "/test", headers, "".as_bytes());
191
192 assert_eq!(true, req.is_keep_alive());
193 }
194 #[test]
195 fn is_keep_alive_is_set_to_off() {
196 let mut headers = Headers::new();
197 headers.set("Connection", "Close");
198
199 let req = Request::new("HTTP/1.1", Method::GET, "/test", headers, "".as_bytes());
200
201 assert_eq!(false, req.is_keep_alive());
202 }
203}