use std::process;
use argh::FromArgs;
use fetch::HttpClient;
use fetch::tls::{ClientIdentity, TlsOptions};
use serde_json::Value;
use tracing::info;
#[path = "util/utils.rs"]
mod utils;
#[derive(FromArgs)]
struct Args {
#[argh(option)]
cert: String,
#[argh(option)]
key: String,
#[argh(option)]
url: String,
}
const MAX_REDIRECTS: u32 = 10;
#[tokio::main]
async fn main() -> Result<(), ohno::AppError> {
utils::init_tracing();
if std::env::args_os().nth(1).is_none() {
info!("No arguments provided; nothing to do. See the module docs for usage.");
return Ok(());
}
let args: Args = argh::from_env();
info!("Loading client certificate from: {}", args.cert);
info!("Loading client private key from: {}", args.key);
let cert_pem = std::fs::read(&args.cert).expect("failed to read certificate PEM file");
let key_pem = std::fs::read(&args.key).expect("failed to read private key PEM file");
let identity = ClientIdentity::from_pem(&cert_pem, &key_pem).expect("failed to parse PEM identity");
info!("Client identity loaded successfully");
let client = HttpClient::builder_tokio(fetch::tokio::TokioDeps::default())
.tls_options(TlsOptions::builder_rustls().client_identity(identity).build())
.build();
let mut url = args.url;
for redirect_count in 0..=MAX_REDIRECTS {
info!("Sending GET request to {url} ...");
let response = client.get(url.as_str()).fetch().await?;
let status = response.status();
info!("Response status: {status}");
if status.is_redirection() {
let location = response
.headers()
.get(http::header::LOCATION)
.expect("redirect response missing Location header")
.to_str()
.expect("Location header is not valid UTF-8");
info!("Following redirect to: {location}");
location.clone_into(&mut url);
drop(response.into_body());
continue;
}
let body_text = response.into_body().into_text().await?;
let json: Value = serde_json::from_str(&body_text).expect("response is not valid JSON");
let pretty = serde_json::to_string_pretty(&json).expect("failed to pretty-print JSON");
println!("\n--- Response Body ---");
println!("{pretty}");
println!("--- End ---");
if redirect_count > 0 {
info!("Followed {redirect_count} redirect(s) to reach final response");
}
return Ok(());
}
eprintln!("Error: too many redirects (>{MAX_REDIRECTS})");
process::exit(1);
}