• 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::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         let uri_formatter = UriFormatter::new();
35         uri_formatter.format(self.part.uri_mut())?;
36 
37         let host_value = self.part.uri().authority().unwrap().to_str();
38 
39         if self.part.headers_mut().get("Accept").is_none() {
40             let _ = self.part.headers_mut().insert("Accept", "*/*");
41         }
42 
43         if self.part.headers_mut().get("Host").is_none() {
44             let _ = self
45                 .part
46                 .headers_mut()
47                 .insert("Host", host_value.as_bytes());
48         }
49 
50         Ok(())
51     }
52 }
53 
54 pub(crate) struct UriFormatter;
55 
56 impl UriFormatter {
new() -> Self57     pub(crate) fn new() -> Self {
58         Self
59     }
60 
format(&self, uri: &mut Uri) -> Result<(), HttpClientError>61     pub(crate) fn format(&self, uri: &mut Uri) -> Result<(), HttpClientError> {
62         let host = match uri.host() {
63             Some(host) => host.clone(),
64             None => {
65                 return Err(HttpClientError::new_with_message(
66                     ErrorKind::Request,
67                     "No host in url",
68                 ))
69             }
70         };
71 
72         #[cfg(feature = "__tls")]
73         let mut scheme = Scheme::HTTPS;
74 
75         #[cfg(not(feature = "__tls"))]
76         let mut scheme = Scheme::HTTP;
77 
78         if let Some(req_scheme) = uri.scheme() {
79             scheme = req_scheme.clone()
80         };
81 
82         let port;
83 
84         if let Some(req_port) = uri.port().and_then(|port| port.as_u16().ok()) {
85             port = req_port;
86         } else {
87             match scheme {
88                 Scheme::HTTPS => port = 443,
89                 Scheme::HTTP => port = 80,
90             }
91         }
92 
93         let mut new_uri = Uri::builder();
94         new_uri = new_uri.scheme(scheme);
95         new_uri = new_uri.authority(format!("{}:{}", host.as_str(), port).as_bytes());
96 
97         if let Some(path) = uri.path() {
98             new_uri = new_uri.path(path.clone());
99         }
100 
101         if let Some(query) = uri.query() {
102             new_uri = new_uri.query(query.clone());
103         }
104 
105         *uri = new_uri.build().map_err(|_| {
106             HttpClientError::new_with_message(ErrorKind::Request, "Normalize url failed")
107         })?;
108 
109         Ok(())
110     }
111 }
112 
113 pub(crate) struct BodyLengthParser<'a> {
114     req_method: &'a Method,
115     part: &'a ResponsePart,
116 }
117 
118 impl<'a> BodyLengthParser<'a> {
new(req_method: &'a Method, part: &'a ResponsePart) -> Self119     pub(crate) fn new(req_method: &'a Method, part: &'a ResponsePart) -> Self {
120         Self { req_method, part }
121     }
122 
parse(&self) -> Result<BodyLength, HttpClientError>123     pub(crate) fn parse(&self) -> Result<BodyLength, HttpClientError> {
124         if self.part.status.is_informational()
125             || self.part.status == StatusCode::NO_CONTENT
126             || self.part.status == StatusCode::NOT_MODIFIED
127         {
128             return Ok(BodyLength::Empty);
129         }
130 
131         if (self.req_method == &Method::CONNECT && self.part.status.is_successful())
132             || self.req_method == &Method::HEAD
133         {
134             return Ok(BodyLength::Empty);
135         }
136 
137         #[cfg(feature = "http1_1")]
138         {
139             let transfer_encoding = self.part.headers.get("Transfer-Encoding");
140 
141             if transfer_encoding.is_some() {
142                 let transfer_encoding_contains_chunk = transfer_encoding
143                     .and_then(|v| v.to_str().ok())
144                     .and_then(|str| str.find("chunked"))
145                     .is_some();
146 
147                 return if transfer_encoding_contains_chunk {
148                     Ok(BodyLength::Chunk)
149                 } else {
150                     Ok(BodyLength::UntilClose)
151                 };
152             }
153         }
154 
155         let content_length = self.part.headers.get("Content-Length");
156 
157         if content_length.is_some() {
158             let content_length_valid = content_length
159                 .and_then(|v| v.to_str().ok())
160                 .and_then(|s| s.parse::<usize>().ok());
161 
162             return match content_length_valid {
163                 // If `content-length` is 0, the io stream cannot be read,
164                 // otherwise it will get stuck.
165                 Some(0) => Ok(BodyLength::Empty),
166                 Some(len) => Ok(BodyLength::Length(len)),
167                 None => Err(HttpClientError::new_with_message(
168                     ErrorKind::Request,
169                     "Invalid response content-length",
170                 )),
171             };
172         }
173 
174         Ok(BodyLength::UntilClose)
175     }
176 }
177 
178 pub(crate) enum BodyLength {
179     #[cfg(feature = "http1_1")]
180     Chunk,
181     Length(usize),
182     Empty,
183     UntilClose,
184 }
185