Minor improvements.
This commit is contained in:
parent
81fdbe7151
commit
bb6437dec4
7 changed files with 54 additions and 60 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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()?;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(),
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue