Browse Source

Mark attributes for internal use with underscore

Unrud 6 years ago
parent
commit
1453c0b72c

+ 19 - 19
radicale/app/__init__.py

@@ -76,11 +76,11 @@ class Application(
         """
         super().__init__()
         self.configuration = configuration
-        self.auth = auth.load(configuration)
-        self.storage = storage.load(configuration)
-        self.rights = rights.load(configuration)
-        self.Web = web.load(configuration)
-        self.encoding = configuration.get("encoding", "request")
+        self._auth = auth.load(configuration)
+        self._storage = storage.load(configuration)
+        self._rights = rights.load(configuration)
+        self._web = web.load(configuration)
+        self._encoding = configuration.get("encoding", "request")
 
     def _headers_log(self, environ):
         """Sanitize headers for logging."""
@@ -107,7 +107,7 @@ class Application(
             charsets.append(
                 content_type.split("charset=")[1].split(";")[0].strip())
         # Then append default Radicale charset
-        charsets.append(self.encoding)
+        charsets.append(self._encoding)
         # Then append various fallbacks
         charsets.append("utf-8")
         charsets.append("iso8859-1")
@@ -153,8 +153,8 @@ class Application(
             if answer:
                 if hasattr(answer, "encode"):
                     logger.debug("Response content:\n%s", answer)
-                    headers["Content-Type"] += "; charset=%s" % self.encoding
-                    answer = answer.encode(self.encoding)
+                    headers["Content-Type"] += "; charset=%s" % self._encoding
+                    answer = answer.encode(self._encoding)
                 accept_encoding = [
                     encoding.strip() for encoding in
                     environ.get("HTTP_ACCEPT_ENCODING", "").split(",")
@@ -231,7 +231,7 @@ class Application(
 
         # Ask authentication backend to check rights
         login = password = ""
-        external_login = self.auth.get_external_login(environ)
+        external_login = self._auth.get_external_login(environ)
         authorization = environ.get("HTTP_AUTHORIZATION", "")
         if external_login:
             login, password = external_login
@@ -241,7 +241,7 @@ class Application(
             login, password = self.decode(base64.b64decode(
                 authorization.encode("ascii")), environ).split(":", 1)
 
-        user = self.auth.login(login, password) or "" if login else ""
+        user = self._auth.login(login, password) or "" if login else ""
         if user and login == user:
             logger.info("Successful login: %r", user)
         elif user:
@@ -263,15 +263,15 @@ class Application(
         # Create principal collection
         if user:
             principal_path = "/%s/" % user
-            if self.rights.authorized(user, principal_path, "W"):
-                with self.storage.acquire_lock("r", user):
+            if self._rights.authorized(user, principal_path, "W"):
+                with self._storage.acquire_lock("r", user):
                     principal = next(
-                        self.storage.discover(principal_path, depth="1"),
+                        self._storage.discover(principal_path, depth="1"),
                         None)
                 if not principal:
-                    with self.storage.acquire_lock("w", user):
+                    with self._storage.acquire_lock("w", user):
                         try:
-                            self.storage.create_collection(principal_path)
+                            self._storage.create_collection(principal_path)
                         except ValueError as e:
                             logger.warning("Failed to create principal "
                                            "collection %r: %s", user, e)
@@ -327,12 +327,12 @@ class Application(
         else:
             permissions = ""
             parent_permissions = permission
-        if permissions and self.rights.authorized(user, path, permissions):
+        if permissions and self._rights.authorized(user, path, permissions):
             return True
         if parent_permissions:
             parent_path = pathutils.unstrip_path(
                 posixpath.dirname(pathutils.strip_path(path)), True)
-            if self.rights.authorized(user, parent_path, parent_permissions):
+            if self._rights.authorized(user, parent_path, parent_permissions):
                 return True
         return False
 
@@ -369,14 +369,14 @@ class Application(
             logger.debug("Response content:\n%s",
                          xmlutils.pretty_xml(xml_content))
         f = io.BytesIO()
-        ET.ElementTree(xml_content).write(f, encoding=self.encoding,
+        ET.ElementTree(xml_content).write(f, encoding=self._encoding,
                                           xml_declaration=True)
         return f.getvalue()
 
     def webdav_error_response(self, namespace, name,
                               status=httputils.WEBDAV_PRECONDITION_FAILED[0]):
         """Generate XML error response."""
-        headers = {"Content-Type": "text/xml; charset=%s" % self.encoding}
+        headers = {"Content-Type": "text/xml; charset=%s" % self._encoding}
         content = self.write_xml_content(
             xmlutils.webdav_error(namespace, name))
         return status, headers, content

+ 3 - 3
radicale/app/delete.py

@@ -51,8 +51,8 @@ class ApplicationDeleteMixin:
         """Manage DELETE request."""
         if not self.access(user, path, "w"):
             return httputils.NOT_ALLOWED
-        with self.storage.acquire_lock("w", user):
-            item = next(self.storage.discover(path), None)
+        with self._storage.acquire_lock("w", user):
+            item = next(self._storage.discover(path), None)
             if not item:
                 return httputils.NOT_FOUND
             if not self.access(user, path, "w", item):
@@ -66,5 +66,5 @@ class ApplicationDeleteMixin:
             else:
                 xml_answer = xml_delete(
                     base_prefix, path, item.collection, item.href)
-            headers = {"Content-Type": "text/xml; charset=%s" % self.encoding}
+            headers = {"Content-Type": "text/xml; charset=%s" % self._encoding}
             return client.OK, headers, self.write_xml_content(xml_answer)

+ 5 - 5
radicale/app/get.py

@@ -47,13 +47,13 @@ class ApplicationGetMixin:
     def _content_disposition_attachement(self, filename):
         value = "attachement"
         try:
-            encoded_filename = quote(filename, encoding=self.encoding)
+            encoded_filename = quote(filename, encoding=self._encoding)
         except UnicodeEncodeError:
             logger.warning("Failed to encode filename: %r", filename,
                            exc_info=True)
             encoded_filename = ""
         if encoded_filename:
-            value += "; filename*=%s''%s" % (self.encoding, encoded_filename)
+            value += "; filename*=%s''%s" % (self._encoding, encoded_filename)
         return value
 
     def do_GET(self, environ, base_prefix, path, user):
@@ -69,11 +69,11 @@ class ApplicationGetMixin:
                     "Redirected to %s" % web_path)
         # Dispatch .web URL to web module
         if path == "/.web" or path.startswith("/.web/"):
-            return self.Web.get(environ, base_prefix, path, user)
+            return self._web.get(environ, base_prefix, path, user)
         if not self.access(user, path, "r"):
             return httputils.NOT_ALLOWED
-        with self.storage.acquire_lock("r", user):
-            item = next(self.storage.discover(path), None)
+        with self._storage.acquire_lock("r", user):
+            item = next(self._storage.discover(path), None)
             if not item:
                 return httputils.NOT_FOUND
             if not self.access(user, path, "r", item):

+ 5 - 5
radicale/app/mkcalendar.py

@@ -30,7 +30,7 @@ from radicale.log import logger
 class ApplicationMkcalendarMixin:
     def do_MKCALENDAR(self, environ, base_prefix, path, user):
         """Manage MKCALENDAR request."""
-        if not self.rights.authorized(user, path, "w"):
+        if not self._rights.authorized(user, path, "w"):
             return httputils.NOT_ALLOWED
         try:
             xml_content = self.read_xml_content(environ)
@@ -51,21 +51,21 @@ class ApplicationMkcalendarMixin:
         except ValueError as e:
             logger.warning(
                 "Bad MKCALENDAR request on %r: %s", path, e, exc_info=True)
-        with self.storage.acquire_lock("w", user):
-            item = next(self.storage.discover(path), None)
+        with self._storage.acquire_lock("w", user):
+            item = next(self._storage.discover(path), None)
             if item:
                 return self.webdav_error_response(
                     "D", "resource-must-be-null")
             parent_path = pathutils.unstrip_path(
                 posixpath.dirname(pathutils.strip_path(path)), True)
-            parent_item = next(self.storage.discover(parent_path), None)
+            parent_item = next(self._storage.discover(parent_path), None)
             if not parent_item:
                 return httputils.CONFLICT
             if (not isinstance(parent_item, storage.BaseCollection) or
                     parent_item.get_meta("tag")):
                 return httputils.FORBIDDEN
             try:
-                self.storage.create_collection(path, props=props)
+                self._storage.create_collection(path, props=props)
             except ValueError as e:
                 logger.warning(
                     "Bad MKCALENDAR request on %r: %s", path, e, exc_info=True)

+ 5 - 5
radicale/app/mkcol.py

@@ -30,7 +30,7 @@ from radicale.log import logger
 class ApplicationMkcolMixin:
     def do_MKCOL(self, environ, base_prefix, path, user):
         """Manage MKCOL request."""
-        permissions = self.rights.authorized(user, path, "Ww")
+        permissions = self._rights.authorized(user, path, "Ww")
         if not permissions:
             return httputils.NOT_ALLOWED
         try:
@@ -53,20 +53,20 @@ class ApplicationMkcolMixin:
         if (props.get("tag") and "w" not in permissions or
                 not props.get("tag") and "W" not in permissions):
             return httputils.NOT_ALLOWED
-        with self.storage.acquire_lock("w", user):
-            item = next(self.storage.discover(path), None)
+        with self._storage.acquire_lock("w", user):
+            item = next(self._storage.discover(path), None)
             if item:
                 return httputils.METHOD_NOT_ALLOWED
             parent_path = pathutils.unstrip_path(
                 posixpath.dirname(pathutils.strip_path(path)), True)
-            parent_item = next(self.storage.discover(parent_path), None)
+            parent_item = next(self._storage.discover(parent_path), None)
             if not parent_item:
                 return httputils.CONFLICT
             if (not isinstance(parent_item, storage.BaseCollection) or
                     parent_item.get_meta("tag")):
                 return httputils.FORBIDDEN
             try:
-                self.storage.create_collection(path, props=props)
+                self._storage.create_collection(path, props=props)
             except ValueError as e:
                 logger.warning(
                     "Bad MKCOL request on %r: %s", path, e, exc_info=True)

+ 5 - 5
radicale/app/move.py

@@ -45,8 +45,8 @@ class ApplicationMoveMixin:
         if not self.access(user, to_path, "w"):
             return httputils.NOT_ALLOWED
 
-        with self.storage.acquire_lock("w", user):
-            item = next(self.storage.discover(path), None)
+        with self._storage.acquire_lock("w", user):
+            item = next(self._storage.discover(path), None)
             if not item:
                 return httputils.NOT_FOUND
             if (not self.access(user, path, "w", item) or
@@ -56,13 +56,13 @@ class ApplicationMoveMixin:
                 # TODO: support moving collections
                 return httputils.METHOD_NOT_ALLOWED
 
-            to_item = next(self.storage.discover(to_path), None)
+            to_item = next(self._storage.discover(to_path), None)
             if isinstance(to_item, storage.BaseCollection):
                 return httputils.FORBIDDEN
             to_parent_path = pathutils.unstrip_path(
                 posixpath.dirname(pathutils.strip_path(to_path)), True)
             to_collection = next(
-                self.storage.discover(to_parent_path), None)
+                self._storage.discover(to_parent_path), None)
             if not to_collection:
                 return httputils.CONFLICT
             tag = item.collection.get_meta("tag")
@@ -78,7 +78,7 @@ class ApplicationMoveMixin:
                     "C" if tag == "VCALENDAR" else "CR", "no-uid-conflict")
             to_href = posixpath.basename(pathutils.strip_path(to_path))
             try:
-                self.storage.move(item, to_collection, to_href)
+                self._storage.move(item, to_collection, to_href)
             except ValueError as e:
                 logger.warning(
                     "Bad MOVE request on %r: %s", path, e, exc_info=True)

+ 15 - 13
radicale/app/propfind.py

@@ -27,7 +27,8 @@ from radicale import httputils, pathutils, rights, storage, xmlutils
 from radicale.log import logger
 
 
-def xml_propfind(base_prefix, path, xml_request, allowed_items, user):
+def xml_propfind(base_prefix, path, xml_request, allowed_items, user,
+                 encoding):
     """Read and answer PROPFIND requests.
 
     Read rfc4918-9.1 for info.
@@ -63,7 +64,7 @@ def xml_propfind(base_prefix, path, xml_request, allowed_items, user):
     for item, permission in allowed_items:
         write = permission == "w"
         response = xml_propfind_response(
-            base_prefix, path, item, props, user, write=write,
+            base_prefix, path, item, props, user, encoding, write=write,
             allprop=allprop, propname=propname)
         if response:
             multistatus.append(response)
@@ -71,8 +72,8 @@ def xml_propfind(base_prefix, path, xml_request, allowed_items, user):
     return client.MULTI_STATUS, multistatus
 
 
-def xml_propfind_response(base_prefix, path, item, props, user, write=False,
-                          propname=False, allprop=False):
+def xml_propfind_response(base_prefix, path, item, props, user, encoding,
+                          write=False, propname=False, allprop=False):
     """Build and return a PROPFIND response."""
     if propname and allprop or (props and (propname or allprop)):
         raise ValueError("Only use one of props, propname and allprops")
@@ -234,7 +235,6 @@ def xml_propfind_response(base_prefix, path, item, props, user, write=False,
                 element.append(supported)
         elif tag == xmlutils.make_tag("D", "getcontentlength"):
             if not is_collection or is_leaf:
-                encoding = collection.configuration.get("encoding", "request")
                 element.text = str(len(item.serialize().encode(encoding)))
             else:
                 is404 = True
@@ -299,7 +299,7 @@ def xml_propfind_response(base_prefix, path, item, props, user, write=False,
                     is404 = True
         # Not for collections
         elif tag == xmlutils.make_tag("D", "getcontenttype"):
-            element.text = xmlutils.get_content_type(item)
+            element.text = xmlutils.get_content_type(item, encoding)
         elif tag == xmlutils.make_tag("D", "resourcetype"):
             # resourcetype must be returned empty for non-collection elements
             pass
@@ -331,14 +331,14 @@ class ApplicationPropfindMixin:
             if isinstance(item, storage.BaseCollection):
                 path = pathutils.unstrip_path(item.path, True)
                 if item.get_meta("tag"):
-                    permissions = self.rights.authorized(user, path, "rw")
+                    permissions = self._rights.authorized(user, path, "rw")
                     target = "collection with tag %r" % item.path
                 else:
-                    permissions = self.rights.authorized(user, path, "RW")
+                    permissions = self._rights.authorized(user, path, "RW")
                     target = "collection %r" % item.path
             else:
                 path = pathutils.unstrip_path(item.collection.path, True)
-                permissions = self.rights.authorized(user, path, "rw")
+                permissions = self._rights.authorized(user, path, "rw")
                 target = "item %r from %r" % (item.href, item.collection.path)
             if rights.intersect_permissions(permissions, "Ww"):
                 permission = "w"
@@ -368,8 +368,9 @@ class ApplicationPropfindMixin:
         except socket.timeout:
             logger.debug("client timed out", exc_info=True)
             return httputils.REQUEST_TIMEOUT
-        with self.storage.acquire_lock("r", user):
-            items = self.storage.discover(path, environ.get("HTTP_DEPTH", "0"))
+        with self._storage.acquire_lock("r", user):
+            items = self._storage.discover(
+                path, environ.get("HTTP_DEPTH", "0"))
             # take root item for rights checking
             item = next(items, None)
             if not item:
@@ -380,9 +381,10 @@ class ApplicationPropfindMixin:
             items = itertools.chain([item], items)
             allowed_items = self._collect_allowed_items(items, user)
             headers = {"DAV": httputils.DAV_HEADERS,
-                       "Content-Type": "text/xml; charset=%s" % self.encoding}
+                       "Content-Type": "text/xml; charset=%s" % self._encoding}
             status, xml_answer = xml_propfind(
-                base_prefix, path, xml_content, allowed_items, user)
+                base_prefix, path, xml_content, allowed_items, user,
+                self._encoding)
             if status == client.FORBIDDEN:
                 return httputils.NOT_ALLOWED
             return status, headers, self.write_xml_content(xml_answer)

+ 3 - 3
radicale/app/proppatch.py

@@ -98,8 +98,8 @@ class ApplicationProppatchMixin:
         except socket.timeout:
             logger.debug("client timed out", exc_info=True)
             return httputils.REQUEST_TIMEOUT
-        with self.storage.acquire_lock("w", user):
-            item = next(self.storage.discover(path), None)
+        with self._storage.acquire_lock("w", user):
+            item = next(self._storage.discover(path), None)
             if not item:
                 return httputils.NOT_FOUND
             if not self.access(user, path, "w", item):
@@ -107,7 +107,7 @@ class ApplicationProppatchMixin:
             if not isinstance(item, storage.BaseCollection):
                 return httputils.FORBIDDEN
             headers = {"DAV": httputils.DAV_HEADERS,
-                       "Content-Type": "text/xml; charset=%s" % self.encoding}
+                       "Content-Type": "text/xml; charset=%s" % self._encoding}
             try:
                 xml_answer = xml_proppatch(base_prefix, path, xml_content,
                                            item)

+ 9 - 8
radicale/app/put.py

@@ -47,8 +47,8 @@ class ApplicationPutMixin:
         # Prepare before locking
         parent_path = pathutils.unstrip_path(
             posixpath.dirname(pathutils.strip_path(path)), True)
-        permissions = self.rights.authorized(user, path, "Ww")
-        parent_permissions = self.rights.authorized(user, parent_path, "w")
+        permissions = self._rights.authorized(user, path, "Ww")
+        parent_permissions = self._rights.authorized(user, parent_path, "w")
 
         def prepare(vobject_items, tag=None, write_whole_collection=None):
             if (write_whole_collection or
@@ -149,9 +149,9 @@ class ApplicationPutMixin:
         (prepared_items, prepared_tag, prepared_write_whole_collection,
          prepared_props, prepared_exc_info) = prepare(vobject_items)
 
-        with self.storage.acquire_lock("w", user):
-            item = next(self.storage.discover(path), None)
-            parent_item = next(self.storage.discover(parent_path), None)
+        with self._storage.acquire_lock("w", user):
+            item = next(self._storage.discover(path), None)
+            parent_item = next(self._storage.discover(parent_path), None)
             if not parent_item:
                 return httputils.CONFLICT
 
@@ -165,9 +165,10 @@ class ApplicationPutMixin:
                 tag = parent_item.get_meta("tag")
 
             if write_whole_collection:
-                if not self.rights.authorized(user, path, "w" if tag else "W"):
+                if not self._rights.authorized(
+                        user, path, "w" if tag else "W"):
                     return httputils.NOT_ALLOWED
-            elif not self.rights.authorized(user, parent_path, "w"):
+            elif not self._rights.authorized(user, parent_path, "w"):
                 return httputils.NOT_ALLOWED
 
             etag = environ.get("HTTP_IF_MATCH", "")
@@ -197,7 +198,7 @@ class ApplicationPutMixin:
 
             if write_whole_collection:
                 try:
-                    etag = self.storage.create_collection(
+                    etag = self._storage.create_collection(
                         path, prepared_items, props).etag
                 except ValueError as e:
                     logger.warning(

+ 7 - 6
radicale/app/report.py

@@ -29,7 +29,8 @@ from radicale.item import filter as radicale_filter
 from radicale.log import logger
 
 
-def xml_report(base_prefix, path, xml_request, collection, unlock_storage_fn):
+def xml_report(base_prefix, path, xml_request, collection, encoding,
+               unlock_storage_fn):
     """Read and answer REPORT requests.
 
     Read rfc3253-3.6 for info.
@@ -208,7 +209,7 @@ def xml_report(base_prefix, path, xml_request, collection, unlock_storage_fn):
                 element.text = item.etag
                 found_props.append(element)
             elif tag == xmlutils.make_tag("D", "getcontenttype"):
-                element.text = xmlutils.get_content_type(item)
+                element.text = xmlutils.get_content_type(item, encoding)
                 found_props.append(element)
             elif tag in (
                     xmlutils.make_tag("C", "calendar-data"),
@@ -270,8 +271,8 @@ class ApplicationReportMixin:
             logger.debug("client timed out", exc_info=True)
             return httputils.REQUEST_TIMEOUT
         with contextlib.ExitStack() as lock_stack:
-            lock_stack.enter_context(self.storage.acquire_lock("r", user))
-            item = next(self.storage.discover(path), None)
+            lock_stack.enter_context(self._storage.acquire_lock("r", user))
+            item = next(self._storage.discover(path), None)
             if not item:
                 return httputils.NOT_FOUND
             if not self.access(user, path, "r", item):
@@ -280,10 +281,10 @@ class ApplicationReportMixin:
                 collection = item
             else:
                 collection = item.collection
-            headers = {"Content-Type": "text/xml; charset=%s" % self.encoding}
+            headers = {"Content-Type": "text/xml; charset=%s" % self._encoding}
             try:
                 status, xml_answer = xml_report(
-                    base_prefix, path, xml_content, collection,
+                    base_prefix, path, xml_content, collection, self._encoding,
                     lock_stack.close)
             except ValueError as e:
                 logger.warning(

+ 1 - 2
radicale/xmlutils.py

@@ -127,11 +127,10 @@ def webdav_error(namespace, name):
     return root
 
 
-def get_content_type(item):
+def get_content_type(item, encoding):
     """Get the content-type of an item with charset and component parameters.
     """
     mimetype = OBJECT_MIMETYPES[item.name]
-    encoding = item.collection.configuration.get("encoding", "request")
     tag = item.component_name
     content_type = "%s;charset=%s" % (mimetype, encoding)
     if tag: