br_web_server/
client.rs

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    /// 重试次数
34    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    /// 重置全部
50    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    /// 设置重置
100    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    /// 请求JSON数据
147    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    /// 请求FormData数据
154    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    /// 表单urlencoded请求
186    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            // 需要小写 http/1.1
223            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        // 拼接 Header 头
249        for (key, value) in self.headers.iter() {
250            header.push(format!("{}: {}", key, value));
251        }
252
253        // 拼接 Cookie 头
254        for (key, value) in self.cookies.iter() {
255            header.push(format!("Set-Cookie: {}={}", key, value));
256        }
257
258        // 消息体隔离符号
259        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