br_reqwest/
lib.rs

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