use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct Response {
pub url: String,
pub status: u16,
pub headers: HashMap<String, String>,
pub body: String,
}
impl Response {
pub fn is_success(&self) -> bool {
(200..300).contains(&self.status)
}
pub fn content_type(&self) -> Option<&str> {
self.headers.get("content-type").map(String::as_str)
}
pub fn is_html(&self) -> bool {
if let Some(ct) = self.content_type() {
let ct_lower = ct.to_ascii_lowercase();
if ct_lower.contains("text/html") || ct_lower.contains("application/xhtml+xml") {
return true;
}
}
let trimmed = self.body.trim_start();
let lower = trimmed[..trimmed.len().min(64)].to_ascii_lowercase();
lower.starts_with("<!doctype html") || lower.starts_with("<html")
}
pub fn is_bot_challenge(&self) -> bool {
if !self.is_html() {
return false;
}
let body_lower = self.body.to_ascii_lowercase();
if body_lower.contains("_pxhd")
|| body_lower.contains("_pxuuid")
|| body_lower.contains("px-captcha")
|| body_lower.contains("pxcaptcha")
|| body_lower.contains("_pxappappid")
|| body_lower.contains("px-cloud.net")
|| body_lower.contains("humansecurity.com")
{
return true;
}
if body_lower.contains("cf-challenge")
|| body_lower.contains("challenge-platform")
|| body_lower.contains("ray id")
&& body_lower.contains("cloudflare")
&& body_lower.contains("enable javascript")
{
return true;
}
if body_lower.contains("datadome")
|| body_lower.contains("captcha-delivery")
{
return true;
}
if body_lower.contains("akamai")
&& (body_lower.contains("bot") || body_lower.contains("challenge"))
{
return true;
}
if body_lower.contains("access to this page")
&& body_lower.contains("denied")
&& (body_lower.contains("captcha")
|| body_lower.contains("human")
|| body_lower.contains("press & hold")
|| body_lower.contains("verify you are"))
{
return true;
}
if (body_lower.contains("<title>")
&& (body_lower.contains("attention required")
|| body_lower.contains("access denied")
|| body_lower.contains("please verify")
|| body_lower.contains("security check")
|| body_lower.contains("robot")
|| body_lower.contains("blocked")))
&& body_lower.contains("challenge")
{
return true;
}
false
}
}