diff --git a/radicale/app/__init__.py b/radicale/app/__init__.py index fdf0d1f..685fb77 100644 --- a/radicale/app/__init__.py +++ b/radicale/app/__init__.py @@ -191,6 +191,12 @@ class Application(ApplicationPartDelete, ApplicationPartHead, base_prefix_src = ("HTTP_X_SCRIPT_NAME" if "HTTP_X_SCRIPT_NAME" in environ else "SCRIPT_NAME") base_prefix = environ.get(base_prefix_src, "") + if base_prefix.endswith("/"): + logger.error("Base prefix (from %s) must not end with '/': %r", + base_prefix_src, base_prefix) + if base_prefix_src == "HTTP_X_SCRIPT_NAME": + return response(*httputils.BAD_REQUEST) + return response(*httputils.INTERNAL_SERVER_ERROR) logger.debug("Base prefix (from %s): %r", base_prefix_src, base_prefix) # Sanitize request URI (a WSGI server indicates with an empty path, # that the URL targets the application root without a trailing slash) diff --git a/radicale/tests/test_base.py b/radicale/tests/test_base.py index 8c89cf4..ea01cf6 100644 --- a/radicale/tests/test_base.py +++ b/radicale/tests/test_base.py @@ -65,6 +65,10 @@ permissions: RrWw""") SCRIPT_NAME="/radicale") assert headers.get("Location") == "/radicale/.web" + def test_root_broken_script_name(self) -> None: + """GET request at "/" with SCRIPT_NAME ending with "/".""" + self.get("/", check=500, SCRIPT_NAME="/radicale/") + def test_root_http_x_script_name(self) -> None: """GET request at "/" with HTTP_X_SCRIPT_NAME.""" for path in ["", "/", "//"]: @@ -72,6 +76,10 @@ permissions: RrWw""") HTTP_X_SCRIPT_NAME="/radicale") assert headers.get("Location") == "/radicale/.web" + def test_root_broken_http_x_script_name(self) -> None: + """GET request at "/" with HTTP_X_SCRIPT_NAME ending with "/".""" + self.get("/", check=400, HTTP_X_SCRIPT_NAME="/radicale/") + def test_sanitized_path(self) -> None: """GET request with unsanitized paths.""" for path, sane_path in [