matrix-sdk: Split out the http errors into a sub-enum
parent
b66c666997
commit
585ca9fdf7
|
@ -118,6 +118,7 @@ use matrix_sdk_common::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
error::HttpError,
|
||||||
http_client::{client_with_config, HttpClient, HttpSend},
|
http_client::{client_with_config, HttpClient, HttpSend},
|
||||||
Error, OutgoingRequest, Result,
|
Error, OutgoingRequest, Result,
|
||||||
};
|
};
|
||||||
|
@ -1451,7 +1452,7 @@ impl Client {
|
||||||
content_type: Some(content_type.essence_str()),
|
content_type: Some(content_type.essence_str()),
|
||||||
});
|
});
|
||||||
|
|
||||||
self.http_client.upload(request).await
|
Ok(self.http_client.upload(request).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send an arbitrary request to the server, without updating client state.
|
/// Send an arbitrary request to the server, without updating client state.
|
||||||
|
@ -1494,9 +1495,9 @@ impl Client {
|
||||||
pub async fn send<Request>(&self, request: Request) -> Result<Request::IncomingResponse>
|
pub async fn send<Request>(&self, request: Request) -> Result<Request::IncomingResponse>
|
||||||
where
|
where
|
||||||
Request: OutgoingRequest + Debug,
|
Request: OutgoingRequest + Debug,
|
||||||
Error: From<FromHttpResponseError<Request::EndpointError>>,
|
HttpError: From<FromHttpResponseError<Request::EndpointError>>,
|
||||||
{
|
{
|
||||||
self.http_client.send(request).await
|
Ok(self.http_client.send(request).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "encryption")]
|
#[cfg(feature = "encryption")]
|
||||||
|
@ -2276,7 +2277,7 @@ impl Client {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::ClientConfig;
|
use crate::{ClientConfig, HttpError};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
get_public_rooms, get_public_rooms_filtered, register::RegistrationKind, Client,
|
get_public_rooms, get_public_rooms_filtered, register::RegistrationKind, Client,
|
||||||
|
@ -2471,12 +2472,12 @@ mod test {
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
if let Err(err) = client.login("example", "wordpass", None, None).await {
|
if let Err(err) = client.login("example", "wordpass", None, None).await {
|
||||||
if let crate::Error::RumaResponse(crate::FromHttpResponseError::Http(
|
if let crate::Error::Http(HttpError::FromHttpResponse(
|
||||||
crate::ServerError::Known(crate::api::Error {
|
crate::FromHttpResponseError::Http(crate::ServerError::Known(crate::api::Error {
|
||||||
kind,
|
kind,
|
||||||
message,
|
message,
|
||||||
status_code,
|
status_code,
|
||||||
}),
|
})),
|
||||||
)) = err
|
)) = err
|
||||||
{
|
{
|
||||||
if let crate::api::error::ErrorKind::Forbidden = kind {
|
if let crate::api::error::ErrorKind::Forbidden = kind {
|
||||||
|
@ -2517,10 +2518,10 @@ mod test {
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Err(err) = client.register(user).await {
|
if let Err(err) = client.register(user).await {
|
||||||
if let crate::Error::UiaaError(crate::FromHttpResponseError::Http(
|
if let crate::Error::Http(HttpError::UiaaError(crate::FromHttpResponseError::Http(
|
||||||
// TODO this should be a UiaaError need to investigate
|
// TODO this should be a UiaaError need to investigate
|
||||||
crate::ServerError::Unknown(e),
|
crate::ServerError::Unknown(e),
|
||||||
)) = err
|
))) = err
|
||||||
{
|
{
|
||||||
assert!(e.to_string().starts_with("EOF while parsing"))
|
assert!(e.to_string().starts_with("EOF while parsing"))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -20,7 +20,7 @@ use matrix_sdk_common::{
|
||||||
r0::uiaa::{UiaaInfo, UiaaResponse as UiaaError},
|
r0::uiaa::{UiaaInfo, UiaaResponse as UiaaError},
|
||||||
Error as RumaClientError,
|
Error as RumaClientError,
|
||||||
},
|
},
|
||||||
FromHttpResponseError as RumaResponseError, IntoHttpError as RumaIntoHttpError, ServerError,
|
FromHttpResponseError, IntoHttpError, ServerError,
|
||||||
};
|
};
|
||||||
use reqwest::Error as ReqwestError;
|
use reqwest::Error as ReqwestError;
|
||||||
use serde_json::Error as JsonError;
|
use serde_json::Error as JsonError;
|
||||||
|
@ -33,9 +33,14 @@ use matrix_sdk_base::crypto::store::CryptoStoreError;
|
||||||
/// Result type of the rust-sdk.
|
/// Result type of the rust-sdk.
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
/// Internal representation of errors.
|
/// An HTTP error, representing either a connection error or an error while
|
||||||
|
/// converting the raw HTTP response into a Matrix response.
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum HttpError {
|
||||||
|
/// An error at the HTTP layer.
|
||||||
|
#[error(transparent)]
|
||||||
|
Reqwest(#[from] ReqwestError),
|
||||||
|
|
||||||
/// Queried endpoint requires authentication but was called on an anonymous client.
|
/// Queried endpoint requires authentication but was called on an anonymous client.
|
||||||
#[error("the queried endpoint requires authentication but was called before logging in")]
|
#[error("the queried endpoint requires authentication but was called before logging in")]
|
||||||
AuthenticationRequired,
|
AuthenticationRequired,
|
||||||
|
@ -44,9 +49,33 @@ pub enum Error {
|
||||||
#[error("the queried endpoint is not meant for clients")]
|
#[error("the queried endpoint is not meant for clients")]
|
||||||
NotClientRequest,
|
NotClientRequest,
|
||||||
|
|
||||||
/// An error at the HTTP layer.
|
/// An error converting between ruma_client_api types and Hyper types.
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Reqwest(#[from] ReqwestError),
|
FromHttpResponse(#[from] FromHttpResponseError<RumaClientError>),
|
||||||
|
|
||||||
|
/// An error converting between ruma_client_api types and Hyper types.
|
||||||
|
#[error(transparent)]
|
||||||
|
IntoHttp(#[from] IntoHttpError),
|
||||||
|
|
||||||
|
/// An error occurred while authenticating.
|
||||||
|
///
|
||||||
|
/// When registering or authenticating the Matrix server can send a `UiaaResponse`
|
||||||
|
/// as the error type, this is a User-Interactive Authentication API response. This
|
||||||
|
/// represents an error with information about how to authenticate the user.
|
||||||
|
#[error(transparent)]
|
||||||
|
UiaaError(#[from] FromHttpResponseError<UiaaError>),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Internal representation of errors.
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Error doing an HTTP request.
|
||||||
|
#[error(transparent)]
|
||||||
|
Http(#[from] HttpError),
|
||||||
|
|
||||||
|
/// Queried endpoint requires authentication but was called on an anonymous client.
|
||||||
|
#[error("the queried endpoint requires authentication but was called before logging in")]
|
||||||
|
AuthenticationRequired,
|
||||||
|
|
||||||
/// An error de/serializing type for the `StateStore`
|
/// An error de/serializing type for the `StateStore`
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
@ -56,14 +85,6 @@ pub enum Error {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
IO(#[from] IoError),
|
IO(#[from] IoError),
|
||||||
|
|
||||||
/// An error converting between ruma_client_api types and Hyper types.
|
|
||||||
#[error("can't parse the JSON response as a Matrix response")]
|
|
||||||
RumaResponse(RumaResponseError<RumaClientError>),
|
|
||||||
|
|
||||||
/// An error converting between ruma_client_api types and Hyper types.
|
|
||||||
#[error("can't convert between ruma_client_api and hyper types.")]
|
|
||||||
IntoHttp(RumaIntoHttpError),
|
|
||||||
|
|
||||||
/// An error occurred in the Matrix client library.
|
/// An error occurred in the Matrix client library.
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
MatrixError(#[from] MatrixError),
|
MatrixError(#[from] MatrixError),
|
||||||
|
@ -76,14 +97,6 @@ pub enum Error {
|
||||||
/// An error occured in the state store.
|
/// An error occured in the state store.
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
StateStore(#[from] StoreError),
|
StateStore(#[from] StoreError),
|
||||||
|
|
||||||
/// An error occurred while authenticating.
|
|
||||||
///
|
|
||||||
/// When registering or authenticating the Matrix server can send a `UiaaResponse`
|
|
||||||
/// as the error type, this is a User-Interactive Authentication API response. This
|
|
||||||
/// represents an error with information about how to authenticate the user.
|
|
||||||
#[error("User-Interactive Authentication required.")]
|
|
||||||
UiaaError(RumaResponseError<UiaaError>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
|
@ -99,9 +112,9 @@ impl Error {
|
||||||
/// This method is an convenience method to get to the info the server
|
/// This method is an convenience method to get to the info the server
|
||||||
/// returned on the first, failed request.
|
/// returned on the first, failed request.
|
||||||
pub fn uiaa_response(&self) -> Option<&UiaaInfo> {
|
pub fn uiaa_response(&self) -> Option<&UiaaInfo> {
|
||||||
if let Error::UiaaError(RumaResponseError::Http(ServerError::Known(
|
if let Error::Http(HttpError::UiaaError(FromHttpResponseError::Http(ServerError::Known(
|
||||||
UiaaError::AuthResponse(i),
|
UiaaError::AuthResponse(i),
|
||||||
))) = self
|
)))) = self
|
||||||
{
|
{
|
||||||
Some(i)
|
Some(i)
|
||||||
} else {
|
} else {
|
||||||
|
@ -110,20 +123,8 @@ impl Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<RumaResponseError<UiaaError>> for Error {
|
impl From<ReqwestError> for Error {
|
||||||
fn from(error: RumaResponseError<UiaaError>) -> Self {
|
fn from(e: ReqwestError) -> Self {
|
||||||
Self::UiaaError(error)
|
Error::Http(HttpError::Reqwest(e))
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<RumaResponseError<RumaClientError>> for Error {
|
|
||||||
fn from(error: RumaResponseError<RumaClientError>) -> Self {
|
|
||||||
Self::RumaResponse(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<RumaIntoHttpError> for Error {
|
|
||||||
fn from(error: RumaIntoHttpError) -> Self {
|
|
||||||
Self::IntoHttp(error)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ use matrix_sdk_common::{
|
||||||
FromHttpResponseError,
|
FromHttpResponseError,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{ClientConfig, Error, OutgoingRequest, Result, Session};
|
use crate::{error::HttpError, ClientConfig, OutgoingRequest, Session};
|
||||||
|
|
||||||
/// Abstraction around the http layer. The allows implementors to use different
|
/// Abstraction around the http layer. The allows implementors to use different
|
||||||
/// http libraries.
|
/// http libraries.
|
||||||
|
@ -74,7 +74,7 @@ pub trait HttpSend: AsyncTraitDeps {
|
||||||
async fn send_request(
|
async fn send_request(
|
||||||
&self,
|
&self,
|
||||||
request: http::Request<Vec<u8>>,
|
request: http::Request<Vec<u8>>,
|
||||||
) -> Result<http::Response<Vec<u8>>>;
|
) -> Result<http::Response<Vec<u8>>, HttpError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -90,7 +90,7 @@ impl HttpClient {
|
||||||
request: Request,
|
request: Request,
|
||||||
session: Arc<RwLock<Option<Session>>>,
|
session: Arc<RwLock<Option<Session>>>,
|
||||||
content_type: Option<HeaderValue>,
|
content_type: Option<HeaderValue>,
|
||||||
) -> Result<http::Response<Vec<u8>>> {
|
) -> Result<http::Response<Vec<u8>>, HttpError> {
|
||||||
let mut request = {
|
let mut request = {
|
||||||
let read_guard;
|
let read_guard;
|
||||||
let access_token = match Request::METADATA.authentication {
|
let access_token = match Request::METADATA.authentication {
|
||||||
|
@ -100,11 +100,11 @@ impl HttpClient {
|
||||||
if let Some(session) = read_guard.as_ref() {
|
if let Some(session) = read_guard.as_ref() {
|
||||||
Some(session.access_token.as_str())
|
Some(session.access_token.as_str())
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::AuthenticationRequired);
|
return Err(HttpError::AuthenticationRequired);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AuthScheme::None => None,
|
AuthScheme::None => None,
|
||||||
_ => return Err(Error::NotClientRequest),
|
_ => return Err(HttpError::NotClientRequest),
|
||||||
};
|
};
|
||||||
|
|
||||||
request.try_into_http_request(&self.homeserver.to_string(), access_token)?
|
request.try_into_http_request(&self.homeserver.to_string(), access_token)?
|
||||||
|
@ -124,17 +124,20 @@ impl HttpClient {
|
||||||
pub async fn upload(
|
pub async fn upload(
|
||||||
&self,
|
&self,
|
||||||
request: create_content::Request<'_>,
|
request: create_content::Request<'_>,
|
||||||
) -> Result<create_content::Response> {
|
) -> Result<create_content::Response, HttpError> {
|
||||||
let response = self
|
let response = self
|
||||||
.send_request(request, self.session.clone(), None)
|
.send_request(request, self.session.clone(), None)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(create_content::Response::try_from(response)?)
|
Ok(create_content::Response::try_from(response)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send<Request>(&self, request: Request) -> Result<Request::IncomingResponse>
|
pub async fn send<Request>(
|
||||||
|
&self,
|
||||||
|
request: Request,
|
||||||
|
) -> Result<Request::IncomingResponse, HttpError>
|
||||||
where
|
where
|
||||||
Request: OutgoingRequest,
|
Request: OutgoingRequest + Debug,
|
||||||
Error: From<FromHttpResponseError<Request::EndpointError>>,
|
HttpError: From<FromHttpResponseError<Request::EndpointError>>,
|
||||||
{
|
{
|
||||||
let content_type = HeaderValue::from_static("application/json");
|
let content_type = HeaderValue::from_static("application/json");
|
||||||
let response = self
|
let response = self
|
||||||
|
@ -143,12 +146,14 @@ impl HttpClient {
|
||||||
|
|
||||||
trace!("Got response: {:?}", response);
|
trace!("Got response: {:?}", response);
|
||||||
|
|
||||||
Ok(Request::IncomingResponse::try_from(response)?)
|
let response = Request::IncomingResponse::try_from(response)?;
|
||||||
|
|
||||||
|
Ok(response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build a client with the specified configuration.
|
/// Build a client with the specified configuration.
|
||||||
pub(crate) fn client_with_config(config: &ClientConfig) -> Result<Client> {
|
pub(crate) fn client_with_config(config: &ClientConfig) -> Result<Client, HttpError> {
|
||||||
let http_client = reqwest::Client::builder();
|
let http_client = reqwest::Client::builder();
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
@ -188,7 +193,9 @@ pub(crate) fn client_with_config(config: &ClientConfig) -> Result<Client> {
|
||||||
Ok(http_client.build()?)
|
Ok(http_client.build()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn response_to_http_response(mut response: Response) -> Result<http::Response<Vec<u8>>> {
|
async fn response_to_http_response(
|
||||||
|
mut response: Response,
|
||||||
|
) -> Result<http::Response<Vec<u8>>, reqwest::Error> {
|
||||||
let status = response.status();
|
let status = response.status();
|
||||||
|
|
||||||
let mut http_builder = HttpResponse::builder().status(status);
|
let mut http_builder = HttpResponse::builder().status(status);
|
||||||
|
@ -211,7 +218,7 @@ impl HttpSend for Client {
|
||||||
async fn send_request(
|
async fn send_request(
|
||||||
&self,
|
&self,
|
||||||
request: http::Request<Vec<u8>>,
|
request: http::Request<Vec<u8>>,
|
||||||
) -> Result<http::Response<Vec<u8>>> {
|
) -> Result<http::Response<Vec<u8>>, HttpError> {
|
||||||
Ok(
|
Ok(
|
||||||
response_to_http_response(self.execute(reqwest::Request::try_from(request)?).await?)
|
response_to_http_response(self.execute(reqwest::Request::try_from(request)?).await?)
|
||||||
.await?,
|
.await?,
|
||||||
|
|
|
@ -90,7 +90,7 @@ pub use client::{Client, ClientConfig, LoopCtrl, SyncSettings};
|
||||||
#[cfg(feature = "encryption")]
|
#[cfg(feature = "encryption")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
||||||
pub use device::Device;
|
pub use device::Device;
|
||||||
pub use error::{Error, Result};
|
pub use error::{Error, HttpError, Result};
|
||||||
pub use http_client::HttpSend;
|
pub use http_client::HttpSend;
|
||||||
#[cfg(feature = "encryption")]
|
#[cfg(feature = "encryption")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
||||||
|
|
Loading…
Reference in New Issue