1//! Minimal HTTP client abstraction shared across crates.
2
3use std::fmt::Display;
4use std::future::Future;
5use std::sync::Arc;
6
7/// HTTP client trait for sending raw HTTP requests.
8pub trait HttpClient {
9 /// Error type returned by the HTTP client
10 type Error: std::error::Error + Display + Send + Sync + 'static;
11 /// Send an HTTP request and return the response.
12 fn send_http(
13 &self,
14 request: http::Request<Vec<u8>>,
15 ) -> impl Future<Output = core::result::Result<http::Response<Vec<u8>>, Self::Error>> + Send;
16}
17
18#[cfg(feature = "reqwest-client")]
19impl HttpClient for reqwest::Client {
20 type Error = reqwest::Error;
21
22 async fn send_http(
23 &self,
24 request: http::Request<Vec<u8>>,
25 ) -> core::result::Result<http::Response<Vec<u8>>, Self::Error> {
26 // Convert http::Request to reqwest::Request
27 let (parts, body) = request.into_parts();
28
29 let mut req = self.request(parts.method, parts.uri.to_string()).body(body);
30
31 // Copy headers
32 for (name, value) in parts.headers.iter() {
33 req = req.header(name.as_str(), value.as_bytes());
34 }
35
36 // Send request
37 let resp = req.send().await?;
38
39 // Convert reqwest::Response to http::Response
40 let mut builder = http::Response::builder().status(resp.status());
41
42 // Copy headers
43 for (name, value) in resp.headers().iter() {
44 builder = builder.header(name.as_str(), value.as_bytes());
45 }
46
47 // Read body
48 let body = resp.bytes().await?.to_vec();
49
50 Ok(builder.body(body).expect("Failed to build response"))
51 }
52}
53
54impl<T: HttpClient> HttpClient for Arc<T> {
55 type Error = T::Error;
56
57 fn send_http(
58 &self,
59 request: http::Request<Vec<u8>>,
60 ) -> impl Future<Output = core::result::Result<http::Response<Vec<u8>>, Self::Error>> + Send
61 {
62 self.as_ref().send_http(request)
63 }
64}