aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQuentin Dufour <quentin@deuxfleurs.fr>2024-03-04 17:55:48 +0100
committerQuentin Dufour <quentin@deuxfleurs.fr>2024-03-04 17:55:48 +0100
commitc9edf6c37c2b2758f0407caa48d7434af7b5a659 (patch)
tree9219161ba88eec6a22786a2444b6c0f642589494
parentad25912a0fc85dab97207b101aa7a5b6efca71b3 (diff)
downloadaerogramme-c9edf6c37c2b2758f0407caa48d7434af7b5a659.tar.gz
aerogramme-c9edf6c37c2b2758f0407caa48d7434af7b5a659.zip
beginning...
-rw-r--r--src/dav/decoder.rs173
-rw-r--r--src/dav/types.rs3
2 files changed, 82 insertions, 94 deletions
diff --git a/src/dav/decoder.rs b/src/dav/decoder.rs
index 5996a05..f6cbd27 100644
--- a/src/dav/decoder.rs
+++ b/src/dav/decoder.rs
@@ -1,17 +1,18 @@
use std::borrow::Cow;
-use im::HashMap;
-use quick_xml::events::{BytesStart, BytesText};
+use quick_xml::events::{Event, BytesStart, BytesDecl, BytesText};
use quick_xml::events::attributes::AttrError;
-use quick_xml::name::PrefixDeclaration;
-use quick_xml::reader::Reader;
+use quick_xml::name::{Namespace, QName, PrefixDeclaration, ResolveResult, ResolveResult::*};
+use quick_xml::reader::NsReader;
use tokio::io::AsyncBufRead;
use super::types::*;
+#[derive(Debug)]
pub enum ParsingError {
NamespacePrefixAlreadyUsed,
WrongToken,
+ TagNotFound,
QuickXml(quick_xml::Error)
}
impl From<AttrError> for ParsingError {
@@ -29,112 +30,98 @@ const DAV_URN: &[u8] = b"DAV:";
const CALDAV_URN: &[u8] = b"urn:ietf:params:xml:ns:caldav";
const CARDDAV_URN: &[u8] = b"urn:ietf:params:xml:ns:carddav";
const XML_URN: &[u8] = b"xml";
+const DAV_NS: ResolveResult = Bound(Namespace(DAV_URN));
-#[derive(PartialEq, Clone)]
-pub enum XmlNamespace {
- None,
- Dav,
- CalDav,
- CardDav,
- Xml,
- Unknown(Vec<u8>),
+pub struct PeekRead<T: AsyncBufRead+Unpin> {
+ evt: Event<'static>,
+ rdr: NsReader<T>,
+ buf: Vec<u8>,
}
-impl From<&[u8]> for XmlNamespace {
- fn from(value: &[u8]) -> Self {
- match value {
- [] => Self::None,
- DAV_URN => Self::Dav,
- CALDAV_URN => Self::CalDav,
- CARDDAV_URN => Self::CardDav,
- XML_URN => Self::Xml,
- v => Self::Unknown(v.into()),
- }
+impl<T: AsyncBufRead+Unpin> PeekRead<T> {
+ async fn new(mut rdr: NsReader<T>) -> Result<Self, ParsingError> {
+ let mut buf: Vec<u8> = vec![];
+ let evt = rdr.read_event_into_async(&mut buf).await?.into_owned();
+ buf.clear();
+ Ok(Self { evt, rdr, buf })
}
-}
-/// Context must stay cheap to clone
-/// as we are cloning it from one fonction to another
-#[derive(Clone)]
-pub struct Context<'a, E: Extension + Clone> {
- pub aliases: HashMap<&'a [u8], XmlNamespace>,
- phantom: std::marker::PhantomData<E>,
-}
-impl<'a, E: Extension + Clone> Context<'a, E> {
- /// External buffer
- pub fn new() -> Self {
- Self {
- aliases: HashMap::new(),
- phantom: std::marker::PhantomData
- }
+ fn peek(&self) -> &Event<'static> {
+ &self.evt
}
-
- pub fn ns_scan(&mut self, token: &'a BytesStart<'a>) -> Result<(XmlNamespace, &[u8]), ParsingError> {
- // Register namespace aliases from attributes (aka namespace bindings)
- for attr_res in token.attributes() {
- let attr = attr_res?;
- match attr.key.as_namespace_binding() {
- None => (),
- Some(PrefixDeclaration::Named(prefix)) => self.ns_alias(attr.value.as_ref(), prefix.as_ref())?,
- Some(PrefixDeclaration::Default) => self.ns_default(attr.value.as_ref())?,
- }
+ // skip tag, some tags can't be skipped like end, text, cdata
+ async fn skip(&mut self) -> Result<(), ParsingError> {
+ match &self.evt {
+ Event::Start(b) => {
+ let _span = self.rdr.read_to_end_into_async(b.to_end().name(), &mut self.buf).await?;
+ self.next().await
+ },
+ Event::Empty(_) | Event::Comment(_) | Event::PI(_) | Event::Decl(_) | Event::DocType(_) => self.next().await,
+ _ => return Err(ParsingError::WrongToken),
}
-
- // Decompose tag name
- let (key, maybe_prefix) = token.name().decompose();
- let ns = self.ns_resolve(maybe_prefix.map(|p| p.into_inner()).unwrap_or(&b""[..]));
-
- Ok((ns, key.into_inner()))
}
- fn ns_default(&mut self, fqns: &[u8]) -> Result<(), ParsingError> {
- self.ns_alias(fqns, &b""[..])
+ // read one more tag
+ async fn next(&mut self) -> Result<(), ParsingError> {
+ let evt = self.rdr.read_event_into_async(&mut self.buf).await?.into_owned();
+ self.buf.clear();
+ self.evt = evt;
+ Ok(())
}
+}
+
+pub trait QReadable<T: AsyncBufRead+Unpin>: Sized {
+ async fn read(xml: &mut PeekRead<T>) -> Result<Self, ParsingError>;
+}
- fn ns_alias(&mut self, fqns: &[u8], alias: &'a [u8]) -> Result<(), ParsingError> {
- let parsed_ns = XmlNamespace::from(fqns);
- if let Some(reg_fqns) = self.aliases.get(alias) {
- if *reg_fqns != parsed_ns {
- return Err(ParsingError::NamespacePrefixAlreadyUsed)
+impl<E: Extension, T: AsyncBufRead+Unpin> QReadable<T> for PropFind<E> {
+ async fn read(xml: &mut PeekRead<T>) -> Result<PropFind<E>, ParsingError> {
+
+ // Find propfind
+ loop {
+ match xml.peek() {
+ Event::Start(b) if b.local_name().into_inner() == &b"propfind"[..] => break,
+ _ => xml.skip().await?,
}
}
- self.aliases.insert(alias, parsed_ns);
- Ok(())
- }
-
- // If the namespace is not found in the alias table (binding table)
- // we suppose it's a fully qualified namespace (fqns)
- fn ns_resolve(&self, prefix: &[u8]) -> XmlNamespace {
- match self.aliases.get(prefix) {
- Some(fqns) => fqns.clone(),
- None => XmlNamespace::from(prefix),
+ xml.next().await?;
+
+ // Find any tag
+ let propfind = loop {
+ match xml.peek() {
+ Event::Start(b) | Event::Empty(b) if b.local_name().into_inner() == &b"allprop"[..] => {
+ unimplemented!()
+ },
+ Event::Start(b) if b.local_name().into_inner() == &b"prop"[..] => {
+ unimplemented!();
+ },
+ Event::Empty(b) if b.local_name().into_inner() == &b"propname"[..] => break PropFind::PropName,
+ _ => xml.skip().await?,
+ }
+ };
+ xml.next().await?;
+
+ // Close tag
+ loop {
+ match xml.peek() {
+ Event::End(b) if b.local_name().into_inner() == &b"propfind"[..] => break,
+ _ => xml.skip().await?,
+ }
}
+
+ Ok(propfind)
}
}
-trait DavReader<'a> {
- async fn doctype(&self) -> Result<(), ParsingError>;
- async fn tag(&self) -> Result<BytesStart<'a>, ParsingError>;
- async fn txt(&self) -> Result<Cow<'a, u8>, ParsingError>;
-}
-/*impl<'a, I: AsyncBufRead+Unpin> DavReader<'a> for Reader<I> {
- async fn doctype(&self) -> Result<(), ParsingError> {
- }
- async fn tag(&self) -> Result<BytesStart<'a>, ParsingError> {
- }
- async fn txt(&self) -> Result<Cow<'a, u8>, ParsingError> {
- }
-}*/
+#[cfg(test)]
+mod tests {
+ use super::*;
-pub async fn propfind<E: Extension+Clone>(
- xml: &mut Reader<impl AsyncBufRead+Unpin>,
- ctx: Context<'_, E>,
- buf: &mut Vec<u8>,
-) -> Result<PropFind<E>, ParsingError> {
- let local = ctx.clone();
+ #[tokio::test]
+ async fn basic_propfind() {
+ let src = r#"<?xml version="1.0" encoding="utf-8" ?><rando/><garbage><old/></garbage><D:propfind xmlns:D="DAV:"><D:propname/></D:propfind>"#;
- match xml.read_event_into_async(buf).await? {
- _ => unimplemented!(),
+ let mut rdr = PeekRead::new(NsReader::from_reader(src.as_bytes())).await.unwrap();
+ let got = PropFind::<NoExtension>::read(&mut rdr).await.unwrap();
+ assert!(matches!(got, PropFind::PropName));
}
-
- unimplemented!();
}
diff --git a/src/dav/types.rs b/src/dav/types.rs
index 7e3eb1c..a1b1c7f 100644
--- a/src/dav/types.rs
+++ b/src/dav/types.rs
@@ -20,7 +20,8 @@ impl Extension for NoExtension {
type Property = Disabled;
type PropertyRequest = Disabled;
type ResourceType = Disabled;
- }
+}
+
/// 14.1. activelock XML Element
///