Skip to main content

http_request/request/http_request/
impl.rs

1use super::*;
2
3impl<T: AsyncRead + AsyncWrite + Unpin + Send> AsyncReadWrite for T {}
4impl<T: Read + Write> ReadWrite for T {}
5
6impl HttpRequest {
7    /// Send the HTTP request synchronously, returning the parsed response.
8    ///
9    /// # Returns
10    ///
11    /// - `RequestResult` - The parsed HTTP response, or a `RequestError` on failure.
12    pub fn send(&mut self) -> RequestResult {
13        self.send_sync()
14    }
15
16    /// Send the HTTP request asynchronously, returning the parsed response.
17    ///
18    /// # Returns
19    ///
20    /// - `RequestResult` - The parsed HTTP response, or a `RequestError` on failure.
21    pub async fn send_async(&mut self) -> RequestResult {
22        self.send_async_impl().await
23    }
24
25    /// Parse the configured URL into a [`HttpUrlComponents`].
26    ///
27    /// # Returns
28    ///
29    /// - `Result<HttpUrlComponents, RequestError>` - The parsed URL components, or a `RequestError` when the URL is malformed.
30    pub(crate) fn parse_url(&self) -> Result<HttpUrlComponents, RequestError> {
31        HttpUrlComponents::parse(self.get_url())
32            .map_err(|e: ::http_type::HttpUrlError| RequestError::Request(e.to_string()))
33    }
34
35    /// `Host` + path (including query string) for the request line.
36    ///
37    /// # Returns
38    ///
39    /// - `String` - The request path, with the query string appended when present.
40    pub(crate) fn full_path(&self) -> String {
41        let url_obj: HttpUrlComponents = self.parse_url().unwrap_or_default();
42        let query: String = url_obj.get_query().unwrap_or_default();
43        let path: String = url_obj.get_path().unwrap_or_default();
44        if query.is_empty() {
45            path
46        } else {
47            format!("{}{}{}", path, QUERY, query)
48        }
49    }
50
51    /// Lower-case the protocol ("http" / "https").
52    ///
53    /// # Arguments
54    ///
55    /// - `&RequestConfig` - The configuration whose HTTP version is lower-cased.
56    ///
57    /// # Returns
58    ///
59    /// - `String` - The lower-cased protocol name.
60    pub(crate) fn protocol_lower(config: &RequestConfig) -> String {
61        config.get_http_version().to_string().to_ascii_lowercase()
62    }
63
64    /// Build the wire-format header bytes, with `Host`, `Content-Length`,
65    /// `Accept`, `User-Agent` auto-filled if missing.
66    ///
67    /// # Arguments
68    ///
69    /// - `usize` - The length of the encoded request body.
70    ///
71    /// # Returns
72    ///
73    /// - `Vec<u8>` - The wire-format request header bytes.
74    pub(crate) fn header_bytes(&self, body_length: usize) -> Vec<u8> {
75        let mut header: HashMap<String, String> = self.get_headers().clone();
76        let host_value: String = self
77            .parse_url()
78            .ok()
79            .and_then(|u: ::http_type::HttpUrlComponents| u.get_host().clone())
80            .unwrap_or_default();
81        let content_length_value: String = body_length.to_string();
82        if !Self::header_has_key(&header, HOST) {
83            header.insert(HOST.to_ascii_lowercase(), host_value);
84        }
85        if !Self::header_has_key(&header, CONTENT_LENGTH) {
86            header.insert(CONTENT_LENGTH.to_ascii_lowercase(), content_length_value);
87        }
88        if !Self::header_has_key(&header, ACCEPT) {
89            header.insert(ACCEPT.to_ascii_lowercase(), ACCEPT_ANY.to_owned());
90        }
91        if !Self::header_has_key(&header, USER_AGENT) {
92            header.insert(USER_AGENT.to_ascii_lowercase(), APP_NAME.to_owned());
93        }
94        let estimated_size: usize = header
95            .iter()
96            .map(|(k, v): (&String, &String)| k.len() + v.len() + 4)
97            .sum();
98        let mut out: Vec<u8> = Vec::with_capacity(estimated_size);
99        for (key, value) in &header {
100            out.extend_from_slice(key.as_bytes());
101            out.extend_from_slice(HEADER_VALUE_SEPARATOR);
102            out.extend_from_slice(value.as_bytes());
103            out.extend_from_slice(HTTP_BR_BYTES);
104        }
105        out
106    }
107
108    /// Check whether a header map already contains a key, comparing case-insensitively.
109    ///
110    /// # Arguments
111    ///
112    /// - `&HashMap<String, String>` - The header map to search.
113    /// - `&str` - The header key to look for.
114    ///
115    /// # Returns
116    ///
117    /// - `bool` - `true` when the map contains the key, `false` otherwise.
118    fn header_has_key(header: &HashMap<String, String>, target_key: &str) -> bool {
119        let target: String = target_key.to_ascii_lowercase();
120        header.keys().any(|k: &String| k == &target)
121    }
122
123    /// Encode `self.body` according to the `Content-Type` header.
124    /// Returns empty bytes if no recognised content type.
125    ///
126    /// # Returns
127    ///
128    /// - `Vec<u8>` - The encoded request body, empty when the content type is unrecognised.
129    pub(crate) fn body_bytes(&self) -> Vec<u8> {
130        let ct: Option<String> = self
131            .headers
132            .iter()
133            .find(|(k, _): &(&String, &String)| k.eq_ignore_ascii_case(CONTENT_TYPE))
134            .map(|(_, v): (&String, &String)| v.clone());
135        match ct {
136            Some(value) => value
137                .to_lowercase()
138                .parse::<ContentType>()
139                .unwrap_or_default()
140                .get_body_string(&String::from_utf8_lossy(self.get_body().as_slice()))
141                .into_bytes(),
142            None => Vec::new(),
143        }
144    }
145
146    /// Synchronous send.
147    ///
148    /// # Returns
149    ///
150    /// - `RequestResult` - The parsed HTTP response, or a `RequestError` on failure.
151    pub(crate) fn send_sync(&mut self) -> RequestResult {
152        let url_obj: HttpUrlComponents = self.parse_url()?;
153        let host: String = url_obj.get_host().clone().unwrap_or_default();
154        let port: u16 = self.resolve_port(url_obj.get_port().unwrap_or_default());
155        let mut stream: BoxReadWrite = self.open_sync_stream(host, port)?;
156        let method: Method = self.get_method();
157        if method.is_get() {
158            self.send_get_request_sync(&mut stream)
159        } else if method.is_post() {
160            self.send_post_request_sync(&mut stream)
161        } else {
162            Err(RequestError::Request(METHOD_NOT_ALLOWED.to_string()))
163        }
164    }
165
166    /// Asynchronous send.
167    ///
168    /// # Returns
169    ///
170    /// - `RequestResult` - The parsed HTTP response, or a `RequestError` on failure.
171    async fn send_async_impl(&mut self) -> RequestResult {
172        let url_obj: HttpUrlComponents = self.parse_url()?;
173        let host: String = url_obj.get_host().clone().unwrap_or_default();
174        let port: u16 = self.resolve_port(url_obj.get_port().unwrap_or_default());
175        let mut stream: BoxAsyncReadWrite = self.open_async_stream(host, port).await?;
176        let method: Method = self.get_method();
177        if method.is_get() {
178            self.send_get_request_async(&mut stream).await
179        } else if method.is_post() {
180            self.send_post_request_async(&mut stream).await
181        } else {
182            Err(RequestError::Request(METHOD_NOT_ALLOWED.to_string()))
183        }
184    }
185
186    /// Resolve the effective TCP port, falling back to the protocol default.
187    ///
188    /// # Arguments
189    ///
190    /// - `u16` - The port parsed from the URL, `0` when the URL omits one.
191    ///
192    /// # Returns
193    ///
194    /// - `u16` - The port from the URL, or the protocol default when it is `0`.
195    fn resolve_port(&self, port: u16) -> u16 {
196        if port != 0 {
197            return port;
198        }
199        let protocol: String = Self::protocol_lower(self.get_config());
200        Protocol::get_port(&protocol)
201    }
202
203    /// Check whether the request uses the HTTPS protocol.
204    ///
205    /// # Returns
206    ///
207    /// - `bool` - `true` when the configured protocol is `https`, `false` otherwise.
208    fn is_https(&self) -> bool {
209        Self::protocol_lower(self.get_config()) == HTTPS_LOWERCASE
210    }
211
212    // ---------- sync stream plumbing ----------
213
214    /// Open a synchronous stream to the target host, directly or through a proxy.
215    ///
216    /// # Arguments
217    ///
218    /// - `String` - The target host name or IP address.
219    /// - `u16` - The target TCP port.
220    ///
221    /// # Returns
222    ///
223    /// - `Result<BoxReadWrite, RequestError>` - The connected stream, TLS-wrapped for HTTPS, or a `RequestError` on failure.
224    fn open_sync_stream(&self, host: String, port: u16) -> Result<BoxReadWrite, RequestError> {
225        if let Some(proxy) = &self.get_config().get_proxy() {
226            return self.open_sync_proxy_stream(host, port, proxy);
227        }
228        let timeout: Duration = Duration::from_millis(self.get_config().get_timeout());
229        let tcp: TcpStream = TcpStream::connect((host.clone(), port))
230            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
231        tcp.set_read_timeout(Some(timeout))
232            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
233        tcp.set_write_timeout(Some(timeout))
234            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
235        if self.is_https() {
236            let roots: RootCertStore = self.get_tmp().get_root_cert().clone();
237            let tls_cfg: ClientConfig = ClientConfig::builder()
238                .with_root_certificates(roots)
239                .with_no_client_auth();
240            let dns: ServerName<'static> = ServerName::try_from(host.clone())
241                .map_err(|e: InvalidDnsNameError| RequestError::Request(e.to_string()))?;
242            let session: ClientConnection = ClientConnection::new(Arc::new(tls_cfg), dns)
243                .map_err(|e: rustls::Error| RequestError::Request(e.to_string()))?;
244            Ok(Box::new(StreamOwned::new(session, tcp)))
245        } else {
246            Ok(Box::new(tcp))
247        }
248    }
249
250    /// Write a GET request to the stream and read the response.
251    ///
252    /// # Arguments
253    ///
254    /// - `&mut BoxReadWrite` - The connected stream used to write the request and read the response.
255    ///
256    /// # Returns
257    ///
258    /// - `Result<HttpResponse, RequestError>` - The parsed response, or a `RequestError` on I/O or parse failure.
259    fn send_get_request_sync(
260        &mut self,
261        stream: &mut BoxReadWrite,
262    ) -> Result<HttpResponse, RequestError> {
263        let path: String = self.full_path();
264        let header_bytes: Vec<u8> = self.header_bytes(0);
265        let version: String = self.get_config().get_http_version().to_string();
266        let request: Vec<u8> = build_http_request("GET", path, header_bytes, None, version);
267        stream
268            .write_all(&request)
269            .and_then(|_: ()| stream.flush())
270            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
271        self.read_response_sync(stream)
272    }
273
274    /// Write a POST request with the encoded body to the stream and read the response.
275    ///
276    /// # Arguments
277    ///
278    /// - `&mut BoxReadWrite` - The connected stream used to write the request and read the response.
279    ///
280    /// # Returns
281    ///
282    /// - `Result<HttpResponse, RequestError>` - The parsed response, or a `RequestError` on I/O or parse failure.
283    fn send_post_request_sync(
284        &mut self,
285        stream: &mut BoxReadWrite,
286    ) -> Result<HttpResponse, RequestError> {
287        let body_bytes: Vec<u8> = self.body_bytes();
288        let path: String = self.full_path();
289        let header_bytes: Vec<u8> = self.header_bytes(body_bytes.len());
290        let version: String = self.get_config().get_http_version().to_string();
291        let request: Vec<u8> = build_http_request(
292            HTTP_METHOD_POST,
293            path,
294            header_bytes,
295            Some(body_bytes),
296            version,
297        );
298        stream
299            .write_all(&request)
300            .and_then(|_: ()| stream.flush())
301            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
302        self.read_response_sync(stream)
303    }
304
305    /// Read a full response from the stream, handling content-length and chunked bodies.
306    ///
307    /// # Arguments
308    ///
309    /// - `&mut BoxReadWrite` - The connected stream to read the response from.
310    ///
311    /// # Returns
312    ///
313    /// - `Result<HttpResponse, RequestError>` - The parsed response, or a `RequestError` on I/O or parse failure.
314    fn read_response_sync(
315        &mut self,
316        stream: &mut BoxReadWrite,
317    ) -> Result<HttpResponse, RequestError> {
318        let buffer_size: usize = self.get_config().buffer_size;
319        let mut buffer: Vec<u8> = vec![0u8; buffer_size];
320        let mut response_bytes: Vec<u8> = Vec::with_capacity(buffer_size.max(8192));
321        let mut headers_done: bool = false;
322        let mut content_length: usize = 0usize;
323        let mut redirect_url: Option<Vec<u8>> = None;
324        let mut headers_end_pos: usize = 0usize;
325        let mut is_chunked: bool = false;
326        let version_bytes: Vec<u8> = self
327            .config
328            .get_http_version()
329            .to_string()
330            .to_ascii_lowercase()
331            .into_bytes();
332        let location_key: Vec<u8> = format!("{}:", LOCATION.to_ascii_lowercase()).into_bytes();
333        loop {
334            let n: usize = stream
335                .read(&mut buffer)
336                .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
337            if n == 0 {
338                break;
339            }
340            let new_cap: usize =
341                calculate_buffer_capacity(&response_bytes, n, response_bytes.capacity());
342            if new_cap > 0 {
343                response_bytes.reserve(new_cap - response_bytes.capacity());
344            }
345            let old_len: usize = response_bytes.len();
346            response_bytes.extend_from_slice(&buffer[..n]);
347            if !headers_done {
348                let search_start: usize = old_len.saturating_sub(3);
349                if let Some(pos) = find_double_crlf(&response_bytes, search_start) {
350                    headers_done = true;
351                    headers_end_pos = pos + 4;
352                    parse_response_headers(
353                        &response_bytes[..headers_end_pos],
354                        &version_bytes,
355                        &location_key,
356                        &mut content_length,
357                        &mut redirect_url,
358                        &mut is_chunked,
359                    )?;
360                }
361            }
362            if headers_done {
363                if is_chunked {
364                    if Self::is_chunked_response_complete(&response_bytes[headers_end_pos..]) {
365                        break;
366                    }
367                } else if response_bytes.len() >= headers_end_pos + content_length {
368                    response_bytes.truncate(headers_end_pos + content_length);
369                    break;
370                }
371            }
372        }
373        if is_chunked {
374            let body_bytes: Vec<u8> = response_bytes[headers_end_pos..].to_vec();
375            let decoded: Vec<u8> = parse_chunked_body(&body_bytes);
376            response_bytes.truncate(headers_end_pos);
377            response_bytes.extend_from_slice(&decoded);
378        }
379        let mut response: HttpResponse = HttpResponse::from_bytes(&response_bytes);
380        if !self.get_config().get_redirect() || redirect_url.is_none() {
381            if self.get_config().get_decode() {
382                response = response.decode(self.get_config().buffer_size);
383            }
384            return Ok(response);
385        }
386        let url_bytes: Vec<u8> = redirect_url
387            .take()
388            .ok_or_else(|| RequestError::Request(MISSING_REDIRECT_URL.to_string()))?;
389        let url: String = String::from_utf8(url_bytes)
390            .map_err(|e: FromUtf8Error| RequestError::Request(e.to_string()))?;
391        self.handle_redirect(url)
392    }
393
394    /// Follow a redirect by recording the visit and re-issuing the request.
395    ///
396    /// # Arguments
397    ///
398    /// - `String` - The absolute redirect target URL taken from the `Location` header.
399    ///
400    /// # Returns
401    ///
402    /// - `Result<HttpResponse, RequestError>` - The response of the redirect target, or a `RequestError` when redirects are disabled, looping, or exhausted.
403    fn handle_redirect(&mut self, url: String) -> Result<HttpResponse, RequestError> {
404        if !self.get_config().get_redirect() {
405            return Err(RequestError::Request(REDIRECT_NOT_ENABLED.to_string()));
406        }
407        if self.get_tmp().get_visit_url().contains(&url) {
408            return Err(RequestError::Request(REDIRECT_URL_DEAD_LOOP.to_string()));
409        }
410        self.get_mut_tmp().get_mut_visit_url().insert(url.clone());
411        if self.get_config().get_max_redirect_times() == 0 {
412            return Err(RequestError::Request(
413                MAX_REDIRECT_TIMES_EXCEEDED.to_string(),
414            ));
415        }
416        let remaining: usize = self.get_config().get_max_redirect_times();
417        self.get_mut_config()
418            .set_max_redirect_times(remaining.saturating_sub(1));
419        self.set_url(url);
420        self.send_sync()
421    }
422
423    /// Check whether a chunked response body has received its terminating zero-length chunk.
424    ///
425    /// # Arguments
426    ///
427    /// - `&[u8]` - The raw chunked body bytes received so far.
428    ///
429    /// # Returns
430    ///
431    /// - `bool` - `true` when the terminating chunk is present, `false` while more bytes are needed.
432    fn is_chunked_response_complete(body_bytes: &[u8]) -> bool {
433        let mut pos: usize = 0;
434        while pos < body_bytes.len() {
435            let chunk_size_end: usize = match body_bytes[pos..]
436                .windows(2)
437                .position(|w: &[u8]| w == HTTP_CARRIAGE_RETURN_LINE_FEED)
438            {
439                Some(p) => pos + p,
440                None => return false,
441            };
442            let raw: &[u8] = &body_bytes[pos..chunk_size_end];
443            let chunk_size_str: &[u8] = match raw.iter().position(|&b: &u8| b == b';') {
444                Some(p) => &raw[..p],
445                None => raw,
446            };
447            let chunk_size: usize = match from_utf8(chunk_size_str) {
448                Ok(s) => match usize::from_str_radix(s.trim(), 16) {
449                    Ok(n) => n,
450                    Err(_) => return false,
451                },
452                Err(_) => return false,
453            };
454            if chunk_size == 0 {
455                return true;
456            }
457            let start: usize = chunk_size_end + 2;
458            let end: usize = start + chunk_size;
459            if end + 2 > body_bytes.len() {
460                return false;
461            }
462            pos = end + 2;
463        }
464        false
465    }
466
467    // ---------- async stream plumbing ----------
468
469    /// Open an asynchronous stream to the target host, directly or through a proxy.
470    ///
471    /// # Arguments
472    ///
473    /// - `String` - The target host name or IP address.
474    /// - `u16` - The target TCP port.
475    ///
476    /// # Returns
477    ///
478    /// - `Result<BoxAsyncReadWrite, RequestError>` - The connected stream, TLS-wrapped for HTTPS, or a `RequestError` on failure.
479    async fn open_async_stream(
480        &self,
481        host: String,
482        port: u16,
483    ) -> Result<BoxAsyncReadWrite, RequestError> {
484        if let Some(proxy) = &self.get_config().get_proxy() {
485            return self.open_async_proxy_stream(host, port, proxy).await;
486        }
487        let tcp: http_type::tokio::net::TcpStream =
488            http_type::tokio::net::TcpStream::connect((host.clone(), port))
489                .await
490                .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
491        if self.is_https() {
492            let roots: RootCertStore = self.get_tmp().get_root_cert().clone();
493            let tls_cfg: ClientConfig = ClientConfig::builder()
494                .with_root_certificates(roots)
495                .with_no_client_auth();
496            let connector: TlsConnector = TlsConnector::from(Arc::new(tls_cfg));
497            let dns: ServerName<'static> = ServerName::try_from(host.clone())
498                .map_err(|e: InvalidDnsNameError| RequestError::Request(e.to_string()))?;
499            let tls: tokio_rustls::client::TlsStream<http_type::tokio::net::TcpStream> = connector
500                .connect(dns, tcp)
501                .await
502                .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
503            Ok(Box::new(tls))
504        } else {
505            Ok(Box::new(tcp))
506        }
507    }
508
509    /// Write a GET request to the stream and read the response.
510    ///
511    /// # Arguments
512    ///
513    /// - `&mut BoxAsyncReadWrite` - The connected stream used to write the request and read the response.
514    ///
515    /// # Returns
516    ///
517    /// - `Result<HttpResponse, RequestError>` - The parsed response, or a `RequestError` on I/O or parse failure.
518    async fn send_get_request_async(
519        &mut self,
520        stream: &mut BoxAsyncReadWrite,
521    ) -> Result<HttpResponse, RequestError> {
522        let path: String = self.full_path();
523        let header_bytes: Vec<u8> = self.header_bytes(0);
524        let version: String = self.get_config().get_http_version().to_string();
525        let request: Vec<u8> = build_http_request("GET", path, header_bytes, None, version);
526        stream
527            .write_all(&request)
528            .await
529            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
530        stream
531            .flush()
532            .await
533            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
534        self.read_response_async(stream).await
535    }
536
537    /// Write a POST request with the encoded body to the stream and read the response.
538    ///
539    /// # Arguments
540    ///
541    /// - `&mut BoxAsyncReadWrite` - The connected stream used to write the request and read the response.
542    ///
543    /// # Returns
544    ///
545    /// - `Result<HttpResponse, RequestError>` - The parsed response, or a `RequestError` on I/O or parse failure.
546    async fn send_post_request_async(
547        &mut self,
548        stream: &mut BoxAsyncReadWrite,
549    ) -> Result<HttpResponse, RequestError> {
550        let body_bytes: Vec<u8> = self.body_bytes();
551        let path: String = self.full_path();
552        let header_bytes: Vec<u8> = self.header_bytes(body_bytes.len());
553        let version: String = self.get_config().get_http_version().to_string();
554        let request: Vec<u8> = build_http_request(
555            HTTP_METHOD_POST,
556            path,
557            header_bytes,
558            Some(body_bytes),
559            version,
560        );
561        stream
562            .write_all(&request)
563            .await
564            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
565        stream
566            .flush()
567            .await
568            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
569        self.read_response_async(stream).await
570    }
571
572    /// Read a full response from the stream, handling content-length and chunked bodies.
573    ///
574    /// # Arguments
575    ///
576    /// - `&mut BoxAsyncReadWrite` - The connected stream to read the response from.
577    ///
578    /// # Returns
579    ///
580    /// - `Result<HttpResponse, RequestError>` - The parsed response, or a `RequestError` on I/O or parse failure.
581    async fn read_response_async(
582        &mut self,
583        stream: &mut BoxAsyncReadWrite,
584    ) -> Result<HttpResponse, RequestError> {
585        let buffer_size: usize = self.get_config().buffer_size;
586        let mut buffer: Vec<u8> = vec![0u8; buffer_size];
587        let mut response_bytes: Vec<u8> = Vec::with_capacity(buffer_size.max(8192));
588        let mut headers_done: bool = false;
589        let mut content_length: usize = 0usize;
590        let mut redirect_url: Option<Vec<u8>> = None;
591        let mut headers_end_pos: usize = 0usize;
592        let mut is_chunked: bool = false;
593        let version_bytes: Vec<u8> = self
594            .config
595            .get_http_version()
596            .to_string()
597            .to_ascii_lowercase()
598            .into_bytes();
599        let location_key: Vec<u8> = format!("{}:", LOCATION.to_ascii_lowercase()).into_bytes();
600        loop {
601            let n: usize = stream
602                .read(&mut buffer)
603                .await
604                .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
605            if n == 0 {
606                break;
607            }
608            let new_cap: usize =
609                calculate_buffer_capacity(&response_bytes, n, response_bytes.capacity());
610            if new_cap > 0 {
611                response_bytes.reserve(new_cap - response_bytes.capacity());
612            }
613            let old_len: usize = response_bytes.len();
614            response_bytes.extend_from_slice(&buffer[..n]);
615            if !headers_done {
616                let search_start: usize = old_len.saturating_sub(3);
617                if let Some(pos) = find_double_crlf(&response_bytes, search_start) {
618                    headers_done = true;
619                    headers_end_pos = pos + 4;
620                    parse_response_headers(
621                        &response_bytes[..headers_end_pos],
622                        &version_bytes,
623                        &location_key,
624                        &mut content_length,
625                        &mut redirect_url,
626                        &mut is_chunked,
627                    )?;
628                }
629            }
630            if headers_done {
631                if is_chunked {
632                    if Self::is_chunked_response_complete(&response_bytes[headers_end_pos..]) {
633                        break;
634                    }
635                } else if response_bytes.len() >= headers_end_pos + content_length {
636                    response_bytes.truncate(headers_end_pos + content_length);
637                    break;
638                }
639            }
640        }
641        if is_chunked {
642            let body_bytes: Vec<u8> = response_bytes[headers_end_pos..].to_vec();
643            let decoded: Vec<u8> = parse_chunked_body(&body_bytes);
644            response_bytes.truncate(headers_end_pos);
645            response_bytes.extend_from_slice(&decoded);
646        }
647        let mut response: HttpResponse = HttpResponse::from_bytes(&response_bytes);
648        if !self.get_config().get_redirect() || redirect_url.is_none() {
649            if self.get_config().get_decode() {
650                response = response.decode(self.get_config().buffer_size);
651            }
652            return Ok(response);
653        }
654        let url_bytes: Vec<u8> = redirect_url
655            .take()
656            .ok_or_else(|| RequestError::Request(MISSING_REDIRECT_URL.to_string()))?;
657        let url: String = String::from_utf8(url_bytes)
658            .map_err(|e: FromUtf8Error| RequestError::Request(e.to_string()))?;
659        self.handle_redirect_async(url).await
660    }
661
662    /// Follow a redirect by recording the visit and re-issuing the request.
663    ///
664    /// # Arguments
665    ///
666    /// - `String` - The absolute redirect target URL taken from the `Location` header.
667    ///
668    /// # Returns
669    ///
670    /// - `Result<HttpResponse, RequestError>` - The response of the redirect target, or a `RequestError` when redirects are disabled, looping, or exhausted.
671    async fn handle_redirect_async(&mut self, url: String) -> Result<HttpResponse, RequestError> {
672        if !self.get_config().get_redirect() {
673            return Err(RequestError::Request(REDIRECT_NOT_ENABLED.to_string()));
674        }
675        if self.get_tmp().get_visit_url().contains(&url) {
676            return Err(RequestError::Request(REDIRECT_URL_DEAD_LOOP.to_string()));
677        }
678        self.get_mut_tmp().get_mut_visit_url().insert(url.clone());
679        if self.get_config().get_max_redirect_times() == 0 {
680            return Err(RequestError::Request(
681                MAX_REDIRECT_TIMES_EXCEEDED.to_string(),
682            ));
683        }
684        let remaining: usize = self.get_config().get_max_redirect_times();
685        self.get_mut_config()
686            .set_max_redirect_times(remaining.saturating_sub(1));
687        self.set_url(url);
688        Box::pin(self.send_async()).await
689    }
690
691    // ---------- proxy: sync ----------
692
693    /// Open a synchronous stream to the target through the configured proxy.
694    ///
695    /// # Arguments
696    ///
697    /// - `String` - The target host name or IP address.
698    /// - `u16` - The target TCP port.
699    /// - `&Proxy` - The proxy configuration selecting the HTTP or SOCKS5 handshake.
700    ///
701    /// # Returns
702    ///
703    /// - `Result<BoxReadWrite, RequestError>` - The tunnelled stream, or a `RequestError` when the handshake fails.
704    fn open_sync_proxy_stream(
705        &self,
706        target_host: String,
707        target_port: u16,
708        proxy: &Proxy,
709    ) -> Result<BoxReadWrite, RequestError> {
710        match *proxy.get_proxy_type() {
711            ProxyType::Http | ProxyType::Https => {
712                self.open_sync_http_proxy(target_host, target_port, proxy)
713            }
714            ProxyType::Socks5 => self.open_sync_socks5_proxy(target_host, target_port, proxy),
715        }
716    }
717
718    /// Open a synchronous stream to the target through an HTTP or HTTPS proxy.
719    ///
720    /// # Arguments
721    ///
722    /// - `String` - The target host name or IP address.
723    /// - `u16` - The target TCP port.
724    /// - `&Proxy` - The proxy configuration selecting the HTTP or SOCKS5 handshake.
725    ///
726    /// # Returns
727    ///
728    /// - `Result<BoxReadWrite, RequestError>` - The tunnelled stream, or a `RequestError` when the handshake fails.
729    fn open_sync_http_proxy(
730        &self,
731        target_host: String,
732        target_port: u16,
733        proxy: &Proxy,
734    ) -> Result<BoxReadWrite, RequestError> {
735        let timeout: Duration = Duration::from_millis(self.get_config().get_timeout());
736        let tcp: TcpStream = TcpStream::connect((proxy.get_host().clone(), *proxy.get_port()))
737            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
738        tcp.set_read_timeout(Some(timeout))
739            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
740        tcp.set_write_timeout(Some(timeout))
741            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
742        let mut proxy_stream: BoxReadWrite = if proxy.get_proxy_type() == &ProxyType::Https {
743            let roots: RootCertStore = self.get_tmp().get_root_cert().clone();
744            let tls_cfg: ClientConfig = ClientConfig::builder()
745                .with_root_certificates(roots)
746                .with_no_client_auth();
747            let dns: ServerName<'static> = ServerName::try_from(proxy.get_host().clone())
748                .map_err(|e: InvalidDnsNameError| RequestError::Request(e.to_string()))?;
749            let session: ClientConnection = ClientConnection::new(Arc::new(tls_cfg), dns)
750                .map_err(|e: rustls::Error| RequestError::Request(e.to_string()))?;
751            Box::new(StreamOwned::new(session, tcp))
752        } else {
753            Box::new(tcp)
754        };
755        let connect_request: String = if let (Some(u), Some(p)) =
756            (proxy.get_username(), proxy.get_password())
757        {
758            let auth: String = format!("{u}:{p}");
759            let encoded: String = crate::utils::base64_encode(auth.as_bytes());
760            format!(
761                "CONNECT {target_host}:{target_port} HTTP/1.1\r\nHost: {target_host}:{target_port}\r\nProxy-Authorization: Basic {encoded}\r\n\r\n"
762            )
763        } else {
764            format!(
765                "CONNECT {target_host}:{target_port} HTTP/1.1\r\nHost: {target_host}:{target_port}\r\n\r\n"
766            )
767        };
768        proxy_stream
769            .write_all(connect_request.as_bytes())
770            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
771        proxy_stream
772            .flush()
773            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
774        let mut buf: [u8; 1024] = [0u8; 1024];
775        let n: usize = proxy_stream
776            .read(&mut buf)
777            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
778        let s: &str = from_utf8(&buf[..n]).unwrap_or("");
779        let pre_read: Vec<u8> = if let Some(pos) = s.find(HEADER_TERMINATOR) {
780            let header_part: &str = &s[..pos];
781            if !header_part.starts_with(HTTP_1_1_OK_PREFIX)
782                && !header_part.starts_with(HTTP_1_0_OK_PREFIX)
783            {
784                return Err(RequestError::Request(INTERNAL_SERVER_ERROR.to_string()));
785            }
786            buf[pos + 4..n].to_vec()
787        } else {
788            if !s.starts_with(HTTP_1_1_OK_PREFIX) && !s.starts_with(HTTP_1_0_OK_PREFIX) {
789                return Err(RequestError::Request(INTERNAL_SERVER_ERROR.to_string()));
790            }
791            Vec::new()
792        };
793        if self.is_https() {
794            let roots: RootCertStore = self.get_tmp().get_root_cert().clone();
795            let tls_cfg: ClientConfig = ClientConfig::builder()
796                .with_root_certificates(roots)
797                .with_no_client_auth();
798            let dns: ServerName<'static> = ServerName::try_from(target_host.clone())
799                .map_err(|e: InvalidDnsNameError| RequestError::Request(e.to_string()))?;
800            let session: ClientConnection = ClientConnection::new(Arc::new(tls_cfg), dns)
801                .map_err(|e: rustls::Error| RequestError::Request(e.to_string()))?;
802            let tunnel: SyncProxyTunnelStream = SyncProxyTunnelStream::new(proxy_stream, pre_read);
803            return Ok(Box::new(StreamOwned::new(session, tunnel)));
804        }
805        Ok(Box::new(SyncProxyTunnelStream::new(proxy_stream, pre_read)))
806    }
807
808    /// Open a synchronous stream to the target through a SOCKS5 proxy.
809    ///
810    /// # Arguments
811    ///
812    /// - `String` - The target host name or IP address.
813    /// - `u16` - The target TCP port.
814    /// - `&Proxy` - The proxy configuration selecting the HTTP or SOCKS5 handshake.
815    ///
816    /// # Returns
817    ///
818    /// - `Result<BoxReadWrite, RequestError>` - The tunnelled stream, or a `RequestError` when the handshake fails.
819    fn open_sync_socks5_proxy(
820        &self,
821        target_host: String,
822        target_port: u16,
823        proxy: &Proxy,
824    ) -> Result<BoxReadWrite, RequestError> {
825        let timeout: Duration = Duration::from_millis(self.get_config().get_timeout());
826        let mut tcp: TcpStream = TcpStream::connect((proxy.get_host().clone(), *proxy.get_port()))
827            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
828        tcp.set_read_timeout(Some(timeout))
829            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
830        tcp.set_write_timeout(Some(timeout))
831            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
832        let auth_methods: Vec<u8> =
833            if proxy.get_username().is_some() && proxy.get_password().is_some() {
834                vec![0x05, 0x02, 0x00, 0x02]
835            } else {
836                vec![0x05, 0x01, 0x00]
837            };
838        tcp.write_all(&auth_methods)
839            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
840        let mut resp: [u8; 2] = [0u8; 2];
841        tcp.read_exact(&mut resp)
842            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
843        if resp[0] != 0x05 {
844            return Err(RequestError::Request(INTERNAL_SERVER_ERROR.to_string()));
845        }
846        match resp[1] {
847            0x00 => {}
848            0x02 => {
849                let (Some(u), Some(p)) = (proxy.get_username(), proxy.get_password()) else {
850                    return Err(RequestError::Request(INTERNAL_SERVER_ERROR.to_string()));
851                };
852                let mut auth_req: Vec<u8> = vec![0x01];
853                auth_req.push(u.len() as u8);
854                auth_req.extend_from_slice(u.as_bytes());
855                auth_req.push(p.len() as u8);
856                auth_req.extend_from_slice(p.as_bytes());
857                tcp.write_all(&auth_req)
858                    .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
859                let mut auth_resp: [u8; 2] = [0u8; 2];
860                tcp.read_exact(&mut auth_resp)
861                    .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
862                if auth_resp[1] != 0x00 {
863                    return Err(RequestError::Request(INTERNAL_SERVER_ERROR.to_string()));
864                }
865            }
866            _ => return Err(RequestError::Request(INTERNAL_SERVER_ERROR.to_string())),
867        }
868        let mut connect_req: Vec<u8> = vec![0x05, 0x01, 0x00];
869        if let Ok(ip) = target_host.parse::<Ipv4Addr>() {
870            connect_req.push(0x01);
871            connect_req.extend_from_slice(&ip.octets());
872        } else if let Ok(ip) = target_host.parse::<Ipv6Addr>() {
873            connect_req.push(0x04);
874            connect_req.extend_from_slice(&ip.octets());
875        } else {
876            connect_req.push(0x03);
877            connect_req.push(target_host.len() as u8);
878            connect_req.extend_from_slice(target_host.as_bytes());
879        }
880        connect_req.extend_from_slice(&target_port.to_be_bytes());
881        tcp.write_all(&connect_req)
882            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
883        let mut connect_resp: [u8; 4] = [0u8; 4];
884        tcp.read_exact(&mut connect_resp)
885            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
886        if connect_resp[0] != 0x05 || connect_resp[1] != 0x00 {
887            return Err(RequestError::Request(INTERNAL_SERVER_ERROR.to_string()));
888        }
889        match connect_resp[3] {
890            0x01 => {
891                let mut skip: [u8; 6] = [0u8; 6];
892                tcp.read_exact(&mut skip)
893                    .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
894            }
895            0x03 => {
896                let mut len: [u8; 1] = [0u8; 1];
897                tcp.read_exact(&mut len)
898                    .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
899                let mut skip: Vec<u8> = vec![0u8; len[0] as usize + 2];
900                tcp.read_exact(&mut skip)
901                    .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
902            }
903            0x04 => {
904                let mut skip: [u8; 18] = [0u8; 18];
905                tcp.read_exact(&mut skip)
906                    .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
907            }
908            _ => return Err(RequestError::Request(INTERNAL_SERVER_ERROR.to_string())),
909        }
910        if self.is_https() {
911            let roots: RootCertStore = self.get_tmp().get_root_cert().clone();
912            let tls_cfg: ClientConfig = ClientConfig::builder()
913                .with_root_certificates(roots)
914                .with_no_client_auth();
915            let dns: ServerName<'static> = ServerName::try_from(target_host)
916                .map_err(|e: InvalidDnsNameError| RequestError::Request(e.to_string()))?;
917            let session: ClientConnection = ClientConnection::new(Arc::new(tls_cfg), dns)
918                .map_err(|e: rustls::Error| RequestError::Request(e.to_string()))?;
919            let proxy_box: BoxReadWrite = Box::new(tcp);
920            let tunnel: SyncProxyTunnelStream = SyncProxyTunnelStream::new(proxy_box, Vec::new());
921            return Ok(Box::new(StreamOwned::new(session, tunnel)));
922        }
923        Ok(Box::new(tcp))
924    }
925
926    // ---------- proxy: async ----------
927
928    /// Open an asynchronous stream to the target through the configured proxy.
929    ///
930    /// # Arguments
931    ///
932    /// - `String` - The target host name or IP address.
933    /// - `u16` - The target TCP port.
934    /// - `&Proxy` - The proxy configuration selecting the HTTP or SOCKS5 handshake.
935    ///
936    /// # Returns
937    ///
938    /// - `Result<BoxAsyncReadWrite, RequestError>` - The tunnelled stream, or a `RequestError` when the handshake fails.
939    async fn open_async_proxy_stream(
940        &self,
941        target_host: String,
942        target_port: u16,
943        proxy: &Proxy,
944    ) -> Result<BoxAsyncReadWrite, RequestError> {
945        match *proxy.get_proxy_type() {
946            ProxyType::Http | ProxyType::Https => {
947                self.open_async_http_proxy(target_host, target_port, proxy)
948                    .await
949            }
950            ProxyType::Socks5 => {
951                self.open_async_socks5_proxy(target_host, target_port, proxy)
952                    .await
953            }
954        }
955    }
956
957    /// Open an asynchronous stream to the target through an HTTP or HTTPS proxy.
958    ///
959    /// # Arguments
960    ///
961    /// - `String` - The target host name or IP address.
962    /// - `u16` - The target TCP port.
963    /// - `&Proxy` - The proxy configuration selecting the HTTP or SOCKS5 handshake.
964    ///
965    /// # Returns
966    ///
967    /// - `Result<BoxAsyncReadWrite, RequestError>` - The tunnelled stream, or a `RequestError` when the handshake fails.
968    async fn open_async_http_proxy(
969        &self,
970        target_host: String,
971        target_port: u16,
972        proxy: &Proxy,
973    ) -> Result<BoxAsyncReadWrite, RequestError> {
974        let tcp: http_type::tokio::net::TcpStream = http_type::tokio::net::TcpStream::connect((
975            proxy.get_host().clone(),
976            *proxy.get_port(),
977        ))
978        .await
979        .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
980        let mut proxy_stream: BoxAsyncReadWrite = if proxy.get_proxy_type() == &ProxyType::Https {
981            let roots: RootCertStore = self.get_tmp().get_root_cert().clone();
982            let tls_cfg: ClientConfig = ClientConfig::builder()
983                .with_root_certificates(roots)
984                .with_no_client_auth();
985            let connector: TlsConnector = TlsConnector::from(Arc::new(tls_cfg));
986            let dns: ServerName<'static> = ServerName::try_from(proxy.get_host().clone())
987                .map_err(|e: InvalidDnsNameError| RequestError::Request(e.to_string()))?;
988            let tls: tokio_rustls::client::TlsStream<http_type::tokio::net::TcpStream> = connector
989                .connect(dns, tcp)
990                .await
991                .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
992            Box::new(tls)
993        } else {
994            Box::new(tcp)
995        };
996        let connect_request: String = if let (Some(u), Some(p)) =
997            (proxy.get_username(), proxy.get_password())
998        {
999            let auth: String = format!("{u}:{p}");
1000            let encoded: String = crate::utils::base64_encode(auth.as_bytes());
1001            format!(
1002                "CONNECT {target_host}:{target_port} HTTP/1.1\r\nHost: {target_host}:{target_port}\r\nProxy-Authorization: Basic {encoded}\r\n\r\n"
1003            )
1004        } else {
1005            format!(
1006                "CONNECT {target_host}:{target_port} HTTP/1.1\r\nHost: {target_host}:{target_port}\r\n\r\n"
1007            )
1008        };
1009        proxy_stream
1010            .write_all(connect_request.as_bytes())
1011            .await
1012            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
1013        proxy_stream
1014            .flush()
1015            .await
1016            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
1017        let mut buf: [u8; 1024] = [0u8; 1024];
1018        let n: usize = proxy_stream
1019            .read(&mut buf)
1020            .await
1021            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
1022        let s: &str = from_utf8(&buf[..n]).unwrap_or("");
1023        let pre_read: Vec<u8> = if let Some(pos) = s.find(HEADER_TERMINATOR) {
1024            let header_part: &str = &s[..pos];
1025            if !header_part.starts_with(HTTP_1_1_OK_PREFIX)
1026                && !header_part.starts_with(HTTP_1_0_OK_PREFIX)
1027            {
1028                return Err(RequestError::Request(INTERNAL_SERVER_ERROR.to_string()));
1029            }
1030            buf[pos + 4..n].to_vec()
1031        } else {
1032            if !s.starts_with(HTTP_1_1_OK_PREFIX) && !s.starts_with(HTTP_1_0_OK_PREFIX) {
1033                return Err(RequestError::Request(INTERNAL_SERVER_ERROR.to_string()));
1034            }
1035            Vec::new()
1036        };
1037        if self.is_https() {
1038            let roots: RootCertStore = self.get_tmp().get_root_cert().clone();
1039            let tls_cfg: ClientConfig = ClientConfig::builder()
1040                .with_root_certificates(roots)
1041                .with_no_client_auth();
1042            let connector: TlsConnector = TlsConnector::from(Arc::new(tls_cfg));
1043            let dns: ServerName<'static> = ServerName::try_from(target_host.clone())
1044                .map_err(|e: InvalidDnsNameError| RequestError::Request(e.to_string()))?;
1045            let tunnel: ProxyTunnelStream = ProxyTunnelStream::new(proxy_stream, pre_read);
1046            let tls: tokio_rustls::client::TlsStream<ProxyTunnelStream> = connector
1047                .connect(dns, tunnel)
1048                .await
1049                .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
1050            Ok(Box::new(tls))
1051        } else {
1052            Ok(Box::new(ProxyTunnelStream::new(proxy_stream, pre_read)))
1053        }
1054    }
1055
1056    /// Open an asynchronous stream to the target through a SOCKS5 proxy.
1057    ///
1058    /// # Arguments
1059    ///
1060    /// - `String` - The target host name or IP address.
1061    /// - `u16` - The target TCP port.
1062    /// - `&Proxy` - The proxy configuration selecting the HTTP or SOCKS5 handshake.
1063    ///
1064    /// # Returns
1065    ///
1066    /// - `Result<BoxAsyncReadWrite, RequestError>` - The tunnelled stream, or a `RequestError` when the handshake fails.
1067    async fn open_async_socks5_proxy(
1068        &self,
1069        target_host: String,
1070        target_port: u16,
1071        proxy: &Proxy,
1072    ) -> Result<BoxAsyncReadWrite, RequestError> {
1073        let mut tcp: http_type::tokio::net::TcpStream = http_type::tokio::net::TcpStream::connect(
1074            (proxy.get_host().clone(), *proxy.get_port()),
1075        )
1076        .await
1077        .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
1078        let auth_methods: Vec<u8> =
1079            if proxy.get_username().is_some() && proxy.get_password().is_some() {
1080                vec![0x05, 0x02, 0x00, 0x02]
1081            } else {
1082                vec![0x05, 0x01, 0x00]
1083            };
1084        tcp.write_all(&auth_methods)
1085            .await
1086            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
1087        let mut resp: [u8; 2] = [0u8; 2];
1088        tcp.read_exact(&mut resp)
1089            .await
1090            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
1091        if resp[0] != 0x05 {
1092            return Err(RequestError::Request(INTERNAL_SERVER_ERROR.to_string()));
1093        }
1094        match resp[1] {
1095            0x00 => {}
1096            0x02 => {
1097                let (Some(u), Some(p)) = (proxy.get_username(), proxy.get_password()) else {
1098                    return Err(RequestError::Request(INTERNAL_SERVER_ERROR.to_string()));
1099                };
1100                let mut auth_req: Vec<u8> = vec![0x01u8];
1101                auth_req.push(u.len() as u8);
1102                auth_req.extend_from_slice(u.as_bytes());
1103                auth_req.push(p.len() as u8);
1104                auth_req.extend_from_slice(p.as_bytes());
1105                tcp.write_all(&auth_req)
1106                    .await
1107                    .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
1108                let mut auth_resp: [u8; 2] = [0u8; 2];
1109                tcp.read_exact(&mut auth_resp)
1110                    .await
1111                    .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
1112                if auth_resp[1] != 0x00 {
1113                    return Err(RequestError::Request(INTERNAL_SERVER_ERROR.to_string()));
1114                }
1115            }
1116            _ => return Err(RequestError::Request(INTERNAL_SERVER_ERROR.to_string())),
1117        }
1118        let mut connect_req: Vec<u8> = vec![0x05, 0x01, 0x00];
1119        if let Ok(ip) = target_host.parse::<Ipv4Addr>() {
1120            connect_req.push(0x01);
1121            connect_req.extend_from_slice(&ip.octets());
1122        } else if let Ok(ip) = target_host.parse::<Ipv6Addr>() {
1123            connect_req.push(0x04);
1124            connect_req.extend_from_slice(&ip.octets());
1125        } else {
1126            connect_req.push(0x03);
1127            connect_req.push(target_host.len() as u8);
1128            connect_req.extend_from_slice(target_host.as_bytes());
1129        }
1130        connect_req.extend_from_slice(&target_port.to_be_bytes());
1131        tcp.write_all(&connect_req)
1132            .await
1133            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
1134        let mut connect_resp: [u8; 4] = [0u8; 4];
1135        tcp.read_exact(&mut connect_resp)
1136            .await
1137            .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
1138        if connect_resp[0] != 0x05 || connect_resp[1] != 0x00 {
1139            return Err(RequestError::Request(INTERNAL_SERVER_ERROR.to_string()));
1140        }
1141        match connect_resp[3] {
1142            0x01 => {
1143                let mut skip: [u8; 6] = [0u8; 6];
1144                tcp.read_exact(&mut skip)
1145                    .await
1146                    .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
1147            }
1148            0x03 => {
1149                let mut len: [u8; 1] = [0u8; 1];
1150                tcp.read_exact(&mut len)
1151                    .await
1152                    .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
1153                let mut skip: Vec<u8> = vec![0u8; len[0] as usize + 2];
1154                tcp.read_exact(&mut skip)
1155                    .await
1156                    .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
1157            }
1158            0x04 => {
1159                let mut skip: [u8; 18] = [0u8; 18];
1160                tcp.read_exact(&mut skip)
1161                    .await
1162                    .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
1163            }
1164            _ => return Err(RequestError::Request(INTERNAL_SERVER_ERROR.to_string())),
1165        }
1166        if self.is_https() {
1167            let roots: RootCertStore = self.get_tmp().get_root_cert().clone();
1168            let tls_cfg: ClientConfig = ClientConfig::builder()
1169                .with_root_certificates(roots)
1170                .with_no_client_auth();
1171            let connector: TlsConnector = TlsConnector::from(Arc::new(tls_cfg));
1172            let dns: ServerName<'static> = ServerName::try_from(target_host)
1173                .map_err(|e: InvalidDnsNameError| RequestError::Request(e.to_string()))?;
1174            let proxy_box: BoxAsyncReadWrite = Box::new(tcp);
1175            let tunnel: ProxyTunnelStream = ProxyTunnelStream::new(proxy_box, Vec::new());
1176            let tls: tokio_rustls::client::TlsStream<ProxyTunnelStream> = connector
1177                .connect(dns, tunnel)
1178                .await
1179                .map_err(|e: io::Error| RequestError::Request(e.to_string()))?;
1180            Ok(Box::new(tls))
1181        } else {
1182            Ok(Box::new(tcp))
1183        }
1184    }
1185}
1186
1187impl HttpRequest {
1188    /// Create a GET request for `url`.
1189    ///
1190    /// # Arguments
1191    ///
1192    /// - `T` - The request URL, converted into an owned `String`.
1193    pub fn get<T: Into<String>>(url: T) -> Self {
1194        Self {
1195            method: Method::Get,
1196            url: url.into(),
1197            headers: HashMap::new(),
1198            body: Body::default(),
1199            config: RequestConfig::default(),
1200            tmp: Tmp::default(),
1201        }
1202    }
1203
1204    /// Create a POST request for `url`.
1205    ///
1206    /// # Arguments
1207    ///
1208    /// - `T` - The request URL, converted into an owned `String`.
1209    pub fn post<T: Into<String>>(url: T) -> Self {
1210        Self {
1211            method: Method::Post,
1212            url: url.into(),
1213            headers: HashMap::new(),
1214            body: Body::default(),
1215            config: RequestConfig::default(),
1216            tmp: Tmp::default(),
1217        }
1218    }
1219
1220    /// Builder-style: set method.
1221    ///
1222    /// # Arguments
1223    ///
1224    /// - `Method` - The HTTP method to use for the request.
1225    ///
1226    /// # Returns
1227    ///
1228    /// - `&mut Self` - The request itself, for chaining.
1229    pub fn set_method(&mut self, method: Method) -> &mut Self {
1230        self.method = method;
1231        self
1232    }
1233
1234    /// Builder-style: set URL.
1235    ///
1236    /// # Arguments
1237    ///
1238    /// - `T` - The request URL, converted into an owned `String`.
1239    ///
1240    /// # Returns
1241    ///
1242    /// - `&mut Self` - The request itself, for chaining.
1243    pub fn set_url<T: Into<String>>(&mut self, url: T) -> &mut Self {
1244        self.url = url.into();
1245        self
1246    }
1247
1248    /// Builder-style: set a single header (case-insensitive on read; the
1249    /// last value wins for repeated keys).
1250    ///
1251    /// # Arguments
1252    ///
1253    /// - `K` - The header name, normalised to lowercase.
1254    /// - `V` - The header value, stored as an owned `String`.
1255    ///
1256    /// # Returns
1257    ///
1258    /// - `&mut Self` - The request itself, for chaining.
1259    pub fn set_header<K: AsRef<str>, V: AsRef<str>>(&mut self, key: K, value: V) -> &mut Self {
1260        let normalized: String = Self::normalize_header_key(key.as_ref());
1261        self.headers.insert(normalized, value.as_ref().to_owned());
1262        self
1263    }
1264
1265    /// Remove a header by key.
1266    ///
1267    /// # Arguments
1268    ///
1269    /// - `K` - The header name to remove, matched case-insensitively.
1270    ///
1271    /// # Returns
1272    ///
1273    /// - `&mut Self` - The request itself, for chaining.
1274    pub fn remove_header<K: AsRef<str>>(&mut self, key: K) -> &mut Self {
1275        let normalized: String = Self::normalize_header_key(key.as_ref());
1276        self.get_mut_headers().remove(&normalized);
1277        self
1278    }
1279
1280    /// Clear all headers.
1281    ///
1282    /// # Returns
1283    ///
1284    /// - `&mut Self` - The request itself, for chaining.
1285    pub fn clear_headers(&mut self) -> &mut Self {
1286        self.get_mut_headers().clear();
1287        self
1288    }
1289
1290    /// Set body (raw bytes).
1291    ///
1292    /// # Arguments
1293    ///
1294    /// - `Body` - The body payload to send.
1295    ///
1296    /// # Returns
1297    ///
1298    /// - `&mut Self` - The request itself, for chaining.
1299    pub fn set_body(&mut self, body: Body) -> &mut Self {
1300        self.body = body;
1301        self
1302    }
1303
1304    /// Set a single config field by mutating the embedded `RequestConfig`.
1305    ///
1306    /// # Arguments
1307    ///
1308    /// - `RequestConfig` - The configuration replacing the current one.
1309    ///
1310    /// # Returns
1311    ///
1312    /// - `&mut Self` - The request itself, for chaining.
1313    pub fn set_config(&mut self, config: RequestConfig) -> &mut Self {
1314        self.config = config;
1315        self
1316    }
1317
1318    /// Normalize a header key to lowercase so `set_header` /
1319    /// `remove_header` lookups are case-insensitive.
1320    ///
1321    /// # Arguments
1322    ///
1323    /// - `&str` - The header key to normalise.
1324    ///
1325    /// # Returns
1326    ///
1327    /// - `String` - The lower-cased header key.
1328    fn normalize_header_key(key: &str) -> String {
1329        key.to_ascii_lowercase()
1330    }
1331}