omaha_client/
http_request.rs1use {futures::future::BoxFuture, futures::prelude::*};
10
11pub use http::{Request, Response};
12pub type Body = http_body_util::Full<bytes::Bytes>;
13
14pub fn empty_body() -> Body {
15 Body::default()
16}
17
18pub fn body_from<T: Into<bytes::Bytes>>(data: T) -> Body {
19 Body::new(data.into())
20}
21
22pub trait IntoBody {
23 type Body: http_body::Body;
24 fn into_body(self) -> Self::Body;
25}
26
27impl<B: http_body::Body> IntoBody for http::Request<B> {
28 type Body = B;
29 fn into_body(self) -> B {
30 self.into_body()
31 }
32}
33
34impl<B: http_body::Body> IntoBody for http::Response<B> {
35 type Body = B;
36 fn into_body(self) -> B {
37 self.into_body()
38 }
39}
40
41impl<D: bytes::Buf> IntoBody for http_body_util::Full<D> {
42 type Body = Self;
43 fn into_body(self) -> Self {
44 self
45 }
46}
47
48impl<D: bytes::Buf> IntoBody for http_body_util::Empty<D> {
49 type Body = Self;
50 fn into_body(self) -> Self {
51 self
52 }
53}
54
55impl IntoBody for hyper::body::Incoming {
56 type Body = Self;
57 fn into_body(self) -> Self {
58 self
59 }
60}
61
62pub async fn to_bytes<I>(item: I) -> Result<bytes::Bytes, <I::Body as http_body::Body>::Error>
63where
64 I: IntoBody,
65{
66 use http_body_util::BodyExt as _;
67 item.into_body().collect().await.map(|buf| buf.to_bytes())
68}
69
70pub mod mock;
71
72pub trait HttpRequest {
79 fn request(&mut self, req: Request<Body>) -> BoxFuture<'_, Result<Response<Vec<u8>>, Error>>;
82}
83
84#[derive(Debug, thiserror::Error)]
85#[error("Http request failed: {}", match (.source, ()).0 {
87 Some(source) => format!("{source}"),
88 None => format!("kind: {:?}", .kind),
89})]
90pub struct Error {
91 kind: ErrorKind,
92 #[source]
93 source: Option<Box<dyn std::error::Error + Send + Sync>>,
94}
95
96#[derive(Debug, Eq, PartialEq)]
97enum ErrorKind {
98 User,
99 Transport,
100 Timeout,
101}
102
103impl Error {
104 pub fn new_timeout() -> Self {
109 Self { kind: ErrorKind::Timeout, source: None }
110 }
111
112 pub fn is_user(&self) -> bool {
115 self.kind == ErrorKind::User
116 }
117
118 pub fn is_timeout(&self) -> bool {
123 self.kind == ErrorKind::Timeout
124 }
125
126 pub fn new_transport(error: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> Self {
128 Self { kind: ErrorKind::Transport, source: Some(error.into()) }
129 }
130}
131
132impl From<hyper::Error> for Error {
133 fn from(error: hyper::Error) -> Self {
134 let kind = if error.is_user() { ErrorKind::User } else { ErrorKind::Transport };
135 Error { kind, source: Some(Box::new(error)) }
136 }
137}
138
139pub mod mock_errors {
140 use super::*;
141
142 pub fn make_user_error() -> Error {
143 Error { kind: ErrorKind::User, source: None }
144 }
145
146 pub fn make_transport_error() -> Error {
147 Error { kind: ErrorKind::Transport, source: None }
148 }
149}
150
151pub struct StubHttpRequest;
153
154impl HttpRequest for StubHttpRequest {
155 fn request(&mut self, _req: Request<Body>) -> BoxFuture<'_, Result<Response<Vec<u8>>, Error>> {
156 future::ok(Response::default()).boxed()
157 }
158}