diff --git a/radicale/app/__init__.py b/radicale/app/__init__.py index ce948e82..fb2e8e82 100644 --- a/radicale/app/__init__.py +++ b/radicale/app/__init__.py @@ -75,6 +75,7 @@ class Application(ApplicationPartDelete, ApplicationPartHead, _extra_headers: Mapping[str, str] _permit_delete_collection: bool _permit_overwrite_collection: bool + _strict_preconditions: bool def __init__(self, configuration: config.Configuration) -> None: """Initialize Application. @@ -116,6 +117,8 @@ class Application(ApplicationPartDelete, ApplicationPartHead, self._extra_headers = dict() for key in self.configuration.options("headers"): self._extra_headers[key] = configuration.get("headers", key) + self._strict_preconditions = configuration.get("storage", "strict_preconditions") + logger.info("strict preconditions check: %s", self._strict_preconditions) def _scrub_headers(self, environ: types.WSGIEnviron) -> types.WSGIEnviron: """Mask passwords and cookies.""" diff --git a/radicale/app/put.py b/radicale/app/put.py index d7818eaa..6cfed1eb 100644 --- a/radicale/app/put.py +++ b/radicale/app/put.py @@ -207,6 +207,9 @@ class ApplicationPartPut(ApplicationBase): return httputils.NOT_ALLOWED etag = environ.get("HTTP_IF_MATCH", "") + if item and not etag and self._strict_preconditions: + logger.warning("Precondition failed for %r: existing item, no If-Match header, strict mode enabled", path) + return httputils.PRECONDITION_FAILED if not item and etag: # Etag asked but no item found: item has been removed logger.warning("Precondition failed on PUT request for %r (HTTP_IF_MATCH: %s, item not existing)", path, etag)