#![no_std]
extern crate no_std_compat as std;
use std::prelude::v1::*;
use async_trait::async_trait;
use std::collections::BTreeMap;
use std::str::FromStr;
use std::time::Duration;
#[cfg(any(feature = "method", feature = "method_std"))]
use serde::{ Serialize, Deserialize };
#[cfg(any(feature = "request", feature = "response", feature = "request_std", feature = "response_std"))]
pub use product_os_http::{
Request, Response,
header::{ HeaderMap, HeaderName, HeaderValue },
StatusCode,
Uri
};
#[cfg(any(feature = "request", feature = "response", feature = "request_std", feature = "response_std"))]
pub use product_os_http_body::*;
#[cfg(any(feature = "method", feature = "method_std"))]
pub use product_os_http::method::Method as HttpMethod;
#[cfg(any(feature = "request", feature = "request_std"))]
use product_os_http::request;
#[cfg(any(feature = "request", feature = "request_std"))]
use bytes::Bytes;
use product_os_http::response::Parts;
#[cfg(any(feature = "request", feature = "request_std"))]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Protocol {
SOCKS5,
HTTP,
HTTPS,
ALL
}
#[cfg(any(feature = "request", feature = "request_std"))]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Proxy {
pub protocol: Protocol,
pub address: String
}
#[cfg(any(feature = "request", feature = "request_std"))]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RedirectPolicy {
None,
Limit(usize),
Default
}
#[cfg(any(feature = "method", feature = "method_std"))]
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
pub enum Method {
GET,
POST,
PATCH,
PUT,
DELETE,
TRACE,
HEAD,
OPTIONS,
CONNECT,
ANY
}
#[cfg(any(feature = "method", feature = "method_std"))]
impl Method {
pub fn to_http_method(&self) -> product_os_http::method::Method {
match self {
Method::GET => product_os_http::method::Method::GET,
Method::POST => product_os_http::method::Method::POST,
Method::PATCH => product_os_http::method::Method::PATCH,
Method::PUT => product_os_http::method::Method::PUT,
Method::DELETE => product_os_http::method::Method::DELETE,
Method::TRACE => product_os_http::method::Method::TRACE,
Method::HEAD => product_os_http::method::Method::HEAD,
Method::OPTIONS => product_os_http::method::Method::OPTIONS,
Method::CONNECT => product_os_http::method::Method::CONNECT,
Method::ANY => product_os_http::method::Method::GET
}
}
pub fn from_http_method(method: product_os_http::Method) -> Self {
match method {
product_os_http::method::Method::GET => Method::GET,
product_os_http::method::Method::POST => Method::POST,
product_os_http::method::Method::PATCH => Method::PATCH,
product_os_http::method::Method::PUT => Method::PUT,
product_os_http::method::Method::DELETE => Method::DELETE,
product_os_http::method::Method::TRACE => Method::TRACE,
product_os_http::method::Method::HEAD => Method::HEAD,
product_os_http::method::Method::OPTIONS => Method::OPTIONS,
product_os_http::method::Method::CONNECT => Method::CONNECT,
_ => Method::ANY
}
}
pub fn from_str(method: &str) -> Self {
match method {
"GET" => Method::GET,
"POST" => Method::POST,
"PATCH" => Method::PATCH,
"PUT" => Method::PUT,
"DELETE" => Method::DELETE,
"TRACE" => Method::TRACE,
"HEAD" => Method::HEAD,
"OPTIONS" => Method::OPTIONS,
"CONNECT" => Method::CONNECT,
_ => Method::ANY
}
}
}
#[cfg(any(feature = "request", feature = "request_std"))]
pub enum BodyType {
Json,
Form
}
#[cfg(any(feature = "request", feature = "request_std"))]
#[derive(Debug)]
pub enum ProductOSRequestError {
Error(String),
None
}
#[cfg(any(feature = "request", feature = "request_std"))]
impl std::fmt::Display for ProductOSRequestError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match &self {
ProductOSRequestError::Error(m) => write!(f, "{}", m),
ProductOSRequestError::None => write!(f, "No error")
}
}
}
#[cfg(any(feature = "request", feature = "request_std"))]
pub struct ProductOSRequest<DReq> {
url: Uri,
method: Method,
headers: BTreeMap<String, HeaderValue>,
bearer_auth: Option<String>,
query: BTreeMap<String, String>,
body: Option<DReq>,
content_type: Option<BodyType>,
}
#[cfg(any(feature = "request", feature = "request_std"))]
impl<DReq: product_os_http_body::Body> ProductOSRequest<DReq> {
fn new(method: Method, url: String) -> Self {
let uri = match Uri::from_str(url.as_str()) {
Ok(u) => u,
Err(e) => {
tracing::error!("Uri is invalid: {:?}", e);
Uri::default()
}
};
Self {
url: uri,
method,
headers: BTreeMap::new(),
bearer_auth: None,
query: BTreeMap::new(),
body: None,
content_type: None,
}
}
fn from_request(r: Request<DReq>) -> Self {
let uri = r.uri().to_owned();
let method = Method::from_http_method(r.method().to_owned());
let mut headers = BTreeMap::new();
let mut bearer_auth = None;
let mut content_type = None;
for (name, value) in r.headers() {
let name = name.to_string();
if name.as_str().to_lowercase() == "authorization" {
match value.to_str() {
Ok(val) => { bearer_auth = Some(val.to_string()); }
Err(_) => {}
}
}
else if name.as_str().to_lowercase() == "content-type" {
match value.to_str() {
Ok(val) => {
content_type = match val {
"application/json" => Some(BodyType::Json),
"application/www-form-url-encoded" => Some(BodyType::Form),
_ => None
}
}
Err(_) => {}
}
}
else {
headers.insert(name.to_string(), value.to_owned());
}
}
let query = match uri.query() {
None => BTreeMap::new(),
Some(query) => {
let mut query_tree = BTreeMap::new();
let query_parts = query.split("&").collect::<Vec<&str>>();
for query_part in query_parts {
let query_sub_parts = query_part.split("=").collect::<Vec<&str>>();
match query_sub_parts.get(0) {
None => {}
Some(key) => {
match query_sub_parts.get(1) {
None => {}
Some(value) => { query_tree.insert(key.to_string(), value.to_string()); }
}
}
}
}
query_tree
}
};
let body = r.into_body();
Self {
url: uri,
method,
headers,
bearer_auth,
query,
body: Some(body),
content_type
}
}
pub fn add_header(&mut self, name: String, value: String, is_sensitive: bool) {
let header_name = HeaderName::try_from(name).unwrap();
let mut header_value = HeaderValue::try_from(value).unwrap();
header_value.set_sensitive(is_sensitive);
self.headers.insert(header_name.as_str().to_string(), header_value);
}
pub fn add_headers(&mut self, headers: BTreeMap<String, String>, are_sensitive: bool) {
for (name, value) in headers {
self.add_header(name, value, are_sensitive.to_owned());
}
}
pub fn bearer_auth(&mut self, token: String) {
self.bearer_auth = Some(token);
}
pub fn add_param(&mut self, key: String, value: String) {
self.query.insert(key, value);
}
pub fn add_params(&mut self, params: BTreeMap<String, String>) {
for (name, value) in params {
self.add_param(name, value);
}
}
pub fn set_query(&mut self, query: BTreeMap<String, String>) {
self.query = query;
}
pub fn set_body(&mut self, data: DReq) {
self.body = Some(data);
}
fn build(self) -> Result<Request<impl product_os_http_body::Body>, ProductOSRequestError> {
let mut request = Request::builder();
let mut query_string = String::new();
for (key, value) in self.query {
query_string.push_str(key.as_str());
query_string.push_str("=");
query_string.push_str(value.as_str());
query_string.push_str("&");
}
match query_string.strip_suffix("&") {
None => {},
Some(q) => { query_string = q.to_string(); }
};
let url = if self.url.to_string().contains("?") {
let mut u = self.url.to_string();
u.push_str("&");
u.push_str(query_string.as_str());
u
}
else {
let mut u = self.url.to_string();
u.push_str("?");
u.push_str(query_string.as_str());
u
};
let mut uri = match Uri::from_str(url.as_str()) {
Ok(u) => u,
Err(e) => {
tracing::error!("Invalid uri: {:?}", e);
Uri::default()
}
};
request = request.uri(uri);
let method = self.method.to_http_method();
request = request.method(method);
for (name, value) in self.headers {
request = request.header(name, value);
}
match self.bearer_auth.clone() {
Some(a) => {
match HeaderValue::from_str(a.as_str()) {
Ok(auth) => { request = request.header(String::from("authorization"), auth); }
Err(e) => { tracing::error!("Invalid bearer auth for header"); }
}
},
None => {}
}
match self.body {
Some(body) => {
match self.content_type {
Some(BodyType::Json) => { request = request.header("content-type", "application/json"); },
Some(BodyType::Form) => { request = request.header("content-type", "application/www-form-url-encoded"); },
_ => ()
};
match request.body(body) {
Ok(req) => Ok(req),
Err(e) => Err(ProductOSRequestError::Error(e.to_string()))
}
},
None => Err(ProductOSRequestError::Error(String::from("No body provided")))
}
}
}
#[cfg(any(feature = "response", feature = "response_std"))]
pub struct ProductOSResponse<DRes: product_os_http_body::Body> {
response_url: String,
response_async: Option<Response<DRes>>,
}
#[cfg(any(feature = "response", feature = "response_std"))]
impl<DRes: product_os_http_body::Body> ProductOSResponse<DRes> {
pub fn new<D>(r: DRes, url: String) -> Self {
Self {
response_url: url,
response_async: Some(Response::new(r)),
}
}
pub fn parts(self) -> (Parts, DRes) {
self.response_async.unwrap().into_parts()
}
pub fn status(&self) -> StatusCode {
self.response_async.as_ref().unwrap().status()
}
pub fn status_code(&self) -> u16 {
self.status().as_u16()
}
pub fn get_headers(&self) -> BTreeMap<String, String> {
let mut map = BTreeMap::new();
let headers = self.response_async.as_ref().unwrap().headers();
for (name, value) in headers {
map.insert(name.to_string(), value.to_str().unwrap().to_string());
}
map
}
pub fn response_url(&self) -> String {
self.response_url.to_owned()
}
}
#[cfg(any(feature = "request", feature = "request_std"))]
#[derive(Clone)]
pub struct ProductOSRequester {
headers: product_os_http::header::HeaderMap,
secure: bool,
timeout: Duration,
connect_timeout: Duration,
certificates: Vec<Vec<u8>>,
trust_all_certificates: bool,
trust_any_certificate_for_hostname: bool,
proxy: Option<Proxy>,
redirect_policy: RedirectPolicy
}
#[cfg(any(feature = "request", feature = "request_std"))]
impl ProductOSRequester {
pub fn new() -> Self {
Self {
headers: product_os_http::header::HeaderMap::new(),
secure: true,
timeout: Duration::from_millis(1000),
connect_timeout: Duration::from_millis(1000),
certificates: vec!(),
trust_all_certificates: false,
trust_any_certificate_for_hostname: false,
proxy: None,
redirect_policy: RedirectPolicy::Default
}
}
pub fn add_header(&mut self, name: String, value: String, is_sensitive: bool) {
let header_name = product_os_http::header::HeaderName::try_from(name).unwrap();
let mut header_value = product_os_http::header::HeaderValue::try_from(value).unwrap();
header_value.set_sensitive(is_sensitive);
self.headers.append(header_name, header_value);
}
pub fn set_headers(&mut self, headers: BTreeMap<String, String>) {
let mut header_map = product_os_http::header::HeaderMap::new();
for (name, value) in headers {
let header_name = product_os_http::header::HeaderName::try_from(name).unwrap();
header_map.insert(header_name, product_os_http::header::HeaderValue::try_from(value).unwrap());
}
self.headers = header_map;
}
pub fn force_secure(&mut self, sec: bool) {
self.secure = sec;
}
pub fn trust_all_certificates(&mut self, trust: bool) {
self.trust_all_certificates = trust;
}
pub fn trust_any_certificate_for_hostname(&mut self, trust: bool) {
self.trust_any_certificate_for_hostname = trust;
}
pub fn set_timeout(&mut self, time: u64) {
self.timeout = Duration::from_millis(time);
}
pub fn set_connect_timeout(&mut self, time: u64) {
self.connect_timeout = Duration::from_millis(time);
}
pub fn add_trusted_certificate_pem(&mut self, certificate: Vec<u8>) {
self.certificates.push(certificate);
}
pub fn get_trusted_certificates(&self) -> &Vec<Vec<u8>> {
&self.certificates
}
pub fn set_redirect_policy(&mut self, policy: RedirectPolicy) {
self.redirect_policy = policy;
}
pub fn set_proxy(&mut self, proxy: Option<(Protocol, String)>) {
match proxy {
None => self.proxy = None,
Some((protocol, address)) => {
let proxy = Proxy {
protocol,
address
};
self.proxy = Some(proxy);
}
}
}
pub fn build<DReq: product_os_http_body::Body, DRes: product_os_http_body::Body>(&self, client: &mut impl ProductOSClient<DReq, DRes>) {
client.build(&self)
}
fn new_request<DReq: product_os_http_body::Body, DRes: product_os_http_body::Body>(&self, method: Method, url: String, client: &mut impl ProductOSClient<DReq, DRes>) -> ProductOSRequest<DReq> {
client.new_request(method, url)
}
async fn request<DReq: product_os_http_body::Body, DRes: product_os_http_body::Body>(&self, r: ProductOSRequest<DReq>, client: &mut impl ProductOSClient<DReq, DRes>) -> Result<ProductOSResponse<DRes>, ProductOSRequestError> {
client.request(r).await
}
async fn request_simple<DReq: product_os_http_body::Body, DRes: product_os_http_body::Body>(&self, method: Method, url: &str, client: &mut impl ProductOSClient<DReq, DRes>) -> Result<ProductOSResponse<DRes>, ProductOSRequestError> {
client.request_simple(method, url).await
}
async fn request_raw<DReq: product_os_http_body::Body, DRes: product_os_http_body::Body>(&self, r: Request<DReq>, client: &mut impl ProductOSClient<DReq, DRes>) -> Result<ProductOSResponse<DRes>, ProductOSRequestError> {
client.request_raw(r).await
}
}
#[cfg(any(feature = "request", feature = "request_std"))]
#[async_trait]
pub trait ProductOSClient<DReq: product_os_http_body::Body, DRes: product_os_http_body::Body> {
fn build(&mut self, requester: &ProductOSRequester);
fn new_request(&self, method: Method, url: String) -> ProductOSRequest<DReq>;
async fn request(&self, r: ProductOSRequest<DReq>) -> Result<ProductOSResponse<DRes>, ProductOSRequestError>;
async fn request_simple(&self, method: Method, url: &str) -> Result<ProductOSResponse<DRes>, ProductOSRequestError>;
async fn request_raw(&self, r: Request<DReq>) -> Result<ProductOSResponse<DRes>, ProductOSRequestError>;
#[cfg(feature = "json")]
async fn set_body_json(&self, r: &mut ProductOSRequest<DReq>, json: serde_json::Value);
#[cfg(feature = "form")]
async fn set_body_form(&self, r: &mut ProductOSRequest<DReq>, form: String);
async fn text(&self, r: ProductOSResponse<DRes>) -> Result<String, ProductOSRequestError>;
#[cfg(feature = "json")]
async fn json(&self, r: ProductOSResponse<DRes>) -> Result<serde_json::Value, ProductOSRequestError>;
async fn bytes(&self, r: ProductOSResponse<DRes>) -> Result<bytes::Bytes, ProductOSRequestError>;
}
#[cfg(any(all(feature = "request", feature = "custom")))]
#[derive(Clone)]
pub struct ProductOSRequestClient {
client: reqwest::Client
}
#[cfg(all(feature = "request", feature = "custom"))]
impl ProductOSRequestClient {
pub fn new() -> Self {
Self {
client: reqwest::Client::new()
}
}
fn build_request<DReq: product_os_http_body::Body>(&self, request: ProductOSRequest<DReq>) -> Result<reqwest::Request, ProductOSRequestError> {
let method = match request.method {
Method::GET => reqwest::Method::GET,
Method::POST => reqwest::Method::POST,
Method::PATCH => reqwest::Method::PATCH,
Method::PUT => reqwest::Method::PUT,
Method::DELETE => reqwest::Method::DELETE,
Method::TRACE => reqwest::Method::TRACE,
Method::HEAD => reqwest::Method::HEAD,
Method::OPTIONS => reqwest::Method::OPTIONS,
Method::CONNECT => reqwest::Method::CONNECT,
Method::ANY => reqwest::Method::GET
};
let mut r = self.client.request(method, request.url.to_string());
let mut query = vec![];
for (key, value) in request.query {
query.push((key, value));
}
r = r.query(query.as_slice());
let mut headers = reqwest::header::HeaderMap::new();
for (key, value) in request.headers {
match reqwest::header::HeaderName::from_str(key.as_str()) {
Ok(k) => {
match value.to_str() {
Ok(val) => {
match reqwest::header::HeaderValue::from_str(val) {
Ok(v) => { headers.insert(k, v); }
Err(_) => {}
}
}
Err(_) => {}
}
}
Err(_) => {}
}
}
r = r.headers(headers);
match r.build() {
Ok(req) => Ok(req),
Err(e) => {
tracing::error!("Failed to create request: {:?}", e);
Err(ProductOSRequestError::Error(e.to_string()))
}
}
}
}
#[cfg(all(feature = "request", feature = "custom"))]
#[async_trait]
impl ProductOSClient<product_os_http_body::BodyBytes, product_os_http_body::BodyBytes> for ProductOSRequestClient {
fn build(&mut self, requester: &ProductOSRequester) {
let mut header_map = reqwest::header::HeaderMap::new();
for (name, value) in requester.headers.iter() {
let name = name.to_string();
match value.to_str() {
Ok(val) => {
match reqwest::header::HeaderName::from_bytes(name.as_bytes()) {
Ok(name) => {
match reqwest::header::HeaderValue::from_str(val) {
Ok(value) => { header_map.insert(name, value); }
Err(_) => {}
}
}
Err(_) => {}
}
}
Err(_) => {}
};
}
let mut builder = reqwest::ClientBuilder::new()
.default_headers(header_map)
.https_only(requester.secure.to_owned())
.timeout(requester.timeout)
.connect_timeout(requester.connect_timeout)
.danger_accept_invalid_certs(requester.trust_all_certificates.to_owned())
.cookie_store(true)
.gzip(true)
.brotli(true);
for cert in &requester.certificates {
let certificate = reqwest::Certificate::from_der(cert.as_slice()).unwrap();
builder = builder.add_root_certificate(certificate);
}
match &requester.proxy {
None => {}
Some(proxy) => {
match proxy.protocol {
Protocol::SOCKS5 => {
let mut address_string = String::from("socks5://");
address_string.push_str(proxy.address.as_str());
match reqwest::Proxy::http(address_string.to_owned()) {
Ok(proxy) => {
tracing::trace!("Async proxy set successfully: {:?}", address_string);
builder = builder.proxy(proxy.to_owned());
},
Err(e) => {
tracing::error!("Failed to setup proxy: {:?}", e);
}
}
}
Protocol::HTTP => {
let mut address_string = String::from("http://");
address_string.push_str(proxy.address.as_str());
match reqwest::Proxy::http(address_string.to_owned()) {
Ok(proxy) => {
tracing::info!("Async proxy set successfully: {:?}", address_string);
builder = builder.proxy(proxy.to_owned());
},
Err(e) => {
tracing::error!("Failed to setup proxy: {:?}", e);
}
}
}
Protocol::HTTPS => {
let mut address_string = String::from("https://");
address_string.push_str(proxy.address.as_str());
match reqwest::Proxy::https(address_string.to_owned()) {
Ok(proxy) => {
tracing::info!("Async proxy set successfully: {:?}", address_string);
builder = builder.proxy(proxy.to_owned());
},
Err(e) => {
tracing::error!("Failed to setup proxy: {:?}", e);
}
}
},
Protocol::ALL => {
let mut address_string = String::from("http://");
address_string.push_str(proxy.address.as_str());
match reqwest::Proxy::all(address_string.to_owned()) {
Ok(proxy) => {
tracing::info!("Async proxy set successfully: {:?}", address_string);
builder = builder.proxy(proxy.to_owned());
},
Err(e) => {
tracing::error!("Failed to setup proxy: {:?}", e);
}
}
}
}
}
}
let redirect_policy = match requester.redirect_policy.to_owned() {
RedirectPolicy::None => reqwest::redirect::Policy::none(),
RedirectPolicy::Limit(hops) => reqwest::redirect::Policy::limited(hops),
RedirectPolicy::Default => reqwest::redirect::Policy::default()
};
builder = builder.redirect(redirect_policy);
tracing::trace!("Updated async client with configuration: {:?}", builder);
self.client = builder.build().unwrap();
}
fn new_request(&self, method: Method, url: String) -> ProductOSRequest<product_os_http_body::BodyBytes> {
ProductOSRequest::new(method, url)
}
async fn request(&self, r: ProductOSRequest<product_os_http_body::BodyBytes>) -> Result<ProductOSResponse<product_os_http_body::BodyBytes>, ProductOSRequestError> {
match self.build_request(r) {
Ok(request) => {
match self.client.execute(request).await {
Ok(response) => {
let url = response.url().to_string();
let body = match response.bytes().await {
Ok(b) => { product_os_http_body::BodyBytes::new(Bytes::from(b.as_ref())) }
Err(e) => { product_os_http_body::BodyBytes::new(Bytes::new()) }
};
Ok(ProductOSResponse::new::<Bytes>(body, url))
},
Err(e) => Err(ProductOSRequestError::Error(e.to_string()))
}
}
Err(e) => Err(e)
}
}
async fn request_simple(&self, method: Method, url: &str) -> Result<ProductOSResponse<product_os_http_body::BodyBytes>, ProductOSRequestError> {
let r = ProductOSRequest::<product_os_http_body::BodyBytes>::new(method, url.to_string());
match self.build_request(r) {
Ok(request) => {
match self.client.execute(request).await {
Ok(response) => {
let url = response.url().to_string();
let body = match response.bytes().await {
Ok(b) => { product_os_http_body::BodyBytes::new(Bytes::from(b.as_ref())) }
Err(e) => { product_os_http_body::BodyBytes::new(Bytes::new()) }
};
Ok(ProductOSResponse::new::<Bytes>(body, url))
},
Err(e) => Err(ProductOSRequestError::Error(e.to_string()))
}
}
Err(e) => Err(e)
}
}
async fn request_raw(&self, r: Request<product_os_http_body::BodyBytes>) -> Result<ProductOSResponse<product_os_http_body::BodyBytes>, ProductOSRequestError> {
let req = ProductOSRequest::from_request(r);
match self.build_request(req) {
Ok(request) => {
match self.client.execute(request).await {
Ok(response) => {
let url = response.url().to_string();
let body = match response.bytes().await {
Ok(b) => { product_os_http_body::BodyBytes::new(Bytes::from(b.as_ref())) }
Err(e) => { product_os_http_body::BodyBytes::new(Bytes::new()) }
};
Ok(ProductOSResponse::new::<Bytes>(body, url))
},
Err(e) => Err(ProductOSRequestError::Error(e.to_string()))
}
}
Err(e) => Err(e)
}
}
#[cfg(feature = "json")]
async fn set_body_json(&self, r: &mut ProductOSRequest<product_os_http_body::BodyBytes>, json: serde_json::Value) {
let json_string = json.to_string();
let body = product_os_http_body::BodyBytes::new(bytes::Bytes::from(json_string));
r.body = Some(body);
}
#[cfg(feature = "form")]
async fn set_body_form(&self, r: &mut ProductOSRequest<product_os_http_body::BodyBytes>, form: &[(String, String)]) {
let form_string = serde_urlencoded::to_string(form);
let body = product_os_http_body::BodyBytes::new(bytes::Bytes::from(form_string));
r.body = Some(body);
}
async fn text(&self, r: ProductOSResponse<product_os_http_body::BodyBytes>) -> Result<String, ProductOSRequestError> {
match r.response_async {
Some(res) => {
match <product_os_http_body::BodyBytes as Clone>::clone(&res.body()).collect().await {
Ok(body) => {
match String::from_utf8(body.to_bytes().as_ref().to_vec()) {
Ok(res) => Ok(res),
Err(e) => Err(ProductOSRequestError::Error(e.to_string()))
}
}
Err(e) => Err(ProductOSRequestError::Error(e.to_string()))
}
}
None => Err(ProductOSRequestError::Error(String::from("No response found")))
}
}
#[cfg(feature = "json")]
async fn json(&self, r: ProductOSResponse<product_os_http_body::BodyBytes>) -> Result<serde_json::Value, ProductOSRequestError> {
match r.response_async {
Some(res) => {
match <product_os_http_body::BodyBytes as Clone>::clone(&res.body()).collect().await {
Ok(body) => {
match String::from_utf8(body.to_bytes().as_ref().to_vec()) {
Ok(res) => {
match serde_json::Value::try_from(res) {
Ok(res) => Ok(res),
Err(e) => Err(ProductOSRequestError::Error(e.to_string()))
}
},
Err(e) => Err(ProductOSRequestError::Error(e.to_string()))
}
}
Err(e) => Err(ProductOSRequestError::Error(e.to_string()))
}
}
None => Err(ProductOSRequestError::Error(String::from("No response found")))
}
}
async fn bytes(&self, r: ProductOSResponse<product_os_http_body::BodyBytes>) -> Result<bytes::Bytes, ProductOSRequestError> {
match r.response_async {
Some(res) => {
match <product_os_http_body::BodyBytes as Clone>::clone(&res.body()).collect().await {
Ok(body) => Ok(Bytes::from(body.to_bytes().as_ref())),
Err(e) => Err(ProductOSRequestError::Error(e.to_string()))
}
}
None => Err(ProductOSRequestError::Error(String::from("No response found")))
}
}
}
#[cfg(all(feature = "request_std", feature = "std"))]
#[derive(Clone)]
pub struct ProductOSRequestClient {
client: reqwest::Client
}
#[cfg(all(feature = "request_std", feature = "std"))]
impl ProductOSRequestClient {
pub fn new() -> Self {
Self {
client: reqwest::Client::new()
}
}
fn build_request<DReq: product_os_http_body::Body>(&self, request: ProductOSRequest<DReq>) -> Result<reqwest::Request, ProductOSRequestError> {
let method = match request.method {
Method::GET => reqwest::Method::GET,
Method::POST => reqwest::Method::POST,
Method::PATCH => reqwest::Method::PATCH,
Method::PUT => reqwest::Method::PUT,
Method::DELETE => reqwest::Method::DELETE,
Method::TRACE => reqwest::Method::TRACE,
Method::HEAD => reqwest::Method::HEAD,
Method::OPTIONS => reqwest::Method::OPTIONS,
Method::CONNECT => reqwest::Method::CONNECT,
Method::ANY => reqwest::Method::GET
};
let mut r = self.client.request(method, request.url.to_string());
let mut query = vec![];
for (key, value) in request.query {
query.push((key, value));
}
r = r.query(query.as_slice());
let mut headers = reqwest::header::HeaderMap::new();
for (key, value) in request.headers {
match reqwest::header::HeaderName::from_str(key.as_str()) {
Ok(k) => {
match value.to_str() {
Ok(val) => {
match reqwest::header::HeaderValue::from_str(val) {
Ok(v) => { headers.insert(k, v); }
Err(_) => {}
}
}
Err(_) => {}
}
}
Err(_) => {}
}
}
r = r.headers(headers);
match r.build() {
Ok(req) => Ok(req),
Err(e) => {
tracing::error!("Failed to create request: {:?}", e);
Err(ProductOSRequestError::Error(e.to_string()))
}
}
}
}
#[cfg(all(feature = "request_std", feature = "std"))]
#[async_trait]
impl ProductOSClient<product_os_http_body::BodyBytes, product_os_http_body::BodyBytes> for ProductOSRequestClient {
fn build(&mut self, requester: &ProductOSRequester) {
let mut header_map = reqwest::header::HeaderMap::new();
for (name, value) in requester.headers.iter() {
let name = name.to_string();
match value.to_str() {
Ok(val) => {
match reqwest::header::HeaderName::from_bytes(name.as_bytes()) {
Ok(name) => {
match reqwest::header::HeaderValue::from_str(val) {
Ok(value) => { header_map.insert(name, value); }
Err(_) => {}
}
}
Err(_) => {}
}
}
Err(_) => {}
};
}
let mut builder = reqwest::ClientBuilder::new()
.default_headers(header_map)
.https_only(requester.secure.to_owned())
.timeout(requester.timeout)
.connect_timeout(requester.connect_timeout)
.danger_accept_invalid_certs(requester.trust_all_certificates.to_owned())
.cookie_store(true)
.gzip(true)
.brotli(true);
for cert in &requester.certificates {
let certificate = reqwest::Certificate::from_der(cert.as_slice()).unwrap();
builder = builder.add_root_certificate(certificate);
}
match &requester.proxy {
None => {}
Some(proxy) => {
match proxy.protocol {
Protocol::SOCKS5 => {
let mut address_string = String::from("socks5://");
address_string.push_str(proxy.address.as_str());
match reqwest::Proxy::http(address_string.to_owned()) {
Ok(proxy) => {
tracing::trace!("Async proxy set successfully: {:?}", address_string);
builder = builder.proxy(proxy.to_owned());
},
Err(e) => {
tracing::error!("Failed to setup proxy: {:?}", e);
}
}
}
Protocol::HTTP => {
let mut address_string = String::from("product_os_http://");
address_string.push_str(proxy.address.as_str());
match reqwest::Proxy::http(address_string.to_owned()) {
Ok(proxy) => {
tracing::info!("Async proxy set successfully: {:?}", address_string);
builder = builder.proxy(proxy.to_owned());
},
Err(e) => {
tracing::error!("Failed to setup proxy: {:?}", e);
}
}
}
Protocol::HTTPS => {
let mut address_string = String::from("https://");
address_string.push_str(proxy.address.as_str());
match reqwest::Proxy::https(address_string.to_owned()) {
Ok(proxy) => {
tracing::info!("Async proxy set successfully: {:?}", address_string);
builder = builder.proxy(proxy.to_owned());
},
Err(e) => {
tracing::error!("Failed to setup proxy: {:?}", e);
}
}
},
Protocol::ALL => {
let mut address_string = String::from("product_os_http://");
address_string.push_str(proxy.address.as_str());
match reqwest::Proxy::all(address_string.to_owned()) {
Ok(proxy) => {
tracing::info!("Async proxy set successfully: {:?}", address_string);
builder = builder.proxy(proxy.to_owned());
},
Err(e) => {
tracing::error!("Failed to setup proxy: {:?}", e);
}
}
}
}
}
}
let redirect_policy = match requester.redirect_policy.to_owned() {
RedirectPolicy::None => reqwest::redirect::Policy::none(),
RedirectPolicy::Limit(hops) => reqwest::redirect::Policy::limited(hops),
RedirectPolicy::Default => reqwest::redirect::Policy::default()
};
builder = builder.redirect(redirect_policy);
tracing::trace!("Updated async client with configuration: {:?}", builder);
self.client = builder.build().unwrap();
}
fn new_request(&self, method: Method, url: String) -> ProductOSRequest<product_os_http_body::BodyBytes> {
ProductOSRequest::new(method, url)
}
async fn request(&self, r: ProductOSRequest<product_os_http_body::BodyBytes>) -> Result<ProductOSResponse<product_os_http_body::BodyBytes>, ProductOSRequestError> {
match self.build_request(r) {
Ok(request) => {
match self.client.execute(request).await {
Ok(response) => {
let url = response.url().to_string();
let body = match response.bytes().await {
Ok(b) => { product_os_http_body::BodyBytes::new(Bytes::from(b)) }
Err(e) => { product_os_http_body::BodyBytes::new(Bytes::new()) }
};
Ok(ProductOSResponse::new::<Bytes>(body, url))
},
Err(e) => Err(ProductOSRequestError::Error(e.to_string()))
}
}
Err(e) => Err(e)
}
}
async fn request_simple(&self, method: Method, url: &str) -> Result<ProductOSResponse<product_os_http_body::BodyBytes>, ProductOSRequestError> {
let r = ProductOSRequest::<product_os_http_body::BodyBytes>::new(method, url.to_string());
match self.build_request(r) {
Ok(request) => {
match self.client.execute(request).await {
Ok(response) => {
let url = response.url().to_string();
let body = match response.bytes().await {
Ok(b) => { product_os_http_body::BodyBytes::new(Bytes::from(b)) }
Err(e) => { product_os_http_body::BodyBytes::new(Bytes::new()) }
};
Ok(ProductOSResponse::new::<Bytes>(body, url))
},
Err(e) => Err(ProductOSRequestError::Error(e.to_string()))
}
}
Err(e) => Err(e)
}
}
async fn request_raw(&self, r: Request<product_os_http_body::BodyBytes>) -> Result<ProductOSResponse<product_os_http_body::BodyBytes>, ProductOSRequestError> {
let req = ProductOSRequest::from_request(r);
match self.build_request(req) {
Ok(request) => {
match self.client.execute(request).await {
Ok(response) => {
let url = response.url().to_string();
let body = match response.bytes().await {
Ok(b) => { product_os_http_body::BodyBytes::new(Bytes::from(b)) }
Err(e) => { product_os_http_body::BodyBytes::new(Bytes::new()) }
};
Ok(ProductOSResponse::new::<Bytes>(body, url))
},
Err(e) => Err(ProductOSRequestError::Error(e.to_string()))
}
}
Err(e) => Err(e)
}
}
#[cfg(feature = "json")]
async fn set_body_json(&self, r: &mut ProductOSRequest::<product_os_http_body::BodyBytes>, json: serde_json::Value) {
let json_string = json.to_string();
let body = product_os_http_body::BodyBytes::new(bytes::Bytes::from(json_string));
r.body = Some(body);
}
#[cfg(feature = "form")]
async fn set_body_form(&self, r: &mut ProductOSRequest::<product_os_http_body::BodyBytes>, form: &[(String, String)]) {
let form_string = serde_urlencoded::to_string(form);
let body = product_os_http_body::BodyBytes::new(bytes::Bytes::from(form_string));
r.body = Some(body);
}
async fn text(&self, r: ProductOSResponse<product_os_http_body::BodyBytes>) -> Result<String, ProductOSRequestError> {
match r.response_async {
Some(res) => {
match <product_os_http_body::BodyBytes as Clone>::clone(&res.body()).collect().await {
Ok(body) => {
match String::from_utf8(body.to_bytes().as_ref().to_vec()) {
Ok(res) => Ok(res),
Err(e) => Err(ProductOSRequestError::Error(e.to_string()))
}
}
Err(e) => Err(ProductOSRequestError::Error(e.to_string()))
}
}
None => Err(ProductOSRequestError::Error(String::from("No response found")))
}
}
#[cfg(feature = "json")]
async fn json(&self, r: ProductOSResponse<product_os_http_body::BodyBytes>) -> Result<serde_json::Value, ProductOSRequestError> {
match r.response_async {
Some(res) => {
match <product_os_http_body::BodyBytes as Clone>::clone(&res.body()).collect().await {
Ok(body) => {
match String::from_utf8(body.to_bytes().as_ref().to_vec()) {
Ok(res) => {
match serde_json::Value::try_from(res) {
Ok(res) => Ok(res),
Err(e) => Err(ProductOSRequestError::Error(e.to_string()))
}
},
Err(e) => Err(ProductOSRequestError::Error(e.to_string()))
}
}
Err(e) => Err(ProductOSRequestError::Error(e.to_string()))
}
}
None => Err(ProductOSRequestError::Error(String::from("No response found")))
}
}
async fn bytes(&self, r: ProductOSResponse<product_os_http_body::BodyBytes>) -> Result<bytes::Bytes, ProductOSRequestError> {
match r.response_async {
Some(res) => {
match <product_os_http_body::BodyBytes as Clone>::clone(&res.body()).collect().await {
Ok(body) => Ok(Bytes::from(body.to_bytes())),
Err(e) => Err(ProductOSRequestError::Error(e.to_string()))
}
}
None => Err(ProductOSRequestError::Error(String::from("No response found")))
}
}
}