1use std::collections::HashMap;
2use rustls::{ClientConnection, StreamOwned};
3use std::net::{IpAddr, TcpStream};
4use std::{fs, thread};
5use std::io::{Read};
6use std::path::Path;
7use std::str::FromStr;
8use std::sync::Arc;
9use std::time::Duration;
10use json::{JsonValue};
11use log::{debug};
12use rand::distr::Alphanumeric;
13use rand::Rng;
14use rustls::RootCertStore;
15use crate::{Method, Protocol};
16use crate::client_response::ClientResponse;
17use crate::stream::ClientStream;
18use crate::url::Url;
19
20pub struct Client {
21 debug: bool,
22 url: String,
23 protocol: Protocol,
24 method: Method,
25 query: HashMap<String, String>,
26 headers: HashMap<String, JsonValue>,
27 cookies: HashMap<String, String>,
28 body: Vec<u8>,
29 read_timeout: u64,
30 write_timeout: u64,
31 auto_location: bool,
32 boundary: String,
33 retry: usize,
35 ca_pem: String,
36 pkcs12: String,
37 pkcs12_password: String,
38}
39impl Default for Client {
40 fn default() -> Self {
41 Self::new()
42 }
43}
44
45impl Client {
46 pub fn new() -> Self {
47 Self { debug: false, url: "".to_string(), protocol: Protocol::HTTP1_1, method: Method::Other("".to_string()), query: HashMap::new(), headers: Default::default(), cookies: Default::default(), body: vec![], read_timeout: 10, write_timeout: 10, auto_location: false, boundary: "".to_string(), retry: 0, ca_pem: "".to_string(), pkcs12: "".to_string(), pkcs12_password: "".to_string() }
48 }
49 pub fn reset(&mut self) -> &mut Self {
51 self.debug = false;
52 self.url = "".to_string();
53 self.protocol = Protocol::HTTP1_1;
54 self.method = Method::Other("".to_string());
55 self.query = HashMap::new();
56 self.headers = Default::default();
57 self.cookies = Default::default();
58 self.body = vec![];
59 self.read_timeout = 0;
60 self.write_timeout = 0;
61 self.auto_location = false;
62 self.boundary = "".to_string();
63 self.retry = 0;
64 self
65 }
66 pub fn debug(&mut self) -> &mut Self {
67 self.debug = true;
68 self
69 }
70 pub fn ca_pem(&mut self, ca_pem: &str) -> &mut Self {
71 self.ca_pem = ca_pem.to_string();
72 self
73 }
74 pub fn pkcs12(&mut self, pkcs12: &str, password: &str) -> &mut Self {
75 self.pkcs12 = pkcs12.to_string();
76 self.pkcs12_password = password.to_string();
77 self
78 }
79 pub fn write_timeout(&mut self, time: u64) -> &mut Self {
80 self.write_timeout = time;
81 self
82 }
83 pub fn read_timeout(&mut self, time: u64) -> &mut Self {
84 self.read_timeout = time;
85 self
86 }
87 pub fn http10(&mut self) -> &mut Self {
88 self.protocol = Protocol::HTTP1_0;
89 self
90 }
91 pub fn http11(&mut self) -> &mut Self {
92 self.protocol = Protocol::HTTP1_1;
93 self
94 }
95 pub fn http2(&mut self) -> &mut Self {
96 self.protocol = Protocol::HTTP2;
97 self
98 }
99 pub fn retry(&mut self, count: usize) -> &mut Self {
101 self.retry = count;
102 self
103 }
104 pub fn auto_location(&mut self) -> &mut Self {
105 self.auto_location = true;
106 self
107 }
108 fn generate_boundary(&mut self) -> String {
109 let rand: String = rand::rng().sample_iter(&Alphanumeric).take(16).map(char::from).collect();
110 format!("----WebKitFormBoundary{}", rand)
111 }
112 pub fn get(&mut self, url: &str) -> &mut Self {
113 self.url = url.to_string();
114 self.method = Method::GET;
115 self
116 }
117 pub fn post(&mut self, url: &str) -> &mut Self {
118 self.url = url.to_string();
119 self.method = Method::POST;
120 self
121 }
122 pub fn head(&mut self, url: &str) -> &mut Self {
123 self.url = url.to_string();
124 self.method = Method::HEAD;
125 self
126 }
127 pub fn delete(&mut self, url: &str) -> &mut Self {
128 self.url = url.to_string();
129 self.method = Method::DELETE;
130 self
131 }
132 pub fn method(&mut self, method: &str, url: &str) -> &mut Self {
133 self.url = url.to_string();
134 self.method = Method::Other(method.to_string());
135 self
136 }
137 pub fn header(&mut self, key: &str, value: JsonValue) -> &mut Self {
138 self.headers.insert(key.to_string(), value);
139 self
140 }
141 pub fn query(&mut self, key: &str, value: JsonValue) -> &mut Self {
142 let value = br_crypto::encoding::urlencoding_encode(value.to_string().as_str());
143 self.query.insert(key.to_string(), value.to_string());
144 self
145 }
146 pub fn raw_json(&mut self, data: JsonValue) -> &mut Self {
148 self.header("Content-Type", "application/json".into());
149 self.body = data.to_string().as_bytes().to_vec();
150 self.header("Content-Length", self.body.len().into());
151 self
152 }
153 pub fn form_data(&mut self, data: JsonValue) -> &mut Self {
155 self.boundary = self.generate_boundary();
156 self.header("Content-Type", format!("multipart/form-data; boundary={}", self.boundary).into());
157 let mut body = vec![];
158 for (key, value) in data.entries() {
159 let file = Path::new(value.as_str().unwrap());
160 if file.is_file() {
161 let mut t = vec![];
162 let r = fs::File::open(file).unwrap().read(&mut t).unwrap();
163 let filename = file.file_name().unwrap().to_str().unwrap().to_string();
164 let content_type = if let Some(kind) = infer::get(&t[..r]) {
165 kind.mime_type()
166 } else {
167 "application/octet-stream"
168 };
169 body.extend(format!("--{}\r\n", self.boundary).as_bytes().to_vec());
170 body.extend(format!(r#"Content-Disposition: form-data; name="{}"; filename="{}"{}"#, key, filename, "\r\n").as_bytes().to_vec());
171 body.extend(format!(r#"Content-Type: {}{}"#, content_type, "\r\n\r\n").as_bytes().to_vec());
172 body.extend(&t[..r]);
173 body.extend("\r\n".to_string().as_bytes().to_vec());
174 } else {
175 body.extend(format!("--{}\r\n", self.boundary).as_bytes().to_vec());
176 body.extend(format!(r#"Content-Disposition: form-data; name="{}"{}"#, key, "\r\n\r\n").as_bytes().to_vec());
177 body.extend(format!("{value}\r\n").as_bytes().to_vec());
178 }
179 }
180 body.extend(format!("--{}--\r\n", self.boundary).as_bytes().to_vec());
181 self.body = body.to_vec();
182 self.header("Content-Length", self.body.len().into());
183 self
184 }
185 pub fn x_www_form_urlencoded(&mut self, data: JsonValue) -> &mut Self {
187 self.header("Content-Type", "application/x-www-form-urlencoded".into());
188 let mut params = vec![];
189 for (key, value) in data.entries() {
190 params.push(format!("{}={}", key, value));
191 }
192 let params = params.join("&");
193 self.body = params.as_bytes().to_vec();
194 self.header("Content-Length", self.body.len().into());
195 self
196 }
197 pub fn send(&mut self) -> Result<ClientResponse, String> {
198 let mut url = Url::parse(&self.url)?;
199 let stream = match TcpStream::connect(format!("{}:{}", url.host, url.port)) {
200 Ok(stream) => stream,
201 Err(e) => {
202 if self.retry > 0 {
203 self.retry -= 1;
204 return self.send();
205 }
206 return Err(e.to_string());
207 }
208 };
209
210 if self.read_timeout > 0 {
211 let _ = stream.set_read_timeout(Option::from(Duration::from_secs(self.read_timeout)));
212 }
213 if self.write_timeout > 0 {
214 let _ = stream.set_write_timeout(Option::from(Duration::from_secs(self.write_timeout)));
215 }
216
217 let mut stream = if url.scheme == "https" {
218 let root_store = RootCertStore::from_iter(
219 webpki_roots::TLS_SERVER_ROOTS.iter().cloned()
220 );
221 let mut config = rustls::ClientConfig::builder().with_root_certificates(root_store).with_no_client_auth();
222 config.alpn_protocols = vec![self.protocol.str().to_lowercase().as_bytes().to_vec()];
224 let example_com = url.host.clone().try_into().unwrap();
225 let client = ClientConnection::new(Arc::new(config), example_com).unwrap();
226 ClientStream::Https(Box::new(StreamOwned::new(client, stream)))
227 } else {
228 ClientStream::Http(stream)
229 };
230
231
232 if !self.query.is_empty() {
233 url.set_query(self.query.clone());
234 }
235
236 let request_line = format!("{} {} {}", self.method.str(), url.path_query.as_str(), self.protocol.str());
237
238 let host = if IpAddr::from_str(url.host.as_str()).is_ok() {
239 format!("Host: {}:{}", url.host, url.port)
240 } else {
241 format!("Host: {}", url.host)
242 };
243
244
245 let mut header = vec![request_line, host];
246
247
248 for (key, value) in self.headers.iter() {
250 header.push(format!("{}: {}", key, value));
251 }
252
253 for (key, value) in self.cookies.iter() {
255 header.push(format!("Set-Cookie: {}={}", key, value));
256 }
257
258 header.push("\r\n".to_string());
260 match stream.write_all(header.join("\r\n").as_bytes()) {
261 Ok(()) => {
262 match stream.flush() {
263 Ok(e) => e,
264 Err(e) => return Err(e.to_string())
265 };
266 }
267 Err(e) => {
268 if self.retry > 0 {
269 self.retry -= 1;
270 return self.send();
271 }
272 return Err(e.to_string());
273 }
274 };
275
276 if self.debug {
277 debug!("\r\n==============请求头 {:?}============== \r\n{}\r\n============================",thread::current().id(), header.join("\r\n"));
278 }
279
280 if !self.body.is_empty() {
281 match stream.write_all(self.body.as_slice()) {
282 Ok(()) => {
283 match stream.flush() {
284 Ok(e) => e,
285 Err(e) => return Err(e.to_string())
286 };
287 }
288 Err(e) => {
289 if self.retry > 0 {
290 self.retry -= 1;
291 return self.send();
292 }
293 return Err(e.to_string());
294 }
295 }
296 }
297
298 if self.debug && self.boundary.is_empty() {
299 debug!("\r\n==============请求体 {:?}============== \r\n{}\r\n============================",thread::current().id(),String::from_utf8_lossy(self.body.as_slice()));
300 }
301
302
303 let mut res = ClientResponse::new(self.debug, stream).handle()?;
304 if [301, 302, 303].contains(&(res.status() as i32)) && !res.location().is_empty() {
305 self.url = res.location();
306 return self.send();
307 }
308 self.reset();
309 Ok(res)
310 }
311}
312
313
314