Skip to content

Commit 5f5eb12

Browse files
committed
Refactor: overhaul errors
Overhauls errors to allow for 3 types of errors: - Concrete errors (enum) from http-types itself - A dynamic error type for response handlers - A combined type for handling request+response for a client
1 parent 1fe07df commit 5f5eb12

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+1184
-652
lines changed

Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ serde_json = { version = "1.0.51", optional = true }
5050
serde_crate = { version = "1.0.106", features = ["derive"], optional = true, package = "serde" }
5151
serde_urlencoded = { version = "0.7.0", optional = true}
5252
serde_qs = { version = "0.9.1", optional = true }
53-
53+
miette = "3"
54+
thiserror = "1.0.29"
5455

5556
[dev-dependencies]
5657
http = "0.2.0"

src/auth/authentication_scheme.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::fmt::{self, Display};
22
use std::str::FromStr;
33

4-
use crate::bail_status as bail;
4+
use crate::errors::AuthError;
55

66
/// HTTP Mutual Authentication Algorithms
77
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
@@ -47,7 +47,7 @@ impl Display for AuthenticationScheme {
4747
}
4848

4949
impl FromStr for AuthenticationScheme {
50-
type Err = crate::Error;
50+
type Err = AuthError;
5151

5252
fn from_str(s: &str) -> Result<Self, Self::Err> {
5353
// NOTE(yosh): matching here is lowercase as specified by RFC2617#section-1.2
@@ -65,7 +65,7 @@ impl FromStr for AuthenticationScheme {
6565
"scram-sha-1" => Ok(Self::ScramSha1),
6666
"scram-sha-256" => Ok(Self::ScramSha256),
6767
"vapid" => Ok(Self::Vapid),
68-
s => bail!(400, "`{}` is not a recognized authentication scheme", s),
68+
s => Err(AuthError::SchemeUnrecognized(s.to_string())),
6969
}
7070
}
7171
}

src/auth/authorization.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::auth::AuthenticationScheme;
2-
use crate::bail_status as bail;
2+
use crate::errors::AuthError;
33
use crate::headers::{Header, HeaderName, HeaderValue, Headers, AUTHORIZATION};
44

55
/// Credentials to authenticate a user agent with a server.
@@ -60,8 +60,8 @@ impl Authorization {
6060
let scheme = iter.next();
6161
let credential = iter.next();
6262
let (scheme, credentials) = match (scheme, credential) {
63-
(None, _) => bail!(400, "Could not find scheme"),
64-
(Some(_), None) => bail!(400, "Could not find credentials"),
63+
(None, _) => return Err(AuthError::SchemeMissing.into()),
64+
(Some(_), None) => return Err(AuthError::CredentialsMissing.into()),
6565
(Some(scheme), Some(credentials)) => (scheme.parse()?, credentials.to_owned()),
6666
};
6767

@@ -107,8 +107,10 @@ impl Header for Authorization {
107107

108108
#[cfg(test)]
109109
mod test {
110-
use super::*;
111110
use crate::headers::Headers;
111+
use crate::StatusCode;
112+
113+
use super::*;
112114

113115
#[test]
114116
fn smoke() -> crate::Result<()> {
@@ -133,6 +135,6 @@ mod test {
133135
.insert(AUTHORIZATION, "<nori ate the tag. yum.>")
134136
.unwrap();
135137
let err = Authorization::from_headers(headers).unwrap_err();
136-
assert_eq!(err.status(), 400);
138+
assert_eq!(err.associated_status_code(), Some(StatusCode::BadRequest));
137139
}
138140
}

src/auth/basic_auth.rs

+27-12
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1+
use crate::errors::AuthError;
12
use crate::headers::{HeaderName, HeaderValue, Headers, AUTHORIZATION};
2-
use crate::Status;
33
use crate::{
44
auth::{AuthenticationScheme, Authorization},
55
headers::Header,
66
};
7-
use crate::{bail_status as bail, ensure_status as ensure};
87

98
/// HTTP Basic authorization.
109
///
@@ -60,28 +59,42 @@ impl BasicAuth {
6059
};
6160

6261
let scheme = auth.scheme();
63-
ensure!(
62+
internal_ensure!(
6463
matches!(scheme, AuthenticationScheme::Basic),
65-
400,
66-
"Expected basic auth scheme found `{}`",
67-
scheme
64+
AuthError::SchemeUnexpected(AuthenticationScheme::Basic, scheme.to_string())
6865
);
6966
Self::from_credentials(auth.credentials()).map(Some)
7067
}
7168

7269
/// Create a new instance from the base64 encoded credentials.
7370
pub fn from_credentials(credentials: impl AsRef<[u8]>) -> crate::Result<Self> {
74-
let bytes = base64::decode(credentials).status(400)?;
75-
let credentials = String::from_utf8(bytes).status(400)?;
71+
let bytes = base64::decode(credentials).map_err(|_| {
72+
AuthError::CredentialsInvalid(AuthenticationScheme::Basic, "invalid base64")
73+
})?;
74+
let credentials = String::from_utf8(bytes).map_err(|_| {
75+
AuthError::CredentialsInvalid(AuthenticationScheme::Basic, "invalid utf8 from base64")
76+
})?;
7677

7778
let mut iter = credentials.splitn(2, ':');
7879
let username = iter.next();
7980
let password = iter.next();
8081

8182
let (username, password) = match (username, password) {
8283
(Some(username), Some(password)) => (username.to_string(), password.to_string()),
83-
(Some(_), None) => bail!(400, "Expected basic auth to contain a password"),
84-
(None, _) => bail!(400, "Expected basic auth to contain a username"),
84+
(Some(_), None) => {
85+
return Err(AuthError::CredentialsInvalid(
86+
AuthenticationScheme::Basic,
87+
"missing password",
88+
)
89+
.into())
90+
}
91+
(None, _) => {
92+
return Err(AuthError::CredentialsInvalid(
93+
AuthenticationScheme::Basic,
94+
"missing username",
95+
)
96+
.into())
97+
}
8598
};
8699

87100
Ok(Self { username, password })
@@ -113,8 +126,10 @@ impl Header for BasicAuth {
113126

114127
#[cfg(test)]
115128
mod test {
116-
use super::*;
117129
use crate::headers::Headers;
130+
use crate::StatusCode;
131+
132+
use super::*;
118133

119134
#[test]
120135
fn smoke() -> crate::Result<()> {
@@ -139,6 +154,6 @@ mod test {
139154
.insert(AUTHORIZATION, "<nori ate the tag. yum.>")
140155
.unwrap();
141156
let err = BasicAuth::from_headers(headers).unwrap_err();
142-
assert_eq!(err.status(), 400);
157+
assert_eq!(err.associated_status_code(), Some(StatusCode::BadRequest));
143158
}
144159
}

src/auth/www_authenticate.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::bail_status as bail;
1+
use crate::errors::{AuthError, HeaderError};
22
use crate::headers::{HeaderName, HeaderValue, Headers, WWW_AUTHENTICATE};
33
use crate::{auth::AuthenticationScheme, headers::Header};
44

@@ -63,15 +63,15 @@ impl WwwAuthenticate {
6363
let scheme = iter.next();
6464
let credential = iter.next();
6565
let (scheme, realm) = match (scheme, credential) {
66-
(None, _) => bail!(400, "Could not find scheme"),
67-
(Some(_), None) => bail!(400, "Could not find realm"),
66+
(None, _) => return Err(AuthError::SchemeMissing.into()),
67+
(Some(_), None) => return Err(AuthError::RealmMissing.into()),
6868
(Some(scheme), Some(realm)) => (scheme.parse()?, realm.to_owned()),
6969
};
7070

7171
let realm = realm.trim_start();
7272
let realm = match realm.strip_prefix(r#"realm=""#) {
7373
Some(realm) => realm,
74-
None => bail!(400, "realm not found"),
74+
None => return Err(AuthError::RealmMissing.into()),
7575
};
7676

7777
let mut chars = realm.chars();
@@ -87,7 +87,7 @@ impl WwwAuthenticate {
8787
})
8888
.collect();
8989
if !closing_quote {
90-
bail!(400, r"Expected a closing quote");
90+
return Err(HeaderError::WWWAuthenticateInvalid("Expected a closing quote").into());
9191
}
9292

9393
Ok(Some(Self { scheme, realm }))
@@ -129,8 +129,10 @@ impl Header for WwwAuthenticate {
129129

130130
#[cfg(test)]
131131
mod test {
132-
use super::*;
133132
use crate::headers::Headers;
133+
use crate::StatusCode;
134+
135+
use super::*;
134136

135137
#[test]
136138
fn smoke() -> crate::Result<()> {
@@ -160,6 +162,6 @@ mod test {
160162
.insert(WWW_AUTHENTICATE, "<nori ate the tag. yum.>")
161163
.unwrap();
162164
let err = WwwAuthenticate::from_headers(headers).unwrap_err();
163-
assert_eq!(err.status(), 400);
165+
assert_eq!(err.associated_status_code(), Some(StatusCode::BadRequest));
164166
}
165167
}

0 commit comments

Comments
 (0)