CalDAV: Limit recurrence expansions in calendar reports

This commit is contained in:
mdecimus
2025-09-09 21:27:15 +02:00
parent 480fb59a09
commit 15762fba2b
4 changed files with 49 additions and 53 deletions

View File

@@ -420,7 +420,12 @@ impl CalendarQueryHandler {
is_all || matches_one
}
pub fn serialize_ical(&mut self, event: &ArchivedCalendarEvent, data: &CalendarData) -> String {
pub fn serialize_ical(
&mut self,
event: &ArchivedCalendarEvent,
data: &CalendarData,
instances_limit: &mut usize,
) -> Option<String> {
let mut out = String::with_capacity(event.size.to_native() as usize);
let _v = [0.into()];
let mut component_iter: Iter<'_, rkyv::rend::u16_le> = _v.iter();
@@ -528,6 +533,11 @@ impl CalendarQueryHandler {
&& (!is_recurrent_or_override
|| expand.is_in_range(is_todo, event.start, event.end))
{
if *instances_limit > 0 {
*instances_limit -= 1;
} else {
return None;
}
let _ = write!(&mut out, "BEGIN:{component_name}\r\n");
// Write DTSTART, DTEND and RECURRENCE-ID
@@ -607,7 +617,7 @@ impl CalendarQueryHandler {
}
}
out
Some(out)
}
pub fn into_expanded_times(self) -> Vec<CalendarEvent<i64, i64>> {

View File

@@ -296,6 +296,7 @@ impl PropFindRequestHandler for Server {
);
let mut is_sync_limited = false;
let mut is_propfind = false;
let mut ical_instances_limit = self.core.groupware.max_ical_instances;
let paths = match std::mem::take(&mut query.resource) {
DavQueryResource::Uri(resource) => {
@@ -351,38 +352,6 @@ impl PropFindRequestHandler for Server {
items
}
/*DavQueryResource::Discovery {
parent_collection,
account_ids,
} => {
collection_container = parent_collection;
collection_children = collection_container.child_collection().unwrap();
sync_collection = SyncCollection::from(collection_container);
// Add container info
if !query.depth_no_root {
add_base_collection_response(
self,
&query.propfind,
parent_collection,
access_token,
&mut response,
)
.await?;
}
discover_root_paths(
self,
access_token,
collection_container,
sync_collection,
&query,
&mut data,
&mut response,
account_ids,
)
.await?
}*/
DavQueryResource::None => unreachable!(),
};
response.set_namespace(collection_container.namespace());
@@ -441,7 +410,7 @@ impl PropFindRequestHandler for Server {
let view_as_id = access_token.primary_id();
let is_scheduling = collection_container == Collection::CalendarScheduling;
for item in paths {
'outer: for item in paths {
let account_id = item.account_id;
let document_id = item.document_id;
let collection = if item.is_container {
@@ -981,20 +950,27 @@ impl PropFindRequestHandler for Server {
CalDavProperty::CalendarData(data),
ArchivedResource::CalendarEvent(event),
) => {
let ical = if calendar_filter.is_some() || !data.properties.is_empty() {
calendar_filter
if calendar_filter.is_some() || !data.properties.is_empty() {
if let Some(ical) = calendar_filter
.get_or_insert_with(|| {
CalendarQueryHandler::new(event.inner, None, Tz::UTC)
})
.serialize_ical(event.inner, data)
.serialize_ical(event.inner, data, &mut ical_instances_limit)
{
fields.push(DavPropertyValue::new(
property.clone(),
DavValue::CData(ical),
));
} else {
limit = 0;
break 'outer;
}
} else {
event.inner.data.event.to_string()
};
fields.push(DavPropertyValue::new(
property.clone(),
DavValue::CData(ical),
));
fields.push(DavPropertyValue::new(
property.clone(),
DavValue::CData(event.inner.data.event.to_string()),
));
}
}
(
CalDavProperty::CalendarData(_),
@@ -1092,12 +1068,21 @@ impl PropFindRequestHandler for Server {
response.add_response(
Response::new_status([query.uri], StatusCode::INSUFFICIENT_STORAGE)
.with_error(BaseCondition::NumberOfMatchesWithinLimit)
.with_response_description(format!(
"The number of matches exceeds the limit of {}",
query
.limit
.unwrap_or(self.core.groupware.max_results as u32)
)),
.with_response_description(if ical_instances_limit > 0 {
format!(
"The number of matches exceeds the limit of {}",
query
.limit
.unwrap_or(self.core.groupware.max_results as u32)
)
} else {
format!(
"The number of recurrence instances exceeds the limit of {}",
query
.limit
.unwrap_or(self.core.groupware.max_ical_instances as u32)
)
}),
);
}