Fixed some parsing bugs
This commit is contained in:
parent
b9f32d720a
commit
4d65366ff3
6 changed files with 206 additions and 152 deletions
|
@ -9,6 +9,7 @@ use quick_xml::reader::NsReader;
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
|
|
||||||
|
// Split this file
|
||||||
const tokens: [&str; 63] = [
|
const tokens: [&str; 63] = [
|
||||||
"0",
|
"0",
|
||||||
"1",
|
"1",
|
||||||
|
@ -125,6 +126,9 @@ impl Tag {
|
||||||
|
|
||||||
#[derive(Arbitrary)]
|
#[derive(Arbitrary)]
|
||||||
enum XmlNode {
|
enum XmlNode {
|
||||||
|
//@FIXME: build RFC3339 and RFC822 Dates with chrono based on timestamps
|
||||||
|
//@FIXME: add small numbers
|
||||||
|
//@FIXME: add http status code
|
||||||
Node(Tag, Vec<Self>),
|
Node(Tag, Vec<Self>),
|
||||||
Number(u64),
|
Number(u64),
|
||||||
Text(Token),
|
Text(Token),
|
||||||
|
|
|
@ -1,9 +1,39 @@
|
||||||
//use super::types as dav;
|
use super::types as dav;
|
||||||
use super::caltypes::*;
|
use super::caltypes::*;
|
||||||
use super::xml;
|
use super::xml;
|
||||||
use super::error;
|
use super::error;
|
||||||
|
|
||||||
// ---- ROOT ELEMENTS ---
|
// ---- ROOT ELEMENTS ---
|
||||||
|
impl<E: dav::Extension> xml::QRead<MkCalendar<E>> for MkCalendar<E> {
|
||||||
|
async fn qread(_xml: &mut xml::Reader<impl xml::IRead>) -> Result<Self, error::ParsingError> {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: dav::Extension, N: xml::Node<N>> xml::QRead<MkCalendarResponse<E,N>> for MkCalendarResponse<E,N> {
|
||||||
|
async fn qread(_xml: &mut xml::Reader<impl xml::IRead>) -> Result<Self, error::ParsingError> {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: dav::Extension> xml::QRead<CalendarQuery<E>> for CalendarQuery<E> {
|
||||||
|
async fn qread(_xml: &mut xml::Reader<impl xml::IRead>) -> Result<Self, error::ParsingError> {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: dav::Extension> xml::QRead<CalendarMultiget<E>> for CalendarMultiget<E> {
|
||||||
|
async fn qread(_xml: &mut xml::Reader<impl xml::IRead>) -> Result<Self, error::ParsingError> {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl xml::QRead<FreeBusyQuery> for FreeBusyQuery {
|
||||||
|
async fn qread(_xml: &mut xml::Reader<impl xml::IRead>) -> Result<Self, error::ParsingError> {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ---- EXTENSIONS ---
|
// ---- EXTENSIONS ---
|
||||||
impl xml::QRead<Violation> for Violation {
|
impl xml::QRead<Violation> for Violation {
|
||||||
|
@ -31,3 +61,8 @@ impl xml::QRead<ResourceType> for ResourceType {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- INNER XML ----
|
// ---- INNER XML ----
|
||||||
|
impl xml::QRead<SupportedCollation> for SupportedCollation {
|
||||||
|
async fn qread(_xml: &mut xml::Reader<impl xml::IRead>) -> Result<Self, error::ParsingError> {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -666,7 +666,7 @@ mod tests {
|
||||||
use crate::types as dav;
|
use crate::types as dav;
|
||||||
use crate::realization::Calendar;
|
use crate::realization::Calendar;
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
use chrono::{Utc,TimeZone,DateTime};
|
use chrono::{Utc,TimeZone};
|
||||||
|
|
||||||
async fn serialize(elem: &impl QWrite) -> String {
|
async fn serialize(elem: &impl QWrite) -> String {
|
||||||
let mut buffer = Vec::new();
|
let mut buffer = Vec::new();
|
||||||
|
|
|
@ -23,8 +23,8 @@ impl<E: Extension> QRead<PropFind<E>> for PropFind<E> {
|
||||||
let propfind: PropFind<E> = loop {
|
let propfind: PropFind<E> = loop {
|
||||||
// allprop
|
// allprop
|
||||||
if let Some(_) = xml.maybe_open(DAV_URN, "allprop").await? {
|
if let Some(_) = xml.maybe_open(DAV_URN, "allprop").await? {
|
||||||
let includ = xml.maybe_find::<Include<E>>().await?;
|
|
||||||
xml.close().await?;
|
xml.close().await?;
|
||||||
|
let includ = xml.maybe_find::<Include<E>>().await?;
|
||||||
break PropFind::AllProp(includ)
|
break PropFind::AllProp(includ)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -594,8 +594,9 @@ impl QRead<Href> for Href {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use chrono::{FixedOffset, DateTime, TimeZone, Utc};
|
use chrono::{FixedOffset, TimeZone};
|
||||||
use crate::realization::Core;
|
use crate::realization::Core;
|
||||||
|
use quick_xml::reader::NsReader;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn basic_propfind_propname() {
|
async fn basic_propfind_propname() {
|
||||||
|
@ -910,7 +911,7 @@ mod tests {
|
||||||
Property::GetContentType("text/html".into()),
|
Property::GetContentType("text/html".into()),
|
||||||
Property::GetEtag(r#""zzyzx""#.into()),
|
Property::GetEtag(r#""zzyzx""#.into()),
|
||||||
Property::GetLastModified(FixedOffset::west_opt(0).unwrap().with_ymd_and_hms(1998, 01, 12, 09, 25, 56).unwrap()),
|
Property::GetLastModified(FixedOffset::west_opt(0).unwrap().with_ymd_and_hms(1998, 01, 12, 09, 25, 56).unwrap()),
|
||||||
//Property::ResourceType(vec![]),
|
Property::ResourceType(vec![]),
|
||||||
Property::SupportedLock(vec![
|
Property::SupportedLock(vec![
|
||||||
LockEntry {
|
LockEntry {
|
||||||
lockscope: LockScope::Exclusive,
|
lockscope: LockScope::Exclusive,
|
||||||
|
|
|
@ -633,6 +633,7 @@ impl<E: Extension> QWrite for Violation<E> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use super::super::xml;
|
||||||
use crate::realization::Core;
|
use crate::realization::Core;
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
|
|
||||||
|
@ -653,43 +654,47 @@ mod tests {
|
||||||
return got.into()
|
return got.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn deserialize<T: xml::Node<T>>(src: &str) -> T {
|
||||||
|
let mut rdr = xml::Reader::new(quick_xml::reader::NsReader::from_reader(src.as_bytes())).await.unwrap();
|
||||||
|
rdr.find().await.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn basic_href() {
|
async fn basic_href() {
|
||||||
|
let orig = Href("/SOGo/dav/so/".into());
|
||||||
|
|
||||||
let got = serialize(
|
let got = serialize(&orig).await;
|
||||||
&Href("/SOGo/dav/so/".into())
|
|
||||||
).await;
|
|
||||||
let expected = r#"<D:href xmlns:D="DAV:">/SOGo/dav/so/</D:href>"#;
|
let expected = r#"<D:href xmlns:D="DAV:">/SOGo/dav/so/</D:href>"#;
|
||||||
|
|
||||||
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
|
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
|
||||||
|
assert_eq!(deserialize::<Href>(got.as_str()).await, orig)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn basic_multistatus() {
|
async fn basic_multistatus() {
|
||||||
let got = serialize(
|
let orig = Multistatus::<Core, PropName<Core>> {
|
||||||
&Multistatus::<Core, PropName<Core>> {
|
|
||||||
responses: vec![],
|
responses: vec![],
|
||||||
responsedescription: Some(ResponseDescription("Hello world".into()))
|
responsedescription: Some(ResponseDescription("Hello world".into()))
|
||||||
},
|
};
|
||||||
).await;
|
let got = serialize(&orig).await;
|
||||||
|
|
||||||
let expected = r#"<D:multistatus xmlns:D="DAV:">
|
let expected = r#"<D:multistatus xmlns:D="DAV:">
|
||||||
<D:responsedescription>Hello world</D:responsedescription>
|
<D:responsedescription>Hello world</D:responsedescription>
|
||||||
</D:multistatus>"#;
|
</D:multistatus>"#;
|
||||||
|
|
||||||
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
|
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
|
||||||
|
assert_eq!(deserialize::<Multistatus::<Core, PropName<Core>>>(got.as_str()).await, orig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn rfc_error_delete_locked() {
|
async fn rfc_error_delete_locked() {
|
||||||
let got = serialize(
|
let orig = Error::<Core>(vec![
|
||||||
&Error::<Core>(vec![
|
|
||||||
Violation::LockTokenSubmitted(vec![
|
Violation::LockTokenSubmitted(vec![
|
||||||
Href("/locked/".into())
|
Href("/locked/".into())
|
||||||
])
|
])
|
||||||
]),
|
]);
|
||||||
).await;
|
let got = serialize(&orig).await;
|
||||||
|
|
||||||
let expected = r#"<D:error xmlns:D="DAV:">
|
let expected = r#"<D:error xmlns:D="DAV:">
|
||||||
<D:lock-token-submitted>
|
<D:lock-token-submitted>
|
||||||
|
@ -698,25 +703,26 @@ mod tests {
|
||||||
</D:error>"#;
|
</D:error>"#;
|
||||||
|
|
||||||
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
|
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
|
||||||
|
assert_eq!(deserialize::<Error<Core>>(got.as_str()).await, orig)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn rfc_propname_req() {
|
async fn rfc_propname_req() {
|
||||||
let got = serialize(
|
let orig = PropFind::<Core>::PropName;
|
||||||
&PropFind::<Core>::PropName,
|
|
||||||
).await;
|
let got = serialize(&orig).await;
|
||||||
|
|
||||||
let expected = r#"<D:propfind xmlns:D="DAV:">
|
let expected = r#"<D:propfind xmlns:D="DAV:">
|
||||||
<D:propname/>
|
<D:propname/>
|
||||||
</D:propfind>"#;
|
</D:propfind>"#;
|
||||||
|
|
||||||
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
|
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
|
||||||
|
assert_eq!(deserialize::<PropFind::<Core>>(got.as_str()).await, orig)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn rfc_propname_res() {
|
async fn rfc_propname_res() {
|
||||||
let got = serialize(
|
let orig = Multistatus::<Core, PropName<Core>> {
|
||||||
&Multistatus::<Core, PropName<Core>> {
|
|
||||||
responses: vec![
|
responses: vec![
|
||||||
Response {
|
Response {
|
||||||
status_or_propstat: StatusOrPropstat::PropStat(
|
status_or_propstat: StatusOrPropstat::PropStat(
|
||||||
|
@ -762,8 +768,9 @@ mod tests {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
responsedescription: None,
|
responsedescription: None,
|
||||||
},
|
};
|
||||||
).await;
|
|
||||||
|
let got = serialize(&orig).await;
|
||||||
|
|
||||||
let expected = r#"<D:multistatus xmlns:D="DAV:">
|
let expected = r#"<D:multistatus xmlns:D="DAV:">
|
||||||
<D:response>
|
<D:response>
|
||||||
|
@ -798,26 +805,27 @@ mod tests {
|
||||||
|
|
||||||
|
|
||||||
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
|
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
|
||||||
|
assert_eq!(deserialize::<Multistatus::<Core, PropName<Core>>>(got.as_str()).await, orig)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn rfc_allprop_req() {
|
async fn rfc_allprop_req() {
|
||||||
let got = serialize(
|
let orig = PropFind::<Core>::AllProp(None);
|
||||||
&PropFind::<Core>::AllProp(None),
|
let got = serialize(&orig).await;
|
||||||
).await;
|
|
||||||
|
|
||||||
let expected = r#"<D:propfind xmlns:D="DAV:">
|
let expected = r#"<D:propfind xmlns:D="DAV:">
|
||||||
<D:allprop/>
|
<D:allprop/>
|
||||||
</D:propfind>"#;
|
</D:propfind>"#;
|
||||||
|
|
||||||
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
|
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
|
||||||
|
assert_eq!(deserialize::<PropFind::<Core>>(got.as_str()).await, orig)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn rfc_allprop_res() {
|
async fn rfc_allprop_res() {
|
||||||
use chrono::{DateTime,FixedOffset,TimeZone};
|
use chrono::{FixedOffset,TimeZone};
|
||||||
let got = serialize(
|
|
||||||
&Multistatus::<Core, PropValue<Core>> {
|
let orig = Multistatus::<Core, PropValue<Core>> {
|
||||||
responses: vec![
|
responses: vec![
|
||||||
Response {
|
Response {
|
||||||
status_or_propstat: StatusOrPropstat::PropStat(
|
status_or_propstat: StatusOrPropstat::PropStat(
|
||||||
|
@ -890,8 +898,9 @@ mod tests {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
responsedescription: None,
|
responsedescription: None,
|
||||||
}
|
};
|
||||||
).await;
|
|
||||||
|
let got = serialize(&orig).await;
|
||||||
|
|
||||||
let expected = r#"<D:multistatus xmlns:D="DAV:">
|
let expected = r#"<D:multistatus xmlns:D="DAV:">
|
||||||
<D:response>
|
<D:response>
|
||||||
|
@ -961,16 +970,17 @@ mod tests {
|
||||||
</D:multistatus>"#;
|
</D:multistatus>"#;
|
||||||
|
|
||||||
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
|
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
|
||||||
|
assert_eq!(deserialize::<Multistatus::<Core, PropValue<Core>>>(got.as_str()).await, orig)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn rfc_allprop_include() {
|
async fn rfc_allprop_include() {
|
||||||
let got = serialize(
|
let orig = PropFind::<Core>::AllProp(Some(Include(vec![
|
||||||
&PropFind::<Core>::AllProp(Some(Include(vec![
|
|
||||||
PropertyRequest::DisplayName,
|
PropertyRequest::DisplayName,
|
||||||
PropertyRequest::ResourceType,
|
PropertyRequest::ResourceType,
|
||||||
]))),
|
])));
|
||||||
).await;
|
|
||||||
|
let got = serialize(&orig).await;
|
||||||
|
|
||||||
let expected = r#"<D:propfind xmlns:D="DAV:">
|
let expected = r#"<D:propfind xmlns:D="DAV:">
|
||||||
<D:allprop/>
|
<D:allprop/>
|
||||||
|
@ -981,6 +991,7 @@ mod tests {
|
||||||
</D:propfind>"#;
|
</D:propfind>"#;
|
||||||
|
|
||||||
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
|
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
|
||||||
|
assert_eq!(deserialize::<PropFind::<Core>>(got.as_str()).await, orig)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -79,7 +79,7 @@ impl<T: IRead> Reader<T> {
|
||||||
/// skip a node at current level
|
/// skip a node at current level
|
||||||
/// I would like to make this one private but not ready
|
/// I would like to make this one private but not ready
|
||||||
pub async fn skip(&mut self) -> Result<Event<'static>, ParsingError> {
|
pub async fn skip(&mut self) -> Result<Event<'static>, ParsingError> {
|
||||||
//println!("skipping inside node {:?}", self.parents.last());
|
//println!("skipping inside node {:?} value {:?}", self.parents.last(), self.cur);
|
||||||
match &self.cur {
|
match &self.cur {
|
||||||
Event::Start(b) => {
|
Event::Start(b) => {
|
||||||
let _span = self.rdr.read_to_end_into_async(b.to_end().name(), &mut self.buf).await?;
|
let _span = self.rdr.read_to_end_into_async(b.to_end().name(), &mut self.buf).await?;
|
||||||
|
@ -212,8 +212,10 @@ impl<T: IRead> Reader<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn collect<N: Node<N>>(&mut self) -> Result<Vec<N>, ParsingError> {
|
pub async fn collect<N: Node<N>>(&mut self) -> Result<Vec<N>, ParsingError> {
|
||||||
self.ensure_parent_has_child()?;
|
|
||||||
let mut acc = Vec::new();
|
let mut acc = Vec::new();
|
||||||
|
if !self.parent_has_child() {
|
||||||
|
return Ok(acc)
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match N::qread(self).await {
|
match N::qread(self).await {
|
||||||
|
@ -230,6 +232,7 @@ impl<T: IRead> Reader<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn open(&mut self, ns: &[u8], key: &str) -> Result<Event<'static>, ParsingError> {
|
pub async fn open(&mut self, ns: &[u8], key: &str) -> Result<Event<'static>, ParsingError> {
|
||||||
|
//println!("try open tag {:?}", key);
|
||||||
let evt = match self.peek() {
|
let evt = match self.peek() {
|
||||||
Event::Empty(_) if self.is_tag(ns, key) => self.cur.clone(),
|
Event::Empty(_) if self.is_tag(ns, key) => self.cur.clone(),
|
||||||
Event::Start(_) if self.is_tag(ns, key) => self.next().await?,
|
Event::Start(_) if self.is_tag(ns, key) => self.next().await?,
|
||||||
|
|
Loading…
Reference in a new issue