diff --git a/logging b/logging index 5943118..250359c 100644 --- a/logging +++ b/logging @@ -53,8 +53,8 @@ formatter = full [formatter_simple] # Simple output format -format = %(message)s +format = [%(thread)x] %(levelname)s: %(message)s [formatter_full] # Full output format -format = %(asctime)s - %(thread)d - %(levelname)s: %(message)s +format = %(asctime)s - [%(thread)x] %(levelname)s: %(message)s diff --git a/radicale/__init__.py b/radicale/__init__.py index 234e0ef..c5266e8 100644 --- a/radicale/__init__.py +++ b/radicale/__init__.py @@ -338,7 +338,7 @@ class Application: user = self.Auth.map_login_to_user(login) else: user = self.Auth.map_login_to_user(environ.get("REMOTE_USER", "")) - password = None + password = "" # If "/.well-known" is not available, clients query "/" if path == "/.well-known" or path.startswith("/.well-known/"): @@ -388,7 +388,7 @@ class Application: self.logger.info("%s refused" % (user or "Anonymous user")) status = client.UNAUTHORIZED realm = self.configuration.get("server", "realm") - headers = headers.copy() + headers = dict(headers) headers.update ({ "WWW-Authenticate": "Basic realm=\"%s\"" % realm}) diff --git a/radicale/log.py b/radicale/log.py index 34d4e4c..f550b48 100644 --- a/radicale/log.py +++ b/radicale/log.py @@ -56,7 +56,8 @@ def start(name="radicale", filename=None, debug=False): "Logging configuration file '%s' not found, using stderr." % filename) handler = logging.StreamHandler(sys.stderr) - handler.setFormatter(logging.Formatter("%(message)s")) + handler.setFormatter( + logging.Formatter("[%(thread)x] %(levelname)s: %(message)s")) logger.addHandler(handler) if debug: logger.setLevel(logging.DEBUG) diff --git a/radicale/rights.py b/radicale/rights.py index bad50a9..0092843 100644 --- a/radicale/rights.py +++ b/radicale/rights.py @@ -134,10 +134,12 @@ class Rights(BaseRights): self.logger.debug( "Test if '%s:%s' matches against '%s:%s' from section '%s'", user, sane_path, re_user, re_collection, section) - user_match = re.fullmatch(re_user, user) + # Emulate fullmatch + user_match = re.match(r"(?:%s)\Z" % re_user, user) if user_match: re_collection = re_collection.format(*user_match.groups()) - if re.fullmatch(re_collection, sane_path): + # Emulate fullmatch + if re.match(r"(?:%s)\Z" % re_collection, sane_path): self.logger.debug("Section '%s' matches", section) return permission in regex.get(section, "permission") else: diff --git a/radicale/storage.py b/radicale/storage.py index 8c4b3a7..de6f8d5 100644 --- a/radicale/storage.py +++ b/radicale/storage.py @@ -254,10 +254,7 @@ class BaseCollection: """ if item.collection.path == to_collection.path and item.href == to_href: return - if to_collection.has(to_href): - to_collection.update(to_href, item.item) - else: - to_collection.upload(to_href, item.item) + to_collection.upload(to_href, item.item) item.collection.delete(item.href) @property diff --git a/radicale/tests/test_base.py b/radicale/tests/test_base.py index f7d2e81..0b604cf 100644 --- a/radicale/tests/test_base.py +++ b/radicale/tests/test_base.py @@ -766,6 +766,14 @@ class BaseRequestsMixIn: assert status == 207 assert "href>/user/<" in answer + def test_authentication(self): + """Test if server sends authentication request.""" + self.configuration.set("rights", "type", "owner_only") + self.application = Application(self.configuration, self.logger) + status, headers, answer = self.request("MKCOL", "/user/") + assert status in (401, 403) + assert headers.get("WWW-Authenticate") + def test_principal_collection_creation(self): """Verify existence of the principal collection.""" status, headers, answer = self.request( @@ -836,6 +844,17 @@ class BaseRequestsMixIn: except Exception: pass + def test_custom_headers(self): + if not self.configuration.has_section("headers"): + self.configuration.add_section("headers") + self.configuration.set("headers", "test", "123") + # Test if header is set on success + status, headers, answer = self.request("GET", "/") + assert headers.get("test") == "123" + # Test if header is set on failure + status, headers, answer = self.request("GET", "/.well-known/does not exist") + assert headers.get("test") == "123" + class BaseFileSystemTest(BaseTest): """Base class for filesystem backend tests."""