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