wow testing

This commit is contained in:
Michael Zhang 2021-08-09 17:56:17 -05:00
parent 0405b478eb
commit 60e0bb3bbb
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
12 changed files with 90 additions and 39 deletions

View file

@ -1,2 +1,5 @@
fmt: fmt:
cargo +nightly fmt --all cargo +nightly fmt --all
doc:
cargo doc --workspace --no-deps

View file

@ -1,7 +1,7 @@
//! Configurable cert verifier for rustls, can disable hostname verification, //! Configurable cert verifier for rustls, can disable hostname verification,
//! etc. //! etc.
//! //!
//! Based closely on https://github.com/rustls/rustls/blob/v/0.19.0/rustls/src/verify.rs#L253 //! Based closely on <https://github.com/rustls/rustls/blob/v/0.19.0/rustls/src/verify.rs#L253>
use tokio_rustls::{ use tokio_rustls::{
rustls::{ rustls::{

View file

@ -1,9 +1,9 @@
use std::io::{self, Write}; use std::io::{self, Write};
use format_bytes::DisplayBytes; use format_bytes::DisplayBytes;
use panorama_proto_common::{quote_string as q, Bytes}; use panorama_proto_common::{quote_string, Bytes};
use super::rfc3501::is_quoted_specials as isq; use super::rfc3501::is_quoted_specials;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Command { pub enum Command {
@ -52,6 +52,7 @@ pub enum Command {
impl DisplayBytes for Command { impl DisplayBytes for Command {
fn display_bytes(&self, w: &mut dyn Write) -> io::Result<()> { fn display_bytes(&self, w: &mut dyn Write) -> io::Result<()> {
let quote = quote_string(b'\x22', b'\\', is_quoted_specials);
match self { match self {
// command-any // command-any
Command::Capability => write_bytes!(w, b"CAPABILITY"), Command::Capability => write_bytes!(w, b"CAPABILITY"),
@ -63,8 +64,8 @@ impl DisplayBytes for Command {
write_bytes!( write_bytes!(
w, w,
b"LOGIN {} {}", b"LOGIN {} {}",
q(&login.userid, isq), quote(&login.userid),
q(&login.password, isq) quote(&login.password)
) )
} }
Command::Starttls => write_bytes!(w, b"STARTTLS"), Command::Starttls => write_bytes!(w, b"STARTTLS"),
@ -74,11 +75,11 @@ impl DisplayBytes for Command {
write_bytes!( write_bytes!(
w, w,
b"LIST {} {}", b"LIST {} {}",
q(&list.reference, isq), quote(&list.reference),
q(&list.mailbox, isq) quote(&list.mailbox)
) )
} }
Command::Select(select) => write_bytes!(w, b"SELECT {}", q(&select.mailbox, isq)), Command::Select(select) => write_bytes!(w, b"SELECT {}", quote(&select.mailbox)),
#[cfg(feature = "rfc2177")] #[cfg(feature = "rfc2177")]
Command::Idle => write_bytes!(w, b"IDLE"), Command::Idle => write_bytes!(w, b"IDLE"),

View file

@ -159,7 +159,7 @@ pub struct MailboxList {
pub mailbox: Mailbox, pub mailbox: Mailbox,
} }
#[derive(Debug)] #[derive(Debug, PartialEq, Eq)]
pub enum MailboxListFlag { pub enum MailboxListFlag {
NoInferiors, NoInferiors,
NoSelect, NoSelect,

View file

@ -19,6 +19,13 @@ use super::response::{
}; };
use super::rfc2234::{is_char, is_cr, is_ctl, is_digit, is_dquote, is_lf, is_sp, CRLF, DQUOTE, SP}; use super::rfc2234::{is_char, is_cr, is_ctl, is_digit, is_dquote, is_lf, is_sp, CRLF, DQUOTE, SP};
#[macro_export]
macro_rules! opt_nil {
($t:expr) => {
alt((map($t, Some), map(crate::proto::rfc3501::nil, |_| None)))
};
}
rule!(pub address : Address => map(paren!(tuple(( rule!(pub address : Address => map(paren!(tuple((
terminated(addr_name, SP), terminated(addr_name, SP),
terminated(addr_adl, SP), terminated(addr_adl, SP),

View file

@ -1,5 +1,6 @@
use panorama_proto_common::Bytes; use panorama_proto_common::Bytes;
use super::response::*;
use super::rfc3501::*; use super::rfc3501::*;
#[test] #[test]
@ -15,7 +16,20 @@ fn test_literal() {
#[test] #[test]
fn test_list() { fn test_list() {
let _ = response(Bytes::from( assert!(matches!(
response(Bytes::from(
b"* LIST (\\HasChildren \\UnMarked \\Trash) \".\" Trash\r\n", b"* LIST (\\HasChildren \\UnMarked \\Trash) \".\" Trash\r\n",
))
.unwrap()
.1,
Response::MailboxData(MailboxData::List(MailboxList {
flags,
delimiter: Some(b'.'),
mailbox: Mailbox::Name(mailbox),
}) ) if flags.len() == 3 &&
flags.contains(&MailboxListFlag::Extension(Atom::from(b"HasChildren"))) &&
flags.contains(&MailboxListFlag::Extension(Atom::from(b"UnMarked"))) &&
flags.contains(&MailboxListFlag::Extension(Atom::from(b"Trash"))) &&
&*mailbox == &b"Trash"[..]
)); ));
} }

View file

@ -7,12 +7,25 @@ use nom::{
CompareResult, Err, IResult, InputLength, Needed, CompareResult, Err, IResult, InputLength, Needed,
}; };
/// Glue code between nom and Bytes so they work together /// Glue code between nom and Bytes so they work together.
#[derive(Clone, Debug, Default, PartialEq, Eq)] #[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Bytes(bytes::Bytes); pub struct Bytes(bytes::Bytes);
impl Bytes { impl Bytes {
/// Length of the internal `Bytes`.
///
/// # Example
///
/// ```
/// # use panorama_proto_common::Bytes;
/// // the &, [..] is needed since &[u8; N] doesn't coerce automatically to &[u8]
/// let b = Bytes::from(&b"hello"[..]);
/// assert_eq!(b.len(), 5);
/// ```
pub fn len(&self) -> usize { self.0.len() } pub fn len(&self) -> usize { self.0.len() }
/// Consumes the wrapper, returning the original `Bytes`.
pub fn inner(self) -> bytes::Bytes { self.0 }
} }
impl DisplayBytes for Bytes { impl DisplayBytes for Bytes {
@ -224,10 +237,6 @@ array_impls! {
50 51 52 53 54 55 56 57 58 59 50 51 52 53 54 55 56 57 58 59
} }
impl Bytes {
pub fn inner(self) -> bytes::Bytes { self.0 }
}
impl Deref for Bytes { impl Deref for Bytes {
type Target = [u8]; type Target = [u8];
fn deref(&self) -> &Self::Target { &*self.0 } fn deref(&self) -> &Self::Target { &*self.0 }

View file

@ -1,15 +1,30 @@
pub fn quote_string(input: impl AsRef<[u8]>, should_escape: impl Fn(u8) -> bool) -> Vec<u8> { /// Adds quotes around a byte-string according to a quote function.
///
/// # Example
///
/// ```
/// # use panorama_proto_common::quote_string;
/// let quote = quote_string(b'\x22', b'\\', |c| c == b'\x22' || c == b'\x27');
/// assert_eq!(quote(b"hello \"' world"), b"\"hello \\\"\\' world\"");
/// ```
pub fn quote_string<B, F>(quote: u8, escape: u8, should_escape: F) -> impl Fn(B) -> Vec<u8>
where
B: AsRef<[u8]>,
F: Fn(u8) -> bool,
{
move |input: B| {
let input = input.as_ref(); let input = input.as_ref();
let mut ret = Vec::with_capacity(input.len() + 2); let mut ret = Vec::with_capacity(input.len() + 2);
ret.push(b'\x22'); ret.push(quote);
for c in input { for c in input {
if should_escape(*c) { if should_escape(*c) {
ret.push(b'\\'); ret.push(escape);
} }
ret.push(*c); ret.push(*c);
} }
ret.push(b'\x22'); ret.push(quote);
ret ret
} }
}

View file

@ -5,6 +5,6 @@ mod bytes;
mod formatter; mod formatter;
mod parsers; mod parsers;
pub use crate::bytes::Bytes; pub use crate::bytes::{Bytes, ShitCompare, ShitNeededForParsing};
pub use crate::formatter::quote_string; pub use crate::formatter::quote_string;
pub use crate::parsers::{byte, never, parse_u32, satisfy, skip, tagi, take, take_while1, VResult}; pub use crate::parsers::{byte, never, parse_u32, satisfy, skip, tagi, take, take_while1, VResult};

View file

@ -6,7 +6,7 @@ use nom::{
use super::bytes::{ShitCompare, ShitNeededForParsing}; use super::bytes::{ShitCompare, ShitNeededForParsing};
/// A specific form of `nom::IResult` that uses `nom::error::VerboseError`. /// A specific form of `IResult` that uses `VerboseError`.
pub type VResult<I, O> = IResult<I, O, VerboseError<I>>; pub type VResult<I, O> = IResult<I, O, VerboseError<I>>;
/// `sep_list!(t, d)` represents `t *(d t)` and automatically collapses it into /// `sep_list!(t, d)` represents `t *(d t)` and automatically collapses it into
@ -20,7 +20,10 @@ pub type VResult<I, O> = IResult<I, O, VerboseError<I>>;
macro_rules! sep_list { macro_rules! sep_list {
($t:expr) => { ($t:expr) => {
map( map(
pair($t, many0(preceded(crate::proto::rfc2234::SP, $t))), pair(
$t,
many0(preceded(panorama_proto_common::byte(b'\x20'), $t)),
),
|(hd, mut tl)| { |(hd, mut tl)| {
tl.insert(0, hd); tl.insert(0, hd);
tl tl
@ -35,7 +38,10 @@ macro_rules! sep_list {
}; };
(? $t:expr) => { (? $t:expr) => {
map( map(
opt(pair($t, many0(preceded(crate::proto::rfc2234::SP, $t)))), opt(pair(
$t,
many0(preceded(panorama_proto_common::byte(b'\x20'), $t)),
)),
|opt| { |opt| {
opt.map(|(hd, mut tl)| { opt.map(|(hd, mut tl)| {
tl.insert(0, hd); tl.insert(0, hd);
@ -56,13 +62,7 @@ macro_rules! sep_list {
}; };
} }
#[macro_export] /// Helper macro for wrapping a parser in parentheses.
macro_rules! opt_nil {
($t:expr) => {
alt((map($t, Some), map(crate::proto::rfc3501::nil, |_| None)))
};
}
#[macro_export] #[macro_export]
macro_rules! paren { macro_rules! paren {
($t:expr) => { ($t:expr) => {

1
smtp/src/client/mod.rs Normal file
View file

@ -0,0 +1 @@

View file

@ -1 +1,2 @@
mod client;
pub mod proto; pub mod proto;