Skip to main content

antibot_rs/
request.rs

1use crate::cookie::Cookie;
2use crate::fingerprint::BrowserFingerprint;
3use crate::proxy::ProxyConfig;
4use std::collections::HashMap;
5
6/// A request to solve a challenge.
7///
8/// Use [`SolveRequest::get`] / [`SolveRequest::post`] to construct, then chain
9/// `with_*` methods to attach headers, cookies, a session, or a proxy.
10#[derive(Debug, Clone)]
11pub struct SolveRequest {
12    pub url: String,
13    pub method: SolveMethod,
14    pub headers: Option<HashMap<String, String>>,
15    pub cookies: Option<Vec<Cookie>>,
16    pub max_timeout_ms: Option<u64>,
17    pub session_id: Option<String>,
18    pub proxy: Option<ProxyConfig>,
19    /// If true, bypass the session cache for this request only.
20    pub bypass_cache: bool,
21    /// Optional browser fingerprint hints (only honored by Byparr-class providers).
22    pub fingerprint: Option<BrowserFingerprint>,
23}
24
25#[derive(Debug, Clone)]
26pub enum SolveMethod {
27    Get,
28    Post { body: PostBody },
29}
30
31#[derive(Debug, Clone)]
32pub enum PostBody {
33    /// `application/x-www-form-urlencoded` body.
34    Form(HashMap<String, String>),
35    /// JSON body sent as `application/json`.
36    Json(serde_json::Value),
37    /// Raw body with caller-specified content type.
38    Raw {
39        content_type: String,
40        body: Vec<u8>,
41    },
42}
43
44impl SolveRequest {
45    pub fn get(url: impl Into<String>) -> Self {
46        Self {
47            url: url.into(),
48            method: SolveMethod::Get,
49            headers: None,
50            cookies: None,
51            max_timeout_ms: None,
52            session_id: None,
53            proxy: None,
54            bypass_cache: false,
55            fingerprint: None,
56        }
57    }
58
59    pub fn post(url: impl Into<String>) -> Self {
60        Self {
61            url: url.into(),
62            method: SolveMethod::Post {
63                body: PostBody::Form(HashMap::new()),
64            },
65            headers: None,
66            cookies: None,
67            max_timeout_ms: None,
68            session_id: None,
69            proxy: None,
70            bypass_cache: false,
71            fingerprint: None,
72        }
73    }
74
75    /// Set a form body. Replaces any existing body.
76    pub fn form<K, V, I>(mut self, fields: I) -> Self
77    where
78        K: Into<String>,
79        V: Into<String>,
80        I: IntoIterator<Item = (K, V)>,
81    {
82        let map = fields.into_iter().map(|(k, v)| (k.into(), v.into())).collect();
83        self.method = SolveMethod::Post {
84            body: PostBody::Form(map),
85        };
86        self
87    }
88
89    /// Set a JSON body. Replaces any existing body.
90    pub fn json(mut self, value: serde_json::Value) -> Self {
91        self.method = SolveMethod::Post {
92            body: PostBody::Json(value),
93        };
94        self
95    }
96
97    /// Set a raw body. Replaces any existing body.
98    pub fn raw_body(mut self, content_type: impl Into<String>, body: Vec<u8>) -> Self {
99        self.method = SolveMethod::Post {
100            body: PostBody::Raw {
101                content_type: content_type.into(),
102                body,
103            },
104        };
105        self
106    }
107
108    pub fn with_headers(mut self, headers: HashMap<String, String>) -> Self {
109        self.headers = Some(headers);
110        self
111    }
112
113    pub fn with_header(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
114        self.headers
115            .get_or_insert_with(HashMap::new)
116            .insert(name.into(), value.into());
117        self
118    }
119
120    pub fn with_cookies(mut self, cookies: Vec<Cookie>) -> Self {
121        self.cookies = Some(cookies);
122        self
123    }
124
125    pub fn with_cookie(mut self, cookie: Cookie) -> Self {
126        self.cookies.get_or_insert_with(Vec::new).push(cookie);
127        self
128    }
129
130    pub fn with_timeout_ms(mut self, ms: u64) -> Self {
131        self.max_timeout_ms = Some(ms);
132        self
133    }
134
135    pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
136        self.session_id = Some(session_id.into());
137        self
138    }
139
140    pub fn with_proxy(mut self, proxy: ProxyConfig) -> Self {
141        self.proxy = Some(proxy);
142        self
143    }
144
145    pub fn bypass_cache(mut self) -> Self {
146        self.bypass_cache = true;
147        self
148    }
149
150    pub fn with_fingerprint(mut self, fingerprint: BrowserFingerprint) -> Self {
151        self.fingerprint = Some(fingerprint);
152        self
153    }
154}