Import upstream v0.16.22, stripped
Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f Enterprise-only files removed or emptied: 63 Enterprise-only snippets removed: 117 in 50 files Dangling module declarations removed: 5 Cargo edits turning enterprise off: 14 Verification: clean Enterprise feature gates left for rebuilt features: 19 in 18 files Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use crate::{
|
||||
parser::{DavParser, RawElement, Token, tokenizer::Tokenizer},
|
||||
schema::Namespace,
|
||||
};
|
||||
use types::dead_property::{DeadElementTag, DeadProperty, DeadPropertyTag};
|
||||
|
||||
pub mod acl;
|
||||
pub mod lockinfo;
|
||||
pub mod mkcol;
|
||||
pub mod propertyupdate;
|
||||
pub mod propfind;
|
||||
pub mod report;
|
||||
|
||||
impl DavParser for DeadProperty {
|
||||
fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
|
||||
let mut depth = 1;
|
||||
let mut items = DeadProperty::default();
|
||||
|
||||
loop {
|
||||
match stream.token()? {
|
||||
Token::ElementStart { raw, .. } | Token::UnknownElement(raw) => {
|
||||
items.0.push(DeadPropertyTag::ElementStart((&raw).into()));
|
||||
depth += 1;
|
||||
}
|
||||
Token::ElementEnd => {
|
||||
depth -= 1;
|
||||
if depth == 0 {
|
||||
break;
|
||||
}
|
||||
items.0.push(DeadPropertyTag::ElementEnd);
|
||||
}
|
||||
Token::Text(text) => {
|
||||
items.0.push(DeadPropertyTag::Text(text.into_owned()));
|
||||
}
|
||||
Token::Bytes(bytes) => {
|
||||
items.0.push(DeadPropertyTag::Text(
|
||||
String::from_utf8_lossy(&bytes).into_owned(),
|
||||
));
|
||||
}
|
||||
Token::Eof => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(items)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait NsDeadProperty {
|
||||
fn single_with_ns(namespace: Namespace, name: &str) -> Self;
|
||||
}
|
||||
|
||||
impl NsDeadProperty for DeadProperty {
|
||||
fn single_with_ns(namespace: Namespace, name: &str) -> Self {
|
||||
DeadProperty(vec![
|
||||
DeadPropertyTag::ElementStart(DeadElementTag {
|
||||
name: format!("{}:{name}", namespace.prefix()),
|
||||
attrs: None,
|
||||
}),
|
||||
DeadPropertyTag::ElementEnd,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&RawElement<'_>> for DeadElementTag {
|
||||
fn from(raw: &RawElement<'_>) -> Self {
|
||||
let name = std::str::from_utf8(raw.element.local_name().as_ref())
|
||||
.unwrap_or("invalid-utf8")
|
||||
.trim_ascii()
|
||||
.to_string();
|
||||
let mut attrs = String::with_capacity(raw.element.attributes_raw().len());
|
||||
if let Some(namespace) = &raw.namespace {
|
||||
attrs.push_str("xmlns=\"");
|
||||
attrs.push_str(std::str::from_utf8(namespace).unwrap_or("invalid-utf8"));
|
||||
attrs.push('"');
|
||||
}
|
||||
|
||||
for attr in raw.element.attributes().flatten() {
|
||||
if attr.key.as_ref() == b"xmlns" || attr.key.as_ref().starts_with(b"xmlns:") {
|
||||
// Skip namespace attributes
|
||||
continue;
|
||||
}
|
||||
if let (Ok(key), Ok(value)) = (
|
||||
std::str::from_utf8(attr.key.as_ref()),
|
||||
std::str::from_utf8(attr.value.as_ref()),
|
||||
) {
|
||||
if !attrs.is_empty() {
|
||||
attrs.push(' ');
|
||||
}
|
||||
attrs.push_str(key);
|
||||
attrs.push('=');
|
||||
attrs.push('"');
|
||||
attrs.push_str(value);
|
||||
attrs.push('"');
|
||||
}
|
||||
}
|
||||
|
||||
DeadElementTag {
|
||||
name,
|
||||
attrs: (!attrs.is_empty()).then_some(attrs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use calcard::vcard::VCardVersion;
|
||||
|
||||
use crate::{
|
||||
parser::{DavParser, tokenizer::Tokenizer},
|
||||
schema::{
|
||||
property::{CardDavProperty, DavProperty},
|
||||
request::{Acl, LockInfo, MkCol, PropFind, PropertyUpdate, Report},
|
||||
},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn parse_address_data_version() {
|
||||
let xml = r#"<?xml version="1.0" encoding="utf-8" ?>
|
||||
<C:addressbook-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav">
|
||||
<D:prop>
|
||||
<C:address-data content-type="text/vcard" version="3.0">
|
||||
<C:prop name="FN"/>
|
||||
</C:address-data>
|
||||
</D:prop>
|
||||
</C:addressbook-query>"#;
|
||||
|
||||
let mut tokenizer = Tokenizer::new(xml.as_bytes());
|
||||
let report = Report::parse(&mut tokenizer).unwrap();
|
||||
let Report::AddressbookQuery(query) = report else {
|
||||
panic!("expected addressbook-query, got {report:?}");
|
||||
};
|
||||
let PropFind::Prop(properties) = query.properties else {
|
||||
panic!("expected prop, got {:?}", query.properties);
|
||||
};
|
||||
|
||||
let version = properties.iter().find_map(|property| match property {
|
||||
DavProperty::CardDav(CardDavProperty::AddressData { version, .. }) => Some(*version),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
assert_eq!(version, Some(Some(VCardVersion::V3_0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_requests() {
|
||||
for entry in std::fs::read_dir("resources/requests").unwrap() {
|
||||
let entry = entry.unwrap();
|
||||
let path = entry.path();
|
||||
|
||||
if path.extension().map(|ext| ext == "xml").unwrap_or(false) {
|
||||
println!("Parsing: {:?}", path);
|
||||
let filename = path.file_name().unwrap().to_str().unwrap();
|
||||
let xml = std::fs::read_to_string(&path).unwrap();
|
||||
let mut tokenizer = Tokenizer::new(xml.as_bytes());
|
||||
|
||||
let json_path = path.with_extension("json");
|
||||
let json_output = match filename.split_once('-').unwrap().0 {
|
||||
"propfind" => match PropFind::parse(&mut tokenizer) {
|
||||
Ok(propfind) => serde_json::to_string_pretty(&propfind).unwrap(),
|
||||
Err(_) => String::new(),
|
||||
},
|
||||
"propertyupdate" => serde_json::to_string_pretty(
|
||||
&PropertyUpdate::parse(&mut tokenizer).unwrap(),
|
||||
)
|
||||
.unwrap(),
|
||||
"mkcol" => serde_json::to_string_pretty(&MkCol::parse(&mut tokenizer).unwrap())
|
||||
.unwrap(),
|
||||
"lockinfo" => {
|
||||
serde_json::to_string_pretty(&LockInfo::parse(&mut tokenizer).unwrap())
|
||||
.unwrap()
|
||||
}
|
||||
"report" => {
|
||||
serde_json::to_string_pretty(&Report::parse(&mut tokenizer).unwrap())
|
||||
.unwrap()
|
||||
}
|
||||
"acl" => {
|
||||
serde_json::to_string_pretty(&Acl::parse(&mut tokenizer).unwrap()).unwrap()
|
||||
}
|
||||
_ => {
|
||||
panic!("Unknown method: {}", filename);
|
||||
}
|
||||
};
|
||||
|
||||
/*if json_path.exists() {
|
||||
let expected = std::fs::read_to_string(json_path).unwrap();
|
||||
assert_eq!(json_output, expected);
|
||||
} else {*/
|
||||
std::fs::write(json_path, json_output).unwrap();
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user