use json::{JsonValue, object};
use std::{str};
use std::collections::HashMap;
use std::fmt::Debug;
use std::str::FromStr;
use log::debug;
use reqwest::{Method};
use reqwest::blocking::multipart::{Form};
use serde_json::Value;
#[derive(Debug)]
pub struct Http {
url: String,
method: Methods,
header: Vec<(String, String)>,
debug: bool,
read_timeout: u64,
write_timeout: u64,
query: String,
content_type: ContentType,
param_form_data: Option<Form>,
param_form_urlencoded: HashMap<String, String>,
param_raw_json: Value,
param_raw_text: String,
status: u16,
response_content_type: ContentType,
}
impl Http {
pub fn new() -> Http {
Self {
url: "".to_string(),
method: Default::default(),
header: vec![],
debug: false,
read_timeout: 5,
write_timeout: 5,
query: "".to_string(),
content_type: ContentType::None,
param_form_data: None,
param_form_urlencoded: Default::default(),
param_raw_json: Default::default(),
param_raw_text: "".to_string(),
status: 0,
response_content_type: ContentType::None,
}
}
pub fn set_read_timeout(&mut self, secs: u64) -> &mut Self {
self.read_timeout = secs;
self
}
pub fn set_write_timeout(&mut self, secs: u64) -> &mut Self {
self.write_timeout = secs;
self
}
pub fn debug(&mut self, open: bool) -> &mut Self {
self.debug = open;
self
}
pub fn get(&mut self, url: &str) -> &mut Self {
self.url = url.to_string();
self.method = Methods::Get;
self
}
pub fn post(&mut self, url: &str) -> &mut Http {
self.url = url.to_string();
self.method = Methods::Post;
self
}
pub fn options(&mut self, url: &str) -> &mut Http {
self.url = url.to_string();
self.method = Methods::Options;
self
}
pub fn put(&mut self, url: &str) -> &mut Http {
self.url = url.to_string();
self.method = Methods::Put;
self
}
pub fn patch(&mut self, url: &str) -> &mut Http {
self.url = url.to_string();
self.method = Methods::Patch;
self
}
pub fn head(&mut self, url: &str) -> &mut Http {
self.url = url.to_string();
self.method = Methods::Head;
self
}
pub fn delete(&mut self, url: &str) -> &mut Http {
self.url = url.to_string();
self.method = Methods::Delete;
self
}
pub fn header(&mut self, key: &str, value: &str) -> &mut Http {
self.header.push((key.to_string(), value.to_string()));
self
}
pub fn bearer_auth(&mut self, token: &str) -> &mut Http {
self.header.push(("Authorization".to_string(), format!("Bearer {}", token)));
self
}
pub fn cookie(&mut self, key: &str, value: &str) -> &mut Http {
self.header.push(("Cookie".to_string(), format!("{}={}", key, value)));
self
}
pub fn query(&mut self, mut data: JsonValue) -> &mut Self {
self.content_type = ContentType::Plain;
let mut t = vec![];
for (key, value) in data.entries_mut() {
t.push(format!("{}={}", key, value))
};
self.query = t.join("&");
self.url = format!("{}?{}", self.url, self.query);
self
}
pub fn form_data(&mut self, data: Vec<FormData>) -> &mut Self
{
self.content_type = ContentType::FormData;
let mut form = Some(Form::default());
for item in data.iter() {
match item {
FormData::Text(key, value) => {
form = Some(form.take().unwrap().text(key.clone(), value.to_string().clone()));
}
FormData::File(key, path) => {
form = Some(form.take().unwrap().file(key.clone(), path.to_string().clone()).unwrap_or_default());
}
FormData::None => {}
}
}
self.param_form_data = form;
self
}
pub fn form_urlencoded(&mut self, data: JsonValue) -> &mut Self {
self.content_type = ContentType::FormUrlencoded;
let mut params = HashMap::new();
for (key, value) in data.entries() {
params.insert(key.to_string(), value.to_string());
}
self.param_form_urlencoded = params;
self
}
pub fn raw_json(&mut self, data: JsonValue) -> &mut Self {
self.content_type = ContentType::Json;
self.param_raw_json = Value::from_str(&*data.dump()).unwrap();
self
}
pub fn raw_xml(&mut self, data: &str) -> &mut Self {
self.header("Content-Type", ContentType::Xml.str());
self.content_type = ContentType::Xml;
self.param_raw_text = data.to_string();
self
}
pub fn raw_html(&mut self, data: &str) -> &mut Self {
self.header("Content-Type", ContentType::Html.str());
self.content_type = ContentType::Html;
self.param_raw_text = data.to_string();
self
}
pub fn raw_text(&mut self, data: &str) -> &mut Self {
self.header("Content-Type", ContentType::Plain.str());
self.content_type = ContentType::Plain;
self.param_raw_text = data.to_string();
self
}
fn send(&mut self, mode: &str) -> Result<Vec<u8>, String> {
let client = reqwest::blocking::Client::new();
let mut request = match self.method {
Methods::Get => {
client.get(self.url.as_str())
}
Methods::Post => {
client.post(self.url.as_str())
}
Methods::Options => {
client.request(Method::OPTIONS, self.url.as_str())
}
Methods::Patch => {
client.patch(self.url.as_str())
}
Methods::Head => {
client.head(self.url.as_str())
}
Methods::Delete => {
client.delete(self.url.as_str())
}
Methods::Put => {
client.put(self.url.as_str())
}
};
match self.content_type {
ContentType::FormData => {
request = request.multipart(self.param_form_data.take().unwrap());
}
ContentType::FormUrlencoded => {
request = request.form(&self.param_form_urlencoded);
}
ContentType::Json => {
request = request.json(&self.param_raw_json);
}
ContentType::Xml | ContentType::Plain | ContentType::Html => {
let body = self.param_raw_text.as_mut_str();
request = request.body(body.as_bytes().to_vec());
}
ContentType::None => {}
}
for (key, value) in self.header.iter() {
request = request.header(key.clone(), value.clone());
}
if self.debug {
debug!("发送数据: {:#?}",request);
}
match request.send() {
Ok(e) => {
if self.debug {
debug!("返回数据: {:#?}",e);
}
self.status = e.status().as_u16();
let mut headers = HashMap::new();
for (key, value) in e.headers().clone() {
if key.clone().is_some(){
headers.insert(key.unwrap().clone().to_string(), value.to_str().unwrap().to_string());
}
}
match headers.get("content-type").clone() {
Some(header) => {
let value = header.clone();
self.response_content_type = ContentType::from(value.clone().leak());
match value.as_str() {
s if s.contains("application/json") => {
let json = e.json::<Value>();
match json {
Ok(e) => {
Ok(e.to_string().as_bytes().to_vec())
}
Err(e) => Err(e.to_string())
}
}
_ => {
let text = e.text();
match text {
Ok(e) => {
Ok(e.as_bytes().to_vec())
}
Err(e) => Err(e.to_string())
}
}
}
}
None => {
match mode {
"json" => {
let r = e.json::<Value>();
match r {
Ok(e) => {
Ok(e.to_string().as_bytes().to_vec())
}
Err(e) => Err(e.to_string())
}
}
"text" => {
let r = e.text();
match r {
Ok(e) => {
Ok(e.as_bytes().to_vec())
}
Err(e) => Err(e.to_string())
}
}
"cookie" => {
let cookies = e.cookies().collect::<Vec<_>>();
let mut list = HashMap::new();
for cookie in cookies.iter() {
list.insert(cookie.name().to_string(), cookie.value().to_string());
}
Ok(JsonValue::from(list).dump().as_bytes().to_vec())
}
&_ => {
Ok(vec![])
}
}
}
}
}
Err(e) => {
Err(e.to_string())
}
}
}
pub fn cookies(&mut self) -> Result<JsonValue, String> {
return match self.send("cookie") {
Ok(e) => {
let res = unsafe { String::from_utf8_unchecked(e) };
Ok(json::parse(&*res).unwrap_or(object! {}))
}
Err(e) => Err(e)
};
}
pub fn text(&mut self) -> Result<String, String> {
return match self.send("text") {
Ok(e) => {
let res = unsafe { String::from_utf8_unchecked(e) };
Ok(res)
}
Err(e) => Err(e)
};
}
pub fn json(&mut self) -> Result<JsonValue, String> {
return match self.send("json") {
Ok(e) => {
let res = unsafe { String::from_utf8_unchecked(e) };
Ok(json::parse(&*res).unwrap_or(object! {}))
}
Err(e) => Err(e)
};
}
pub fn info(&mut self) -> Result<(u16, &'static str, String), String> {
return match self.send("text") {
Ok(e) => {
let res = unsafe { String::from_utf8_unchecked(e) };
Ok((self.status, self.response_content_type.str(), res))
}
Err(e) => Err(e)
};
}
}
#[derive(Clone, Debug)]
pub enum Methods {
Get,
Post,
Options,
Patch,
Head,
Delete,
Put,
}
impl Default for Methods {
fn default() -> Self {
Methods::Get
}
}
#[derive(Clone, Debug)]
pub enum Version {
Http09,
Http10,
Http11,
H2,
H3,
None,
}
impl Version {
pub fn str(&mut self) -> &'static str {
match self {
Version::Http09 => "HTTP/0.9",
Version::Http10 => "HTTP/1.0",
Version::Http11 => "HTTP/1.1",
Version::H2 => "HTTP/2.0",
Version::H3 => "HTTP/3.0",
Version::None => ""
}
}
pub fn from(name: &str) -> Version {
match name {
"HTTP/0.9" => Self::Http09,
"HTTP/1.0" => Self::Http10,
"HTTP/1.1" => Self::Http11,
"HTTP/2.0" => Self::H2,
"HTTP/3.0" => Self::H3,
_ => Self::None
}
}
pub fn set_version(name: &str) -> Version {
match name {
"0.9" => Self::Http09,
"1.0" => Self::Http10,
"1.1" => Self::Http11,
"2.0" => Self::H2,
"3.0" => Self::H3,
_ => Self::None
}
}
}
#[derive(Clone, Debug)]
pub enum Body {
Json(JsonValue),
Text(String),
Xml(String),
FormData(Vec<u8>),
XWwwFormUrlencoded(String),
None,
}
impl Body {
pub fn default() -> Body {
Self::None
}
pub fn bytes(&mut self) -> Vec<u8> {
match self {
Body::Json(e) => e.to_string().as_bytes().to_vec(),
Body::Text(e) => e.clone().as_bytes().to_vec(),
Body::Xml(e) => e.clone().as_bytes().to_vec(),
Body::FormData(e) => e.to_vec().clone(),
Body::XWwwFormUrlencoded(e) => e.clone().as_bytes().to_vec(),
Body::None => "".as_bytes().to_vec()
}
}
}
#[derive(Clone, Debug)]
pub enum ContentType {
FormData,
FormUrlencoded,
Json,
Xml,
Plain,
Html,
None,
}
impl ContentType {
pub fn str(&mut self) -> &'static str {
match self {
ContentType::Xml => "application/xml",
ContentType::Plain => "text/plain",
ContentType::Html => "text/html",
ContentType::None | _ => ""
}
}
pub fn from(name: &'static str) -> Self {
match name {
"application/xml" => ContentType::Xml,
"text/plain" => ContentType::Plain,
"text/html" => ContentType::Html,
_ => ContentType::None
}
}
}
#[derive(Clone, Debug)]
pub enum FormData {
Text(&'static str, &'static str),
File(&'static str, &'static str),
None,
}
impl Default for FormData {
fn default() -> Self {
FormData::None
}
}