Skip to content

Commit 8f22834

Browse files
committed
irondrop: more prop* fizes
1 parent aa49e07 commit 8f22834

2 files changed

Lines changed: 78 additions & 27 deletions

File tree

src/webdav.rs

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,10 @@ fn handle_propfind(
154154
"#,
155155
);
156156

157+
let compact_children = depth == DavDepth::One && target_path.is_dir();
157158
for resource in resources {
158-
append_multistatus_response(&mut body, base_dir, &resource, &mode)?;
159+
let compact = compact_children && resource != target_path;
160+
append_multistatus_response(&mut body, base_dir, &resource, &mode, compact)?;
159161
}
160162
body.push_str("</D:multistatus>\n");
161163

@@ -1726,6 +1728,7 @@ fn append_multistatus_response(
17261728
base_dir: &Path,
17271729
resource: &Path,
17281730
mode: &PropfindMode,
1731+
compact: bool,
17291732
) -> Result<(), AppError> {
17301733
let metadata = std::fs::metadata(resource)?;
17311734
let is_dir = metadata.is_dir();
@@ -1743,27 +1746,40 @@ fn append_multistatus_response(
17431746
xml.push_str(" <D:href>");
17441747
xml.push_str(&xml_escape(&href));
17451748
xml.push_str("</D:href>\n");
1746-
let live_props = build_live_props(resource, is_dir, &displayname, &metadata);
1749+
let include_lock_props = !compact;
1750+
let live_props = build_live_props(
1751+
resource,
1752+
is_dir,
1753+
&displayname,
1754+
&metadata,
1755+
include_lock_props,
1756+
);
17471757
match mode {
17481758
PropfindMode::AllProp => {
1749-
let mut merged = live_props.clone();
1750-
let dead = dead_props_for_path(resource);
1751-
for (name, value) in dead {
1752-
if !merged.iter().any(|(live_name, _)| live_name == &name) {
1753-
merged.push((name, Some(xml_escape(&value))));
1759+
if compact {
1760+
append_propstat(xml, &live_props, "HTTP/1.1 200 OK");
1761+
} else {
1762+
let mut merged = live_props.clone();
1763+
let dead = dead_props_for_path(resource);
1764+
for (name, value) in dead {
1765+
if !merged.iter().any(|(live_name, _)| live_name == &name) {
1766+
merged.push((name, Some(xml_escape(&value))));
1767+
}
17541768
}
1769+
append_propstat(xml, &merged, "HTTP/1.1 200 OK");
17551770
}
1756-
append_propstat(xml, &merged, "HTTP/1.1 200 OK");
17571771
}
17581772
PropfindMode::PropName => {
17591773
let mut names: Vec<(PropName, Option<String>)> = live_props
17601774
.iter()
17611775
.map(|(name, _)| (name.clone(), None))
17621776
.collect();
1763-
let dead = dead_props_for_path(resource);
1764-
for dead_name in dead.keys() {
1765-
if !names.iter().any(|(name, _)| name == dead_name) {
1766-
names.push((dead_name.clone(), None));
1777+
if !compact {
1778+
let dead = dead_props_for_path(resource);
1779+
for dead_name in dead.keys() {
1780+
if !names.iter().any(|(name, _)| name == dead_name) {
1781+
names.push((dead_name.clone(), None));
1782+
}
17671783
}
17681784
}
17691785
append_propstat(xml, &names, "HTTP/1.1 200 OK");
@@ -1850,6 +1866,7 @@ fn build_live_props(
18501866
is_dir: bool,
18511867
displayname: &str,
18521868
metadata: &std::fs::Metadata,
1869+
include_lock_props: bool,
18531870
) -> Vec<(PropName, Option<String>)> {
18541871
let mut props = Vec::new();
18551872
props.push((dav_prop_name("displayname"), Some(xml_escape(displayname))));
@@ -1891,23 +1908,25 @@ fn build_live_props(
18911908
dav_prop_name("getetag"),
18921909
Some(etag_for_resource(resource, metadata)),
18931910
));
1894-
props.push((
1895-
dav_prop_name("supportedlock"),
1896-
Some("<D:lockentry><D:lockscope><D:exclusive/></D:lockscope><D:locktype><D:write/></D:locktype></D:lockentry>".to_string()),
1897-
));
1898-
if let Some(lock) = current_lock_for_path(resource) {
1911+
if include_lock_props {
18991912
props.push((
1900-
dav_prop_name("lockdiscovery"),
1901-
Some(format!(
1902-
"<D:activelock><D:locktype><D:write/></D:locktype><D:lockscope><D:exclusive/></D:lockscope><D:depth>{}</D:depth><D:timeout>Second-{}</D:timeout><D:lockroot><D:href>{}</D:href></D:lockroot><D:locktoken><D:href>{}</D:href></D:locktoken></D:activelock>",
1903-
if lock.depth_infinity { "Infinity" } else { "0" },
1904-
lock.timeout_secs,
1905-
xml_escape(&lock.lockroot_href),
1906-
xml_escape(&lock.token)
1907-
)),
1913+
dav_prop_name("supportedlock"),
1914+
Some("<D:lockentry><D:lockscope><D:exclusive/></D:lockscope><D:locktype><D:write/></D:locktype></D:lockentry>".to_string()),
19081915
));
1909-
} else {
1910-
props.push((dav_prop_name("lockdiscovery"), Some(String::new())));
1916+
if let Some(lock) = current_lock_for_path(resource) {
1917+
props.push((
1918+
dav_prop_name("lockdiscovery"),
1919+
Some(format!(
1920+
"<D:activelock><D:locktype><D:write/></D:locktype><D:lockscope><D:exclusive/></D:lockscope><D:depth>{}</D:depth><D:timeout>Second-{}</D:timeout><D:lockroot><D:href>{}</D:href></D:lockroot><D:locktoken><D:href>{}</D:href></D:locktoken></D:activelock>",
1921+
if lock.depth_infinity { "Infinity" } else { "0" },
1922+
lock.timeout_secs,
1923+
xml_escape(&lock.lockroot_href),
1924+
xml_escape(&lock.token)
1925+
)),
1926+
));
1927+
} else {
1928+
props.push((dav_prop_name("lockdiscovery"), Some(String::new())));
1929+
}
19111930
}
19121931

19131932
props

tests/webdav_options_propfind_test.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,38 @@ fn test_propfind_finder_probe_missing_returns_not_found_fast() {
179179
assert_eq!(response.status(), StatusCode::NOT_FOUND);
180180
}
181181

182+
#[test]
183+
fn test_propfind_depth_one_compacts_lock_props_for_children() {
184+
let server = setup_test_server_with_tree_and_webdav(
185+
|root| {
186+
std::fs::create_dir_all(root.join("call_rec_feb25").join("+911726132348")).unwrap();
187+
let mut f = std::fs::File::create(
188+
root.join("call_rec_feb25")
189+
.join("+911726132348")
190+
.join("x.txt"),
191+
)
192+
.unwrap();
193+
write!(f, "x").unwrap();
194+
},
195+
true,
196+
);
197+
let client = Client::new();
198+
199+
let response = client
200+
.request(
201+
Method::from_bytes(b"PROPFIND").unwrap(),
202+
format!("http://{}/call_rec_feb25/", server.addr),
203+
)
204+
.header("Depth", "1")
205+
.send()
206+
.unwrap();
207+
208+
assert_eq!(response.status().as_u16(), 207);
209+
let xml = response.text().unwrap();
210+
let count = xml.matches("supportedlock").count();
211+
assert!(count <= 1);
212+
}
213+
182214
#[test]
183215
fn test_propfind_depth_one_on_collection_includes_children() {
184216
let server = setup_test_server_with_tree(|root| {

0 commit comments

Comments
 (0)