Minor improvements.

This commit is contained in:
Mauro D 2022-12-21 16:51:03 +00:00
parent 81fdbe7151
commit bb6437dec4
7 changed files with 54 additions and 60 deletions

View file

@ -217,7 +217,7 @@ pub struct EhloResponse<T: Display> {
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct Response<T: Display> { pub struct Response<T: Display> {
pub code: [u8; 3], pub code: u16,
pub esc: [u8; 3], pub esc: [u8; 3],
pub message: T, pub message: T,
} }
@ -251,15 +251,14 @@ pub enum Error {
SyntaxError { syntax: &'static str }, SyntaxError { syntax: &'static str },
InvalidParameter { param: &'static str }, InvalidParameter { param: &'static str },
UnsupportedParameter { param: String }, UnsupportedParameter { param: String },
LineTooLong,
ResponseTooLong, ResponseTooLong,
InvalidResponse { code: [u8; 3] }, InvalidResponse { code: u16 },
} }
pub(crate) const LF: u8 = b'\n'; pub(crate) const LF: u8 = b'\n';
pub(crate) const SP: u8 = b' '; pub(crate) const SP: u8 = b' ';
pub(crate) trait IntoString: Sized { pub trait IntoString: Sized {
fn into_string(self) -> String; fn into_string(self) -> String;
} }

View file

@ -32,7 +32,7 @@ pub(crate) const ETRN: u64 =
(b'E' as u64) | (b'T' as u64) << 8 | (b'R' as u64) << 16 | (b'N' as u64) << 24; (b'E' as u64) | (b'T' as u64) << 8 | (b'R' as u64) << 16 | (b'N' as u64) << 24;
pub(crate) const ATRN: u64 = pub(crate) const ATRN: u64 =
(b'A' as u64) | (b'T' as u64) << 8 | (b'R' as u64) << 16 | (b'N' as u64) << 24; (b'A' as u64) | (b'T' as u64) << 8 | (b'R' as u64) << 16 | (b'N' as u64) << 24;
pub(crate) const AUTH: u64 = pub const AUTH: u64 =
(b'A' as u64) | (b'U' as u64) << 8 | (b'T' as u64) << 16 | (b'H' as u64) << 24; (b'A' as u64) | (b'U' as u64) << 8 | (b'T' as u64) << 16 | (b'H' as u64) << 24;
pub(crate) const BURL: u64 = pub(crate) const BURL: u64 =
(b'B' as u64) | (b'U' as u64) << 8 | (b'R' as u64) << 16 | (b'L' as u64) << 24; (b'B' as u64) | (b'U' as u64) << 8 | (b'R' as u64) << 16 | (b'L' as u64) << 24;

View file

@ -289,9 +289,9 @@ impl Request<String> {
} }
} }
pub(crate) struct Rfc5321Parser<'x, 'y> { pub struct Rfc5321Parser<'x, 'y> {
bytes: &'x mut Iter<'y, u8>, bytes: &'x mut Iter<'y, u8>,
pub(crate) stop_char: u8, pub stop_char: u8,
pub bytes_left: usize, pub bytes_left: usize,
} }
@ -1046,7 +1046,7 @@ impl<'x, 'y> Rfc5321Parser<'x, 'y> {
Ok(params) Ok(params)
} }
pub(crate) fn mechanism(&mut self) -> Result<Option<u64>, Error> { pub fn mechanism(&mut self) -> Result<Option<u64>, Error> {
let mut trailing_chars = [0u8; 8]; let mut trailing_chars = [0u8; 8];
let mut pos = 0; let mut pos = 0;
let mechanism = self.hashed_value_long()?; let mechanism = self.hashed_value_long()?;

View file

@ -28,6 +28,7 @@ pub struct DummyDataReceiver {
prev_last_ch: u8, prev_last_ch: u8,
} }
#[derive(Default)]
pub struct DummyLineReceiver {} pub struct DummyLineReceiver {}
impl RequestReceiver { impl RequestReceiver {
@ -43,7 +44,7 @@ impl RequestReceiver {
if bytes_left < MAX_LINE_LENGTH { if bytes_left < MAX_LINE_LENGTH {
self.buf = buf[buf.len() - bytes_left..].to_vec(); self.buf = buf[buf.len() - bytes_left..].to_vec();
} else { } else {
return Err(Error::LineTooLong); return Err(Error::ResponseTooLong);
} }
} }
} }
@ -58,7 +59,7 @@ impl RequestReceiver {
return result; return result;
} else if self.buf.len() == MAX_LINE_LENGTH { } else if self.buf.len() == MAX_LINE_LENGTH {
self.buf.clear(); self.buf.clear();
return Err(Error::LineTooLong); return Err(Error::ResponseTooLong);
} }
} }
} }

View file

@ -25,7 +25,7 @@ impl<T: Display> EhloResponse<T> {
let mut capabilities = self.capabilities; let mut capabilities = self.capabilities;
while capabilities != 0 { while capabilities != 0 {
let capability = 63 - capabilities.leading_zeros(); let capability = 31 - capabilities.leading_zeros();
capabilities ^= 1 << capability; capabilities ^= 1 << capability;
writer.write_all(b"250")?; writer.write_all(b"250")?;
@ -109,14 +109,8 @@ impl<T: Display> Response<T> {
pub fn write(&self, mut writer: impl Write) -> io::Result<()> { pub fn write(&self, mut writer: impl Write) -> io::Result<()> {
write!( write!(
writer, writer,
"{}{}{} {}.{}.{} {}\r\n", "{} {}.{}.{} {}\r\n",
self.code[0], self.code, self.esc[0], self.esc[1], self.esc[2], self.message
self.code[1],
self.code[2],
self.esc[0],
self.esc[1],
self.esc[2],
self.message
) )
} }
} }
@ -176,17 +170,17 @@ impl BitToString for u64 {
} }
impl<T: Display> Response<T> { impl<T: Display> Response<T> {
pub fn new(c0: u8, c1: u8, c2: u8, e0: u8, e1: u8, e2: u8, message: T) -> Self { pub fn new(code: u16, e0: u8, e1: u8, e2: u8, message: T) -> Self {
Self { Self {
code: [c0, c1, c2], code,
esc: [e0, e1, e2], esc: [e0, e1, e2],
message, message,
} }
} }
/// Returns the reply's numeric status. /// Returns the reply's numeric status.
pub fn code(&self) -> &[u8] { pub fn code(&self) -> u16 {
&self.code self.code
} }
/// Returns the message included in the reply. /// Returns the message included in the reply.
@ -196,18 +190,18 @@ impl<T: Display> Response<T> {
/// Returns the status severity (first digit of the status code). /// Returns the status severity (first digit of the status code).
pub fn severity(&self) -> Severity { pub fn severity(&self) -> Severity {
match self.code[0] { match self.code {
2 => Severity::PositiveCompletion, 200..=299 => Severity::PositiveCompletion,
3 => Severity::PositiveIntermediate, 300..=399 => Severity::PositiveIntermediate,
4 => Severity::TransientNegativeCompletion, 400..=499 => Severity::TransientNegativeCompletion,
5 => Severity::PermanentNegativeCompletion, 500..=599 => Severity::PermanentNegativeCompletion,
_ => Severity::Invalid, _ => Severity::Invalid,
} }
} }
/// Returns the status category (second digit of the status code). /// Returns the status category (second digit of the status code).
pub fn category(&self) -> Category { pub fn category(&self) -> Category {
match self.code[1] { match (self.code / 10) % 10 {
0 => Category::Syntax, 0 => Category::Syntax,
1 => Category::Information, 1 => Category::Information,
2 => Category::Connections, 2 => Category::Connections,
@ -219,8 +213,8 @@ impl<T: Display> Response<T> {
} }
/// Returns the status details (third digit of the status code). /// Returns the status details (third digit of the status code).
pub fn details(&self) -> u8 { pub fn details(&self) -> u16 {
self.code[2] self.code % 10
} }
/// Returns `true` if the reply is a positive completion. /// Returns `true` if the reply is a positive completion.

View file

@ -221,14 +221,8 @@ impl<T: Display> Display for Response<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!( write!(
f, f,
"Code: {}{}{}, Enhanced code: {}.{}.{}, Message: {}", "Code: {}, Enhanced code: {}.{}.{}, Message: {}",
self.code[0], self.code, self.esc[0], self.esc[1], self.esc[2], self.message,
self.code[1],
self.code[2],
self.esc[0],
self.esc[1],
self.esc[2],
self.message,
) )
} }
} }

View file

@ -9,15 +9,17 @@ pub const MAX_REPONSE_LENGTH: usize = 4096;
#[derive(Default)] #[derive(Default)]
pub struct ResponseReceiver { pub struct ResponseReceiver {
buf: Vec<u8>, buf: Vec<u8>,
code: [u8; 6], code: u16,
esc: [u8; 3],
is_last: bool, is_last: bool,
pos: usize, pos: usize,
} }
impl ResponseReceiver { impl ResponseReceiver {
pub fn from_code(code: [u8; 3]) -> Self { pub fn from_code(code: u16) -> Self {
Self { Self {
code: [code[0], code[1], code[2], 0, 0, 0], code,
esc: [0, 0, 0],
pos: 3, pos: 3,
is_last: false, is_last: false,
buf: Vec::new(), buf: Vec::new(),
@ -30,7 +32,10 @@ impl ResponseReceiver {
0..=2 => { 0..=2 => {
if ch.is_ascii_digit() { if ch.is_ascii_digit() {
if self.buf.is_empty() { if self.buf.is_empty() {
self.code[self.pos] = ch - b'0'; self.code = self
.code
.saturating_mul(10)
.saturating_add((ch - b'0') as u16);
} }
self.pos += 1; self.pos += 1;
} else { } else {
@ -62,11 +67,11 @@ impl ResponseReceiver {
4 | 5 | 6 => match ch { 4 | 5 | 6 => match ch {
b'0'..=b'9' => { b'0'..=b'9' => {
if self.buf.is_empty() { if self.buf.is_empty() {
let code = &mut self.code[self.pos - 1]; let code = &mut self.esc[self.pos - 4];
*code = code.saturating_mul(10).saturating_add(ch - b'0'); *code = code.saturating_mul(10).saturating_add(ch - b'0');
} }
} }
b'.' if self.pos < 6 && self.code[self.pos - 1] > 0 => { b'.' if self.pos < 6 && self.esc[self.pos - 4] > 0 => {
self.pos += 1; self.pos += 1;
} }
_ => { _ => {
@ -91,8 +96,8 @@ impl ResponseReceiver {
if ch == b'\n' { if ch == b'\n' {
if self.is_last { if self.is_last {
return Ok(Response { return Ok(Response {
code: [self.code[0], self.code[1], self.code[2]], code: self.code,
esc: [self.code[3], self.code[4], self.code[5]], esc: self.esc,
message: std::mem::take(&mut self.buf).into_string(), message: std::mem::take(&mut self.buf).into_string(),
}); });
} else { } else {
@ -107,7 +112,8 @@ impl ResponseReceiver {
pub fn reset(&mut self) { pub fn reset(&mut self) {
self.is_last = false; self.is_last = false;
self.code.fill(0); self.code = 0;
self.esc.fill(0);
self.pos = 0; self.pos = 0;
} }
} }
@ -116,15 +122,15 @@ impl EhloResponse<String> {
pub fn parse(bytes: &mut Iter<'_, u8>) -> Result<Self, Error> { pub fn parse(bytes: &mut Iter<'_, u8>) -> Result<Self, Error> {
let mut parser = Rfc5321Parser::new(bytes); let mut parser = Rfc5321Parser::new(bytes);
let mut response = EhloResponse::default(); let mut response = EhloResponse::default();
let mut code = [0u8; 3];
let mut eol = false; let mut eol = false;
let mut is_first_line = true; let mut is_first_line = true;
while !eol { while !eol {
for code in code.iter_mut() { let mut code: u16 = 0;
for _ in 0..3 {
match parser.read_char()? { match parser.read_char()? {
ch @ b'0'..=b'9' => { ch @ b'0'..=b'9' => {
*code = ch - b'0'; code = code.saturating_mul(10).saturating_add((ch - b'0') as u16);
} }
_ => { _ => {
return Err(Error::SyntaxError { return Err(Error::SyntaxError {
@ -134,7 +140,7 @@ impl EhloResponse<String> {
} }
} }
if code[0] != 2 || code[1] != 5 || code[2] != 0 { if code != 250 {
return Err(Error::InvalidResponse { code }); return Err(Error::InvalidResponse { code });
} }
@ -143,7 +149,7 @@ impl EhloResponse<String> {
eol = true; eol = true;
} }
b'-' => (), b'-' => (),
b'\n' if code[0] < 6 => { b'\n' if code < 600 => {
break; break;
} }
_ => { _ => {
@ -416,7 +422,7 @@ mod tests {
), ),
( (
concat!("523-Massive\n", "523-Error\n", "523 Message\n"), concat!("523-Massive\n", "523-Error\n", "523 Message\n"),
Err(Error::UnknownCommand), Err(Error::InvalidResponse { code: 523 }),
), ),
] { ] {
let (response, parsed_response): (&str, Result<EhloResponse<String>, Error>) = item; let (response, parsed_response): (&str, Result<EhloResponse<String>, Error>) = item;
@ -446,7 +452,7 @@ mod tests {
( (
"250 2.1.1 Originator <ned@ymir.claremont.edu> ok\n", "250 2.1.1 Originator <ned@ymir.claremont.edu> ok\n",
Response { Response {
code: [2, 5, 0], code: 250,
esc: [2, 1, 1], esc: [2, 1, 1],
message: "Originator <ned@ymir.claremont.edu> ok".to_string(), message: "Originator <ned@ymir.claremont.edu> ok".to_string(),
}, },
@ -458,7 +464,7 @@ mod tests {
"551 5.7.1 Select another host to act as your forwarder\n" "551 5.7.1 Select another host to act as your forwarder\n"
), ),
Response { Response {
code: [5, 5, 1], code: 551,
esc: [5, 7, 1], esc: [5, 7, 1],
message: concat!( message: concat!(
"Forwarding to remote hosts disabled\n", "Forwarding to remote hosts disabled\n",
@ -474,7 +480,7 @@ mod tests {
"550 user has moved with no forwarding address\n" "550 user has moved with no forwarding address\n"
), ),
Response { Response {
code: [5, 5, 0], code: 550,
esc: [0, 0, 0], esc: [0, 0, 0],
message: "mailbox unavailable\nuser has moved with no forwarding address" message: "mailbox unavailable\nuser has moved with no forwarding address"
.to_string(), .to_string(),
@ -487,7 +493,7 @@ mod tests {
"550 user has moved with no forwarding address\n" "550 user has moved with no forwarding address\n"
), ),
Response { Response {
code: [5, 5, 0], code: 550,
esc: [0, 0, 0], esc: [0, 0, 0],
message: "mailbox unavailable\nuser has moved with no forwarding address" message: "mailbox unavailable\nuser has moved with no forwarding address"
.to_string(), .to_string(),
@ -508,7 +514,7 @@ mod tests {
"432 6.8.9 World!\n" "432 6.8.9 World!\n"
), ),
Response { Response {
code: [4, 3, 2], code: 432,
esc: [6, 8, 9], esc: [6, 8, 9],
message: "\nHello\n\n,\n\n\n\n\n\nWorld!".to_string(), message: "\nHello\n\n,\n\n\n\n\n\nWorld!".to_string(),
}, },
@ -517,7 +523,7 @@ mod tests {
( (
concat!("250-Missing space\n", "250\n", "250 Ignore this"), concat!("250-Missing space\n", "250\n", "250 Ignore this"),
Response { Response {
code: [2, 5, 0], code: 250,
esc: [0, 0, 0], esc: [0, 0, 0],
message: "Missing space\n".to_string(), message: "Missing space\n".to_string(),
}, },