and implement it for ruma_api::error::FromHttpResponseError and Void. This allows integrating EndpointErrors in the common rust error ecosystem like thiserror and anyhow.
320 lines
9.4 KiB
Rust
320 lines
9.4 KiB
Rust
//! This module contains types for all kinds of errors that can occur when
|
|
//! converting between http requests / responses and ruma's representation of
|
|
//! matrix API requests / responses.
|
|
|
|
use std::fmt::{self, Display, Formatter};
|
|
|
|
// FIXME when `!` becomes stable use it
|
|
/// Default `ResponseError` for `ruma_api!` macro
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub struct Void;
|
|
|
|
impl crate::EndpointError for Void {
|
|
fn try_from_response(
|
|
response: http::Response<Vec<u8>>,
|
|
) -> Result<Self, ResponseDeserializationError> {
|
|
Err(ResponseDeserializationError::from_response(response))
|
|
}
|
|
}
|
|
|
|
impl Display for Void {
|
|
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {}
|
|
}
|
|
}
|
|
|
|
impl std::error::Error for Void {}
|
|
|
|
/// An error when converting one of ruma's endpoint-specific request or response
|
|
/// types to the corresponding http type.
|
|
#[derive(Debug)]
|
|
pub struct IntoHttpError(InnerIntoHttpError);
|
|
|
|
impl IntoHttpError {
|
|
// For usage in macros
|
|
#[doc(hidden)]
|
|
pub fn needs_authentication() -> Self {
|
|
Self(InnerIntoHttpError::NeedsAuthentication)
|
|
}
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
impl From<serde_json::Error> for IntoHttpError {
|
|
fn from(err: serde_json::Error) -> Self {
|
|
Self(InnerIntoHttpError::Json(err))
|
|
}
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
impl From<ruma_serde::urlencoded::ser::Error> for IntoHttpError {
|
|
fn from(err: ruma_serde::urlencoded::ser::Error) -> Self {
|
|
Self(InnerIntoHttpError::Query(err))
|
|
}
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
impl From<http::header::InvalidHeaderValue> for IntoHttpError {
|
|
fn from(err: http::header::InvalidHeaderValue) -> Self {
|
|
Self(InnerIntoHttpError::Header(err))
|
|
}
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
impl From<http::Error> for IntoHttpError {
|
|
fn from(err: http::Error) -> Self {
|
|
Self(InnerIntoHttpError::Http(err))
|
|
}
|
|
}
|
|
|
|
impl Display for IntoHttpError {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
match &self.0 {
|
|
InnerIntoHttpError::NeedsAuthentication => write!(
|
|
f,
|
|
"This endpoint has to be converted to http::Request using \
|
|
try_into_authenticated_http_request"
|
|
),
|
|
InnerIntoHttpError::Json(err) => write!(f, "JSON serialization failed: {}", err),
|
|
InnerIntoHttpError::Query(err) => {
|
|
write!(f, "Query parameter serialization failed: {}", err)
|
|
}
|
|
InnerIntoHttpError::Header(err) => write!(f, "Header serialization failed: {}", err),
|
|
InnerIntoHttpError::Http(err) => write!(f, "HTTP request construction failed: {}", err),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::error::Error for IntoHttpError {}
|
|
|
|
/// An error when converting a http request to one of ruma's endpoint-specific
|
|
/// request types.
|
|
#[derive(Debug)]
|
|
#[non_exhaustive]
|
|
pub enum FromHttpRequestError {
|
|
/// Deserialization failed
|
|
Deserialization(RequestDeserializationError),
|
|
}
|
|
|
|
impl Display for FromHttpRequestError {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
Self::Deserialization(err) => write!(f, "deserialization failed: {}", err),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<RequestDeserializationError> for FromHttpRequestError {
|
|
fn from(err: RequestDeserializationError) -> Self {
|
|
Self::Deserialization(err)
|
|
}
|
|
}
|
|
|
|
impl std::error::Error for FromHttpRequestError {}
|
|
|
|
/// An error that occurred when trying to deserialize a request.
|
|
#[derive(Debug)]
|
|
pub struct RequestDeserializationError {
|
|
inner: DeserializationError,
|
|
http_request: http::Request<Vec<u8>>,
|
|
}
|
|
|
|
impl RequestDeserializationError {
|
|
/// This method is public so it is accessible from `ruma_api!` generated
|
|
/// code. It is not considered part of ruma-api's public API.
|
|
#[doc(hidden)]
|
|
pub fn new(
|
|
inner: impl Into<DeserializationError>,
|
|
http_request: http::Request<Vec<u8>>,
|
|
) -> Self {
|
|
Self { inner: inner.into(), http_request }
|
|
}
|
|
}
|
|
|
|
impl Display for RequestDeserializationError {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
Display::fmt(&self.inner, f)
|
|
}
|
|
}
|
|
|
|
impl std::error::Error for RequestDeserializationError {}
|
|
|
|
/// An error when converting a http response to one of ruma's endpoint-specific
|
|
/// response types.
|
|
#[derive(Debug)]
|
|
#[non_exhaustive]
|
|
pub enum FromHttpResponseError<E> {
|
|
/// Deserialization failed
|
|
Deserialization(ResponseDeserializationError),
|
|
/// The server returned a non-success status
|
|
Http(ServerError<E>),
|
|
}
|
|
|
|
impl<E: Display> Display for FromHttpResponseError<E> {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
Self::Deserialization(err) => write!(f, "deserialization failed: {}", err),
|
|
Self::Http(err) => write!(f, "the server returned an error: {}", err),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<E> From<ServerError<E>> for FromHttpResponseError<E> {
|
|
fn from(err: ServerError<E>) -> Self {
|
|
Self::Http(err)
|
|
}
|
|
}
|
|
|
|
impl<E> From<ResponseDeserializationError> for FromHttpResponseError<E> {
|
|
fn from(err: ResponseDeserializationError) -> Self {
|
|
Self::Deserialization(err)
|
|
}
|
|
}
|
|
|
|
impl<E: std::error::Error> std::error::Error for FromHttpResponseError<E> {}
|
|
|
|
/// An error that occurred when trying to deserialize a response.
|
|
#[derive(Debug)]
|
|
pub struct ResponseDeserializationError {
|
|
inner: Option<DeserializationError>,
|
|
http_response: http::Response<Vec<u8>>,
|
|
}
|
|
|
|
impl ResponseDeserializationError {
|
|
/// This method is public so it is accessible from `ruma_api!` generated
|
|
/// code. It is not considered part of ruma-api's public API.
|
|
#[doc(hidden)]
|
|
pub fn new(
|
|
inner: impl Into<DeserializationError>,
|
|
http_response: http::Response<Vec<u8>>,
|
|
) -> Self {
|
|
Self { inner: Some(inner.into()), http_response }
|
|
}
|
|
|
|
/// This method is public so it is accessible from `ruma_api!` generated
|
|
/// code. It is not considered part of ruma-api's public API.
|
|
/// Creates an Error from a `http::Response`.
|
|
#[doc(hidden)]
|
|
pub fn from_response(http_response: http::Response<Vec<u8>>) -> Self {
|
|
Self { http_response, inner: None }
|
|
}
|
|
}
|
|
|
|
impl Display for ResponseDeserializationError {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
if let Some(ref inner) = self.inner {
|
|
Display::fmt(inner, f)
|
|
} else {
|
|
Display::fmt("deserialization error, no error specified", f)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::error::Error for ResponseDeserializationError {}
|
|
|
|
/// An error was reported by the server (HTTP status code 4xx or 5xx)
|
|
#[derive(Debug)]
|
|
pub enum ServerError<E> {
|
|
/// An error that is expected to happen under certain circumstances and
|
|
/// that has a well-defined structure
|
|
Known(E),
|
|
/// An error of unexpected type of structure
|
|
Unknown(ResponseDeserializationError),
|
|
}
|
|
|
|
impl<E: Display> Display for ServerError<E> {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
ServerError::Known(e) => Display::fmt(e, f),
|
|
ServerError::Unknown(res_err) => Display::fmt(res_err, f),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<E: std::error::Error> std::error::Error for ServerError<E> {}
|
|
|
|
#[derive(Debug)]
|
|
enum InnerIntoHttpError {
|
|
NeedsAuthentication,
|
|
Json(serde_json::Error),
|
|
Query(ruma_serde::urlencoded::ser::Error),
|
|
Header(http::header::InvalidHeaderValue),
|
|
Http(http::Error),
|
|
}
|
|
|
|
/// This type is public so it is accessible from `ruma_api!` generated code.
|
|
/// It is not considered part of ruma-api's public API.
|
|
#[doc(hidden)]
|
|
#[derive(Debug)]
|
|
pub enum DeserializationError {
|
|
Utf8(std::str::Utf8Error),
|
|
Json(serde_json::Error),
|
|
Query(ruma_serde::urlencoded::de::Error),
|
|
Ident(ruma_identifiers::Error),
|
|
// String <> Enum conversion failed. This can currently only happen in path
|
|
// segment deserialization
|
|
Strum(strum::ParseError),
|
|
Header(http::header::ToStrError),
|
|
}
|
|
|
|
impl Display for DeserializationError {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
DeserializationError::Utf8(err) => Display::fmt(err, f),
|
|
DeserializationError::Json(err) => Display::fmt(err, f),
|
|
DeserializationError::Query(err) => Display::fmt(err, f),
|
|
DeserializationError::Ident(err) => Display::fmt(err, f),
|
|
DeserializationError::Strum(err) => Display::fmt(err, f),
|
|
DeserializationError::Header(err) => Display::fmt(err, f),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
impl From<http::header::ToStrError> for DeserializationError {
|
|
fn from(err: http::header::ToStrError) -> Self {
|
|
Self::Header(err)
|
|
}
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
impl From<std::str::Utf8Error> for DeserializationError {
|
|
fn from(err: std::str::Utf8Error) -> Self {
|
|
Self::Utf8(err)
|
|
}
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
impl From<serde_json::Error> for DeserializationError {
|
|
fn from(err: serde_json::Error) -> Self {
|
|
Self::Json(err)
|
|
}
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
impl From<ruma_serde::urlencoded::de::Error> for DeserializationError {
|
|
fn from(err: ruma_serde::urlencoded::de::Error) -> Self {
|
|
Self::Query(err)
|
|
}
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
impl From<ruma_identifiers::Error> for DeserializationError {
|
|
fn from(err: ruma_identifiers::Error) -> Self {
|
|
Self::Ident(err)
|
|
}
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
impl From<strum::ParseError> for DeserializationError {
|
|
fn from(err: strum::ParseError) -> Self {
|
|
Self::Strum(err)
|
|
}
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
impl From<std::convert::Infallible> for DeserializationError {
|
|
fn from(err: std::convert::Infallible) -> Self {
|
|
match err {}
|
|
}
|
|
}
|