reqwest_proxy_pool/classifier.rs
1//! Body-aware classification for proxy health feedback.
2
3/// Result of classifying a response body from a proxy.
4#[derive(Debug, Clone, Copy, PartialEq)]
5pub enum ProxyBodyVerdict {
6 /// Response is good. Proxy records a success.
7 Success,
8 /// Proxy is blocked (e.g. captcha, anti-bot). Records failure, retries with another proxy.
9 ProxyBlocked,
10 /// Server-side issue unrelated to proxy. Returns response as-is without affecting proxy stats.
11 Passthrough,
12}
13
14/// Classify responses with full body to determine proxy health at business level.
15///
16/// # Example
17/// ```rust,no_run
18/// use reqwest_proxy_pool::{BodyClassifier, ProxyBodyVerdict};
19///
20/// struct CaptchaDetector;
21///
22/// impl BodyClassifier for CaptchaDetector {
23/// fn classify(
24/// &self,
25/// status: reqwest::StatusCode,
26/// _headers: &reqwest::header::HeaderMap,
27/// body: &[u8],
28/// ) -> ProxyBodyVerdict {
29/// if status == reqwest::StatusCode::TOO_MANY_REQUESTS
30/// || String::from_utf8_lossy(body).contains("captcha")
31/// {
32/// ProxyBodyVerdict::ProxyBlocked
33/// } else if status.is_success() {
34/// ProxyBodyVerdict::Success
35/// } else {
36/// ProxyBodyVerdict::Passthrough
37/// }
38/// }
39/// }
40/// ```
41pub trait BodyClassifier: Send + Sync + 'static {
42 fn classify(
43 &self,
44 status: reqwest::StatusCode,
45 headers: &reqwest::header::HeaderMap,
46 body: &[u8],
47 ) -> ProxyBodyVerdict;
48}
49
50/// Default classifier: HTTP success = Success, otherwise Passthrough.
51pub struct DefaultBodyClassifier;
52
53impl BodyClassifier for DefaultBodyClassifier {
54 fn classify(
55 &self,
56 status: reqwest::StatusCode,
57 _headers: &reqwest::header::HeaderMap,
58 _body: &[u8],
59 ) -> ProxyBodyVerdict {
60 if status.is_success() {
61 ProxyBodyVerdict::Success
62 } else {
63 ProxyBodyVerdict::Passthrough
64 }
65 }
66}