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.
294 lines
9.4 KiB
Rust
294 lines
9.4 KiB
Rust
/*
|
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
|
*/
|
|
|
|
use hyper::StatusCode;
|
|
|
|
use crate::webdav::{TEST_FILE_1, TEST_ICAL_1, TEST_VCARD_1, TEST_VTIMEZONE_1};
|
|
|
|
use crate::utils::server::TestServer;
|
|
|
|
pub async fn test(test: &TestServer) {
|
|
println!("Running MKCOL tests...");
|
|
let client = test.account("[email protected]").webdav_client();
|
|
|
|
// Creating collections in root elements is not allowed
|
|
for path in [
|
|
"/dav/file/test",
|
|
"/dav/card/test",
|
|
"/dav/cal/test",
|
|
"/dav/test",
|
|
] {
|
|
client
|
|
.request("MKCOL", path, "")
|
|
.await
|
|
.with_status(StatusCode::NOT_FOUND);
|
|
}
|
|
|
|
// Create collections using MKCOL (empty body)
|
|
for path in [
|
|
"/dav/file/john%40example.com/my-files",
|
|
"/dav/card/john%40example.com/my-cards",
|
|
"/dav/cal/john%40example.com/my-events",
|
|
] {
|
|
client
|
|
.request("MKCOL", path, "")
|
|
.await
|
|
.with_status(StatusCode::CREATED);
|
|
}
|
|
|
|
// Create resources under the newly created collections
|
|
for (path, content) in [
|
|
(
|
|
"/dav/file/john%40example.com/my-files/file1.txt",
|
|
TEST_FILE_1,
|
|
),
|
|
(
|
|
"/dav/card/john%40example.com/my-cards/card1.vcf",
|
|
TEST_VCARD_1,
|
|
),
|
|
(
|
|
"/dav/cal/john%40example.com/my-events/event1.ics",
|
|
TEST_ICAL_1,
|
|
),
|
|
] {
|
|
client
|
|
.request("PUT", path, content)
|
|
.await
|
|
.with_status(StatusCode::CREATED);
|
|
}
|
|
|
|
// Creating a collection on a mapped resource should fail
|
|
for path in [
|
|
"/dav/file/john%40example.com/my-files",
|
|
"/dav/card/john%40example.com/my-cards",
|
|
"/dav/cal/john%40example.com/my-events",
|
|
"/dav/file/john%40example.com/my-files/file1.txt",
|
|
"/dav/card/john%40example.com/my-cards/card1.vcf",
|
|
"/dav/cal/john%40example.com/my-events/event1.ics",
|
|
] {
|
|
client
|
|
.request("MKCOL", path, "")
|
|
.await
|
|
.with_status(StatusCode::METHOD_NOT_ALLOWED);
|
|
}
|
|
|
|
// Creating a sub-collections is allowed in FileDAV but in CalDAV and CardDAV
|
|
for (path, expected_status) in [
|
|
(
|
|
"/dav/file/john%40example.com/my-files/my-sub-files",
|
|
StatusCode::CREATED,
|
|
),
|
|
(
|
|
"/dav/card/john%40example.com/my-cards/my-sub-cards",
|
|
StatusCode::METHOD_NOT_ALLOWED,
|
|
),
|
|
(
|
|
"/dav/cal/john%40example.com/my-events/my-sub-events",
|
|
StatusCode::METHOD_NOT_ALLOWED,
|
|
),
|
|
] {
|
|
client
|
|
.request("MKCOL", path, "")
|
|
.await
|
|
.with_status(expected_status);
|
|
}
|
|
|
|
// Extended MKCOL with an unsupported resource types should fail
|
|
for (path, resource_type) in [
|
|
(
|
|
"/dav/file/john%40example.com/my-named-files",
|
|
"B:addressbook",
|
|
),
|
|
("/dav/card/john%40example.com/my-named-cards", "A:calendar"),
|
|
(
|
|
"/dav/cal/john%40example.com/my-named-events",
|
|
"B:addressbook",
|
|
),
|
|
] {
|
|
client
|
|
.mkcol("MKCOL", path, ["D:collection", resource_type], [])
|
|
.await
|
|
.with_status(StatusCode::FORBIDDEN)
|
|
.with_value(
|
|
"D:mkcol-response.D:propstat.D:error.D:valid-resourcetype",
|
|
"",
|
|
)
|
|
.with_value("D:mkcol-response.D:propstat.D:prop.D:resourcetype", "");
|
|
}
|
|
|
|
// Create using extended MKCOL
|
|
for (path, expected_properties, resource_types) in [
|
|
(
|
|
"/dav/file/john%40example.com/my-named-files/",
|
|
[("D:displayname", "Named Files")].as_slice(),
|
|
["D:collection"].as_slice(),
|
|
),
|
|
(
|
|
"/dav/card/john%40example.com/my-named-cards/",
|
|
[
|
|
("D:displayname", "Named Cards"),
|
|
("B:addressbook-description", "Some amazing contacts"),
|
|
]
|
|
.as_slice(),
|
|
["D:collection", "B:addressbook"].as_slice(),
|
|
),
|
|
(
|
|
"/dav/cal/john%40example.com/my-named-events/",
|
|
[
|
|
("D:displayname", "Named Events"),
|
|
("A:calendar-description", "Some amazing events"),
|
|
(
|
|
"A:calendar-timezone",
|
|
&TEST_VTIMEZONE_1.replace("\n", "\r\n"),
|
|
),
|
|
]
|
|
.as_slice(),
|
|
["D:collection", "A:calendar"].as_slice(),
|
|
),
|
|
] {
|
|
let response = client
|
|
.mkcol(
|
|
"MKCOL",
|
|
path,
|
|
resource_types.iter().copied(),
|
|
expected_properties.iter().copied(),
|
|
)
|
|
.await
|
|
.with_status(StatusCode::CREATED)
|
|
.into_propfind_response("D:mkcol-response".into());
|
|
let properties = response.properties("");
|
|
for (property, _) in expected_properties {
|
|
properties
|
|
.get(property)
|
|
.with_status(StatusCode::OK)
|
|
.with_values([""]);
|
|
}
|
|
|
|
// Check the properties of the created collection
|
|
let response = client
|
|
.propfind(path, expected_properties.iter().map(|x| x.0))
|
|
.await;
|
|
let properties = response.properties(path);
|
|
for (property, value) in expected_properties {
|
|
properties
|
|
.get(property)
|
|
.with_status(StatusCode::OK)
|
|
.with_values([*value]);
|
|
}
|
|
}
|
|
|
|
// Test MKCALENDAR
|
|
client
|
|
.mkcol(
|
|
"MKCALENDAR",
|
|
"/dav/cal/john%40example.com/my-named-events2",
|
|
[],
|
|
[
|
|
("D:displayname", "Named Events 2"),
|
|
("A:calendar-description", ""),
|
|
],
|
|
)
|
|
.await
|
|
.with_status(StatusCode::CREATED)
|
|
.with_value("A:mkcalendar-response.D:propstat.D:prop.D:displayname", "")
|
|
.with_values(
|
|
"A:mkcalendar-response.D:propstat.D:status",
|
|
["HTTP/1.1 200 OK"],
|
|
);
|
|
client
|
|
.mkcol(
|
|
"MKCALENDAR",
|
|
"/dav/cal/john%40example.com/my-named-events3",
|
|
[],
|
|
[
|
|
("D:displayname", "Named Events 3"),
|
|
(
|
|
"A:supported-calendar-component-set",
|
|
"<A:comp name=\"VEVENT\"/><A:comp name=\"VTODO\"/>",
|
|
),
|
|
],
|
|
)
|
|
.await
|
|
.with_status(StatusCode::CREATED)
|
|
.with_value("A:mkcalendar-response.D:propstat.D:prop.D:displayname", "")
|
|
.with_values(
|
|
"A:mkcalendar-response.D:propstat.D:status",
|
|
["HTTP/1.1 200 OK"],
|
|
);
|
|
// Check the properties of the created calendars
|
|
client
|
|
.propfind(
|
|
"/dav/cal/john%40example.com/my-named-events2/",
|
|
["A:supported-calendar-component-set"],
|
|
)
|
|
.await
|
|
.properties("/dav/cal/john%40example.com/my-named-events2/")
|
|
.get("A:supported-calendar-component-set")
|
|
.with_status(StatusCode::OK)
|
|
.with_values([
|
|
"A:comp.[name]:VJOURNAL",
|
|
"A:comp.[name]:VTIMEZONE",
|
|
"A:comp.[name]:VAVAILABILITY",
|
|
"A:comp.[name]:VALARM",
|
|
"A:comp.[name]:VRESOURCE",
|
|
"A:comp.[name]:AVAILABLE",
|
|
"A:comp.[name]:VTODO",
|
|
"A:comp.[name]:VFREEBUSY",
|
|
"A:comp.[name]:VEVENT",
|
|
"A:comp.[name]:STANDARD",
|
|
"A:comp.[name]:DAYLIGHT",
|
|
"A:comp.[name]:VLOCATION",
|
|
"A:comp.[name]:PARTICIPANT",
|
|
]);
|
|
client
|
|
.propfind(
|
|
"/dav/cal/john%40example.com/my-named-events3/",
|
|
["A:supported-calendar-component-set"],
|
|
)
|
|
.await
|
|
.properties("/dav/cal/john%40example.com/my-named-events3/")
|
|
.get("A:supported-calendar-component-set")
|
|
.with_status(StatusCode::OK)
|
|
.with_values(["A:comp.[name]:VEVENT", "A:comp.[name]:VTODO"]);
|
|
|
|
// Resource names arriving through the URI are echoed back verbatim
|
|
for name in ["My%20Folder", "file(1)+a:b", "%C3%9Cnterlagen", "Q&A"] {
|
|
let path = format!("/dav/file/john%40example.com/{name}");
|
|
let href = format!("{path}/");
|
|
client
|
|
.request("MKCOL", &path, "")
|
|
.await
|
|
.with_status(StatusCode::CREATED);
|
|
client
|
|
.propfind(&path, ["D:getetag"])
|
|
.await
|
|
.with_hrefs([href.as_str()]);
|
|
}
|
|
|
|
// Delete everything
|
|
for path in [
|
|
"/dav/file/john%40example.com/My%20Folder",
|
|
"/dav/file/john%40example.com/file(1)+a:b",
|
|
"/dav/file/john%40example.com/%C3%9Cnterlagen",
|
|
"/dav/file/john%40example.com/Q&A",
|
|
"/dav/file/john%40example.com/my-files",
|
|
"/dav/card/john%40example.com/my-cards",
|
|
"/dav/cal/john%40example.com/my-events",
|
|
"/dav/file/john%40example.com/my-named-files",
|
|
"/dav/card/john%40example.com/my-named-cards",
|
|
"/dav/cal/john%40example.com/my-named-events",
|
|
"/dav/cal/john%40example.com/my-named-events2",
|
|
"/dav/cal/john%40example.com/my-named-events3",
|
|
] {
|
|
client
|
|
.request("DELETE", path, "")
|
|
.await
|
|
.with_status(StatusCode::NO_CONTENT);
|
|
}
|
|
client.delete_default_containers().await;
|
|
test.assert_is_empty().await;
|
|
}
|