1use super::decompress::decompress;
19use super::error::{Error, Result};
20use super::finish_with_error;
21use super::grpc::grpc_request;
22use super::net::{dns_resolve, parse_certificates, quic_connect, tcp_connect, tls_handshake};
23use super::proxy::{http_connect, socks5_connect, ProxyConfig, ProxyKind};
24use super::stats::{
25 parse_alt_svc, parse_hsts, parse_server_timing, HttpStat, ALPN_HTTP3, FIRST_CHUNK_BYTES,
26};
27use super::HttpRequest;
28use bytes::{Buf, Bytes, BytesMut};
29use futures::future;
30
31use http::Request;
32use http::Response;
33use http::Version;
34use http_body::{Body, Frame, SizeHint};
35use http_body_util::BodyExt;
36use hyper::body::Incoming;
37use hyper_util::rt::TokioExecutor;
38use hyper_util::rt::TokioIo;
39use std::pin::Pin;
40use std::sync::{Arc, Once, OnceLock};
41use std::task::{Context, Poll};
42use std::time::Duration;
43use std::time::Instant;
44use tokio::net::TcpStream;
45use tokio::sync::oneshot;
46use tokio::time::timeout;
47use tokio_rustls::client::TlsStream;
48
49pub(crate) struct TrackedBody {
57 data: Option<Bytes>,
58 done: Arc<OnceLock<Instant>>,
59}
60
61impl TrackedBody {
62 pub(crate) fn new(data: Bytes) -> (Self, Arc<OnceLock<Instant>>) {
63 let done = Arc::new(OnceLock::new());
64 (
65 Self {
66 data: Some(data),
67 done: done.clone(),
68 },
69 done,
70 )
71 }
72}
73
74impl Body for TrackedBody {
75 type Data = Bytes;
76 type Error = std::convert::Infallible;
77
78 fn poll_frame(
79 self: Pin<&mut Self>,
80 _cx: &mut Context<'_>,
81 ) -> Poll<Option<std::result::Result<Frame<Self::Data>, Self::Error>>> {
82 let this = self.get_mut();
83 if let Some(bytes) = this.data.take() {
84 Poll::Ready(Some(Ok(Frame::data(bytes))))
85 } else {
86 let _ = this.done.set(Instant::now());
87 Poll::Ready(None)
88 }
89 }
90
91 fn is_end_stream(&self) -> bool {
92 false
94 }
95
96 fn size_hint(&self) -> SizeHint {
97 match &self.data {
98 Some(b) => SizeHint::with_exact(b.len() as u64),
99 None => SizeHint::with_exact(0),
100 }
101 }
102}
103
104fn build_tracked_request(
106 req: &HttpRequest,
107 is_http1: bool,
108) -> Result<(Request<TrackedBody>, Arc<OnceLock<Instant>>)> {
109 let body = req.body.clone().unwrap_or_default();
110 let (tracked, done) = TrackedBody::new(body);
111 let request = req
112 .builder(is_http1)
113 .body(tracked)
114 .map_err(|e| Error::Http { source: e })?;
115 Ok((request, done))
116}
117
118fn record_send_split(
123 stat: &mut HttpStat,
124 send_start: Instant,
125 response_at: Instant,
126 done: &Arc<OnceLock<Instant>>,
127) {
128 match done.get().copied() {
129 Some(done_at) if done_at >= send_start && done_at <= response_at => {
130 stat.request_send = Some(done_at.duration_since(send_start));
131 stat.server_processing = Some(response_at.duration_since(done_at));
132 }
133 _ => {
134 stat.server_processing = Some(response_at.duration_since(send_start));
135 }
136 }
137}
138
139fn capture_server_timing(stat: &mut HttpStat, headers: &http::HeaderMap) {
141 let values: Vec<&str> = headers
142 .get_all("server-timing")
143 .iter()
144 .filter_map(|v| v.to_str().ok())
145 .collect();
146 if !values.is_empty() {
147 stat.server_timing = parse_server_timing(values.iter().copied());
148 }
149}
150
151fn capture_protocol_advertisements(stat: &mut HttpStat, headers: &http::HeaderMap) {
154 let alt_svc_values: Vec<&str> = headers
155 .get_all("alt-svc")
156 .iter()
157 .filter_map(|v| v.to_str().ok())
158 .collect();
159 if !alt_svc_values.is_empty() {
160 stat.alt_svc = parse_alt_svc(alt_svc_values.iter().copied());
161 }
162 if let Some(v) = headers
163 .get("strict-transport-security")
164 .and_then(|v| v.to_str().ok())
165 {
166 stat.hsts = parse_hsts(v);
167 }
168}
169
170async fn drain_body_with_split(
177 body: Incoming,
178 start: Instant,
179 max_body_size: Option<usize>,
180) -> std::result::Result<(Bytes, Option<Duration>), String> {
181 let mut body = body;
182 let mut buf = BytesMut::new();
183 let mut first_chunk_at: Option<Duration> = None;
184 while let Some(frame_res) = body.frame().await {
185 let frame = frame_res.map_err(|e| format!("Failed to read response body: {e}"))?;
186 if let Ok(data) = frame.into_data() {
187 if let Some(max) = max_body_size {
188 if buf.len() + data.len() > max {
189 return Err(body_limit_error(max));
190 }
191 }
192 buf.extend_from_slice(&data);
193 if first_chunk_at.is_none() && buf.len() >= FIRST_CHUNK_BYTES {
194 first_chunk_at = Some(start.elapsed());
195 }
196 }
197 }
198 Ok((buf.freeze(), first_chunk_at))
199}
200
201fn body_limit_error(max: usize) -> String {
202 format!("response body exceeds the {max} byte limit (--max-filesize, 0 = unlimited)")
203}
204
205const DEFAULT_REQUEST_TIMEOUT: Duration = Duration::from_secs(30);
209
210static INIT: Once = Once::new();
212
213fn ensure_crypto_provider() {
214 INIT.call_once(|| {
215 let _ = tokio_rustls::rustls::crypto::ring::default_provider().install_default();
216 });
217}
218
219async fn send_http1_request<S>(
221 req: Request<TrackedBody>,
222 done: Arc<OnceLock<Instant>>,
223 stream: S,
224 request_timeout: Option<Duration>,
225 tx: oneshot::Sender<String>,
226 stat: &mut HttpStat,
227) -> Result<Response<Incoming>>
228where
229 S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + 'static,
230{
231 let (mut sender, conn) = timeout(
232 request_timeout.unwrap_or(DEFAULT_REQUEST_TIMEOUT),
233 hyper::client::conn::http1::handshake(TokioIo::new(stream)),
234 )
235 .await
236 .map_err(|e| Error::Timeout { source: e })?
237 .map_err(|e| Error::Hyper { source: e })?;
238
239 tokio::spawn(async move {
241 if let Err(e) = conn.await {
242 let _ = tx.send(e.to_string());
243 }
244 });
245
246 let send_start = Instant::now();
247 let resp = timeout(
251 request_timeout.unwrap_or(DEFAULT_REQUEST_TIMEOUT),
252 sender.send_request(req),
253 )
254 .await
255 .map_err(|e| Error::Timeout { source: e })?
256 .map_err(|e| Error::Hyper { source: e })?;
257 let response_at = Instant::now();
258 record_send_split(stat, send_start, response_at, &done);
259 Ok(resp)
260}
261
262async fn send_https2_request(
264 req: Request<TrackedBody>,
265 done: Arc<OnceLock<Instant>>,
266 tls_stream: TlsStream<TcpStream>,
267 request_timeout: Option<Duration>,
268 tx: oneshot::Sender<String>,
269 stat: &mut HttpStat,
270) -> Result<Response<Incoming>> {
271 let (mut sender, conn) = timeout(
272 request_timeout.unwrap_or(DEFAULT_REQUEST_TIMEOUT),
273 hyper::client::conn::http2::handshake(TokioExecutor::new(), TokioIo::new(tls_stream)),
274 )
275 .await
276 .map_err(|e| Error::Timeout { source: e })?
277 .map_err(|e| Error::Hyper { source: e })?;
278
279 tokio::spawn(async move {
281 if let Err(e) = conn.await {
282 let _ = tx.send(e.to_string());
283 }
284 });
285
286 let mut req = req;
287 *req.version_mut() = hyper::Version::HTTP_2;
288 req.headers_mut().remove("Host");
290
291 let send_start = Instant::now();
292 let resp = timeout(
294 request_timeout.unwrap_or(DEFAULT_REQUEST_TIMEOUT),
295 sender.send_request(req),
296 )
297 .await
298 .map_err(|e| Error::Timeout { source: e })?
299 .map_err(|e| Error::Hyper { source: e })?;
300 let response_at = Instant::now();
301 record_send_split(stat, send_start, response_at, &done);
302 Ok(resp)
303}
304
305async fn http3_request(http_req: HttpRequest) -> HttpStat {
307 let start = Instant::now();
308 let mut stat = HttpStat {
309 alpn: Some(ALPN_HTTP3.to_string()),
310 ..Default::default()
311 };
312
313 let dns_result = dns_resolve(&http_req, &mut stat).await;
315 let (addr, host) = match dns_result {
316 Ok(result) => result,
317 Err(e) => {
318 return finish_with_error(stat, e, start);
319 }
320 };
321
322 let (client_endpoint, conn) = match timeout(
324 http_req.quic_timeout.unwrap_or(Duration::from_secs(30)),
325 quic_connect(
326 host,
327 addr,
328 http_req.skip_verify,
329 http_req.client_cert.as_deref(),
330 http_req.client_key.as_deref(),
331 http_req.bind_addr,
332 &mut stat,
333 ),
334 )
335 .await
336 {
337 Ok(Ok(result)) => result,
338 Ok(Err(e)) => {
339 return finish_with_error(stat, e, start);
340 }
341 Err(e) => {
342 return finish_with_error(stat, e, start);
343 }
344 };
345
346 stat.tls = Some("tls 1.3".to_string()); stat.alpn = Some(ALPN_HTTP3.to_string()); if let Some(peer_identity) = conn.peer_identity() {
355 if let Ok(certs) = peer_identity.downcast::<Vec<rustls::pki_types::CertificateDer>>() {
356 parse_certificates(&certs, &mut stat);
357 }
358 }
359
360 let quinn_conn = h3_quinn::Connection::new(conn);
362
363 let (mut driver, mut send_request) = match timeout(
364 http_req.request_timeout.unwrap_or(Duration::from_secs(30)),
365 h3::client::new(quinn_conn),
366 )
367 .await
368 {
369 Ok(Ok(result)) => result,
370 Ok(Err(e)) => {
371 return finish_with_error(stat, e, start);
372 }
373 Err(e) => {
374 return finish_with_error(stat, e, start);
375 }
376 };
377
378 let mut req = match http_req.builder(false).body(()) {
380 Ok(req) => req,
381 Err(e) => {
382 return finish_with_error(stat, e, start);
383 }
384 };
385 *req.version_mut() = Version::HTTP_3;
386 stat.request_headers = req.headers().clone();
387 let request_timeout = http_req.request_timeout.unwrap_or(DEFAULT_REQUEST_TIMEOUT);
388 let max_body_size = http_req.max_body_size;
389 let body = http_req.body.unwrap_or_default();
390
391 let drive = async move {
393 Err::<(), h3::error::ConnectionError>(future::poll_fn(|cx| driver.poll_close(cx)).await)
394 };
395
396 let request = async move {
398 let mut sub_stat = HttpStat::default();
399
400 let request_send_start = Instant::now();
401 let mut stream = send_request.send_request(req).await?;
402 stream.send_data(body).await?;
403 stream.finish().await?;
405 sub_stat.request_send = Some(request_send_start.elapsed());
406
407 let server_processing_start = Instant::now();
408 let resp = stream.recv_response().await?;
409 sub_stat.server_processing = Some(server_processing_start.elapsed());
410
411 sub_stat.status = Some(resp.status());
412 sub_stat.headers = Some(resp.headers().clone());
413 sub_stat.version = Some(format!("{:?}", resp.version()));
414 capture_server_timing(&mut sub_stat, resp.headers());
415 capture_protocol_advertisements(&mut sub_stat, resp.headers());
416
417 let content_transfer_start = Instant::now();
420 let mut buf = BytesMut::new();
421 let mut first_chunk_at: Option<Duration> = None;
422 while let Some(chunk) = stream.recv_data().await? {
423 if let Some(max) = max_body_size {
424 if buf.len() + chunk.chunk().len() > max {
425 sub_stat.error = Some(body_limit_error(max));
426 break;
427 }
428 }
429 buf.extend(chunk.chunk());
430 if first_chunk_at.is_none() && buf.len() >= FIRST_CHUNK_BYTES {
431 first_chunk_at = Some(content_transfer_start.elapsed());
432 }
433 }
434 sub_stat.content_transfer = Some(content_transfer_start.elapsed());
435 sub_stat.wire_body_size = Some(buf.len());
436 sub_stat.time_to_first_100k = first_chunk_at;
437 sub_stat.body = Some(Bytes::from(buf));
438 Ok::<HttpStat, h3::error::StreamError>(sub_stat)
439 };
440
441 let (req_res, drive_res) = tokio::join!(timeout(request_timeout, request), drive);
445 match req_res {
446 Ok(Ok(sub_stat)) => {
447 stat.request_send = sub_stat.request_send;
448 stat.server_processing = sub_stat.server_processing;
449 stat.content_transfer = sub_stat.content_transfer;
450 stat.status = sub_stat.status;
451 stat.headers = sub_stat.headers;
452 stat.body = sub_stat.body;
453 stat.wire_body_size = sub_stat.wire_body_size;
454 stat.time_to_first_100k = sub_stat.time_to_first_100k;
455 stat.server_timing = sub_stat.server_timing;
456 stat.alt_svc = sub_stat.alt_svc;
457 stat.hsts = sub_stat.hsts;
458 stat.error = sub_stat.error;
460 stat.version = sub_stat.version;
461 }
462 Ok(Err(err)) => {
463 if !err.is_h3_no_error() {
464 stat.error = Some(err.to_string());
465 }
466 }
467 Err(e) => {
468 stat.error = Some(format!("request timeout: {e}"));
469 }
470 }
471 if let Err(err) = drive_res {
472 if !err.is_h3_no_error() {
473 stat.error = Some(err.to_string());
474 }
475 }
476
477 stat.total = Some(start.elapsed());
478 client_endpoint.close(0u32.into(), b"done");
480
481 stat
482}
483
484async fn tcp_via_proxy(
494 http_req: &HttpRequest,
495 stat: &mut HttpStat,
496) -> Result<(
497 TcpStream,
498 String,
499 bool,
500 Option<crate::tcp_info::TcpInfoProbe>,
501)> {
502 let uri = &http_req.uri;
503 let is_https = uri.scheme() == Some(&http::uri::Scheme::HTTPS);
504 let target_host = uri.host().unwrap_or_default().to_string();
505 let target_port = http_req.get_port();
506
507 if let Some(proxy) = http_req.proxy.as_deref().and_then(ProxyConfig::parse) {
508 let proxy_addr = format!("{}:{}", proxy.host, proxy.port);
509 let tcp_start = Instant::now();
510 let proxy_stream = timeout(
511 http_req.tcp_timeout.unwrap_or(Duration::from_secs(5)),
512 TcpStream::connect(&proxy_addr),
513 )
514 .await
515 .map_err(|e| Error::Timeout { source: e })?
516 .map_err(|e| Error::Io { source: e })?;
517
518 if let Ok(peer) = proxy_stream.peer_addr() {
519 stat.addr = Some(peer.to_string());
520 }
521
522 let (baseline, probe) = crate::tcp_info::TcpInfoProbe::capture(&proxy_stream);
525 stat.tcp_info_post_connect = baseline;
526
527 let is_http_forward = !is_https && matches!(proxy.kind, ProxyKind::Http);
529 let stream = if is_http_forward {
530 proxy_stream
531 } else {
532 match proxy.kind {
533 ProxyKind::Socks5 => {
534 socks5_connect(proxy_stream, &target_host, target_port).await?
535 }
536 ProxyKind::Http => http_connect(proxy_stream, &target_host, target_port).await?,
537 }
538 };
539 stat.tcp_connect = Some(tcp_start.elapsed());
540 Ok((stream, target_host, is_http_forward, probe))
541 } else {
542 let (addr, host) = dns_resolve(http_req, stat).await?;
543 let (stream, probe) =
544 tcp_connect(addr, http_req.tcp_timeout, http_req.bind_addr, stat).await?;
545 Ok((stream, host, false, probe))
546 }
547}
548
549async fn http1_2_request(mut http_req: HttpRequest) -> HttpStat {
550 let start = Instant::now();
551 let mut stat = HttpStat::default();
552
553 let is_https = http_req.uri.scheme() == Some(&http::uri::Scheme::HTTPS);
554
555 let (tcp_stream, host, is_http_forward, tcp_probe) =
557 match tcp_via_proxy(&http_req, &mut stat).await {
558 Ok(r) => r,
559 Err(e) => return finish_with_error(stat, e, start),
560 };
561
562 if is_http_forward {
564 http_req.use_absolute_uri = true;
565 }
566
567 let (tx, mut rx) = oneshot::channel();
569
570 let resp = if is_https {
572 let tls_result = tls_handshake(host.clone(), tcp_stream, &http_req, &mut stat).await;
574 let (tls_stream, is_http2) = match tls_result {
575 Ok(result) => result,
576 Err(e) => {
577 return finish_with_error(stat, e, start);
578 }
579 };
580
581 if is_http2 {
583 let (req, done) = match build_tracked_request(&http_req, false) {
584 Ok(r) => r,
585 Err(e) => {
586 return finish_with_error(stat, e, start);
587 }
588 };
589 stat.request_headers = req.headers().clone();
590 match send_https2_request(
591 req,
592 done,
593 tls_stream,
594 http_req.request_timeout,
595 tx,
596 &mut stat,
597 )
598 .await
599 {
600 Ok(resp) => resp,
601 Err(e) => {
602 return finish_with_error(stat, e, start);
603 }
604 }
605 } else {
606 let (req, done) = match build_tracked_request(&http_req, true) {
607 Ok(r) => r,
608 Err(e) => {
609 return finish_with_error(stat, e, start);
610 }
611 };
612 stat.request_headers = req.headers().clone();
613 match send_http1_request(
614 req,
615 done,
616 tls_stream,
617 http_req.request_timeout,
618 tx,
619 &mut stat,
620 )
621 .await
622 {
623 Ok(resp) => resp,
624 Err(e) => {
625 return finish_with_error(stat, e, start);
626 }
627 }
628 }
629 } else {
630 let (req, done) = match build_tracked_request(&http_req, true) {
631 Ok(r) => r,
632 Err(e) => {
633 return finish_with_error(stat, e, start);
634 }
635 };
636 stat.request_headers = req.headers().clone();
637 match send_http1_request(
639 req,
640 done,
641 tcp_stream,
642 http_req.request_timeout,
643 tx,
644 &mut stat,
645 )
646 .await
647 {
648 Ok(resp) => resp,
649 Err(e) => {
650 return finish_with_error(stat, e, start);
651 }
652 }
653 };
654
655 stat.status = Some(resp.status());
657 stat.headers = Some(resp.headers().clone());
658 stat.version = Some(format!("{:?}", resp.version()));
659 capture_server_timing(&mut stat, resp.headers());
660 capture_protocol_advertisements(&mut stat, resp.headers());
661
662 if let Ok(error) = rx.try_recv() {
664 stat.error = Some(error);
665 }
666 let content_transfer_start = Instant::now();
671 let drain_result = timeout(
672 http_req.request_timeout.unwrap_or(DEFAULT_REQUEST_TIMEOUT),
673 drain_body_with_split(
674 resp.into_body(),
675 content_transfer_start,
676 http_req.max_body_size,
677 ),
678 )
679 .await;
680 let (body_bytes, time_to_first_100k) = match drain_result {
681 Ok(Ok(p)) => p,
682 Ok(Err(e)) => return finish_with_error(stat, e, start),
683 Err(e) => return finish_with_error(stat, Error::Timeout { source: e }, start),
684 };
685 stat.wire_body_size = Some(body_bytes.len());
686 stat.time_to_first_100k = time_to_first_100k;
687 stat.body = Some(body_bytes);
688 stat.content_transfer = Some(content_transfer_start.elapsed());
689
690 if let Some(probe) = &tcp_probe {
694 stat.tcp_info_final = probe.sample();
695 }
696
697 stat.total = Some(start.elapsed());
698 stat
699}
700
701pub async fn request(http_req: HttpRequest) -> HttpStat {
736 ensure_crypto_provider();
737 let is_grpc = matches!(http_req.uri.scheme_str().unwrap_or(""), "grpc" | "grpcs");
738
739 let mut stat = if is_grpc {
741 grpc_request(http_req).await
742 } else if http_req.alpn_protocols.iter().any(|p| p == ALPN_HTTP3) {
743 http3_request(http_req).await
744 } else {
745 http1_2_request(http_req).await
746 };
747 if let Some(body) = &stat.body {
748 stat.body_size = Some(body.len());
749 }
750 let encoding = if let Some(headers) = &stat.headers {
751 headers
752 .get("content-encoding")
753 .map(|v| v.to_str().unwrap_or_default())
754 .unwrap_or_default()
755 } else {
756 ""
757 };
758
759 if !encoding.is_empty() {
760 if let Some(body) = &stat.body {
761 match decompress(encoding, body) {
762 Ok(data) => {
763 stat.body = Some(data);
764 }
765 Err(e) => {
766 stat.error = Some(e.to_string());
767 }
768 }
769 }
770 }
771
772 stat
773}
774
775enum ConnectionSender {
778 Http1(hyper::client::conn::http1::SendRequest<TrackedBody>),
779 Http2(hyper::client::conn::http2::SendRequest<TrackedBody>),
780}
781
782pub struct HttpConnection {
784 sender: ConnectionSender,
785 is_http2: bool,
786 tcp_probe: Option<crate::tcp_info::TcpInfoProbe>,
790 last_tcp_info: Option<crate::TcpInfo>,
794}
795
796async fn establish_http1<S>(
797 stream: S,
798 handshake_timeout: Duration,
799 mut stat: HttpStat,
800 tcp_probe: Option<crate::tcp_info::TcpInfoProbe>,
801 start: Instant,
802) -> (HttpStat, Option<HttpConnection>)
803where
804 S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + 'static,
805{
806 match timeout(
807 handshake_timeout,
808 hyper::client::conn::http1::handshake(TokioIo::new(stream)),
809 )
810 .await
811 {
812 Ok(Ok((sender, conn))) => {
813 tokio::spawn(async move {
814 let _ = conn.await;
815 });
816 stat.total = Some(start.elapsed());
817 let last_tcp_info = stat.tcp_info_post_connect.clone();
818 (
819 stat,
820 Some(HttpConnection {
821 sender: ConnectionSender::Http1(sender),
822 is_http2: false,
823 tcp_probe,
824 last_tcp_info,
825 }),
826 )
827 }
828 Ok(Err(e)) => (
829 finish_with_error(stat, Error::Hyper { source: e }, start),
830 None,
831 ),
832 Err(e) => (
833 finish_with_error(stat, Error::Timeout { source: e }, start),
834 None,
835 ),
836 }
837}
838
839async fn establish_http2<S>(
840 stream: S,
841 handshake_timeout: Duration,
842 mut stat: HttpStat,
843 tcp_probe: Option<crate::tcp_info::TcpInfoProbe>,
844 start: Instant,
845) -> (HttpStat, Option<HttpConnection>)
846where
847 S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + 'static,
848{
849 match timeout(
850 handshake_timeout,
851 hyper::client::conn::http2::handshake(TokioExecutor::new(), TokioIo::new(stream)),
852 )
853 .await
854 {
855 Ok(Ok((sender, conn))) => {
856 tokio::spawn(async move {
857 let _ = conn.await;
858 });
859 stat.total = Some(start.elapsed());
860 let last_tcp_info = stat.tcp_info_post_connect.clone();
861 (
862 stat,
863 Some(HttpConnection {
864 sender: ConnectionSender::Http2(sender),
865 is_http2: true,
866 tcp_probe,
867 last_tcp_info,
868 }),
869 )
870 }
871 Ok(Err(e)) => (
872 finish_with_error(stat, Error::Hyper { source: e }, start),
873 None,
874 ),
875 Err(e) => (
876 finish_with_error(stat, Error::Timeout { source: e }, start),
877 None,
878 ),
879 }
880}
881
882pub async fn connect(http_req: &HttpRequest) -> (HttpStat, Option<HttpConnection>) {
887 ensure_crypto_provider();
888 let start = Instant::now();
889 let mut stat = HttpStat::default();
890
891 let is_https = http_req.uri.scheme() == Some(&http::uri::Scheme::HTTPS);
892
893 let (tcp_stream, host, _is_http_forward, tcp_probe) =
894 match tcp_via_proxy(http_req, &mut stat).await {
895 Ok(r) => r,
896 Err(e) => return (finish_with_error(stat, e, start), None),
897 };
898
899 let handshake_timeout = http_req.request_timeout.unwrap_or(Duration::from_secs(30));
900
901 if is_https {
902 let (tls_stream, is_h2) = match tls_handshake(host, tcp_stream, http_req, &mut stat).await {
903 Ok(r) => r,
904 Err(e) => return (finish_with_error(stat, e, start), None),
905 };
906
907 if is_h2 {
908 establish_http2(tls_stream, handshake_timeout, stat, tcp_probe, start).await
909 } else {
910 establish_http1(tls_stream, handshake_timeout, stat, tcp_probe, start).await
911 }
912 } else {
913 establish_http1(tcp_stream, handshake_timeout, stat, tcp_probe, start).await
914 }
915}
916
917impl HttpConnection {
918 pub async fn send(&mut self, http_req: &HttpRequest) -> HttpStat {
920 let start = Instant::now();
921 let mut stat = HttpStat {
926 tcp_info_post_connect: self.last_tcp_info.clone(),
927 ..HttpStat::default()
928 };
929
930 let is_http1 = !self.is_http2;
931 let (req, done) = match build_tracked_request(http_req, is_http1) {
932 Ok(r) => r,
933 Err(e) => return finish_with_error(stat, e, start),
934 };
935 stat.request_headers = req.headers().clone();
936
937 match &mut self.sender {
939 ConnectionSender::Http1(sender) => {
940 if let Err(e) = sender.ready().await {
941 return finish_with_error(stat, Error::Hyper { source: e }, start);
942 }
943 }
944 ConnectionSender::Http2(sender) => {
945 if let Err(e) = sender.ready().await {
946 return finish_with_error(stat, Error::Hyper { source: e }, start);
947 }
948 }
949 }
950
951 let send_start = Instant::now();
952 let request_timeout = http_req.request_timeout.unwrap_or(DEFAULT_REQUEST_TIMEOUT);
953 let resp = match &mut self.sender {
955 ConnectionSender::Http1(sender) => {
956 timeout(request_timeout, sender.send_request(req)).await
957 }
958 ConnectionSender::Http2(sender) => {
959 let mut req = req;
960 *req.version_mut() = Version::HTTP_2;
961 req.headers_mut().remove("Host");
962 timeout(request_timeout, sender.send_request(req)).await
963 }
964 };
965
966 let resp = match resp {
967 Ok(Ok(resp)) => resp,
968 Ok(Err(e)) => return finish_with_error(stat, Error::Hyper { source: e }, start),
969 Err(e) => return finish_with_error(stat, Error::Timeout { source: e }, start),
970 };
971 let response_at = Instant::now();
972 record_send_split(&mut stat, send_start, response_at, &done);
973 stat.status = Some(resp.status());
974 stat.headers = Some(resp.headers().clone());
975 stat.version = Some(format!("{:?}", resp.version()));
976 capture_server_timing(&mut stat, resp.headers());
977 capture_protocol_advertisements(&mut stat, resp.headers());
978
979 let content_transfer_start = Instant::now();
983 let drained = timeout(
984 request_timeout,
985 drain_body_with_split(
986 resp.into_body(),
987 content_transfer_start,
988 http_req.max_body_size,
989 ),
990 )
991 .await;
992 match drained {
993 Ok(Ok((body_bytes, first_100k))) => {
994 stat.wire_body_size = Some(body_bytes.len());
995 stat.time_to_first_100k = first_100k;
996 stat.body = Some(body_bytes);
997 stat.content_transfer = Some(content_transfer_start.elapsed());
998 }
999 Ok(Err(e)) => {
1000 return finish_with_error(stat, e, start);
1001 }
1002 Err(e) => {
1003 return finish_with_error(stat, Error::Timeout { source: e }, start);
1004 }
1005 }
1006
1007 if let Some(probe) = &self.tcp_probe {
1011 let now = probe.sample();
1012 stat.tcp_info_final = now.clone();
1013 if now.is_some() {
1014 self.last_tcp_info = now;
1015 }
1016 }
1017
1018 stat.total = Some(start.elapsed());
1019
1020 if let Some(body) = &stat.body {
1022 stat.body_size = Some(body.len());
1023 }
1024 let encoding = stat
1025 .headers
1026 .as_ref()
1027 .and_then(|h| h.get("content-encoding"))
1028 .and_then(|v| v.to_str().ok())
1029 .unwrap_or_default();
1030 if !encoding.is_empty() {
1031 if let Some(body) = &stat.body {
1032 match decompress(encoding, body) {
1033 Ok(data) => stat.body = Some(data),
1034 Err(e) => stat.error = Some(e.to_string()),
1035 }
1036 }
1037 }
1038
1039 stat
1040 }
1041}