From e1b0721f9ec7562e343ee8c3c44c96791a2d6125 Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Thu, 11 Dec 2025 22:55:41 +0100 Subject: [PATCH] change to dedicated option for propfind/max_resource_size --- radicale/app/__init__.py | 9 +++++++++ radicale/app/base.py | 3 +-- radicale/app/propfind.py | 12 ++++++------ 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/radicale/app/__init__.py b/radicale/app/__init__.py index d96de77f..7d02c2f8 100644 --- a/radicale/app/__init__.py +++ b/radicale/app/__init__.py @@ -73,6 +73,7 @@ class Application(ApplicationPartDelete, ApplicationPartHead, _auth_delay: float _internal_server: bool _max_content_length: int + _max_resource_size: int _auth_realm: str _auth_type: str _web_type: str @@ -95,6 +96,14 @@ class Application(ApplicationPartDelete, ApplicationPartHead, """ super().__init__(configuration) self._mask_passwords = configuration.get("logging", "mask_passwords") + self._max_content_length = configuration.get("server", "max_content_length") + self._max_resource_size = configuration.get("server", "max_resource_size") + if (self._max_resource_size > (self._max_content_length * 0.8)): + max_resource_size_limited = int(self._max_content_length * 0.8) + logger.warning("max_resource_size capped to: %d bytes (from %d to 80%% of max_content_length %d)", max_resource_size_limited, self._max_resource_size, self._max_content_length) + self._max_resource_size = max_resource_size_limited + else: + logger.info("max_resource_size set to: %d bytes", self._max_resource_size) self._bad_put_request_content = configuration.get("logging", "bad_put_request_content") logger.info("log bad put request content: %s", self._bad_put_request_content) self._request_header_on_debug = configuration.get("logging", "request_header_on_debug") diff --git a/radicale/app/base.py b/radicale/app/base.py index a5536cce..aa0af7a2 100644 --- a/radicale/app/base.py +++ b/radicale/app/base.py @@ -39,7 +39,7 @@ class ApplicationBase: _rights: rights.BaseRights _web: web.BaseWeb _encoding: str - _max_content_length: int + _max_resource_size: int _permit_delete_collection: bool _permit_overwrite_collection: bool _strict_preconditions: bool @@ -52,7 +52,6 @@ class ApplicationBase: self._rights = rights.load(configuration) self._web = web.load(configuration) self._encoding = configuration.get("encoding", "request") - self._max_content_length = configuration.get("server", "max_content_length") self._log_bad_put_request_content = configuration.get("logging", "bad_put_request_content") self._response_content_on_debug = configuration.get("logging", "response_content_on_debug") self._request_content_on_debug = configuration.get("logging", "request_content_on_debug") diff --git a/radicale/app/propfind.py b/radicale/app/propfind.py index 4d985429..2ef89315 100644 --- a/radicale/app/propfind.py +++ b/radicale/app/propfind.py @@ -34,7 +34,7 @@ from radicale.log import logger def xml_propfind(base_prefix: str, path: str, xml_request: Optional[ET.Element], allowed_items: Iterable[Tuple[types.CollectionOrItem, str]], - user: str, encoding: str, max_content_length: int) -> Optional[ET.Element]: + user: str, encoding: str, max_resource_size: int) -> Optional[ET.Element]: """Read and answer PROPFIND requests. Read rfc4918-9.1 for info. @@ -71,14 +71,14 @@ def xml_propfind(base_prefix: str, path: str, write = permission == "w" multistatus.append(xml_propfind_response( base_prefix, path, item, props, user, encoding, write=write, - allprop=allprop, propname=propname, max_content_length=max_content_length)) + allprop=allprop, propname=propname, max_resource_size=max_resource_size)) return multistatus def xml_propfind_response( base_prefix: str, path: str, item: types.CollectionOrItem, - props: Sequence[str], user: str, encoding: str, max_content_length: int, write: bool = False, + props: Sequence[str], user: str, encoding: str, max_resource_size: int, write: bool = False, propname: bool = False, allprop: bool = False) -> ET.Element: """Build and return a PROPFIND response.""" if propname and allprop or (props and (propname or allprop)): @@ -241,8 +241,8 @@ def xml_propfind_response( base_prefix, "/%s/" % collection.owner) element.append(child_element) elif tag == xmlutils.make_clark("C:max-resource-size"): - # RFC4791#5.2.5 use 80% of max_content_length to cover base64 encoding - element.text = str(int(max_content_length * 0.8)) + # RFC4791#5.2.5 + element.text = str(max_resource_size) elif is_collection: if tag == xmlutils.make_clark("D:getcontenttype"): if is_leaf: @@ -411,7 +411,7 @@ class ApplicationPartPropfind(ApplicationBase): headers = {"DAV": httputils.DAV_HEADERS, "Content-Type": "text/xml; charset=%s" % self._encoding} xml_answer = xml_propfind(base_prefix, path, xml_content, - allowed_items, user, self._encoding, max_content_length=self._max_content_length) + allowed_items, user, self._encoding, max_resource_size=self._max_resource_size) if xml_answer is None: return httputils.NOT_ALLOWED return client.MULTI_STATUS, headers, self._xml_response(xml_answer), xmlutils.pretty_xml(xml_content)