1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 use ylong_http::request::method::Method;
15 use ylong_http::request::uri::{Scheme, Uri};
16 use ylong_http::request::Request;
17 use ylong_http::response::status::StatusCode;
18 use ylong_http::response::ResponsePart;
19 use ylong_http::version::Version;
20
21 use crate::error::{ErrorKind, HttpClientError};
22
23 pub(crate) struct RequestFormatter<'a, T> {
24 part: &'a mut Request<T>,
25 }
26
27 impl<'a, T> RequestFormatter<'a, T> {
new(part: &'a mut Request<T>) -> Self28 pub(crate) fn new(part: &'a mut Request<T>) -> Self {
29 Self { part }
30 }
31
format(&mut self) -> Result<(), HttpClientError>32 pub(crate) fn format(&mut self) -> Result<(), HttpClientError> {
33 if Version::HTTP1_0 == *self.part.version() && Method::CONNECT == *self.part.method() {
34 return Err(HttpClientError::from_str(
35 ErrorKind::Request,
36 "Unknown METHOD in HTTP/1.0",
37 ));
38 }
39 // TODO Formatting the uri in the request doesn't seem necessary.
40 let uri_formatter = UriFormatter::new();
41 uri_formatter.format(self.part.uri_mut())?;
42
43 let host_value = format_host_value(self.part.uri())?;
44
45 if self.part.headers_mut().get("Accept").is_none() {
46 let _ = self.part.headers_mut().insert("Accept", "*/*");
47 }
48
49 let _ = self
50 .part
51 .headers_mut()
52 .insert("Host", host_value.as_bytes());
53
54 Ok(())
55 }
56 }
57
58 pub(crate) struct UriFormatter;
59
60 impl UriFormatter {
new() -> Self61 pub(crate) fn new() -> Self {
62 Self
63 }
64
format(&self, uri: &mut Uri) -> Result<(), HttpClientError>65 pub(crate) fn format(&self, uri: &mut Uri) -> Result<(), HttpClientError> {
66 let host = match uri.host() {
67 Some(host) => host.clone(),
68 None => return err_from_msg!(Request, "No host in url"),
69 };
70
71 #[cfg(feature = "__tls")]
72 let mut scheme = Scheme::HTTPS;
73
74 #[cfg(not(feature = "__tls"))]
75 let mut scheme = Scheme::HTTP;
76
77 if let Some(req_scheme) = uri.scheme() {
78 scheme = req_scheme.clone()
79 };
80
81 let port;
82
83 if let Some(req_port) = uri.port().and_then(|port| port.as_u16().ok()) {
84 port = req_port;
85 } else {
86 match scheme {
87 Scheme::HTTPS => port = 443,
88 Scheme::HTTP => port = 80,
89 }
90 }
91
92 let mut new_uri = Uri::builder();
93 new_uri = new_uri.scheme(scheme);
94 new_uri = new_uri.authority(format!("{}:{}", host.as_str(), port).as_bytes());
95
96 match uri.path() {
97 None => new_uri = new_uri.path("/"),
98 Some(path) => {
99 new_uri = new_uri.path(path.clone());
100 }
101 }
102
103 if let Some(query) = uri.query() {
104 new_uri = new_uri.query(query.clone());
105 }
106
107 *uri = new_uri
108 .build()
109 .map_err(|_| HttpClientError::from_str(ErrorKind::Request, "Normalize url failed"))?;
110
111 Ok(())
112 }
113 }
114
115 pub(crate) struct BodyLengthParser<'a> {
116 req_method: &'a Method,
117 part: &'a ResponsePart,
118 }
119
120 impl<'a> BodyLengthParser<'a> {
new(req_method: &'a Method, part: &'a ResponsePart) -> Self121 pub(crate) fn new(req_method: &'a Method, part: &'a ResponsePart) -> Self {
122 Self { req_method, part }
123 }
124
parse(&self) -> Result<BodyLength, HttpClientError>125 pub(crate) fn parse(&self) -> Result<BodyLength, HttpClientError> {
126 if self.part.status.is_informational()
127 || self.part.status == StatusCode::NO_CONTENT
128 || self.part.status == StatusCode::NOT_MODIFIED
129 {
130 return Ok(BodyLength::Empty);
131 }
132
133 if (self.req_method == &Method::CONNECT && self.part.status.is_successful())
134 || self.req_method == &Method::HEAD
135 {
136 return Ok(BodyLength::Empty);
137 }
138
139 #[cfg(feature = "http1_1")]
140 {
141 let transfer_encoding = self.part.headers.get("Transfer-Encoding");
142
143 if transfer_encoding.is_some() {
144 if self.part.version == Version::HTTP1_0 {
145 return err_from_msg!(Request, "Illegal Transfer-Encoding in HTTP/1.0");
146 }
147 let transfer_encoding_contains_chunk = transfer_encoding
148 .and_then(|v| v.to_string().ok())
149 .and_then(|str| str.find("chunked"))
150 .is_some();
151
152 return if transfer_encoding_contains_chunk {
153 Ok(BodyLength::Chunk)
154 } else {
155 Ok(BodyLength::UntilClose)
156 };
157 }
158 }
159
160 let content_length = self.part.headers.get("Content-Length");
161
162 if content_length.is_some() {
163 let content_length_valid = content_length
164 .and_then(|v| v.to_string().ok())
165 .and_then(|s| s.parse::<u64>().ok());
166
167 return match content_length_valid {
168 // If `content-length` is 0, the io stream cannot be read,
169 // otherwise it will get stuck.
170 Some(0) => Ok(BodyLength::Empty),
171 Some(len) => Ok(BodyLength::Length(len)),
172 None => err_from_msg!(Request, "Invalid response content-length"),
173 };
174 }
175
176 Ok(BodyLength::UntilClose)
177 }
178 }
179 #[derive(PartialEq, Debug)]
180 pub(crate) enum BodyLength {
181 #[cfg(feature = "http1_1")]
182 Chunk,
183 Length(u64),
184 Empty,
185 UntilClose,
186 }
187
format_host_value(uri: &Uri) -> Result<String, HttpClientError>188 pub(crate) fn format_host_value(uri: &Uri) -> Result<String, HttpClientError> {
189 let host_value = match (uri.host(), uri.port()) {
190 (Some(host), Some(port)) => {
191 if port
192 .as_u16()
193 .map_err(|e| HttpClientError::from_error(ErrorKind::Request, e))?
194 == uri.scheme().unwrap_or(&Scheme::HTTP).default_port()
195 {
196 host.to_string()
197 } else {
198 uri.authority().unwrap().to_str()
199 }
200 }
201 (Some(host), None) => host.to_string(),
202 (None, _) => {
203 return err_from_msg!(Request, "Request Uri lack host");
204 }
205 };
206 Ok(host_value)
207 }
208
209 #[cfg(test)]
210 mod ut_normalizer {
211 use ylong_http::h1::ResponseDecoder;
212 use ylong_http::request::method::Method;
213 use ylong_http::request::uri::{Uri, UriBuilder};
214 use ylong_http::request::Request;
215
216 use crate::normalizer::UriFormatter;
217 use crate::util::normalizer::{
218 format_host_value, BodyLength, BodyLengthParser, RequestFormatter,
219 };
220
221 /// UT test cases for `UriFormatter::format`.
222 ///
223 /// # Brief
224 /// 1. Creates a `UriFormatter`.
225 /// 2. Calls `UriFormatter::format` with `Uri` to get the result.
226 /// 3. Checks if the uri port result is correct.
227 #[test]
ut_uri_format()228 fn ut_uri_format() {
229 let mut uri = UriBuilder::new()
230 .scheme("http")
231 .authority("example.com")
232 .path("/foo")
233 .query("a=1")
234 .build()
235 .unwrap();
236 let uni = UriFormatter::new();
237 let _ = uni.format(&mut uri);
238 assert_eq!(uri.port().unwrap().as_str(), "80");
239
240 let mut uri = Uri::from_bytes(b"http://example.com").unwrap();
241 let uni = UriFormatter::new();
242 let _ = uni.format(&mut uri);
243 assert_eq!(uri.path().unwrap().as_str(), "/");
244 }
245
246 /// UT test cases for `RequestFormatter::normalize`.
247 ///
248 /// # Brief
249 /// 1. Creates a `RequestFormatter`.
250 /// 2. Calls `UriFormatter::normalize` to get the result.
251 /// 3. Checks if the request's header result is correct.
252 #[test]
ut_request_format()253 fn ut_request_format() {
254 let mut request = Request::new("this is a body");
255 let request_uri = request.uri_mut();
256 *request_uri = Uri::from_bytes(b"http://example1.com").unwrap();
257 let mut formatter = RequestFormatter::new(&mut request);
258 let _ = formatter.format();
259 let (part, _) = request.into_parts();
260 let res = part.headers.get("Host").unwrap();
261 assert_eq!(res.to_string().unwrap().as_bytes(), b"example1.com");
262 }
263
264 /// UT test cases for `BodyLengthParser::parse`.
265 ///
266 /// # Brief
267 /// 1. Creates a `BodyLengthParser`.
268 /// 2. Calls `BodyLengthParser::parse` to get the result.
269 /// 3. Checks if the BodyLength result is correct.
270 #[test]
ut_body_length_parser()271 fn ut_body_length_parser() {
272 let response_str = "HTTP/1.1 202 \r\nAge: \t 270646 \t \t\r\nLocation: \t example3.com:80 \t \t\r\nDate: \t Mon, 19 Dec 2022 01:46:59 GMT \t \t\r\nEtag:\t \"3147526947+gzip\" \t \t\r\n\r\n".as_bytes();
273 let mut decoder = ResponseDecoder::new();
274 let result = decoder.decode(response_str).unwrap().unwrap();
275 let method = Method::GET;
276 let body_len_parser = BodyLengthParser::new(&method, &result.0);
277 let res = body_len_parser.parse().unwrap();
278 assert_eq!(res, BodyLength::UntilClose);
279
280 let response_str = "HTTP/1.1 202 \r\nTransfer-Encoding: \t chunked \t \t\r\nLocation: \t example3.com:80 \t \t\r\nDate: \t Mon, 19 Dec 2022 01:46:59 GMT \t \t\r\nEtag:\t \"3147526947+gzip\" \t \t\r\n\r\n".as_bytes();
281 let mut decoder = ResponseDecoder::new();
282 let result = decoder.decode(response_str).unwrap().unwrap();
283 let method = Method::GET;
284 let body_len_parser = BodyLengthParser::new(&method, &result.0);
285 let res = body_len_parser.parse().unwrap();
286 assert_eq!(res, BodyLength::Chunk);
287
288 let response_str = "HTTP/1.1 202 \r\nContent-Length: \t 20 \t \t\r\nLocation: \t example3.com:80 \t \t\r\nDate: \t Mon, 19 Dec 2022 01:46:59 GMT \t \t\r\nEtag:\t \"3147526947+gzip\" \t \t\r\n\r\n".as_bytes();
289 let mut decoder = ResponseDecoder::new();
290 let result = decoder.decode(response_str).unwrap().unwrap();
291 let method = Method::GET;
292 let body_len_parser = BodyLengthParser::new(&method, &result.0);
293 let res = body_len_parser.parse().unwrap();
294 assert_eq!(res, BodyLength::Length(20));
295
296 let response_str = "HTTP/1.0 202 \r\nTransfer-Encoding: \t chunked \t \t\r\nLocation: \t example3.com:80 \t \t\r\nDate: \t Mon, 19 Dec 2022 01:46:59 GMT \t \t\r\nEtag:\t \"3147526947+gzip\" \t \t\r\n\r\n".as_bytes();
297 let mut decoder = ResponseDecoder::new();
298 let result = decoder.decode(response_str).unwrap().unwrap();
299 let method = Method::GET;
300 let body_len_parser = BodyLengthParser::new(&method, &result.0);
301 let res = body_len_parser.parse();
302 assert!(res
303 .map_err(|e| {
304 assert_eq!(
305 format!("{e}"),
306 "Request Error: Illegal Transfer-Encoding in HTTP/1.0"
307 );
308 e
309 })
310 .is_err());
311 }
312
313 /// UT test cases for function `format_host_value`.
314 ///
315 /// # Brief
316 /// 1. Creates a uri by calling `Uri::from_bytes`.
317 /// 2. Calls `format_host_value` to get the formatted `Host Header` value.
318 /// 3. Checks whether the `Host Header` value is correct.
319 #[test]
ut_format_host_value()320 fn ut_format_host_value() {
321 let uri = Uri::from_bytes(b"https://www.example.com:80").expect("Uri parse failed");
322 assert_eq!(format_host_value(&uri).unwrap(), "www.example.com:80");
323 let uri = Uri::from_bytes(b"https://www.example.com:443").expect("Uri parse failed");
324 assert_eq!(format_host_value(&uri).unwrap(), "www.example.com");
325 let uri = Uri::from_bytes(b"http://www.example.com:80").expect("Uri parse failed");
326 assert_eq!(format_host_value(&uri).unwrap(), "www.example.com");
327 let uri = Uri::from_bytes(b"http://www.example.com:443").expect("Uri parse failed");
328 assert_eq!(format_host_value(&uri).unwrap(), "www.example.com:443");
329 let uri = Uri::from_bytes(b"www.example.com:443").expect("Uri parse failed");
330 assert_eq!(format_host_value(&uri).unwrap(), "www.example.com:443");
331 let uri = Uri::from_bytes(b"www.example.com:80").expect("Uri parse failed");
332 assert_eq!(format_host_value(&uri).unwrap(), "www.example.com");
333 let uri = Uri::from_bytes(b"www.example.com").expect("Uri parse failed");
334 assert_eq!(format_host_value(&uri).unwrap(), "www.example.com");
335 }
336 }
337