1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use thiserror::Error;

///
/// Error type returned by failed reqwest HTTP requests.
///
#[derive(Debug, Error)]
pub enum Error<T>
where
    T: std::error::Error + 'static,
{
    /// Error returned by reqwest crate.
    #[error("request failed")]
    Reqwest(#[source] T),
    /// Non-reqwest HTTP error.
    #[error("HTTP error")]
    Http(#[source] http::Error),
    /// I/O error.
    #[error("I/O error")]
    Io(#[source] std::io::Error),
    /// Other error.
    #[error("Other error: {}", _0)]
    Other(String),
}

pub use blocking::http_client;
///
/// Error type returned by failed reqwest blocking HTTP requests.
///
pub type HttpClientError = Error<blocking::reqwest::Error>;

pub use async_client::async_http_client;

///
/// Error type returned by failed reqwest async HTTP requests.
///
pub type AsyncHttpClientError = Error<reqwest_0_10::Error>;

mod blocking {
    use super::super::{HttpRequest, HttpResponse};
    use super::Error;

    pub use reqwest_0_10 as reqwest;
    use reqwest_0_10::blocking;
    use reqwest_0_10::redirect::Policy as RedirectPolicy;

    use std::io::Read;

    ///
    /// Synchronous HTTP client.
    ///
    pub fn http_client(request: HttpRequest) -> Result<HttpResponse, Error<reqwest::Error>> {
        let client = blocking::Client::builder()
            // Following redirects opens the client up to SSRF vulnerabilities.
            .redirect(RedirectPolicy::none())
            .build()
            .map_err(Error::Reqwest)?;

        #[cfg(feature = "reqwest-010")]
        let mut request_builder = client
            .request(request.method, request.url.as_str())
            .body(request.body);

        for (name, value) in &request.headers {
            request_builder = request_builder.header(name.as_str(), value.as_bytes());
        }
        let mut response = client
            .execute(request_builder.build().map_err(Error::Reqwest)?)
            .map_err(Error::Reqwest)?;

        let mut body = Vec::new();
        response.read_to_end(&mut body).map_err(Error::Io)?;

        #[cfg(feature = "reqwest-010")]
        {
            Ok(HttpResponse {
                status_code: response.status(),
                headers: response.headers().to_owned(),
                body,
            })
        }
    }
}

mod async_client {
    use super::super::{HttpRequest, HttpResponse};
    use super::Error;

    pub use reqwest_0_10 as reqwest;
    use reqwest_0_10::redirect::Policy as RedirectPolicy;

    ///
    /// Asynchronous HTTP client.
    ///
    pub async fn async_http_client(
        request: HttpRequest,
    ) -> Result<HttpResponse, Error<reqwest::Error>> {
        let client = reqwest::Client::builder()
            // Following redirects opens the client up to SSRF vulnerabilities.
            .redirect(RedirectPolicy::none())
            .build()
            .map_err(Error::Reqwest)?;

        let mut request_builder = client
            .request(request.method, request.url.as_str())
            .body(request.body);
        for (name, value) in &request.headers {
            request_builder = request_builder.header(name.as_str(), value.as_bytes());
        }
        let request = request_builder.build().map_err(Error::Reqwest)?;

        let response = client.execute(request).await.map_err(Error::Reqwest)?;

        let status_code = response.status();
        let headers = response.headers().to_owned();
        let chunks = response.bytes().await.map_err(Error::Reqwest)?;
        Ok(HttpResponse {
            status_code,
            headers,
            body: chunks.to_vec(),
        })
    }
}