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