Skip to main content

br_reqwest/
lib.rs

1//pub mod client;
2//pub mod response;
3//pub mod request;
4
5use json::{array, object, JsonValue};
6use log::{debug, error, info};
7use std::collections::HashMap;
8use std::fmt::Debug;
9use std::io::Write;
10use std::path::Path;
11use std::process::Command;
12use std::str::Lines;
13use std::{env, fs, str};
14use xmltree::Element;
15
16pub struct Client {
17    pub url: String,
18    debug: bool,
19    pub method: Method,
20    pub header: HashMap<String, String>,
21    body_data: JsonValue,
22    pub content_type: ContentType,
23    proxy: ProxyInfo,
24    cert_p12: bool,
25    cert_p12_filename: String,
26    cert_p12_password: String,
27    args: Vec<String>,
28    /// 请求超时
29    request_timeout: usize,
30    /// 响应超时
31    response_timeout: usize,
32    /// 重试次数
33    retry: usize,
34    command: Vec<String>,
35}
36
37impl Default for Client {
38    fn default() -> Self {
39        Self::new()
40    }
41}
42
43impl Client {
44    pub fn new() -> Self {
45        Self {
46            url: "".to_string(),
47            debug: false,
48            method: Method::NONE,
49            header: Default::default(),
50            body_data: object! {},
51            content_type: ContentType::Text,
52            proxy: ProxyInfo::None,
53            cert_p12: false,
54            cert_p12_filename: "".to_string(),
55            cert_p12_password: "".to_string(),
56            args: vec![],
57            request_timeout: 0,
58            response_timeout: 0,
59            retry: 0,
60            command: vec![],
61        }
62    }
63    pub fn debug(&mut self) -> &mut Self {
64        self.debug = true;
65        self
66    }
67    pub fn post(&mut self, url: &str) -> &mut Self {
68        self.url = url.to_string();
69        self.method = Method::POST;
70        self
71    }
72    pub fn get(&mut self, url: &str) -> &mut Self {
73        self.url = url.to_string();
74        self.method = Method::GET;
75        self
76    }
77    pub fn put(&mut self, url: &str) -> &mut Self {
78        self.url = url.to_string();
79        self.method = Method::PUT;
80        self
81    }
82    pub fn patch(&mut self, url: &str) -> &mut Self {
83        self.url = url.to_string();
84        self.method = Method::PATCH;
85        self
86    }
87    pub fn delete(&mut self, url: &str) -> &mut Self {
88        self.url = url.to_string();
89        self.method = Method::DELETE;
90        self
91    }
92    pub fn head(&mut self, url: &str) -> &mut Self {
93        self.url = url.to_string();
94        self.method = Method::HEAD;
95        self
96    }
97    pub fn options(&mut self, url: &str) -> &mut Self {
98        self.url = url.to_string();
99        self.method = Method::OPTIONS;
100        self
101    }
102    pub fn trace(&mut self, url: &str) -> &mut Self {
103        self.url = url.to_string();
104        self.method = Method::TRACE;
105        self
106    }
107    pub fn header(&mut self, key: &str, value: &str) -> &mut Self {
108        self.header.insert(key.to_string(), value.to_string());
109        self
110    }
111
112    pub fn query(&mut self, params: JsonValue) -> &mut Self {
113        let mut txt = vec![];
114        for (key, value) in params.entries() {
115            txt.push(format!("{key}={value}"));
116        }
117        if self.url.contains('?') {
118            if !txt.is_empty() {
119                self.url = format!("{}&{}", self.url, txt.join("&"));
120            }
121        } else if !txt.is_empty() {
122            self.url = format!("{}?{}", self.url, txt.join("&"));
123        }
124        self
125    }
126    /// 设置连接超时
127    pub fn set_request_timeout(&mut self, s: usize) -> &mut Self {
128        self.request_timeout = s;
129        self
130    }
131
132    pub fn set_response_timeout(&mut self, s: usize) -> &mut Self {
133        self.response_timeout = s;
134        self
135    }
136
137    pub fn set_retry(&mut self, count: usize) -> &mut Self {
138        self.retry = count;
139        self
140    }
141
142    pub fn set_command(&mut self, cmd: Vec<String>) -> &mut Self {
143        self.command = cmd;
144        self
145    }
146
147    /// JSON请求
148    pub fn raw_json(&mut self, data: JsonValue) -> &mut Self {
149        self.header("Content-Type", ContentType::Json.str().as_str());
150        self.content_type = ContentType::Json;
151        self.body_data = data;
152        self
153    }
154    pub fn raw_xml(&mut self, data: JsonValue) -> &mut Self {
155        self.header("Content-Type", ContentType::Xml.str().as_str());
156        self.content_type = ContentType::Xml;
157        self.body_data = data;
158        self
159    }
160    pub fn raw_stream(&mut self, filename: &str) -> &mut Self {
161        self.content_type = ContentType::Stream;
162        self.body_data = filename.into();
163        self
164    }
165    pub fn raw_binary_str(&mut self, text: &str) -> &mut Self {
166        self.content_type = ContentType::BinaryStr;
167        self.body_data = text.into();
168        self
169    }
170    pub fn raw_stream_urlencode(&mut self, text: &str) -> &mut Self {
171        self.content_type = ContentType::StreamUrlencode;
172        self.body_data = text.into();
173        self
174    }
175    /// FormData请求
176    pub fn form_data(&mut self, data: JsonValue) -> &mut Self {
177        self.header("Content-Type", ContentType::FormData.str().as_str());
178        self.content_type = ContentType::FormData;
179        self.body_data = data;
180        self
181    }
182    /// FormData请求
183    pub fn form_urlencoded(&mut self, data: JsonValue) -> &mut Self {
184        self.header("Content-Type", ContentType::FormUrlencoded.str().as_str());
185        self.content_type = ContentType::FormUrlencoded;
186        self.body_data = data;
187        self
188    }
189    /// 开启旧的ssl
190    pub fn set_cert_p12(&mut self, filename: &str, password: &str) -> &mut Self {
191        self.cert_p12_filename = filename.to_string();
192        self.cert_p12_password = password.to_string();
193        self.cert_p12 = true;
194        self
195    }
196    /// 指定代理
197    // curl -x socks5://proxy.example.com:1080 http://example.com
198    pub fn add_proxy(&mut self, proxy_addr: String) {
199        self.proxy = ProxyInfo::Addr(proxy_addr);
200    }
201
202    /// 指定代理, 该代理需要用户名和密码认证
203    // curl -x http://proxy-server:port -U username:password http://example.com
204    pub fn add_proxy_with_account(&mut self, proxy_addr: String, user: String, password: String) {
205        self.proxy = ProxyInfo::AddrWithAccount(proxy_addr, user, password);
206    }
207
208    pub fn send(&mut self) -> Result<Response, String> {
209        let mut output = Command::new("curl");
210
211        if !self.command.is_empty() {
212            self.args.extend(self.command.clone());
213        }
214        if self.cert_p12 {
215            self.args.extend([
216                "--cert-type".to_string(),
217                "P12".to_string(),
218                "--cert".to_string(),
219                self.cert_p12_filename.to_string(),
220                "--pass".to_string(),
221                self.cert_p12_password.to_string(),
222            ]);
223        }
224
225        if self.debug {
226            self.args.extend(["--trace-ascii".to_string(), "br-reqwest.log".to_string()]);
227        }
228
229        if self.request_timeout > 0 {
230            self.args.extend([
231                "--connect-timeout".to_string(),
232                self.request_timeout.to_string(),
233            ]);
234        }
235        if self.response_timeout > 0 {
236            self.args.extend(["--max-time".to_string(), self.response_timeout.to_string()]);
237        }
238
239        if self.retry > 0 {
240            self.args.extend(["--retry".to_string(), self.retry.to_string()]);
241        }
242
243        match &self.proxy {
244            ProxyInfo::None => {
245                self.args.extend(["--noproxy".to_string(), "*".to_string()]);
246            }
247            ProxyInfo::Addr(proxy) => {
248                self.args.extend(["-x".to_string(), proxy.to_string()]);
249            }
250            ProxyInfo::AddrWithAccount(proxy, user, pwd) => {
251                self.args.extend([
252                    "-x".to_string(),
253                    proxy.to_string(),
254                    "-U".to_string(),
255                    format!("{user}:{pwd}"),
256                ]);
257            }
258        }
259
260        match self.method {
261            Method::HEAD => {
262                self.args.push("-I".to_string());
263            }
264            _ => {
265                self.args.extend([
266                    "-i".to_string(),
267                    "-X".to_string(),
268                    self.method.to_str().to_uppercase(),
269                ]);
270            }
271        }
272        self.args.push(self.url.to_string());
273
274        if !self.header.is_empty() {
275            for (key, value) in self.header.iter() {
276                self.args.extend(["-H".to_string(), format!("{key}: {value}")]);
277            }
278        }
279
280        match self.content_type {
281            ContentType::FormData => {
282                for (_, value) in self.body_data.entries() {
283                    self.args.push("-F".to_string());
284
285                    if value[2].is_empty() {
286                        self.args.push(format!("{}={}", value[0], value[1]));
287                    } else {
288                        self.args.push(format!("{}={};{}", value[0], value[1], value[2]));
289                    }
290                }
291            }
292            ContentType::FormUrlencoded => {
293                self.args.push("-d".to_string());
294                let mut d = vec![];
295                for (key, value) in self.body_data.entries() {
296                    d.push(format!("{key}={value}"))
297                }
298                self.args.push(d.join("&").to_string());
299            }
300            ContentType::Json | ContentType::Xml => {
301                self.args.extend(["-d".to_string(), format!("{}", self.body_data)]);
302            }
303            ContentType::Javascript => {}
304            ContentType::Text => {}
305            ContentType::Html => {}
306            ContentType::Other(_) => {}
307            ContentType::Stream => {
308                // 文件路径
309                self.args.push("--data-binary".to_string());
310                self.args.push(format!("@{}", self.body_data));
311            }
312            ContentType::BinaryStr => {
313                self.args.push("--data-binary".to_string());
314                self.args.push(format!("{}", self.body_data));
315            }
316            ContentType::StreamUrlencode => {
317                self.args.push("--data-urlencode".to_string());
318                self.args.push(format!("{}", self.body_data));
319            }
320        }
321        output.args(self.args.as_slice());
322        if self.debug {
323            info!("curl {}", self.args.join(" "));
324        }
325        let req = match output.output() {
326            Ok(e) => e,
327            Err(e) => {
328                return Err(e.to_string());
329            }
330        };
331
332        if req.status.success() {
333            let body = req.stdout.clone();
334            if self.debug {
335                let text = String::from_utf8_lossy(&req.stdout);
336                info!("响应内容:\n{text}");
337            }
338            Ok(Response::new(self.debug, body)?)
339        } else {
340            let err = String::from_utf8_lossy(&req.stderr).to_string();
341            let txt = match err.find("ms:") {
342                None => err,
343                Some(e) => err[e + 3..].trim().to_string(),
344            };
345            Err(txt)
346        }
347    }
348}
349
350enum ProxyInfo {
351    None,
352    Addr(String),
353    AddrWithAccount(String, String, String),
354}
355
356#[derive(Debug)]
357pub struct Response {
358    debug: bool,
359    version: String,
360    status: i32,
361    status_text: String,
362    headers: JsonValue,
363    cookies: JsonValue,
364    /// 请求体
365    body: Body,
366}
367impl Response {
368    const CRLF2: [u8; 4] = [13, 10, 13, 10];
369
370    fn new(debug: bool, body: Vec<u8>) -> Result<Self, String> {
371        let mut that = Self {
372            debug,
373            version: "".to_string(),
374            status: 0,
375            status_text: "".to_string(),
376            headers: object! {},
377            cookies: object! {},
378            body: Default::default(),
379        };
380
381        let (header, body) = match body.windows(Self::CRLF2.len()).position(|window| window == Self::CRLF2) {
382            None => (vec![], vec![]),
383            Some(index) => {
384                let header = body[..index].to_vec();
385                let body = Vec::from(&body[index + Self::CRLF2.len()..]);
386                (header, body)
387            }
388        };
389
390        let text = String::from_utf8_lossy(header.as_slice());
391        let lines = text.lines();
392
393        that.get_request_line(lines.clone().next().expect("get next line in response err"))?;
394        // Header处理
395        that.get_header(lines.clone())?;
396        that.body.stream = body.clone();
397        that.body.set_content(body);
398        Ok(that)
399    }
400
401    /// 获取请求行信息
402    fn get_request_line(&mut self, line: &str) -> Result<(), String> {
403        let lines = line.split_whitespace().collect::<Vec<&str>>();
404        if lines.len() < 2 {
405            return Err("请求行错误".to_string());
406        }
407        self.version = lines[0].to_string();
408        self.status = lines[1].parse::<i32>().unwrap();
409        if lines.len() > 2 && !lines[2].is_empty() {
410            self.status_text = lines[2].trim().to_string();
411        }
412        Ok(())
413    }
414
415    /// Header处理
416    fn get_header(&mut self, data: Lines) -> Result<(), String> {
417        let mut header = object! {};
418        let mut cookie = object! {};
419        let mut body = Body::default();
420
421        for text in data {
422            let (key, value) = match text.trim().find(":") {
423                None => continue,
424                Some(e) => {
425                    let key = text[..e].trim().to_lowercase().clone();
426                    let value = text[e + 1..].trim().to_string();
427                    (key, value)
428                }
429            };
430            match key.as_str() {
431                "content-type" => match value {
432                    _ if value.contains("multipart/form-data") => {
433                        let boundarys = value.split("boundary=").collect::<Vec<&str>>();
434                        body.boundary = boundarys[1..].join("");
435                        body.content_type = ContentType::from("multipart/form-data");
436                        let _ = header.insert(key.as_str(), "multipart/form-data");
437                    }
438                    _ => {
439                        let value = match value.find(";") {
440                            None => value,
441                            Some(e) => value[..e].trim().to_string(),
442                        };
443                        body.content_type = ContentType::from(value.as_str());
444                        let _ = header.insert(key.as_str(), body.content_type.str());
445                    }
446                },
447                "content-length" => {
448                    body.content_length = value.to_string().parse::<usize>().unwrap_or(0);
449                }
450                "cookie" => {
451                    let _ = value.split(";").collect::<Vec<&str>>().iter().map(|&x| {
452                        match x.find("=") {
453                            None => {}
454                            Some(index) => {
455                                let key = x[..index].trim().to_string();
456                                let val = x[index + 1..].trim().to_string();
457                                let _ = cookie.insert(key.as_str(), val);
458                            }
459                        };
460                        ""
461                    }).collect::<Vec<&str>>();
462                }
463                _ => {
464                    if self.debug {
465                        debug!("header: {key} = {value}");
466                    }
467                    let _ = header.insert(key.as_str(), value);
468                }
469            };
470        }
471        self.headers = header.clone();
472        self.cookies = cookie.clone();
473        self.body = body.clone();
474        Ok(())
475    }
476    pub fn status(&self) -> i32 {
477        self.status
478    }
479    pub fn status_text(&self) -> String {
480        self.status_text.clone()
481    }
482    pub fn version(&self) -> String {
483        self.version.clone()
484    }
485    pub fn headers(&self) -> JsonValue {
486        self.headers.clone()
487    }
488    pub fn cookies(&self) -> JsonValue {
489        self.cookies.clone()
490    }
491    pub fn content_type(&self) -> String {
492        self.body.content_type.str().clone()
493    }
494    pub fn json(&self) -> Result<JsonValue, String> {
495        if self.body.content.is_empty() {
496            Ok(object! {})
497        } else {
498            match json::parse(self.body.content.to_string().as_str()) {
499                Ok(e) => Ok(e),
500                Err(e) => Err(e.to_string()),
501            }
502        }
503    }
504    pub fn xml(&self) -> Result<JsonValue, String> {
505        if self.body.content.is_empty() {
506            Ok(object! {})
507        } else {
508            let json = match Element::parse(self.body.content.to_string().as_bytes()) {
509                Ok(e) => xml_element_to_json(&e),
510                Err(e) => {
511                    if self.debug {
512                        error!("{:?} {}", e.to_string(), self.body.content.clone());
513                    }
514                    self.body.content.clone()
515                }
516            };
517            Ok(json)
518        }
519    }
520    pub fn body(&self) -> JsonValue {
521        self.body.content.clone()
522    }
523    pub fn stream(&self) -> Vec<u8> {
524        self.body.stream.clone()
525    }
526}
527fn xml_element_to_json(elem: &Element) -> JsonValue {
528    let mut obj = object! {};
529
530    for child in &elem.children {
531        if let xmltree::XMLNode::Element(e) = child {
532            obj[e.name.clone()] = xml_element_to_json(e);
533        }
534    }
535
536    match elem.get_text() {
537        None => obj,
538        Some(text) => JsonValue::from(text.to_string()),
539    }
540}
541
542#[derive(Clone, Debug)]
543pub enum Method {
544    GET,
545    POST,
546    OPTIONS,
547    PATCH,
548    HEAD,
549    DELETE,
550    TRACE,
551    PUT,
552    NONE,
553}
554
555impl Method {
556    pub fn to_str(&self) -> String {
557        match self {
558            Method::GET => "GET",
559            Method::POST => "POST",
560            Method::OPTIONS => "OPTIONS",
561            Method::PATCH => "PATCH",
562            Method::HEAD => "HEAD",
563            Method::DELETE => "DELETE",
564            Method::TRACE => "TRACE",
565            Method::PUT => "PUT",
566            Method::NONE => "NONE",
567        }.to_string()
568    }
569    pub fn from(name: &str) -> Self {
570        match name.to_lowercase().as_str() {
571            "post" => Self::POST,
572            "get" => Self::GET,
573            "head" => Self::HEAD,
574            "put" => Self::PUT,
575            "delete" => Self::DELETE,
576            "options" => Self::OPTIONS,
577            "patch" => Self::PATCH,
578            "trace" => Self::TRACE,
579            _ => Self::NONE,
580        }
581    }
582}
583#[derive(Clone, Debug)]
584pub enum Version {
585    Http09,
586    Http10,
587    Http11,
588    H2,
589    H3,
590    None,
591}
592
593impl Version {
594    pub fn str(&mut self) -> String {
595        match self {
596            Version::Http09 => "HTTP/0.9",
597            Version::Http10 => "HTTP/1.0",
598            Version::Http11 => "HTTP/1.1",
599            Version::H2 => "HTTP/2.0",
600            Version::H3 => "HTTP/3.0",
601            Version::None => "",
602        }.to_string()
603    }
604    pub fn from(name: &str) -> Version {
605        match name {
606            "HTTP/0.9" => Self::Http09,
607            "HTTP/1.0" => Self::Http10,
608            "HTTP/1.1" => Self::Http11,
609            "HTTP/2.0" => Self::H2,
610            "HTTP/3.0" => Self::H3,
611            _ => Self::None,
612        }
613    }
614    pub fn set_version(name: &str) -> Version {
615        match name {
616            "0.9" => Self::Http09,
617            "1.0" => Self::Http10,
618            "1.1" => Self::Http11,
619            "2.0" => Self::H2,
620            "3.0" => Self::H3,
621            _ => Self::None,
622        }
623    }
624}
625
626#[derive(Clone, Debug)]
627pub enum FormData {
628    /// KEY
629    /// value
630    /// 文本类型
631    Text(String, JsonValue, String),
632    /// 文件名
633    /// 文件路径
634    /// 文件类型
635    File(String, String, String),
636    None,
637}
638
639#[derive(Debug, Clone)]
640pub struct Body {
641    pub content_type: ContentType,
642    pub boundary: String,
643    pub content_length: usize,
644    pub content: JsonValue,
645    pub stream: Vec<u8>,
646}
647impl Body {
648    /// 解码
649    pub fn decode(input: &str) -> Result<String, String> {
650        let mut decoded = String::new();
651        let bytes = input.as_bytes();
652        let mut i = 0;
653
654        while i < bytes.len() {
655            if bytes[i] == b'%' {
656                if i + 2 >= bytes.len() {
657                    return Err("Incomplete percent-encoding".into());
658                }
659                let hex = &input[i + 1..i + 3];
660                match u8::from_str_radix(hex, 16) {
661                    Ok(byte) => decoded.push(byte as char),
662                    Err(_) => return Err(format!("Invalid percent-encoding: %{hex}")),
663                }
664                i += 3;
665            } else if bytes[i] == b'+' {
666                decoded.push(' ');
667                i += 1;
668            } else {
669                decoded.push(bytes[i] as char);
670                i += 1;
671            }
672        }
673
674        Ok(decoded)
675    }
676    pub fn set_content(&mut self, data: Vec<u8>) {
677        match self.content_type.clone() {
678            ContentType::FormData | ContentType::Stream => {
679                let mut fields = object! {};
680                let boundary_marker = format!("--{}", self.boundary);
681                let text = unsafe { String::from_utf8_unchecked(data) };
682                let parts = text.split(&boundary_marker).collect::<Vec<&str>>();
683                for part in parts {
684                    let part = part.trim();
685                    if part.is_empty() || part == "--" {
686                        continue; // 跳过无效部分
687                    }
688
689                    let mut headers_and_body = part.splitn(2, "\r\n\r\n");
690                    if let (Some(headers), Some(body)) = (headers_and_body.next(), headers_and_body.next())
691                    {
692                        // 解析头部,查找 Content-Disposition
693                        let headers = headers.split("\r\n");
694
695                        let mut field_name = "";
696                        let mut filename = "";
697                        let mut content_type = ContentType::Text;
698
699                        for header in headers {
700                            if header.to_lowercase().starts_with("content-disposition:") {
701                                match header.find("filename=\"") {
702                                    None => {}
703                                    Some(filename_start) => {
704                                        let filename_len = filename_start + 10;
705                                        let filename_end = header[filename_len..].find('"').unwrap() + filename_len;
706                                        filename = &header[filename_len..filename_end];
707                                    }
708                                }
709
710                                match header.find("name=\"") {
711                                    None => {}
712                                    Some(name_start) => {
713                                        let name_start = name_start + 6;
714                                        let name_end = header[name_start..].find('"').unwrap() + name_start;
715                                        field_name = &header[name_start..name_end];
716                                    }
717                                }
718                            }
719                            if header.to_lowercase().starts_with("content-type:") {
720                                content_type = ContentType::from(
721                                    header.to_lowercase().trim_start_matches("content-type:").trim(),
722                                );
723                            }
724                        }
725
726                        if filename.is_empty() {
727                            fields[field_name.to_string()] = JsonValue::from(body);
728                        } else {
729                            // 获取系统临时目录
730                            let mut temp_dir = env::temp_dir();
731                            // 构造临时文件的完整路径
732                            temp_dir.push(filename);
733                            // 打开(创建)临时文件
734                            let mut temp_file = match fs::File::create(&temp_dir) {
735                                Ok(e) => e,
736                                Err(_) => continue,
737                            };
738                            if temp_file.write(body.as_bytes()).is_ok() {
739                                if fields[field_name.to_string()].is_empty() {
740                                    fields[field_name.to_string()] = array![]
741                                }
742
743                                let extension = Path::new(filename).extension() // 可能返回 None
744                                                                   .and_then(|ext| ext.to_str()); // 转换为 &str
745
746                                let suffix = extension.unwrap_or("txt");
747
748                                fields[field_name.to_string()].push(object! {
749                                        //id:sha_256(body.as_bytes().to_vec()),
750                                        name:filename,
751                                        suffix:suffix,
752                                        size:body.len(),
753                                        "type":content_type.str(),
754                                        file:temp_dir.to_str()
755                                    }).unwrap();
756                            };
757                        }
758                    }
759                }
760                self.content = fields;
761            }
762            ContentType::FormUrlencoded => {
763                let text = unsafe { String::from_utf8_unchecked(data) };
764                let params = text.split("&").collect::<Vec<&str>>();
765                let mut list = object! {};
766                for param in params.iter() {
767                    let t = param.split("=").collect::<Vec<&str>>().iter().map(|&x| Body::decode(x).unwrap_or(x.to_string())).collect::<Vec<String>>();
768                    list[t[0].to_string()] = t[1].clone().into();
769                }
770                self.content = list;
771            }
772            ContentType::Json => {
773                let text = unsafe { String::from_utf8_unchecked(data) };
774                self.content = json::parse(text.as_str()).unwrap_or(object! {});
775            }
776            ContentType::Xml => {
777                let text = unsafe { String::from_utf8_unchecked(data) };
778                self.content = text.into();
779            }
780            ContentType::Html | ContentType::Text | ContentType::Javascript => {
781                let text = unsafe { String::from_utf8_unchecked(data) };
782                self.content = text.into();
783            }
784            ContentType::Other(_) => self.content = data.into(),
785            ContentType::BinaryStr => todo!(),
786            ContentType::StreamUrlencode => todo!(),
787        }
788    }
789}
790
791impl Default for Body {
792    fn default() -> Self {
793        Self {
794            content_type: ContentType::Other("text/plain".to_string()),
795            boundary: "".to_string(),
796            content_length: 0,
797            content: object! {},
798            stream: vec![],
799        }
800    }
801}
802
803/// 内容类型
804#[derive(Debug, Clone)]
805pub enum ContentType {
806    FormData,
807    FormUrlencoded,
808    Json,
809    Xml,
810    Javascript,
811    Text,
812    Html,
813    Stream,
814    BinaryStr,
815    StreamUrlencode,
816    Other(String),
817}
818impl ContentType {
819    pub fn from(name: &str) -> Self {
820        match name {
821            "multipart/form-data" => Self::FormData,
822            "application/x-www-form-urlencoded" => Self::FormUrlencoded,
823            "application/json" => Self::Json,
824            "application/xml" | "text/xml" => Self::Xml,
825            "application/javascript" => Self::Javascript,
826            "text/html" => Self::Html,
827            "text/plain" => Self::Text,
828            "application/octet-stream" => Self::Stream,
829            _ => Self::Other(name.to_string()),
830        }
831    }
832    pub fn str(&self) -> String {
833        match self {
834            Self::FormData => "multipart/form-data",
835            Self::FormUrlencoded => "application/x-www-form-urlencoded",
836            Self::Json => "application/json",
837            Self::Xml => "application/xml",
838            Self::Javascript => "application/javascript",
839            Self::Text => "text/plain",
840            Self::Html => "text/html",
841            Self::Other(name) => name,
842            Self::Stream => "application/octet-stream",
843            Self::BinaryStr => "application/octet-stream",
844            ContentType::StreamUrlencode => "application/x-www-form-urlencoded",
845        }.to_string()
846    }
847}