@@ -65,6 +65,22 @@ fn tls_config_h2() -> Arc<rustls::ClientConfig> { Arc::new(cfg)}/// Round a duration to whole milliseconds, but report a sub-ms phase as/// 1 rather than 0. The Linux kernel routes traffic destined for the/// host's own public IP via `lo`, so loopback TCP/handshake phases/// genuinely take 200-500 microseconds, which `as_millis()` truncates to/// zero. A `0` in the chart reads as "this phase didn't happen" rather/// than "this phase was instant", so floor it at 1 ms when the phase did/// run. Total is unaffected: any real probe takes well over 1 ms.fn elapsed_ms_atleast1(d: std::time::Duration) -> i64 { let ms = d.as_millis() as i64; if ms > 0 || d.is_zero() { ms } else { 1 }}fn looks_like_ssl_error(e: &anyhow::Error) -> bool { let s = format!("{e:?}").to_lowercase(); s.contains("certificate")
@@ -187,13 +203,13 @@ async fn phased_hop(url: &Url) -> anyhow::Result<HopResult> { .iter() .next() .ok_or_else(|| anyhow!("no addresses for {host}"))?; let dns_ms = dns_start.elapsed().as_millis() as i64; let dns_ms = elapsed_ms_atleast1(dns_start.elapsed()); let addr = SocketAddr::new(ip, port); let tcp_start = Instant::now(); let tcp = TcpStream::connect(addr).await.context("tcp connect")?; tcp.set_nodelay(true).ok(); let tcp_ms = tcp_start.elapsed().as_millis() as i64; let tcp_ms = elapsed_ms_atleast1(tcp_start.elapsed()); if !is_https { // h2 over plain TCP (h2c with prior knowledge) is rare in the
@@ -210,7 +226,7 @@ async fn phased_hop(url: &Url) -> anyhow::Result<HopResult> { .connect(server_name, tcp) .await .context("tls handshake")?; let tls_ms = tls_start.elapsed().as_millis() as i64; let tls_ms = elapsed_ms_atleast1(tls_start.elapsed()); let (status, headers, raw_headers_json, ttfb_ms) = h2_request(tls_stream, &host, &path_q).await?;
@@ -263,7 +279,7 @@ async fn h2_request( .context("h2 request build")?; let (rsp_fut, _send_stream) = sr.send_request(req, true).context("h2 send_request")?; let rsp = rsp_fut.await.context("h2 response")?; let ttfb_ms = ttfb_start.elapsed().as_millis() as i64; let ttfb_ms = elapsed_ms_atleast1(ttfb_start.elapsed()); let status = rsp.status().as_u16() as i64; let mut headers = BTreeMap::new();