use serde_json::Value;
use std::time::Duration;
use tokio::time::{sleep, timeout};
use tracing::debug;
fn canonicalize_url(raw: &str) -> String {
let raw = raw.trim();
if raw.starts_with("https://https://") {
raw["https://".len()..].to_string()
} else if raw.starts_with("https://") || raw.starts_with("http://") {
raw.to_string()
} else {
format!("https://{}", raw)
}
}
pub async fn run_curl(raw_url: &str, no_timeout: bool, debug: bool) -> Result<(), String> {
let url = canonicalize_url(raw_url);
let client = reqwest::Client::builder()
.redirect(reqwest::redirect::Policy::limited(10))
.build()
.map_err(|e| format!("failed to build HTTP client: {}", e))?;
if debug {
debug!("Requesting {}", url);
}
let progress = tokio::spawn(async {
sleep(Duration::from_secs(5)).await;
eprintln!("Taking longer than expected to respond...");
});
let request = async {
let response = client
.get(&url)
.send()
.await
.map_err(|e| format!("request failed: {}", e))?;
let status = response.status();
let headers = response.headers().clone();
let body = response
.text()
.await
.map_err(|e| format!("failed to read response body: {}", e))?;
Ok::<_, String>((status, headers, body))
};
let result = if no_timeout {
request.await
} else {
timeout(Duration::from_secs(15), request)
.await
.map_err(|_| {
format!(
"Request to {} timed out after 15 seconds. Use --no-timeout to wait longer.",
url
)
})?
};
progress.abort();
let (status, headers, body) = result?;
println!("=== Curl to {}", url);
println!("--- Status --- {}", status);
println!("--- Headers ---");
for (name, value) in &headers {
println!("{}: {}", name, value.to_str().unwrap_or("<binary>"));
}
println!("--- Body ---");
if let Ok(json) = serde_json::from_str::<Value>(&body) {
let pretty = serde_json::to_string_pretty(&json)
.map_err(|e| format!("failed to pretty-print JSON body: {}", e))?;
println!("{}", pretty);
} else if body.is_empty() {
println!("<empty>");
} else {
println!("{}", body);
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::canonicalize_url;
#[test]
fn canonicalizes_plain_domains() {
assert_eq!(canonicalize_url("example.com"), "https://example.com");
}
#[test]
fn deduplicates_https_prefix() {
assert_eq!(
canonicalize_url("https://https://example.com"),
"https://example.com"
);
}
}