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> { 28 pub(crate) fn new(part: &'a mut Request<T>) -> Self { 29 Self { part } 30 } 31 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 { 61 pub(crate) fn new() -> Self { 62 Self 63 } 64 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> { 121 pub(crate) fn new(req_method: &'a Method, part: &'a ResponsePart) -> Self { 122 Self { req_method, part } 123 } 124 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 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_formatnull228 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_formatnull253 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_parsernull271 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_valuenull320 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