http/
lib.rs

1#![cfg_attr(docs_rs, feature(doc_cfg, doc_auto_cfg))]
2#![doc = include_str!("../README.md")]
3
4mod error;
5
6use std::sync::Arc;
7
8pub use ureq;
9use ureq::{
10    config::Config,
11    http::Response,
12    tls::{RootCerts, TlsConfig, TlsProvider},
13    Agent, Body,
14};
15
16#[doc(inline)]
17pub use crate::error::{Error, Result};
18
19#[cfg(any(
20    all(feature = "tokio", feature = "async-std"),
21    not(any(feature = "tokio", feature = "async-std"))
22))]
23compile_error!("Either feature `tokio` or `async-std` must be enabled for this crate.");
24
25#[cfg(any(
26    all(feature = "rustls", feature = "native-tls"),
27    not(any(feature = "rustls", feature = "native-tls"))
28))]
29compile_error!("Either feature `rustls` or `native-tls` must be enabled for this crate.");
30
31/// The HTTP client structure.
32///
33/// This structure wraps a HTTP agent, which is used by the
34/// [`Client::send`] function.
35#[derive(Clone, Debug)]
36pub struct Client {
37    /// The HTTP agent used to perform calls.
38    // TODO: agent pool?
39    agent: Arc<Agent>,
40}
41
42impl Client {
43    /// Creates a new HTTP client with sane defaults.
44    pub fn new() -> Self {
45        let tls = TlsConfig::builder()
46            .root_certs(RootCerts::PlatformVerifier)
47            .provider(
48                #[cfg(feature = "native-tls")]
49                TlsProvider::NativeTls,
50                #[cfg(feature = "rustls")]
51                TlsProvider::Rustls,
52            );
53
54        let config = Config::builder().tls_config(tls.build()).build();
55        let agent = Arc::new(config.new_agent());
56
57        Self { agent }
58    }
59
60    /// Sends a request.
61    ///
62    /// This function takes a callback that tells how the request
63    /// looks like. It takes a reference to the inner HTTP agent as
64    /// parameter.
65    pub async fn send(
66        &self,
67        f: impl FnOnce(&Agent) -> std::result::Result<Response<Body>, ureq::Error> + Send + 'static,
68    ) -> Result<Response<Body>> {
69        let agent = self.agent.clone();
70
71        spawn_blocking(move || f(&agent))
72            .await?
73            .map_err(Error::SendRequestError)
74    }
75}
76
77/// Spawns a blocking task using [`async_std`].
78#[cfg(feature = "async-std")]
79async fn spawn_blocking<F, T>(f: F) -> Result<T>
80where
81    F: FnOnce() -> T + Send + 'static,
82    T: Send + 'static,
83{
84    Ok(async_std::task::spawn_blocking(f).await)
85}
86
87/// Spawns a blocking task using [`tokio`].
88#[cfg(feature = "tokio")]
89async fn spawn_blocking<F, T>(f: F) -> Result<T>
90where
91    F: FnOnce() -> T + Send + 'static,
92    T: Send + 'static,
93{
94    Ok(tokio::task::spawn_blocking(f).await?)
95}