Skip to content

Commit

Permalink
client(error): make display impl less verbose (#1283)
Browse files Browse the repository at this point in the history
* client(error): make display impl less verbose

* Update core/src/http_helpers.rs
  • Loading branch information
niklasad1 authored Feb 5, 2024
1 parent 6975a79 commit 8f73dbe
Show file tree
Hide file tree
Showing 9 changed files with 54 additions and 79 deletions.
6 changes: 2 additions & 4 deletions client/http-client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,8 @@ impl<B, S> ClientT for HttpClient<S>
where
S: Service<hyper::Request<Body>, Response = hyper::Response<B>, Error = TransportError> + Send + Sync + Clone,
<S as Service<hyper::Request<Body>>>::Future: Send,
B: HttpBody + Send + 'static,
B: HttpBody<Error = hyper::Error> + Send + 'static,
B::Data: Send,
B::Error: Into<Box<dyn StdError + Send + Sync>>,
{
#[instrument(name = "notification", skip(self, params), level = "trace")]
async fn notification<Params>(&self, method: &str, params: Params) -> Result<(), Error>
Expand Down Expand Up @@ -408,9 +407,8 @@ impl<B, S> SubscriptionClientT for HttpClient<S>
where
S: Service<hyper::Request<Body>, Response = hyper::Response<B>, Error = TransportError> + Send + Sync + Clone,
<S as Service<hyper::Request<Body>>>::Future: Send,
B: HttpBody + Send + 'static,
B: HttpBody<Error = hyper::Error> + Send + 'static,
B::Data: Send,
B::Error: Into<Box<dyn StdError + Send + Sync>>,
{
/// Send a subscription request to the server. Not implemented for HTTP; will always return
/// [`Error::HttpNotImplemented`].
Expand Down
46 changes: 14 additions & 32 deletions client/http-client/src/transport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ use hyper::client::{Client, HttpConnector};
use hyper::http::{HeaderMap, HeaderValue};
use jsonrpsee_core::client::CertificateStore;
use jsonrpsee_core::tracing::client::{rx_log_from_bytes, tx_log_from_str};
use jsonrpsee_core::{http_helpers, GenericTransportError, TEN_MB_SIZE_BYTES};
use jsonrpsee_core::{
http_helpers::{self, HttpError},
TEN_MB_SIZE_BYTES,
};
use std::error::Error as StdError;
use std::future::Future;
use std::pin::Pin;
Expand Down Expand Up @@ -45,7 +48,7 @@ impl Clone for HttpBackend {

impl<B> tower::Service<hyper::Request<B>> for HttpBackend<B>
where
B: HttpBody + Send + 'static,
B: HttpBody<Error = hyper::Error> + Send + 'static,
B::Data: Send,
B::Error: Into<Box<dyn StdError + Send + Sync>>,
{
Expand All @@ -59,7 +62,7 @@ where
#[cfg(feature = "__tls")]
Self::Https(inner) => inner.poll_ready(ctx),
}
.map_err(Into::into)
.map_err(|e| Error::Http(e.into()))
}

fn call(&mut self, req: hyper::Request<B>) -> Self::Future {
Expand All @@ -69,7 +72,7 @@ where
Self::Https(inner) => inner.call(req),
};

Box::pin(async move { resp.await.map_err(Into::into) })
Box::pin(async move { resp.await.map_err(|e| Error::Http(e.into())) })
}
}

Expand Down Expand Up @@ -279,9 +282,8 @@ pub struct HttpTransportClient<S> {
impl<B, S> HttpTransportClient<S>
where
S: Service<hyper::Request<Body>, Response = hyper::Response<B>, Error = Error> + Clone,
B: HttpBody + Send + 'static,
B: HttpBody<Error = hyper::Error> + Send + 'static,
B::Data: Send,
B::Error: Into<Box<dyn StdError + Send + Sync>>,
{
async fn inner_send(&self, body: String) -> Result<hyper::Response<B>, Error> {
if body.len() > self.max_request_size as usize {
Expand All @@ -298,7 +300,7 @@ where
if response.status().is_success() {
Ok(response)
} else {
Err(Error::RequestFailure { status_code: response.status().into() })
Err(Error::Rejected { status_code: response.status().into() })
}
}

Expand Down Expand Up @@ -331,45 +333,25 @@ pub enum Error {
Url(String),

/// Error during the HTTP request, including networking errors and HTTP protocol errors.
#[error("HTTP error: {0}")]
Http(Box<dyn std::error::Error + Send + Sync>),
#[error("{0}")]
Http(#[from] HttpError),

/// Server returned a non-success status code.
#[error("Server returned an error status code: {:?}", status_code)]
RequestFailure {
/// Status code returned by the server.
#[error("Request rejected `{status_code}`")]
Rejected {
/// HTTP Status code returned by the server.
status_code: u16,
},

/// Request body too large.
#[error("The request body was too large")]
RequestTooLarge,

/// Malformed request.
#[error("Malformed request")]
Malformed,

/// Invalid certificate store.
#[error("Invalid certificate store")]
InvalidCertficateStore,
}

impl From<GenericTransportError> for Error {
fn from(err: GenericTransportError) -> Self {
match err {
GenericTransportError::TooLarge => Self::RequestTooLarge,
GenericTransportError::Malformed => Self::Malformed,
GenericTransportError::Inner(e) => Self::Http(e.into()),
}
}
}

impl From<hyper::Error> for Error {
fn from(err: hyper::Error) -> Self {
Self::Http(Box::new(err))
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
2 changes: 1 addition & 1 deletion client/transport/src/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub enum Error {
#[error("JS Error: {0:?}")]
Js(String),
/// WebSocket error
#[error("WebSocket Error: {0:?}")]
#[error("{0}")]
WebSocket(WebSocketError),
/// Operation not supported
#[error("Operation not supported")]
Expand Down
4 changes: 2 additions & 2 deletions client/transport/src/ws/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ pub enum WsHandshakeError {
Io(io::Error),

/// Error in the transport layer.
#[error("Error in the WebSocket handshake: {0}")]
#[error("{0}")]
Transport(#[source] soketto::handshake::Error),

/// Server rejected the handshake.
Expand Down Expand Up @@ -223,7 +223,7 @@ pub enum WsHandshakeError {
#[derive(Debug, Error)]
pub enum WsError {
/// Error in the WebSocket connection.
#[error("WebSocket connection error: {0}")]
#[error("{0}")]
Connection(#[source] soketto::connection::Error),
/// Message was too large.
#[error("The message was too large")]
Expand Down
10 changes: 5 additions & 5 deletions core/src/client/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@

//! Error type for client(s).

use std::sync::Arc;
use crate::{params::EmptyBatchRequest, RegisterMethodError};
use jsonrpsee_types::{ErrorObjectOwned, InvalidRequestId};
use std::sync::Arc;

/// Error type.
#[derive(Debug, thiserror::Error)]
Expand All @@ -37,10 +37,10 @@ pub enum Error {
#[error("{0}")]
Call(#[from] ErrorObjectOwned),
/// Networking error or error on the low-level protocol layer.
#[error("Networking or low-level protocol error: {0}")]
#[error("{0}")]
Transport(#[source] anyhow::Error),
/// The background task has been terminated.
#[error("The background task been terminated because: {0}; restart required")]
#[error("The background task closed {0}; restart required")]
RestartNeeded(Arc<Error>),
/// Failed to parse the data.
#[error("Parse error: {0}")]
Expand All @@ -55,7 +55,7 @@ pub enum Error {
#[error("Request timeout")]
RequestTimeout,
/// Max number of request slots exceeded.
#[error("Configured max number of request slots exceeded")]
#[error("Max concurrent requests exceeded")]
MaxSlotsExceeded,
/// Custom error.
#[error("Custom error: {0}")]
Expand All @@ -69,4 +69,4 @@ pub enum Error {
/// The error returned when registering a method or subscription failed.
#[error("{0}")]
RegisterMethod(#[from] RegisterMethodError),
}
}
14 changes: 0 additions & 14 deletions core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,6 @@
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

/// Generic transport error.
#[derive(Debug, thiserror::Error)]
pub enum GenericTransportError {
/// Request was too large.
#[error("The request was too big")]
TooLarge,
/// Malformed request
#[error("Malformed request")]
Malformed,
/// Concrete transport error.
#[error("Transport error: {0}")]
Inner(anyhow::Error),
}

/// A type that returns the error as a `String` from `SubscriptionCallback`.
#[derive(Debug)]
pub struct StringError(pub(crate) String);
Expand Down
38 changes: 22 additions & 16 deletions core/src/http_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,38 @@

//! Utility methods relying on hyper

use crate::error::GenericTransportError;
use anyhow::anyhow;
use hyper::body::{Buf, HttpBody};
use std::error::Error as StdError;

/// Represents error that can when reading with a HTTP body.
#[derive(Debug, thiserror::Error)]
pub enum HttpError {
/// The HTTP message was too large.
#[error("The HTTP message was too big")]
TooLarge,
/// Malformed request
#[error("Malformed request")]
Malformed,
/// Represents error that can happen when dealing with HTTP streams.
#[error("{0}")]
Stream(#[from] hyper::Error),
}

/// Read a data from [`hyper::body::HttpBody`] and return the data if it is valid JSON and within the allowed size range.
///
/// Returns `Ok((bytes, single))` if the body was in valid size range; and a bool indicating whether the JSON-RPC
/// request is a single or a batch.
/// Returns `Err` if the body was too large or the body couldn't be read.
pub async fn read_body<B>(
headers: &hyper::HeaderMap,
body: B,
max_body_size: u32,
) -> Result<(Vec<u8>, bool), GenericTransportError>
pub async fn read_body<B>(headers: &hyper::HeaderMap, body: B, max_body_size: u32) -> Result<(Vec<u8>, bool), HttpError>
where
B: HttpBody + Send + 'static,
B: HttpBody<Error = hyper::Error> + Send + 'static,
B::Data: Send,
B::Error: Into<Box<dyn StdError + Send + Sync>>,
{
// NOTE(niklasad1): Values bigger than `u32::MAX` will be turned into zero here. This is unlikely to occur in
// practice and in that case we fallback to allocating in the while-loop below instead of pre-allocating.
let body_size = read_header_content_length(headers).unwrap_or(0);

if body_size > max_body_size {
return Err(GenericTransportError::TooLarge);
return Err(HttpError::TooLarge);
}

futures_util::pin_mut!(body);
Expand All @@ -61,7 +67,7 @@ where
let mut is_single = None;

while let Some(d) = body.data().await {
let data = d.map_err(|e| GenericTransportError::Inner(anyhow!(e.into())))?;
let data = d.map_err(HttpError::Stream)?;

// If it's the first chunk, trim the whitespaces to determine whether it's valid JSON-RPC call.
if received_data.is_empty() {
Expand All @@ -77,18 +83,18 @@ where
is_single = Some(false);
idx
}
_ => return Err(GenericTransportError::Malformed),
_ => return Err(HttpError::Malformed),
};

if data.chunk().len() - skip > max_body_size as usize {
return Err(GenericTransportError::TooLarge);
return Err(HttpError::TooLarge);
}

// ignore whitespace as these doesn't matter just makes the JSON decoding slower.
received_data.extend_from_slice(&data.chunk()[skip..]);
} else {
if data.chunk().len() + received_data.len() > max_body_size as usize {
return Err(GenericTransportError::TooLarge);
return Err(HttpError::TooLarge);
}

received_data.extend_from_slice(data.chunk());
Expand All @@ -104,7 +110,7 @@ where
);
Ok((received_data, single))
}
_ => Err(GenericTransportError::Malformed),
_ => Err(HttpError::Malformed),
}
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ cfg_client! {
/// Shared tracing helpers to trace RPC calls.
pub mod tracing;
pub use async_trait::async_trait;
pub use error::{GenericTransportError, RegisterMethodError, StringError};
pub use error::{RegisterMethodError, StringError};

/// JSON-RPC result.
pub type RpcResult<T> = std::result::Result<T, jsonrpsee_types::ErrorObjectOwned>;
Expand Down
11 changes: 7 additions & 4 deletions server/src/transport/http.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use http::Method;
use jsonrpsee_core::{http_helpers::read_body, server::Methods, GenericTransportError};
use jsonrpsee_core::{
http_helpers::{read_body, HttpError},
server::Methods,
};

use crate::{
middleware::rpc::{RpcService, RpcServiceBuilder, RpcServiceCfg, RpcServiceT},
Expand Down Expand Up @@ -77,9 +80,9 @@ where

let (body, is_single) = match read_body(&parts.headers, body, max_request_size).await {
Ok(r) => r,
Err(GenericTransportError::TooLarge) => return response::too_large(max_request_size),
Err(GenericTransportError::Malformed) => return response::malformed(),
Err(GenericTransportError::Inner(e)) => {
Err(HttpError::TooLarge) => return response::too_large(max_request_size),
Err(HttpError::Malformed) => return response::malformed(),
Err(HttpError::Stream(e)) => {
tracing::warn!(target: LOG_TARGET, "Internal error reading request body: {}", e);
return response::internal_error();
}
Expand Down

0 comments on commit 8f73dbe

Please sign in to comment.