• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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