|
@@ -1,337 +1,9 @@
|
|
|
//! HTTP client wrapper
|
|
//! HTTP client wrapper
|
|
|
|
|
|
|
|
-#[cfg(feature = "bitreq")]
|
|
|
|
|
-use std::sync::Arc;
|
|
|
|
|
-
|
|
|
|
|
-#[cfg(feature = "bitreq")]
|
|
|
|
|
-use bitreq::RequestExt;
|
|
|
|
|
use serde::de::DeserializeOwned;
|
|
use serde::de::DeserializeOwned;
|
|
|
-use serde::Serialize;
|
|
|
|
|
-
|
|
|
|
|
-use crate::error::HttpError;
|
|
|
|
|
-use crate::request::RequestBuilder;
|
|
|
|
|
-use crate::response::{RawResponse, Response};
|
|
|
|
|
-
|
|
|
|
|
-/// HTTP client wrapper
|
|
|
|
|
-#[derive(Clone)]
|
|
|
|
|
-pub struct HttpClient {
|
|
|
|
|
- #[cfg(feature = "reqwest")]
|
|
|
|
|
- inner: reqwest::Client,
|
|
|
|
|
- #[cfg(feature = "bitreq")]
|
|
|
|
|
- inner: Arc<bitreq::Client>,
|
|
|
|
|
- #[cfg(feature = "bitreq")]
|
|
|
|
|
- proxy_config: Option<ProxyConfig>,
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-impl std::fmt::Debug for HttpClient {
|
|
|
|
|
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
|
- f.debug_struct("HttpClient").finish()
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-#[cfg(feature = "reqwest")]
|
|
|
|
|
-impl HttpClient {
|
|
|
|
|
- /// Create a new HTTP client with default settings
|
|
|
|
|
- pub fn new() -> Self {
|
|
|
|
|
- Self {
|
|
|
|
|
- inner: reqwest::Client::new(),
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// Create an HttpClient from a reqwest::Client
|
|
|
|
|
- pub fn from_reqwest(client: reqwest::Client) -> Self {
|
|
|
|
|
- Self { inner: client }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// Create a new HTTP client builder
|
|
|
|
|
- pub fn builder() -> HttpClientBuilder {
|
|
|
|
|
- HttpClientBuilder::default()
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// GET request, returns JSON deserialized to R
|
|
|
|
|
- pub async fn fetch<R: DeserializeOwned>(&self, url: &str) -> Response<R> {
|
|
|
|
|
- let response = self.inner.get(url).send().await.map_err(HttpError::from)?;
|
|
|
|
|
- let status = response.status();
|
|
|
|
|
-
|
|
|
|
|
- if !status.is_success() {
|
|
|
|
|
- let message = response.text().await.unwrap_or_default();
|
|
|
|
|
- return Err(HttpError::Status {
|
|
|
|
|
- status: status.as_u16(),
|
|
|
|
|
- message,
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- response.json().await.map_err(HttpError::from)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// POST with JSON body, returns JSON deserialized to R
|
|
|
|
|
- pub async fn post_json<B: Serialize + ?Sized, R: DeserializeOwned>(
|
|
|
|
|
- &self,
|
|
|
|
|
- url: &str,
|
|
|
|
|
- body: &B,
|
|
|
|
|
- ) -> Response<R> {
|
|
|
|
|
- let response = self
|
|
|
|
|
- .inner
|
|
|
|
|
- .post(url)
|
|
|
|
|
- .json(body)
|
|
|
|
|
- .send()
|
|
|
|
|
- .await
|
|
|
|
|
- .map_err(HttpError::from)?;
|
|
|
|
|
- let status = response.status();
|
|
|
|
|
-
|
|
|
|
|
- if !status.is_success() {
|
|
|
|
|
- let message = response.text().await.unwrap_or_default();
|
|
|
|
|
- return Err(HttpError::Status {
|
|
|
|
|
- status: status.as_u16(),
|
|
|
|
|
- message,
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- response.json().await.map_err(HttpError::from)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// POST with form data, returns JSON deserialized to R
|
|
|
|
|
- pub async fn post_form<F: Serialize + ?Sized, R: DeserializeOwned>(
|
|
|
|
|
- &self,
|
|
|
|
|
- url: &str,
|
|
|
|
|
- form: &F,
|
|
|
|
|
- ) -> Response<R> {
|
|
|
|
|
- let response = self
|
|
|
|
|
- .inner
|
|
|
|
|
- .post(url)
|
|
|
|
|
- .form(form)
|
|
|
|
|
- .send()
|
|
|
|
|
- .await
|
|
|
|
|
- .map_err(HttpError::from)?;
|
|
|
|
|
- let status = response.status();
|
|
|
|
|
-
|
|
|
|
|
- if !status.is_success() {
|
|
|
|
|
- let message = response.text().await.unwrap_or_default();
|
|
|
|
|
- return Err(HttpError::Status {
|
|
|
|
|
- status: status.as_u16(),
|
|
|
|
|
- message,
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- response.json().await.map_err(HttpError::from)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// PATCH with JSON body, returns JSON deserialized to R
|
|
|
|
|
- pub async fn patch_json<B: Serialize + ?Sized, R: DeserializeOwned>(
|
|
|
|
|
- &self,
|
|
|
|
|
- url: &str,
|
|
|
|
|
- body: &B,
|
|
|
|
|
- ) -> Response<R> {
|
|
|
|
|
- let response = self
|
|
|
|
|
- .inner
|
|
|
|
|
- .patch(url)
|
|
|
|
|
- .json(body)
|
|
|
|
|
- .send()
|
|
|
|
|
- .await
|
|
|
|
|
- .map_err(HttpError::from)?;
|
|
|
|
|
- let status = response.status();
|
|
|
|
|
-
|
|
|
|
|
- if !status.is_success() {
|
|
|
|
|
- let message = response.text().await.unwrap_or_default();
|
|
|
|
|
- return Err(HttpError::Status {
|
|
|
|
|
- status: status.as_u16(),
|
|
|
|
|
- message,
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- response.json().await.map_err(HttpError::from)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// GET request returning raw response body
|
|
|
|
|
- pub async fn get_raw(&self, url: &str) -> Response<RawResponse> {
|
|
|
|
|
- let response = self.inner.get(url).send().await.map_err(HttpError::from)?;
|
|
|
|
|
- Ok(RawResponse::new(response))
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// POST request builder for complex cases
|
|
|
|
|
- pub fn post(&self, url: &str) -> RequestBuilder {
|
|
|
|
|
- RequestBuilder::new(self.inner.post(url))
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// GET request builder for complex cases
|
|
|
|
|
- pub fn get(&self, url: &str) -> RequestBuilder {
|
|
|
|
|
- RequestBuilder::new(self.inner.get(url))
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// PATCH request builder for complex cases
|
|
|
|
|
- pub fn patch(&self, url: &str) -> RequestBuilder {
|
|
|
|
|
- RequestBuilder::new(self.inner.patch(url))
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-#[cfg(feature = "bitreq")]
|
|
|
|
|
-impl HttpClient {
|
|
|
|
|
- /// Create a new HTTP client with default settings
|
|
|
|
|
- pub fn new() -> Self {
|
|
|
|
|
- Self {
|
|
|
|
|
- inner: Arc::new(bitreq::Client::new(10)), // Default capacity of 10
|
|
|
|
|
- proxy_config: None,
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// Create a new HTTP client builder
|
|
|
|
|
- pub fn builder() -> HttpClientBuilder {
|
|
|
|
|
- HttpClientBuilder::default()
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// Helper method to apply proxy if URL matches the configured proxy rules
|
|
|
|
|
- fn apply_proxy_if_needed(
|
|
|
|
|
- &self,
|
|
|
|
|
- request: bitreq::Request,
|
|
|
|
|
- url: &str,
|
|
|
|
|
- ) -> Response<bitreq::Request> {
|
|
|
|
|
- apply_proxy_if_needed(request, url, &self.proxy_config)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// GET request, returns JSON deserialized to R
|
|
|
|
|
- pub async fn fetch<R: DeserializeOwned>(&self, url: &str) -> Response<R> {
|
|
|
|
|
- let request = bitreq::get(url);
|
|
|
|
|
- let request = self.apply_proxy_if_needed(request, url)?;
|
|
|
|
|
- let response = request
|
|
|
|
|
- .send_async_with_client(&self.inner)
|
|
|
|
|
- .await
|
|
|
|
|
- .map_err(HttpError::from)?;
|
|
|
|
|
- let status = response.status_code;
|
|
|
|
|
|
|
|
|
|
- if !(200..300).contains(&status) {
|
|
|
|
|
- let message = response.as_str().unwrap_or("").to_string();
|
|
|
|
|
- return Err(HttpError::Status {
|
|
|
|
|
- status: status as u16,
|
|
|
|
|
- message,
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- response.json().map_err(HttpError::from)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// POST with JSON body, returns JSON deserialized to R
|
|
|
|
|
- pub async fn post_json<B: Serialize, R: DeserializeOwned>(
|
|
|
|
|
- &self,
|
|
|
|
|
- url: &str,
|
|
|
|
|
- body: &B,
|
|
|
|
|
- ) -> Response<R> {
|
|
|
|
|
- let request = bitreq::post(url).with_json(body).map_err(HttpError::from)?;
|
|
|
|
|
- let request = self.apply_proxy_if_needed(request, url)?;
|
|
|
|
|
- let response: bitreq::Response = request
|
|
|
|
|
- .send_async_with_client(&self.inner)
|
|
|
|
|
- .await
|
|
|
|
|
- .map_err(HttpError::from)?;
|
|
|
|
|
- let status = response.status_code;
|
|
|
|
|
-
|
|
|
|
|
- if !(200..300).contains(&status) {
|
|
|
|
|
- let message = response.as_str().unwrap_or("").to_string();
|
|
|
|
|
- return Err(HttpError::Status {
|
|
|
|
|
- status: status as u16,
|
|
|
|
|
- message,
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- response.json().map_err(HttpError::from)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// POST with form data, returns JSON deserialized to R
|
|
|
|
|
- pub async fn post_form<F: Serialize, R: DeserializeOwned>(
|
|
|
|
|
- &self,
|
|
|
|
|
- url: &str,
|
|
|
|
|
- form: &F,
|
|
|
|
|
- ) -> Response<R> {
|
|
|
|
|
- let form_str = serde_urlencoded::to_string(form)
|
|
|
|
|
- .map_err(|e| HttpError::Serialization(e.to_string()))?;
|
|
|
|
|
- let request = bitreq::post(url)
|
|
|
|
|
- .with_body(form_str.into_bytes())
|
|
|
|
|
- .with_header("Content-Type", "application/x-www-form-urlencoded");
|
|
|
|
|
- let request = self.apply_proxy_if_needed(request, url)?;
|
|
|
|
|
- let response: bitreq::Response = request
|
|
|
|
|
- .send_async_with_client(&self.inner)
|
|
|
|
|
- .await
|
|
|
|
|
- .map_err(HttpError::from)?;
|
|
|
|
|
- let status = response.status_code;
|
|
|
|
|
-
|
|
|
|
|
- if !(200..300).contains(&status) {
|
|
|
|
|
- let message = response.as_str().unwrap_or("").to_string();
|
|
|
|
|
- return Err(HttpError::Status {
|
|
|
|
|
- status: status as u16,
|
|
|
|
|
- message,
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- response.json().map_err(HttpError::from)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// PATCH with JSON body, returns JSON deserialized to R
|
|
|
|
|
- pub async fn patch_json<B: Serialize, R: DeserializeOwned>(
|
|
|
|
|
- &self,
|
|
|
|
|
- url: &str,
|
|
|
|
|
- body: &B,
|
|
|
|
|
- ) -> Response<R> {
|
|
|
|
|
- let request = bitreq::patch(url)
|
|
|
|
|
- .with_json(body)
|
|
|
|
|
- .map_err(HttpError::from)?;
|
|
|
|
|
- let request = self.apply_proxy_if_needed(request, url)?;
|
|
|
|
|
- let response: bitreq::Response = request
|
|
|
|
|
- .send_async_with_client(&self.inner)
|
|
|
|
|
- .await
|
|
|
|
|
- .map_err(HttpError::from)?;
|
|
|
|
|
- let status = response.status_code;
|
|
|
|
|
-
|
|
|
|
|
- if !(200..300).contains(&status) {
|
|
|
|
|
- let message = response.as_str().unwrap_or("").to_string();
|
|
|
|
|
- return Err(HttpError::Status {
|
|
|
|
|
- status: status as u16,
|
|
|
|
|
- message,
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- response.json().map_err(HttpError::from)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// GET request returning raw response body
|
|
|
|
|
- pub async fn get_raw(&self, url: &str) -> Response<RawResponse> {
|
|
|
|
|
- let request = bitreq::get(url);
|
|
|
|
|
- let request = self.apply_proxy_if_needed(request, url)?;
|
|
|
|
|
- let response = request
|
|
|
|
|
- .send_async_with_client(&self.inner)
|
|
|
|
|
- .await
|
|
|
|
|
- .map_err(HttpError::from)?;
|
|
|
|
|
- Ok(RawResponse::new(response))
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// POST request builder for complex cases
|
|
|
|
|
- pub fn post(&self, url: &str) -> RequestBuilder {
|
|
|
|
|
- // Note: Proxy will be applied when the request is sent
|
|
|
|
|
- RequestBuilder::new(
|
|
|
|
|
- bitreq::post(url),
|
|
|
|
|
- url,
|
|
|
|
|
- self.inner.clone(),
|
|
|
|
|
- self.proxy_config.clone(),
|
|
|
|
|
- )
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// GET request builder for complex cases
|
|
|
|
|
- pub fn get(&self, url: &str) -> RequestBuilder {
|
|
|
|
|
- RequestBuilder::new(
|
|
|
|
|
- bitreq::get(url),
|
|
|
|
|
- url,
|
|
|
|
|
- self.inner.clone(),
|
|
|
|
|
- self.proxy_config.clone(),
|
|
|
|
|
- )
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// PATCH request builder for complex cases
|
|
|
|
|
- pub fn patch(&self, url: &str) -> RequestBuilder {
|
|
|
|
|
- RequestBuilder::new(
|
|
|
|
|
- bitreq::patch(url),
|
|
|
|
|
- url,
|
|
|
|
|
- self.inner.clone(),
|
|
|
|
|
- self.proxy_config.clone(),
|
|
|
|
|
- )
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
|
|
+pub use crate::backends::{HttpClient, HttpClientBuilder};
|
|
|
|
|
+use crate::response::Response;
|
|
|
|
|
|
|
|
impl Default for HttpClient {
|
|
impl Default for HttpClient {
|
|
|
fn default() -> Self {
|
|
fn default() -> Self {
|
|
@@ -339,154 +11,6 @@ impl Default for HttpClient {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-/// HTTP client builder for configuring proxy and TLS settings
|
|
|
|
|
-#[derive(Debug, Default)]
|
|
|
|
|
-pub struct HttpClientBuilder {
|
|
|
|
|
- #[cfg(any(feature = "reqwest", feature = "bitreq"))]
|
|
|
|
|
- proxy: Option<ProxyConfig>,
|
|
|
|
|
- #[cfg(feature = "bitreq")]
|
|
|
|
|
- accept_invalid_certs: bool,
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-#[cfg_attr(target_arch = "wasm32", allow(dead_code))]
|
|
|
|
|
-#[cfg(any(feature = "bitreq", feature = "reqwest"))]
|
|
|
|
|
-#[derive(Debug, Clone)]
|
|
|
|
|
-pub(crate) struct ProxyConfig {
|
|
|
|
|
- url: url::Url,
|
|
|
|
|
- matcher: Option<regex::Regex>,
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-#[cfg(feature = "bitreq")]
|
|
|
|
|
-pub(crate) fn apply_proxy_if_needed(
|
|
|
|
|
- request: bitreq::Request,
|
|
|
|
|
- url: &str,
|
|
|
|
|
- proxy_config: &Option<ProxyConfig>,
|
|
|
|
|
-) -> Response<bitreq::Request> {
|
|
|
|
|
- if let Some(ref config) = proxy_config {
|
|
|
|
|
- if let Some(ref matcher) = config.matcher {
|
|
|
|
|
- // Check if URL host matches the regex pattern
|
|
|
|
|
- if let Ok(parsed_url) = url::Url::parse(url) {
|
|
|
|
|
- if let Some(host) = parsed_url.host_str() {
|
|
|
|
|
- if matcher.is_match(host) {
|
|
|
|
|
- let proxy = bitreq::Proxy::new_http(&config.url)
|
|
|
|
|
- .map_err(|e| HttpError::Proxy(e.to_string()))?;
|
|
|
|
|
- return Ok(request.with_proxy(proxy));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- // No matcher, apply proxy to all requests
|
|
|
|
|
- let proxy = bitreq::Proxy::new_http(&config.url)
|
|
|
|
|
- .map_err(|e| HttpError::Proxy(e.to_string()))?;
|
|
|
|
|
- return Ok(request.with_proxy(proxy));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- Ok(request)
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-impl HttpClientBuilder {
|
|
|
|
|
- /// Set a proxy URL (reqwest only)
|
|
|
|
|
- #[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))]
|
|
|
|
|
- pub fn proxy(mut self, url: url::Url) -> Self {
|
|
|
|
|
- self.proxy = Some(ProxyConfig { url, matcher: None });
|
|
|
|
|
- self
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// Set a proxy URL with a host pattern matcher (reqwest only)
|
|
|
|
|
- #[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))]
|
|
|
|
|
- pub fn proxy_with_matcher(mut self, url: url::Url, pattern: &str) -> Response<Self> {
|
|
|
|
|
- let matcher = regex::Regex::new(pattern)
|
|
|
|
|
- .map_err(|e| HttpError::Proxy(format!("Invalid proxy pattern: {}", e)))?;
|
|
|
|
|
- self.proxy = Some(ProxyConfig {
|
|
|
|
|
- url,
|
|
|
|
|
- matcher: Some(matcher),
|
|
|
|
|
- });
|
|
|
|
|
- Ok(self)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// Accept invalid TLS certificates (bitreq only)
|
|
|
|
|
- #[cfg(feature = "bitreq")]
|
|
|
|
|
- pub fn danger_accept_invalid_certs(mut self, accept: bool) -> Self {
|
|
|
|
|
- self.accept_invalid_certs = accept;
|
|
|
|
|
- self
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// Set a proxy URL (bitreq only)
|
|
|
|
|
- #[cfg(feature = "bitreq")]
|
|
|
|
|
- pub fn proxy(mut self, url: url::Url) -> Self {
|
|
|
|
|
- self.proxy = Some(ProxyConfig { url, matcher: None });
|
|
|
|
|
- self
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// Set a proxy URL with a host pattern matcher (bitreq only)
|
|
|
|
|
- #[cfg(feature = "bitreq")]
|
|
|
|
|
- pub fn proxy_with_matcher(mut self, url: url::Url, pattern: &str) -> Response<Self> {
|
|
|
|
|
- let matcher = regex::Regex::new(pattern)
|
|
|
|
|
- .map_err(|e| HttpError::Proxy(format!("Invalid proxy pattern: {}", e)))?;
|
|
|
|
|
- self.proxy = Some(ProxyConfig {
|
|
|
|
|
- url,
|
|
|
|
|
- matcher: Some(matcher),
|
|
|
|
|
- });
|
|
|
|
|
- Ok(self)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// Build the HTTP client
|
|
|
|
|
- pub fn build(self) -> Response<HttpClient> {
|
|
|
|
|
- #[cfg(feature = "reqwest")]
|
|
|
|
|
- {
|
|
|
|
|
- #[cfg(not(target_arch = "wasm32"))]
|
|
|
|
|
- let mut builder = reqwest::Client::builder();
|
|
|
|
|
- #[cfg(target_arch = "wasm32")]
|
|
|
|
|
- let builder = reqwest::Client::builder();
|
|
|
|
|
- #[cfg(not(target_arch = "wasm32"))]
|
|
|
|
|
- if let Some(proxy) = self.proxy {
|
|
|
|
|
- let proxy_url = proxy.url;
|
|
|
|
|
- if let Some(matcher) = proxy.matcher {
|
|
|
|
|
- let custom_proxy = reqwest::Proxy::custom(move |url| {
|
|
|
|
|
- url.host_str().and_then(|host| {
|
|
|
|
|
- if matcher.is_match(host) {
|
|
|
|
|
- Some(proxy_url.clone())
|
|
|
|
|
- } else {
|
|
|
|
|
- None
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- });
|
|
|
|
|
- builder = builder.proxy(custom_proxy);
|
|
|
|
|
- } else {
|
|
|
|
|
- let proxy = reqwest::Proxy::all(proxy_url)
|
|
|
|
|
- .map_err(|e| HttpError::Proxy(e.to_string()))?;
|
|
|
|
|
- builder = builder.proxy(proxy);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- #[cfg(target_arch = "wasm32")]
|
|
|
|
|
- if self.proxy.is_some() {
|
|
|
|
|
- return Err(HttpError::Build(
|
|
|
|
|
- "proxy configuration is not supported on wasm".to_string(),
|
|
|
|
|
- ));
|
|
|
|
|
- }
|
|
|
|
|
- let client = builder
|
|
|
|
|
- .build()
|
|
|
|
|
- .map_err(|e| HttpError::Build(e.to_string()))?;
|
|
|
|
|
- Ok(HttpClient { inner: client })
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- #[cfg(feature = "bitreq")]
|
|
|
|
|
- {
|
|
|
|
|
- // Return error if danger_accept_invalid_certs was set
|
|
|
|
|
- if self.accept_invalid_certs {
|
|
|
|
|
- return Err(HttpError::Build(
|
|
|
|
|
- "danger_accept_invalid_certs is not supported".to_string(),
|
|
|
|
|
- ));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- Ok(HttpClient {
|
|
|
|
|
- inner: Arc::new(bitreq::Client::new(10)), // Default capacity of 10
|
|
|
|
|
- proxy_config: self.proxy,
|
|
|
|
|
- })
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
/// Convenience function for simple GET requests
|
|
/// Convenience function for simple GET requests
|
|
|
pub async fn fetch<R: DeserializeOwned>(url: &str) -> Response<R> {
|
|
pub async fn fetch<R: DeserializeOwned>(url: &str) -> Response<R> {
|
|
|
HttpClient::new().fetch(url).await
|
|
HttpClient::new().fetch(url).await
|
|
@@ -499,14 +23,12 @@ mod tests {
|
|
|
#[test]
|
|
#[test]
|
|
|
fn test_client_new() {
|
|
fn test_client_new() {
|
|
|
let client = HttpClient::new();
|
|
let client = HttpClient::new();
|
|
|
- // Client should be constructable without panicking
|
|
|
|
|
let _ = format!("{:?}", client);
|
|
let _ = format!("{:?}", client);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
|
fn test_client_default() {
|
|
fn test_client_default() {
|
|
|
let client = HttpClient::default();
|
|
let client = HttpClient::default();
|
|
|
- // Default should produce a valid client
|
|
|
|
|
let _ = format!("{:?}", client);
|
|
let _ = format!("{:?}", client);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -522,17 +44,10 @@ mod tests {
|
|
|
assert!(result.is_ok());
|
|
assert!(result.is_ok());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- #[cfg(feature = "reqwest")]
|
|
|
|
|
- #[test]
|
|
|
|
|
- fn test_from_reqwest() {
|
|
|
|
|
- let reqwest_client = reqwest::Client::new();
|
|
|
|
|
- let client = HttpClient::from_reqwest(reqwest_client);
|
|
|
|
|
- let _ = format!("{:?}", client);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- #[cfg(feature = "bitreq")]
|
|
|
|
|
|
|
+ #[cfg(not(target_arch = "wasm32"))]
|
|
|
mod bitreq_tests {
|
|
mod bitreq_tests {
|
|
|
use super::*;
|
|
use super::*;
|
|
|
|
|
+ use crate::error::HttpError;
|
|
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
|
fn test_builder_accept_invalid_certs_returns_error() {
|
|
fn test_builder_accept_invalid_certs_returns_error() {
|
|
@@ -577,7 +92,6 @@ mod tests {
|
|
|
#[test]
|
|
#[test]
|
|
|
fn test_builder_proxy_with_invalid_matcher() {
|
|
fn test_builder_proxy_with_invalid_matcher() {
|
|
|
let proxy_url = url::Url::parse("http://localhost:8080").expect("Valid proxy URL");
|
|
let proxy_url = url::Url::parse("http://localhost:8080").expect("Valid proxy URL");
|
|
|
- // Invalid regex pattern (unclosed bracket)
|
|
|
|
|
let result = HttpClientBuilder::default().proxy_with_matcher(proxy_url, r"[invalid");
|
|
let result = HttpClientBuilder::default().proxy_with_matcher(proxy_url, r"[invalid");
|
|
|
assert!(result.is_err());
|
|
assert!(result.is_err());
|
|
|
|
|
|