diff --git a/CHANGELOG.md b/CHANGELOG.md index ab1afb9f..ebd95e96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## 3.7.7.dev +* Fix: web plugin helpers httputils.serve_resource/serve_folder ignored their mimetypes and fallback_mimetype parameters and always used the built-in mapping, so custom web plugins could not serve additional file types with a correct Content-Type * Fix: free-busy REPORT always failed with HTTP 400 ("FREEBUSY occurrences limit of 0 hit") when [reporting] max_freebusy_occurrence is set to 0 (limit disabled), because the limit check did not honor the disabled limit * Fix: time-range filter treated a VEVENT with a whole-day DURATION (e.g. P1D, P2D) as zero-length (timedelta.seconds instead of total_seconds), so such events were missing from calendar-query REPORT results * Fix: calendar-data expand (REPORT) left recurrence properties (e.g. RDATE) on the expanded single-occurrence VEVENTs; a single try/except around the sequential delattr() calls stopped at the first absent property (e.g. missing EXDATE), so later ones were never removed diff --git a/radicale/httputils.py b/radicale/httputils.py index e030cdce..2259d5d7 100644 --- a/radicale/httputils.py +++ b/radicale/httputils.py @@ -209,8 +209,8 @@ def _serve_traversable( traversable = traversable.joinpath(index_file) if not traversable.is_file(): return NOT_FOUND - content_type = MIMETYPES.get( - os.path.splitext(traversable.name)[1].lower(), FALLBACK_MIMETYPE) + content_type = mimetypes.get( + os.path.splitext(traversable.name)[1].lower(), fallback_mimetype) headers = { "Content-Type": content_type, } diff --git a/radicale/tests/test_web.py b/radicale/tests/test_web.py index ab4de538..f6e7964b 100644 --- a/radicale/tests/test_web.py +++ b/radicale/tests/test_web.py @@ -19,6 +19,7 @@ Test web plugin. """ +from radicale import httputils from radicale.tests import BaseTest @@ -52,3 +53,20 @@ class TestBaseWebRequests(BaseTest): assert answer == "custom" _, answer = self.post("/.web", "body content") assert answer == "echo:body content" + + def test_serve_resource_custom_mimetypes(self) -> None: + """serve_resource must honor mimetypes and fallback_mimetype.""" + status, headers, _, _ = httputils.serve_resource( + "radicale.web", "internal_data", "", "/.web/index.html") + assert status == 200 + assert dict(headers)["Content-Type"] == "text/html" + status, headers, _, _ = httputils.serve_resource( + "radicale.web", "internal_data", "", "/.web/index.html", + mimetypes={".html": "text/x-custom"}) + assert status == 200 + assert dict(headers)["Content-Type"] == "text/x-custom" + status, headers, _, _ = httputils.serve_resource( + "radicale.web", "internal_data", "", "/.web/index.html", + mimetypes={}, fallback_mimetype="application/x-fallback") + assert status == 200 + assert dict(headers)["Content-Type"] == "application/x-fallback"