Skip to content

Commit

Permalink
chore(volo-http): implement source for Errors (#519)
Browse files Browse the repository at this point in the history
Signed-off-by: Yu Li <[email protected]>
  • Loading branch information
yukiiiteru authored Nov 5, 2024
1 parent 092f318 commit b59621f
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 31 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 26 additions & 22 deletions volo-http/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "volo-http"
version = "0.2.14"
version = "0.3.0-rc.1"
edition.workspace = true
homepage.workspace = true
repository.workspace = true
Expand All @@ -15,8 +15,6 @@ keywords = ["async", "rpc", "http"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html



[badges]
maintenance = { status = "actively-developed" }

Expand Down Expand Up @@ -61,28 +59,30 @@ tracing.workspace = true
url.workspace = true

# =====optional=====
multer = { workspace = true, optional = true }

# server optional
matchit = { workspace = true, optional = true }

# protocol optional
# serde and form, query, json
serde = { workspace = true, optional = true }
serde_urlencoded = { workspace = true, optional = true }
sonic-rs = { workspace = true, optional = true }

# cookie support
cookie = { workspace = true, optional = true, features = ["percent-encode"] }
cookie_store = { workspace = true, optional = true }

# multipart optional
multer = { workspace = true, optional = true }

# websocket optional
tungstenite = { workspace = true, optional = true }
tokio-tungstenite = { workspace = true, optional = true }

# tls optional
tokio-rustls = { workspace = true, optional = true }
tokio-native-tls = { workspace = true, optional = true }

# cookie support
cookie = { workspace = true, optional = true, features = ["percent-encode"] }
cookie_store = { workspace = true, optional = true }

# serde and form, query, json
serde = { workspace = true, optional = true }
serde_urlencoded = { workspace = true, optional = true }
sonic-rs = { workspace = true, optional = true }

[dev-dependencies]
async-stream.workspace = true
libc.workspace = true
Expand All @@ -96,11 +96,22 @@ default = []
default_client = ["client", "json"]
default_server = ["server", "query", "form", "json", "multipart"]

full = ["client", "server", "rustls", "cookie", "query", "form", "json", "multipart", "tls", "ws"]
full = [
"client", "server", # core
"query", "form", "json", # serde
"tls", # https
"cookie", "multipart", "ws",
]

client = ["hyper/client", "hyper/http1"] # client core
server = ["hyper/server", "hyper/http1", "dep:matchit"] # server core

__serde = ["dep:serde"] # a private feature for enabling `serde` by `serde_xxx`
query = ["__serde", "dep:serde_urlencoded"]
form = ["__serde", "dep:serde_urlencoded"]
json = ["__serde", "dep:sonic-rs"]

cookie = ["dep:cookie", "dep:cookie_store"]
multipart = ["dep:multer"]
ws = ["dep:tungstenite", "dep:tokio-tungstenite"]

Expand All @@ -110,13 +121,6 @@ rustls = ["__tls", "dep:tokio-rustls", "volo/rustls"]
native-tls = ["__tls", "dep:tokio-native-tls", "volo/native-tls"]
native-tls-vendored = ["native-tls", "volo/native-tls-vendored"]

cookie = ["dep:cookie", "dep:cookie_store"]

__serde = ["dep:serde"] # a private feature for enabling `serde` by `serde_xxx`
query = ["__serde", "dep:serde_urlencoded"]
form = ["__serde", "dep:serde_urlencoded"]
json = ["__serde", "dep:sonic-rs"]

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
10 changes: 9 additions & 1 deletion volo-http/src/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,15 @@ impl fmt::Display for BodyConvertError {
}
}

impl Error for BodyConvertError {}
impl Error for BodyConvertError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
#[cfg(feature = "json")]
Self::JsonDeserializeError(e) => Some(e),
_ => None,
}
}
}

impl From<()> for Body {
fn from(_: ()) -> Self {
Expand Down
30 changes: 28 additions & 2 deletions volo-http/src/error/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,11 @@ impl fmt::Display for ClientError {
}
}

impl Error for ClientError {}
impl Error for ClientError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(self.source.as_ref()?.as_ref())
}
}

/// Error kind of [`ClientError`]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
Expand Down Expand Up @@ -174,7 +178,7 @@ macro_rules! simple_error {
paste! {
#[doc = $kind " error \"" $msg "\""]
$(#[$attr])*
#[derive(Debug)]
#[derive(Debug, PartialEq, Eq)]
pub struct $name;

$(#[$attr])*
Expand All @@ -200,3 +204,25 @@ simple_error!(Builder => BadScheme => "bad scheme");
simple_error!(Builder => BadHostName => "bad host name");
simple_error!(Request => Timeout => "request timeout");
simple_error!(LoadBalance => NoAvailableEndpoint => "no available endpoint");

#[cfg(test)]
mod client_error_tests {
use std::error::Error;

use crate::error::client::{
bad_host_name, bad_scheme, no_address, no_available_endpoint, timeout, BadHostName,
BadScheme, NoAddress, NoAvailableEndpoint, Timeout,
};

#[test]
fn types_downcast() {
assert!(no_address().source().unwrap().is::<NoAddress>());
assert!(bad_scheme().source().unwrap().is::<BadScheme>());
assert!(bad_host_name().source().unwrap().is::<BadHostName>());
assert!(timeout().source().unwrap().is::<Timeout>());
assert!(no_available_endpoint()
.source()
.unwrap()
.is::<NoAvailableEndpoint>());
}
}
13 changes: 13 additions & 0 deletions volo-http/src/error/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@ impl fmt::Display for ExtractBodyError {
}
}

impl Error for ExtractBodyError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Generic(e) => Some(e),
Self::String(e) => Some(e),
#[cfg(feature = "json")]
Self::Json(e) => Some(e),
#[cfg(feature = "form")]
Self::Form(e) => Some(e),
}
}
}

impl IntoResponse for ExtractBodyError {
fn into_response(self) -> ServerResponse {
let status = match self {
Expand Down
9 changes: 8 additions & 1 deletion volo-http/src/server/param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,14 @@ impl fmt::Display for PathParamsRejection {
}
}

impl Error for PathParamsRejection {}
impl Error for PathParamsRejection {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::LengthMismatch => None,
Self::ParseError(e) => Some(e.as_ref()),
}
}
}

impl IntoResponse for PathParamsRejection {
fn into_response(self) -> ServerResponse {
Expand Down
10 changes: 9 additions & 1 deletion volo-http/src/server/route/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,15 @@ impl fmt::Display for MatcherError {
}
}

impl Error for MatcherError {}
impl Error for MatcherError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::UriConflict(_) => None,
Self::RouterInsertError(e) => Some(e),
Self::RouterMatchError(e) => Some(e),
}
}
}

pub(super) struct StripPrefixLayer;

Expand Down
12 changes: 9 additions & 3 deletions volo-http/src/server/utils/ws.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
use std::{
borrow::Cow,
error::Error,
fmt,
future::Future,
ops::{Deref, DerefMut},
Expand Down Expand Up @@ -467,7 +468,13 @@ impl fmt::Display for WebSocketError {
}
}

impl std::error::Error for WebSocketError {}
impl Error for WebSocketError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Upgrade(e) => Some(e),
}
}
}

/// What to do when a connection upgrade fails.
///
Expand Down Expand Up @@ -498,7 +505,6 @@ impl OnFailedUpgrade for DefaultOnFailedUpgrade {

/// [`Error`]s while extracting [`WebSocketUpgrade`].
///
/// [`Error`]: std::error::Error
/// [`WebSocketUpgrade`]: crate::server::utils::ws::WebSocketUpgrade
#[derive(Debug)]
pub enum WebSocketUpgradeRejectionError {
Expand Down Expand Up @@ -530,7 +536,7 @@ impl WebSocketUpgradeRejectionError {
}
}

impl std::error::Error for WebSocketUpgradeRejectionError {}
impl Error for WebSocketUpgradeRejectionError {}

impl fmt::Display for WebSocketUpgradeRejectionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down

0 comments on commit b59621f

Please sign in to comment.