atlas_http/
client_builder.rs1use base64::{engine::general_purpose::STANDARD, Engine as _};
2use rustls::{ClientConfig, RootCertStore};
3use std::path::Path;
4use std::sync::Arc;
5use super::{CookieJar, HttpClient, HttpHeaders, HttpSyncClient, ProxyType};
6use crate::{tls_noverify, user_agent};
7
8#[derive(Debug, Clone)]
9pub struct HttpClientConfig {
10 pub tls_config: Arc<rustls::ClientConfig>,
11 pub user_agent: Option<String>,
12 pub headers: HttpHeaders,
13 pub cookie: CookieJar,
14 pub follow_location: bool,
15 pub timeout: u64,
16 pub proxy_type: ProxyType,
17 pub proxy_host: String,
18 pub proxy_port: u16,
19 pub proxy_user: String,
20 pub proxy_password: String,
21}
22
23pub struct HttpClientBuilder {
24 config: HttpClientConfig,
25}
26
27impl Default for HttpClientBuilder {
28 fn default() -> HttpClientBuilder {
29 Self::new()
30 }
31}
32
33impl HttpClientBuilder {
34 pub fn new() -> Self {
35 Self {
36 config: HttpClientConfig::default()
37 }
38 }
39
40 pub fn build_async(&mut self) -> HttpClient {
42 HttpClient::new(&self.config)
43 }
44
45 pub fn build_sync(&mut self) -> HttpSyncClient {
47 HttpSyncClient::new(&self.config)
48 }
49
50 pub fn follow_location(mut self) -> Self {
52 self.config.follow_location = true;
53 self
54 }
55
56 pub fn timeout(mut self, seconds: u64) -> Self {
58 self.config.timeout = seconds;
59 self
60 }
61
62 pub fn cookie_jar(mut self, jar_file: &str) -> Self {
64 if !Path::new(&jar_file).exists() {
65 self.config.cookie.set_jar_file(jar_file);
66 self.config.cookie.set_auto_update(true);
67 } else {
68 self.config.cookie = CookieJar::from_file(jar_file, true).unwrap();
69 }
70 self
71 }
72
73 pub fn cookie_string(mut self, cookie_str: &str) -> Self {
75 self.config.cookie = CookieJar::from_string(&cookie_str.to_string());
76 self
77 }
78
79 pub fn noverify_ssl(mut self) -> Self {
81 let mut root_store = RootCertStore::empty();
83 root_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
84
85 let mut tls_config = ClientConfig::builder()
87 .with_root_certificates(root_store)
88 .with_no_client_auth();
89
90 tls_config.dangerous().set_certificate_verifier(Arc::new(
91 tls_noverify::NoCertificateVerification::new(rustls::crypto::ring::default_provider()),
92 ));
93
94 self.config.tls_config = Arc::new(tls_config);
95 self
96 }
97
98 pub fn user_agent(mut self, user_agent: &str) -> Self {
100 self.config.user_agent = Some(user_agent.to_string());
101 self
102 }
103
104 pub fn browser(mut self) -> Self {
106 self.config.headers = HttpHeaders::new();
108 self.config.headers.set(
109 "Accept",
110 "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
111 );
112 self.config.headers.set("Accept-Language", "en-US,en;q=0.5");
113 self.config.headers.set("Accept-Encoding", "identity");
114 self.config.headers.set("Connection", "close");
115
116 if self.config.user_agent.is_none() {
118 self.config.user_agent = Some(user_agent::random());
119 }
120 self.config.follow_location = true;
121 self
122 }
123
124 pub fn basic_auth(mut self, user: &str, password: &str) -> Self {
126 if user.is_empty() {
128 self.config.headers.delete("Authorization");
129 return self;
130 }
131
132 let auth_userpass = format!("{}:{}", user, password);
134 let auth_line = format!("Basic {}", STANDARD.encode(auth_userpass));
135 self.config.headers.set("Authorization", auth_line.as_str());
136
137 self
138 }
139
140 pub fn tor(mut self) -> Self {
142 self.config.proxy_host = "127.0.0.1".to_string();
143 self.config.proxy_port = 9050;
144 self.config.proxy_type = ProxyType::SOCKS5;
145 self
146 }
147
148 pub fn proxy(mut self, host: &str, port: &u16) -> Self {
150 if self.config.proxy_type == ProxyType::None {
151 self.config.proxy_type = ProxyType::SOCKS5;
152 }
153 self.config.proxy_host = host.to_string();
154 self.config.proxy_port = *port;
155 self
156 }
157
158 pub fn proxy_auth(mut self, user: &str, password: &str) -> Self {
160 self.config.proxy_user = user.to_string();
161 self.config.proxy_password = password.to_string();
162
163 if self.config.proxy_user.is_empty() {
164 self.config.headers.delete("Proxy-Authorization");
165 } else {
166 let auth_userpass = format!("{}:{}", user, password);
167 let auth_line = format!("Basic {}", STANDARD.encode(auth_userpass));
168 self.config
169 .headers
170 .set("Proxy-Authorization", auth_line.as_str());
171 }
172
173 self
174 }
175
176 pub fn proxy_type(mut self, proxy_type: ProxyType) -> Self {
178 self.config.proxy_type = proxy_type;
179 self
180 }
181}
182
183impl Default for HttpClientConfig {
184 fn default() -> HttpClientConfig {
185
186 let mut root_store = RootCertStore::empty();
188 root_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
189
190 let tls_config = ClientConfig::builder()
192 .with_root_certificates(root_store)
193 .with_no_client_auth();
194
195 HttpClientConfig {
196 tls_config: Arc::new(tls_config),
197 user_agent: None,
198 headers: HttpHeaders::from_vec(&vec!["Connection: close".to_string()]),
199 cookie: CookieJar::new(),
200 follow_location: false,
201 timeout: 5,
202 proxy_type: ProxyType::None,
203 proxy_host: String::new(),
204 proxy_port: 0,
205 proxy_user: String::new(),
206 proxy_password: String::new(),
207 }
208
209 }
210}
211
212
213