grr_cli/commands/
transport.rs1use crate::core::RuntimeFeatures;
13use crate::core::auth::GoogleAuth;
14use crate::core::http::{HttpCore, TransportInfo};
15use anyhow::Result;
16use clap::Args;
17
18const PROBE_BASE_URL: &str = "https://gmail.googleapis.com/gmail/v1/";
21const PROBE_PATH: &str = "users/me/profile";
22
23#[derive(Args, Debug)]
24pub struct TransportArgs {}
25
26fn normalize_version(raw: &str) -> &str {
30 match raw {
31 "HTTP/1.1" => "HTTP_11",
32 "HTTP/2" | "HTTP/2.0" => "HTTP_2",
33 "HTTP/3" | "HTTP/3.0" => "HTTP_3",
34 other => other,
35 }
36}
37
38fn format_transport_report(info: &TransportInfo, features: &RuntimeFeatures) -> String {
40 format!(
41 "negotiated_protocol: {}\n\
42 http3_requested: {}\n\
43 http3_effective: {}\n\
44 fell_back: {}\n\
45 cpus: {}\n\
46 io_uring: {}\n\
47 http3_always_compiled: true\n\
48 runtime: tokio multi-thread (auto-sized to cores)",
49 normalize_version(&info.negotiated_version),
50 info.http3_requested,
51 info.http3_effective,
52 info.fell_back,
53 features.num_cpus,
54 features.io_uring,
55 )
56}
57
58pub async fn handle_transport_cmd(auth: GoogleAuth, _args: TransportArgs) -> Result<()> {
59 let base = crate::core::http::parse_url(PROBE_BASE_URL, "transport probe base")?;
60 let core = HttpCore::connect(auth, &base, PROBE_PATH).await?;
62 let report = format_transport_report(
63 core.transport_info(),
64 &crate::core::runtime::detect_runtime_features().await,
65 );
66 println!("{report}");
67 Ok(())
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 fn features() -> RuntimeFeatures {
75 RuntimeFeatures {
76 io_uring: false,
77 num_cpus: 8,
78 }
79 }
80
81 #[test]
82 fn normalizes_known_versions() {
83 assert_eq!(normalize_version("HTTP/3"), "HTTP_3");
84 assert_eq!(normalize_version("HTTP/3.0"), "HTTP_3");
85 assert_eq!(normalize_version("HTTP/2"), "HTTP_2");
86 assert_eq!(normalize_version("HTTP/2.0"), "HTTP_2");
87 assert_eq!(normalize_version("HTTP/1.1"), "HTTP_11");
88 assert_eq!(normalize_version("not-probed"), "not-probed");
89 }
90
91 #[test]
92 fn report_h3_effective() {
93 let info = TransportInfo {
94 negotiated_version: "HTTP/3".into(),
95 http3_requested: true,
96 http3_effective: true,
97 fell_back: false,
98 };
99 let report = format_transport_report(&info, &features());
100 for line in [
101 "negotiated_protocol: HTTP_3",
102 "http3_requested: true",
103 "http3_effective: true",
104 "fell_back: false",
105 "cpus: 8",
106 "io_uring: false",
107 "http3_always_compiled: true",
108 ] {
109 assert!(report.contains(line), "missing `{line}` in:\n{report}");
110 }
111 }
112
113 #[test]
114 fn report_h3_fell_back_to_h2() {
115 let info = TransportInfo {
116 negotiated_version: "HTTP/2".into(),
117 http3_requested: true,
118 http3_effective: false,
119 fell_back: true,
120 };
121 let report = format_transport_report(&info, &features());
122 assert!(report.contains("negotiated_protocol: HTTP_2"));
123 assert!(report.contains("fell_back: true"));
124 assert!(report.contains("http3_effective: false"));
125 }
126
127 #[test]
128 fn report_not_probed() {
129 let info = TransportInfo {
130 negotiated_version: "not-probed".into(),
131 ..TransportInfo::default()
132 };
133 let report = format_transport_report(&info, &features());
134 assert!(report.contains("negotiated_protocol: not-probed"));
135 assert!(report.contains("http3_requested: true"));
136 assert!(report.contains("http3_always_compiled: true"));
137 }
138}