Commit
+25 -14 +/-3 browse
1 | diff --git a/maitred/src/error.rs b/maitred/src/error.rs |
2 | index 6fc07a3..b43c80f 100644 |
3 | --- a/maitred/src/error.rs |
4 | +++ b/maitred/src/error.rs |
5 | @@ -5,7 +5,4 @@ pub enum Error { |
6 | /// An IO related error such as not being able to bind to a TCP socket |
7 | #[error("Io: {0}")] |
8 | Io(#[from] std::io::Error), |
9 | - /// Session timeout |
10 | - #[error("Client took too long to respond: {0}s")] |
11 | - Timeout(u64), |
12 | } |
13 | diff --git a/maitred/src/server.rs b/maitred/src/server.rs |
14 | index 4a5517f..2906b8e 100644 |
15 | --- a/maitred/src/server.rs |
16 | +++ b/maitred/src/server.rs |
17 | @@ -21,7 +21,7 @@ use crate::error::Error; |
18 | use crate::milter::Milter; |
19 | use crate::session::{Session, SessionOptions}; |
20 | use crate::smtp_response; |
21 | - use crate::transport::{Command, Transport}; |
22 | + use crate::transport::{Command, Transport, TransportError}; |
23 | use crate::worker::{Packet, Worker}; |
24 | use crate::{Response, SmtpResponse}; |
25 | |
26 | @@ -38,6 +38,20 @@ fn is_quit(reqs: &[Request<String>]) -> bool { |
27 | reqs.last().is_some_and(|req| matches!(req, Request::Quit)) |
28 | } |
29 | |
30 | + /// Top level error encountered while processing a client connection, causes |
31 | + /// a warning to be logged but is not fatal. |
32 | + #[derive(Debug, thiserror::Error)] |
33 | + pub(crate) enum ClientError { |
34 | + /// An IO related error such as not being able to bind to a TCP socket |
35 | + #[error("Io: {0}")] |
36 | + Io(#[from] std::io::Error), |
37 | + #[error("Transport Error: {0}")] |
38 | + Transport(#[from] TransportError), |
39 | + /// Session timeout |
40 | + #[error("Client took too long to respond: {0}s")] |
41 | + Timeout(u64), |
42 | + } |
43 | + |
44 | /// Server implements everything that is required to run an SMTP server by |
45 | /// binding to the configured address and processing individual TCP connections |
46 | /// as they are received. |
47 | @@ -110,7 +124,7 @@ impl Server { |
48 | &self, |
49 | mut framed: Framed<T, Transport>, |
50 | msg_queue: Arc<Injector<Packet>>, |
51 | - ) -> Result<(), Error> |
52 | + ) -> Result<(), ClientError> |
53 | where |
54 | T: tokio::io::AsyncRead + tokio::io::AsyncWrite + std::marker::Unpin, |
55 | { |
56 | @@ -161,10 +175,10 @@ impl Server { |
57 | Ok(Some(Err(err))) => { |
58 | tracing::warn!("Client Error: {}", err); |
59 | let response = match err { |
60 | - crate::transport::Error::PipelineNotEnabled => { |
61 | + crate::transport::TransportError::PipelineNotEnabled => { |
62 | crate::smtp_response!(500, 0, 0, 0, "Pipelining is not enabled") |
63 | } |
64 | - crate::transport::Error::Smtp(e) => { |
65 | + crate::transport::TransportError::Smtp(e) => { |
66 | match e { |
67 | smtp_proto::Error::NeedsMoreData { bytes_left: _ } => { |
68 | // TODO |
69 | @@ -201,7 +215,7 @@ impl Server { |
70 | } |
71 | } |
72 | // IO Errors considered fatal for the entire session |
73 | - crate::transport::Error::Io(e) => return Err(Error::Io(e)), |
74 | + crate::transport::TransportError::Io(e) => return Err(ClientError::Io(e)), |
75 | }; |
76 | framed.send(response).await?; |
77 | } |
78 | @@ -214,7 +228,7 @@ impl Server { |
79 | framed |
80 | .send(crate::session::timeout(&timeout.to_string())) |
81 | .await?; |
82 | - return Err(Error::Timeout(self.global_timeout.as_secs())); |
83 | + return Err(ClientError::Timeout(self.global_timeout.as_secs())); |
84 | } |
85 | } |
86 | } |
87 | diff --git a/maitred/src/transport.rs b/maitred/src/transport.rs |
88 | index e35f8a8..74e3c4c 100644 |
89 | --- a/maitred/src/transport.rs |
90 | +++ b/maitred/src/transport.rs |
91 | @@ -7,7 +7,7 @@ pub use smtp_proto::{EhloResponse, Request, Response as SmtpResponse}; |
92 | use tokio_util::codec::{Decoder, Encoder}; |
93 | |
94 | #[derive(Debug, thiserror::Error)] |
95 | - pub enum Error { |
96 | + pub(crate) enum TransportError { |
97 | /// Returned when a client attempts to send multiple commands sequentially |
98 | /// to the server without waiting for a response but piplining isn't |
99 | /// enabled. |
100 | @@ -109,7 +109,7 @@ impl Transport { |
101 | } |
102 | |
103 | impl Encoder<Response<String>> for Transport { |
104 | - type Error = crate::Error; |
105 | + type Error = TransportError; |
106 | |
107 | fn encode(&mut self, item: Response<String>, dst: &mut BytesMut) -> Result<(), Self::Error> { |
108 | match item { |
109 | @@ -126,7 +126,7 @@ impl Encoder<Response<String>> for Transport { |
110 | |
111 | impl Decoder for Transport { |
112 | type Item = Command; |
113 | - type Error = Error; |
114 | + type Error = TransportError; |
115 | |
116 | fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> { |
117 | if src.is_empty() { |
118 | @@ -172,7 +172,7 @@ impl Decoder for Transport { |
119 | match r.ingest(&mut iter, src) { |
120 | Ok(request) => { |
121 | if !requests.is_empty() && !self.pipelining { |
122 | - return Err(Error::PipelineNotEnabled) |
123 | + return Err(TransportError::PipelineNotEnabled) |
124 | } |
125 | requests.push(request); |
126 | } |
127 | @@ -180,7 +180,7 @@ impl Decoder for Transport { |
128 | if matches!(err, smtp_proto::Error::NeedsMoreData { bytes_left: _ }) { |
129 | break 'outer; |
130 | } else { |
131 | - return Err(Error::Smtp(err)); |
132 | + return Err(TransportError::Smtp(err)); |
133 | } |
134 | } |
135 | } |