Improved error handling (part 4)

This commit is contained in:
mdecimus
2024-07-18 20:04:09 +02:00
parent d2ad44cf9f
commit d48523583b
70 changed files with 1114 additions and 973 deletions

View File

@@ -11,7 +11,7 @@ use store::query::Filter;
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use trc::AddContext;
use super::{Command, ResponseCode, SerializeResponse, Session, State, StatusResponse};
use super::{Command, ResponseCode, SerializeResponse, Session, State};
impl<T: SessionStream> Session<T> {
pub async fn ingest(&mut self, bytes: &[u8]) -> SessionResult {
@@ -31,8 +31,14 @@ impl<T: SessionStream> Session<T> {
requests.push(request);
}
Err(err) => {
let mut disconnect = err.must_disconnect();
if let Err(err) = self.write_error(err).await {
tracing::error!(parent: &self.span, event = "error", error = ?err);
disconnect = true;
}
if disconnect {
return SessionResult::Close;
}
}
@@ -45,10 +51,7 @@ impl<T: SessionStream> Session<T> {
break;
}
Err(receiver::Error::Error { response }) => {
if let Err(err) = self
.write(&StatusResponse::no(response.message).into_bytes())
.await
{
if let Err(err) = self.write_error(response).await {
tracing::error!(parent: &self.span, event = "error", error = ?err);
return SessionResult::Close;
}
@@ -88,8 +91,14 @@ impl<T: SessionStream> Session<T> {
}
}
Err(err) => {
let mut disconnect = err.must_disconnect();
if let Err(err) = self.write_error(err).await {
tracing::error!(parent: &self.span, event = "error", error = ?err);
disconnect = true;
}
if disconnect {
return SessionResult::Close;
}
}

View File

@@ -264,27 +264,35 @@ pub trait SerializeResponse {
impl SerializeResponse for trc::Error {
fn serialize(&self) -> Vec<u8> {
let todo = "serialize messages properly in all protocols";
let mut buf = Vec::with_capacity(64);
buf.extend_from_slice(self.value_as_str(trc::Key::Type).unwrap_or("NO").as_bytes());
if let Some(code) = self.value_as_str(trc::Key::Code) {
if let Some(code) = self
.value_as_str(trc::Key::Code)
.or_else(|| match self.as_ref() {
trc::Cause::Store(trc::StoreCause::NotFound) => {
Some(ResponseCode::NonExistent.as_str())
}
trc::Cause::Store(_) => Some(ResponseCode::TryLater.as_str()),
trc::Cause::Limit(trc::LimitCause::Quota) => Some(ResponseCode::Quota.as_str()),
trc::Cause::Limit(_) => Some(ResponseCode::TryLater.as_str()),
_ => None,
})
{
buf.extend_from_slice(b" (");
buf.extend_from_slice(code.as_bytes());
buf.push(b')');
}
if let Some(message) = self
let message = self
.value_as_str(trc::Key::Details)
.or_else(|| self.value_as_str(trc::Key::Reason))
{
buf.extend_from_slice(b" \"");
for ch in message.as_bytes() {
if [b'\"', b'\\'].contains(ch) {
buf.push(b'\\');
}
buf.push(*ch);
.unwrap_or_else(|| self.as_ref().message());
buf.extend_from_slice(b" \"");
for ch in message.as_bytes() {
if [b'\"', b'\\'].contains(ch) {
buf.push(b'\\');
}
buf.push(b'\"');
buf.push(*ch);
}
buf.push(b'\"');
buf.extend_from_slice(b"\r\n");
buf
}

View File

@@ -71,7 +71,6 @@ impl<T: SessionStream> Session<T> {
self.jmap.is_auth_allowed_soft(&self.remote_addr).await?;
// Authenticate
let mut is_totp_error = false;
let access_token = match credentials {
Credentials::Plain { username, secret } | Credentials::XOauth2 { username, secret } => {
self.jmap
@@ -81,16 +80,37 @@ impl<T: SessionStream> Session<T> {
self.remote_addr,
ServerProtocol::ManageSieve,
)
.await?
.await
}
Credentials::OAuthBearer { token } => {
let (account_id, _, _) = self
match self
.jmap
.validate_access_token("access_token", &token)
.await?;
self.jmap.get_access_token(account_id).await?
.await
{
Ok((account_id, _, _)) => self.jmap.get_access_token(account_id).await,
Err(err) => Err(err),
}
}
};
}
.map_err(|err| {
if err.matches(trc::Cause::Auth(trc::AuthCause::Failed)) {
match &self.state {
State::NotAuthenticated { auth_failures }
if *auth_failures < self.jmap.core.imap.max_auth_failures =>
{
self.state = State::NotAuthenticated {
auth_failures: auth_failures + 1,
};
}
_ => {
return trc::AuthCause::TooManyAttempts.into_err().caused_by(err);
}
}
}
err
})?;
// Enforce concurrency limits
let in_flight = match self
@@ -114,35 +134,7 @@ impl<T: SessionStream> Session<T> {
in_flight,
};
let todo = "implement this";
Ok(StatusResponse::ok("Authentication successful").into_bytes())
/*} else {
match &self.state {
State::NotAuthenticated { auth_failures }
if *auth_failures < self.jmap.core.imap.max_auth_failures =>
{
self.state = State::NotAuthenticated {
auth_failures: auth_failures + 1,
};
Err(trc::Cause::Authentication
.into_err()
.details(if is_totp_error {
"Missing TOTP code, try with 'secret$totp_code'."
} else {
"Authentication failed."
}))
}
_ => {
tracing::debug!(
parent: &self.span,
event = "disconnect",
"Too many authentication failures, disconnecting.",
);
Err(StatusResponse::bye("Too many authentication failures"))
}
}
}*/
}
pub async fn handle_unauthenticate(&mut self) -> trc::Result<Vec<u8>> {