use reqwest::redirect::Policy;
use reqwest::Client;
use std::time::Instant;
use colored::Colorize;
use crate::error::Result;
use super::request::HttpRequest;
use super::response::HttpResponse;
pub struct HttpClient {
verbose: bool,
}
impl HttpClient {
pub fn new(verbose: bool) -> Self {
Self { verbose }
}
pub async fn execute(&self, request: &HttpRequest) -> Result<HttpResponse> {
let redirect_policy = if request.follow_redirects {
Policy::limited(10)
} else {
Policy::none()
};
let client = Client::builder()
.timeout(request.timeout)
.redirect(redirect_policy)
.build()?;
if self.verbose {
self.print_request_info(request);
}
let start = Instant::now();
let mut req_builder = client.request(request.method.clone(), &request.url);
for (key, value) in &request.headers {
req_builder = req_builder.header(key, value);
}
if let Some(body) = &request.body {
req_builder = req_builder.body(body.clone());
}
let response = req_builder.send().await?;
let duration = start.elapsed();
let status = response.status();
let headers = response.headers().clone();
let body = response.text().await?;
Ok(HttpResponse::new(status, headers, body, duration))
}
fn print_request_info(&self, request: &HttpRequest) {
println!("{}", ">>> Request".blue().bold());
println!("{} {}", request.method.as_str().green(), request.url.cyan());
for (key, value) in &request.headers {
println!("{}: {}", key.yellow(), value);
}
if let Some(body) = &request.body {
println!();
if let Ok(json) = serde_json::from_str::<serde_json::Value>(body) {
if let Ok(pretty) = serde_json::to_string_pretty(&json) {
println!("{}", pretty);
} else {
println!("{}", body);
}
} else {
println!("{}", body);
}
}
println!();
println!("{}", "<<< Response".blue().bold());
}
}