Skip to content

Commit 659be12

Browse files
committed
Wrap HTTP client errors and make converions private
1 parent c309f0e commit 659be12

4 files changed

Lines changed: 37 additions & 45 deletions

File tree

src/clients/hyper_client.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use async_trait::async_trait;
22
use http::header::RETRY_AFTER;
3-
use hyper::{body::HttpBody, client::HttpConnector, Body, Client, Request as HttpRequest};
3+
use hyper::{Body, Client, Request as HttpRequest, body::HttpBody, client::HttpConnector};
44
use hyper_tls::HttpsConnector;
55

66
use crate::{
7-
clients::{request_builder, WebPushClient, MAX_RESPONSE_SIZE},
8-
error::{RetryAfter, WebPushError},
7+
clients::{MAX_RESPONSE_SIZE, WebPushClient, request_builder},
8+
error::{WebPushError, parse_retry_after},
99
message::WebPushMessage,
1010
};
1111

@@ -54,23 +54,25 @@ impl WebPushClient for HyperWebPushClient {
5454

5555
let requesting = self.client.request(request);
5656

57-
let response = requesting.await?;
57+
let response = requesting
58+
.await
59+
.map_err(|err| WebPushError::ClientError(Box::new(err)))?;
5860

5961
trace!("Response: {:?}", response);
6062

6163
let retry_after = response
6264
.headers()
6365
.get(RETRY_AFTER)
6466
.and_then(|ra| ra.to_str().ok())
65-
.and_then(RetryAfter::from_str);
67+
.and_then(parse_retry_after);
6668

6769
let response_status = response.status();
6870
trace!("Response status: {}", response_status);
6971

7072
let mut chunks = response.into_body();
7173
let mut body = Vec::new();
7274
while let Some(chunk) = chunks.data().await {
73-
body.extend(&chunk?);
75+
body.extend(&chunk.map_err(|err| WebPushError::ClientError(Box::new(err)))?);
7476
if body.len() > MAX_RESPONSE_SIZE {
7577
return Err(WebPushError::ResponseTooLarge);
7678
}

src/clients/isahc_client.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use http::header::RETRY_AFTER;
44
use isahc::HttpClient;
55

66
use crate::{
7-
clients::{request_builder, WebPushClient, MAX_RESPONSE_SIZE},
8-
error::{RetryAfter, WebPushError},
7+
clients::{MAX_RESPONSE_SIZE, WebPushClient, request_builder},
8+
error::{WebPushError, parse_retry_after},
99
message::WebPushMessage,
1010
};
1111

@@ -38,7 +38,7 @@ impl IsahcWebPushClient {
3838
/// Creates a new client. Can fail under resource depletion.
3939
pub fn new() -> Result<Self, WebPushError> {
4040
Ok(Self {
41-
client: HttpClient::new()?,
41+
client: HttpClient::new().map_err(|err| WebPushError::ClientError(Box::new(err)))?,
4242
})
4343
}
4444
}
@@ -55,15 +55,17 @@ impl WebPushClient for IsahcWebPushClient {
5555

5656
let requesting = self.client.send_async(request);
5757

58-
let response = requesting.await?;
58+
let response = requesting
59+
.await
60+
.map_err(|err| WebPushError::ClientError(Box::new(err)))?;
5961

6062
trace!("Response: {:?}", response);
6163

6264
let retry_after = response
6365
.headers()
6466
.get(RETRY_AFTER)
6567
.and_then(|ra| ra.to_str().ok())
66-
.and_then(RetryAfter::from_str);
68+
.and_then(parse_retry_after);
6769

6870
let response_status = response.status();
6971
trace!("Response status: {}", response_status);
@@ -73,7 +75,8 @@ impl WebPushClient for IsahcWebPushClient {
7375
.into_body()
7476
.take(MAX_RESPONSE_SIZE as u64 + 1)
7577
.read_to_end(&mut body)
76-
.await?
78+
.await
79+
.map_err(|err| WebPushError::ClientError(Box::new(err)))?
7780
> MAX_RESPONSE_SIZE
7881
{
7982
return Err(WebPushError::ResponseTooLarge);

src/error.rs

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,13 @@ impl fmt::Display for ErrorInfo {
2828
}
2929
}
3030

31+
/// Web push failed.
3132
#[derive(Debug)]
33+
#[non_exhaustive]
3234
pub enum WebPushError {
33-
/// An unknown error happened while encrypting or sending the message
34-
Unspecified,
35+
/// HTTP client error (network, DNS, TLS, protocol-level HTTP) while trying
36+
/// to send the notification.
37+
ClientError(Box<dyn Error>),
3538
/// Please provide valid credentials to send the notification
3639
Unauthorized(ErrorInfo),
3740
/// Request was badly formed
@@ -93,20 +96,6 @@ impl From<InvalidUri> for WebPushError {
9396
}
9497
}
9598

96-
#[cfg(feature = "hyper-client")]
97-
impl From<hyper::Error> for WebPushError {
98-
fn from(_: hyper::Error) -> Self {
99-
Self::Unspecified
100-
}
101-
}
102-
103-
#[cfg(feature = "isahc-client")]
104-
impl From<isahc::Error> for WebPushError {
105-
fn from(_: isahc::Error) -> Self {
106-
Self::Unspecified
107-
}
108-
}
109-
11099
impl From<IoError> for WebPushError {
111100
fn from(err: IoError) -> WebPushError {
112101
WebPushError::Io(err)
@@ -116,7 +105,7 @@ impl From<IoError> for WebPushError {
116105
impl WebPushError {
117106
pub fn short_description(&self) -> &'static str {
118107
match *self {
119-
WebPushError::Unspecified => "unspecified",
108+
WebPushError::ClientError(_) => "client_error",
120109
WebPushError::Unauthorized(_) => "unauthorized",
121110
WebPushError::BadRequest(_) => "bad_request",
122111
WebPushError::ServerError { .. } => "server_error",
@@ -142,7 +131,7 @@ impl WebPushError {
142131
impl fmt::Display for WebPushError {
143132
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
144133
match self {
145-
WebPushError::Unspecified => write!(f, "unspecified error"),
134+
WebPushError::ClientError(err) => write!(f, "client error: {}", err),
146135
WebPushError::Unauthorized(info) => write!(f, "unauthorized: {}", info),
147136
WebPushError::BadRequest(info) => write!(f, "bad request: {}", info),
148137
WebPushError::ServerError { info, .. } => write!(f, "server error: {}", info),
@@ -168,21 +157,18 @@ impl fmt::Display for WebPushError {
168157
}
169158
}
170159

171-
pub struct RetryAfter;
172-
impl RetryAfter {
173-
pub fn from_str(header_value: &str) -> Option<Duration> {
174-
if let Ok(seconds) = header_value.parse::<u64>() {
175-
Some(Duration::from_secs(seconds))
176-
} else {
177-
chrono::DateTime::parse_from_rfc2822(header_value)
178-
.map(|date_time| {
179-
let systime: SystemTime = date_time.into();
160+
pub fn parse_retry_after(header_value: &str) -> Option<Duration> {
161+
if let Ok(seconds) = header_value.parse::<u64>() {
162+
Some(Duration::from_secs(seconds))
163+
} else {
164+
chrono::DateTime::parse_from_rfc2822(header_value)
165+
.map(|date_time| {
166+
let systime: SystemTime = date_time.into();
180167

181-
systime
182-
.duration_since(SystemTime::now())
183-
.unwrap_or_else(|_| Duration::new(0, 0))
184-
})
185-
.ok()
186-
}
168+
systime
169+
.duration_since(SystemTime::now())
170+
.unwrap_or_else(|_| Duration::new(0, 0))
171+
})
172+
.ok()
187173
}
188174
}

src/message.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ pub struct WebPushPayload {
5858
pub content_encoding: ContentEncoding,
5959
}
6060

61+
/// Urgency of a web push message.
6162
#[derive(Debug, Deserialize, Serialize, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash)]
6263
#[serde(rename_all = "kebab-case")]
6364
pub enum Urgency {

0 commit comments

Comments
 (0)