Mark attributes for internal use with underscore
This commit is contained in:
parent
9b51e495ea
commit
1453c0b72c
@ -76,11 +76,11 @@ class Application(
|
|||||||
"""
|
"""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.configuration = configuration
|
self.configuration = configuration
|
||||||
self.auth = auth.load(configuration)
|
self._auth = auth.load(configuration)
|
||||||
self.storage = storage.load(configuration)
|
self._storage = storage.load(configuration)
|
||||||
self.rights = rights.load(configuration)
|
self._rights = rights.load(configuration)
|
||||||
self.Web = web.load(configuration)
|
self._web = web.load(configuration)
|
||||||
self.encoding = configuration.get("encoding", "request")
|
self._encoding = configuration.get("encoding", "request")
|
||||||
|
|
||||||
def _headers_log(self, environ):
|
def _headers_log(self, environ):
|
||||||
"""Sanitize headers for logging."""
|
"""Sanitize headers for logging."""
|
||||||
@ -107,7 +107,7 @@ class Application(
|
|||||||
charsets.append(
|
charsets.append(
|
||||||
content_type.split("charset=")[1].split(";")[0].strip())
|
content_type.split("charset=")[1].split(";")[0].strip())
|
||||||
# Then append default Radicale charset
|
# Then append default Radicale charset
|
||||||
charsets.append(self.encoding)
|
charsets.append(self._encoding)
|
||||||
# Then append various fallbacks
|
# Then append various fallbacks
|
||||||
charsets.append("utf-8")
|
charsets.append("utf-8")
|
||||||
charsets.append("iso8859-1")
|
charsets.append("iso8859-1")
|
||||||
@ -153,8 +153,8 @@ class Application(
|
|||||||
if answer:
|
if answer:
|
||||||
if hasattr(answer, "encode"):
|
if hasattr(answer, "encode"):
|
||||||
logger.debug("Response content:\n%s", answer)
|
logger.debug("Response content:\n%s", answer)
|
||||||
headers["Content-Type"] += "; charset=%s" % self.encoding
|
headers["Content-Type"] += "; charset=%s" % self._encoding
|
||||||
answer = answer.encode(self.encoding)
|
answer = answer.encode(self._encoding)
|
||||||
accept_encoding = [
|
accept_encoding = [
|
||||||
encoding.strip() for encoding in
|
encoding.strip() for encoding in
|
||||||
environ.get("HTTP_ACCEPT_ENCODING", "").split(",")
|
environ.get("HTTP_ACCEPT_ENCODING", "").split(",")
|
||||||
@ -231,7 +231,7 @@ class Application(
|
|||||||
|
|
||||||
# Ask authentication backend to check rights
|
# Ask authentication backend to check rights
|
||||||
login = password = ""
|
login = password = ""
|
||||||
external_login = self.auth.get_external_login(environ)
|
external_login = self._auth.get_external_login(environ)
|
||||||
authorization = environ.get("HTTP_AUTHORIZATION", "")
|
authorization = environ.get("HTTP_AUTHORIZATION", "")
|
||||||
if external_login:
|
if external_login:
|
||||||
login, password = external_login
|
login, password = external_login
|
||||||
@ -241,7 +241,7 @@ class Application(
|
|||||||
login, password = self.decode(base64.b64decode(
|
login, password = self.decode(base64.b64decode(
|
||||||
authorization.encode("ascii")), environ).split(":", 1)
|
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:
|
if user and login == user:
|
||||||
logger.info("Successful login: %r", user)
|
logger.info("Successful login: %r", user)
|
||||||
elif user:
|
elif user:
|
||||||
@ -263,15 +263,15 @@ class Application(
|
|||||||
# Create principal collection
|
# Create principal collection
|
||||||
if user:
|
if user:
|
||||||
principal_path = "/%s/" % user
|
principal_path = "/%s/" % user
|
||||||
if self.rights.authorized(user, principal_path, "W"):
|
if self._rights.authorized(user, principal_path, "W"):
|
||||||
with self.storage.acquire_lock("r", user):
|
with self._storage.acquire_lock("r", user):
|
||||||
principal = next(
|
principal = next(
|
||||||
self.storage.discover(principal_path, depth="1"),
|
self._storage.discover(principal_path, depth="1"),
|
||||||
None)
|
None)
|
||||||
if not principal:
|
if not principal:
|
||||||
with self.storage.acquire_lock("w", user):
|
with self._storage.acquire_lock("w", user):
|
||||||
try:
|
try:
|
||||||
self.storage.create_collection(principal_path)
|
self._storage.create_collection(principal_path)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
logger.warning("Failed to create principal "
|
logger.warning("Failed to create principal "
|
||||||
"collection %r: %s", user, e)
|
"collection %r: %s", user, e)
|
||||||
@ -327,12 +327,12 @@ class Application(
|
|||||||
else:
|
else:
|
||||||
permissions = ""
|
permissions = ""
|
||||||
parent_permissions = permission
|
parent_permissions = permission
|
||||||
if permissions and self.rights.authorized(user, path, permissions):
|
if permissions and self._rights.authorized(user, path, permissions):
|
||||||
return True
|
return True
|
||||||
if parent_permissions:
|
if parent_permissions:
|
||||||
parent_path = pathutils.unstrip_path(
|
parent_path = pathutils.unstrip_path(
|
||||||
posixpath.dirname(pathutils.strip_path(path)), True)
|
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 True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -369,14 +369,14 @@ class Application(
|
|||||||
logger.debug("Response content:\n%s",
|
logger.debug("Response content:\n%s",
|
||||||
xmlutils.pretty_xml(xml_content))
|
xmlutils.pretty_xml(xml_content))
|
||||||
f = io.BytesIO()
|
f = io.BytesIO()
|
||||||
ET.ElementTree(xml_content).write(f, encoding=self.encoding,
|
ET.ElementTree(xml_content).write(f, encoding=self._encoding,
|
||||||
xml_declaration=True)
|
xml_declaration=True)
|
||||||
return f.getvalue()
|
return f.getvalue()
|
||||||
|
|
||||||
def webdav_error_response(self, namespace, name,
|
def webdav_error_response(self, namespace, name,
|
||||||
status=httputils.WEBDAV_PRECONDITION_FAILED[0]):
|
status=httputils.WEBDAV_PRECONDITION_FAILED[0]):
|
||||||
"""Generate XML error response."""
|
"""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(
|
content = self.write_xml_content(
|
||||||
xmlutils.webdav_error(namespace, name))
|
xmlutils.webdav_error(namespace, name))
|
||||||
return status, headers, content
|
return status, headers, content
|
||||||
|
@ -51,8 +51,8 @@ class ApplicationDeleteMixin:
|
|||||||
"""Manage DELETE request."""
|
"""Manage DELETE request."""
|
||||||
if not self.access(user, path, "w"):
|
if not self.access(user, path, "w"):
|
||||||
return httputils.NOT_ALLOWED
|
return httputils.NOT_ALLOWED
|
||||||
with self.storage.acquire_lock("w", user):
|
with self._storage.acquire_lock("w", user):
|
||||||
item = next(self.storage.discover(path), None)
|
item = next(self._storage.discover(path), None)
|
||||||
if not item:
|
if not item:
|
||||||
return httputils.NOT_FOUND
|
return httputils.NOT_FOUND
|
||||||
if not self.access(user, path, "w", item):
|
if not self.access(user, path, "w", item):
|
||||||
@ -66,5 +66,5 @@ class ApplicationDeleteMixin:
|
|||||||
else:
|
else:
|
||||||
xml_answer = xml_delete(
|
xml_answer = xml_delete(
|
||||||
base_prefix, path, item.collection, item.href)
|
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)
|
return client.OK, headers, self.write_xml_content(xml_answer)
|
||||||
|
@ -47,13 +47,13 @@ class ApplicationGetMixin:
|
|||||||
def _content_disposition_attachement(self, filename):
|
def _content_disposition_attachement(self, filename):
|
||||||
value = "attachement"
|
value = "attachement"
|
||||||
try:
|
try:
|
||||||
encoded_filename = quote(filename, encoding=self.encoding)
|
encoded_filename = quote(filename, encoding=self._encoding)
|
||||||
except UnicodeEncodeError:
|
except UnicodeEncodeError:
|
||||||
logger.warning("Failed to encode filename: %r", filename,
|
logger.warning("Failed to encode filename: %r", filename,
|
||||||
exc_info=True)
|
exc_info=True)
|
||||||
encoded_filename = ""
|
encoded_filename = ""
|
||||||
if encoded_filename:
|
if encoded_filename:
|
||||||
value += "; filename*=%s''%s" % (self.encoding, encoded_filename)
|
value += "; filename*=%s''%s" % (self._encoding, encoded_filename)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def do_GET(self, environ, base_prefix, path, user):
|
def do_GET(self, environ, base_prefix, path, user):
|
||||||
@ -69,11 +69,11 @@ class ApplicationGetMixin:
|
|||||||
"Redirected to %s" % web_path)
|
"Redirected to %s" % web_path)
|
||||||
# Dispatch .web URL to web module
|
# Dispatch .web URL to web module
|
||||||
if path == "/.web" or path.startswith("/.web/"):
|
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"):
|
if not self.access(user, path, "r"):
|
||||||
return httputils.NOT_ALLOWED
|
return httputils.NOT_ALLOWED
|
||||||
with self.storage.acquire_lock("r", user):
|
with self._storage.acquire_lock("r", user):
|
||||||
item = next(self.storage.discover(path), None)
|
item = next(self._storage.discover(path), None)
|
||||||
if not item:
|
if not item:
|
||||||
return httputils.NOT_FOUND
|
return httputils.NOT_FOUND
|
||||||
if not self.access(user, path, "r", item):
|
if not self.access(user, path, "r", item):
|
||||||
|
@ -30,7 +30,7 @@ from radicale.log import logger
|
|||||||
class ApplicationMkcalendarMixin:
|
class ApplicationMkcalendarMixin:
|
||||||
def do_MKCALENDAR(self, environ, base_prefix, path, user):
|
def do_MKCALENDAR(self, environ, base_prefix, path, user):
|
||||||
"""Manage MKCALENDAR request."""
|
"""Manage MKCALENDAR request."""
|
||||||
if not self.rights.authorized(user, path, "w"):
|
if not self._rights.authorized(user, path, "w"):
|
||||||
return httputils.NOT_ALLOWED
|
return httputils.NOT_ALLOWED
|
||||||
try:
|
try:
|
||||||
xml_content = self.read_xml_content(environ)
|
xml_content = self.read_xml_content(environ)
|
||||||
@ -51,21 +51,21 @@ class ApplicationMkcalendarMixin:
|
|||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Bad MKCALENDAR request on %r: %s", path, e, exc_info=True)
|
"Bad MKCALENDAR request on %r: %s", path, e, exc_info=True)
|
||||||
with self.storage.acquire_lock("w", user):
|
with self._storage.acquire_lock("w", user):
|
||||||
item = next(self.storage.discover(path), None)
|
item = next(self._storage.discover(path), None)
|
||||||
if item:
|
if item:
|
||||||
return self.webdav_error_response(
|
return self.webdav_error_response(
|
||||||
"D", "resource-must-be-null")
|
"D", "resource-must-be-null")
|
||||||
parent_path = pathutils.unstrip_path(
|
parent_path = pathutils.unstrip_path(
|
||||||
posixpath.dirname(pathutils.strip_path(path)), True)
|
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:
|
if not parent_item:
|
||||||
return httputils.CONFLICT
|
return httputils.CONFLICT
|
||||||
if (not isinstance(parent_item, storage.BaseCollection) or
|
if (not isinstance(parent_item, storage.BaseCollection) or
|
||||||
parent_item.get_meta("tag")):
|
parent_item.get_meta("tag")):
|
||||||
return httputils.FORBIDDEN
|
return httputils.FORBIDDEN
|
||||||
try:
|
try:
|
||||||
self.storage.create_collection(path, props=props)
|
self._storage.create_collection(path, props=props)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Bad MKCALENDAR request on %r: %s", path, e, exc_info=True)
|
"Bad MKCALENDAR request on %r: %s", path, e, exc_info=True)
|
||||||
|
@ -30,7 +30,7 @@ from radicale.log import logger
|
|||||||
class ApplicationMkcolMixin:
|
class ApplicationMkcolMixin:
|
||||||
def do_MKCOL(self, environ, base_prefix, path, user):
|
def do_MKCOL(self, environ, base_prefix, path, user):
|
||||||
"""Manage MKCOL request."""
|
"""Manage MKCOL request."""
|
||||||
permissions = self.rights.authorized(user, path, "Ww")
|
permissions = self._rights.authorized(user, path, "Ww")
|
||||||
if not permissions:
|
if not permissions:
|
||||||
return httputils.NOT_ALLOWED
|
return httputils.NOT_ALLOWED
|
||||||
try:
|
try:
|
||||||
@ -53,20 +53,20 @@ class ApplicationMkcolMixin:
|
|||||||
if (props.get("tag") and "w" not in permissions or
|
if (props.get("tag") and "w" not in permissions or
|
||||||
not props.get("tag") and "W" not in permissions):
|
not props.get("tag") and "W" not in permissions):
|
||||||
return httputils.NOT_ALLOWED
|
return httputils.NOT_ALLOWED
|
||||||
with self.storage.acquire_lock("w", user):
|
with self._storage.acquire_lock("w", user):
|
||||||
item = next(self.storage.discover(path), None)
|
item = next(self._storage.discover(path), None)
|
||||||
if item:
|
if item:
|
||||||
return httputils.METHOD_NOT_ALLOWED
|
return httputils.METHOD_NOT_ALLOWED
|
||||||
parent_path = pathutils.unstrip_path(
|
parent_path = pathutils.unstrip_path(
|
||||||
posixpath.dirname(pathutils.strip_path(path)), True)
|
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:
|
if not parent_item:
|
||||||
return httputils.CONFLICT
|
return httputils.CONFLICT
|
||||||
if (not isinstance(parent_item, storage.BaseCollection) or
|
if (not isinstance(parent_item, storage.BaseCollection) or
|
||||||
parent_item.get_meta("tag")):
|
parent_item.get_meta("tag")):
|
||||||
return httputils.FORBIDDEN
|
return httputils.FORBIDDEN
|
||||||
try:
|
try:
|
||||||
self.storage.create_collection(path, props=props)
|
self._storage.create_collection(path, props=props)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Bad MKCOL request on %r: %s", path, e, exc_info=True)
|
"Bad MKCOL request on %r: %s", path, e, exc_info=True)
|
||||||
|
@ -45,8 +45,8 @@ class ApplicationMoveMixin:
|
|||||||
if not self.access(user, to_path, "w"):
|
if not self.access(user, to_path, "w"):
|
||||||
return httputils.NOT_ALLOWED
|
return httputils.NOT_ALLOWED
|
||||||
|
|
||||||
with self.storage.acquire_lock("w", user):
|
with self._storage.acquire_lock("w", user):
|
||||||
item = next(self.storage.discover(path), None)
|
item = next(self._storage.discover(path), None)
|
||||||
if not item:
|
if not item:
|
||||||
return httputils.NOT_FOUND
|
return httputils.NOT_FOUND
|
||||||
if (not self.access(user, path, "w", item) or
|
if (not self.access(user, path, "w", item) or
|
||||||
@ -56,13 +56,13 @@ class ApplicationMoveMixin:
|
|||||||
# TODO: support moving collections
|
# TODO: support moving collections
|
||||||
return httputils.METHOD_NOT_ALLOWED
|
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):
|
if isinstance(to_item, storage.BaseCollection):
|
||||||
return httputils.FORBIDDEN
|
return httputils.FORBIDDEN
|
||||||
to_parent_path = pathutils.unstrip_path(
|
to_parent_path = pathutils.unstrip_path(
|
||||||
posixpath.dirname(pathutils.strip_path(to_path)), True)
|
posixpath.dirname(pathutils.strip_path(to_path)), True)
|
||||||
to_collection = next(
|
to_collection = next(
|
||||||
self.storage.discover(to_parent_path), None)
|
self._storage.discover(to_parent_path), None)
|
||||||
if not to_collection:
|
if not to_collection:
|
||||||
return httputils.CONFLICT
|
return httputils.CONFLICT
|
||||||
tag = item.collection.get_meta("tag")
|
tag = item.collection.get_meta("tag")
|
||||||
@ -78,7 +78,7 @@ class ApplicationMoveMixin:
|
|||||||
"C" if tag == "VCALENDAR" else "CR", "no-uid-conflict")
|
"C" if tag == "VCALENDAR" else "CR", "no-uid-conflict")
|
||||||
to_href = posixpath.basename(pathutils.strip_path(to_path))
|
to_href = posixpath.basename(pathutils.strip_path(to_path))
|
||||||
try:
|
try:
|
||||||
self.storage.move(item, to_collection, to_href)
|
self._storage.move(item, to_collection, to_href)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Bad MOVE request on %r: %s", path, e, exc_info=True)
|
"Bad MOVE request on %r: %s", path, e, exc_info=True)
|
||||||
|
@ -27,7 +27,8 @@ from radicale import httputils, pathutils, rights, storage, xmlutils
|
|||||||
from radicale.log import logger
|
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 and answer PROPFIND requests.
|
||||||
|
|
||||||
Read rfc4918-9.1 for info.
|
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:
|
for item, permission in allowed_items:
|
||||||
write = permission == "w"
|
write = permission == "w"
|
||||||
response = xml_propfind_response(
|
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)
|
allprop=allprop, propname=propname)
|
||||||
if response:
|
if response:
|
||||||
multistatus.append(response)
|
multistatus.append(response)
|
||||||
@ -71,8 +72,8 @@ def xml_propfind(base_prefix, path, xml_request, allowed_items, user):
|
|||||||
return client.MULTI_STATUS, multistatus
|
return client.MULTI_STATUS, multistatus
|
||||||
|
|
||||||
|
|
||||||
def xml_propfind_response(base_prefix, path, item, props, user, write=False,
|
def xml_propfind_response(base_prefix, path, item, props, user, encoding,
|
||||||
propname=False, allprop=False):
|
write=False, propname=False, allprop=False):
|
||||||
"""Build and return a PROPFIND response."""
|
"""Build and return a PROPFIND response."""
|
||||||
if propname and allprop or (props and (propname or allprop)):
|
if propname and allprop or (props and (propname or allprop)):
|
||||||
raise ValueError("Only use one of props, propname and allprops")
|
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)
|
element.append(supported)
|
||||||
elif tag == xmlutils.make_tag("D", "getcontentlength"):
|
elif tag == xmlutils.make_tag("D", "getcontentlength"):
|
||||||
if not is_collection or is_leaf:
|
if not is_collection or is_leaf:
|
||||||
encoding = collection.configuration.get("encoding", "request")
|
|
||||||
element.text = str(len(item.serialize().encode(encoding)))
|
element.text = str(len(item.serialize().encode(encoding)))
|
||||||
else:
|
else:
|
||||||
is404 = True
|
is404 = True
|
||||||
@ -299,7 +299,7 @@ def xml_propfind_response(base_prefix, path, item, props, user, write=False,
|
|||||||
is404 = True
|
is404 = True
|
||||||
# Not for collections
|
# Not for collections
|
||||||
elif tag == xmlutils.make_tag("D", "getcontenttype"):
|
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"):
|
elif tag == xmlutils.make_tag("D", "resourcetype"):
|
||||||
# resourcetype must be returned empty for non-collection elements
|
# resourcetype must be returned empty for non-collection elements
|
||||||
pass
|
pass
|
||||||
@ -331,14 +331,14 @@ class ApplicationPropfindMixin:
|
|||||||
if isinstance(item, storage.BaseCollection):
|
if isinstance(item, storage.BaseCollection):
|
||||||
path = pathutils.unstrip_path(item.path, True)
|
path = pathutils.unstrip_path(item.path, True)
|
||||||
if item.get_meta("tag"):
|
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
|
target = "collection with tag %r" % item.path
|
||||||
else:
|
else:
|
||||||
permissions = self.rights.authorized(user, path, "RW")
|
permissions = self._rights.authorized(user, path, "RW")
|
||||||
target = "collection %r" % item.path
|
target = "collection %r" % item.path
|
||||||
else:
|
else:
|
||||||
path = pathutils.unstrip_path(item.collection.path, True)
|
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)
|
target = "item %r from %r" % (item.href, item.collection.path)
|
||||||
if rights.intersect_permissions(permissions, "Ww"):
|
if rights.intersect_permissions(permissions, "Ww"):
|
||||||
permission = "w"
|
permission = "w"
|
||||||
@ -368,8 +368,9 @@ class ApplicationPropfindMixin:
|
|||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
logger.debug("client timed out", exc_info=True)
|
logger.debug("client timed out", exc_info=True)
|
||||||
return httputils.REQUEST_TIMEOUT
|
return httputils.REQUEST_TIMEOUT
|
||||||
with self.storage.acquire_lock("r", user):
|
with self._storage.acquire_lock("r", user):
|
||||||
items = self.storage.discover(path, environ.get("HTTP_DEPTH", "0"))
|
items = self._storage.discover(
|
||||||
|
path, environ.get("HTTP_DEPTH", "0"))
|
||||||
# take root item for rights checking
|
# take root item for rights checking
|
||||||
item = next(items, None)
|
item = next(items, None)
|
||||||
if not item:
|
if not item:
|
||||||
@ -380,9 +381,10 @@ class ApplicationPropfindMixin:
|
|||||||
items = itertools.chain([item], items)
|
items = itertools.chain([item], items)
|
||||||
allowed_items = self._collect_allowed_items(items, user)
|
allowed_items = self._collect_allowed_items(items, user)
|
||||||
headers = {"DAV": httputils.DAV_HEADERS,
|
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(
|
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:
|
if status == client.FORBIDDEN:
|
||||||
return httputils.NOT_ALLOWED
|
return httputils.NOT_ALLOWED
|
||||||
return status, headers, self.write_xml_content(xml_answer)
|
return status, headers, self.write_xml_content(xml_answer)
|
||||||
|
@ -98,8 +98,8 @@ class ApplicationProppatchMixin:
|
|||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
logger.debug("client timed out", exc_info=True)
|
logger.debug("client timed out", exc_info=True)
|
||||||
return httputils.REQUEST_TIMEOUT
|
return httputils.REQUEST_TIMEOUT
|
||||||
with self.storage.acquire_lock("w", user):
|
with self._storage.acquire_lock("w", user):
|
||||||
item = next(self.storage.discover(path), None)
|
item = next(self._storage.discover(path), None)
|
||||||
if not item:
|
if not item:
|
||||||
return httputils.NOT_FOUND
|
return httputils.NOT_FOUND
|
||||||
if not self.access(user, path, "w", item):
|
if not self.access(user, path, "w", item):
|
||||||
@ -107,7 +107,7 @@ class ApplicationProppatchMixin:
|
|||||||
if not isinstance(item, storage.BaseCollection):
|
if not isinstance(item, storage.BaseCollection):
|
||||||
return httputils.FORBIDDEN
|
return httputils.FORBIDDEN
|
||||||
headers = {"DAV": httputils.DAV_HEADERS,
|
headers = {"DAV": httputils.DAV_HEADERS,
|
||||||
"Content-Type": "text/xml; charset=%s" % self.encoding}
|
"Content-Type": "text/xml; charset=%s" % self._encoding}
|
||||||
try:
|
try:
|
||||||
xml_answer = xml_proppatch(base_prefix, path, xml_content,
|
xml_answer = xml_proppatch(base_prefix, path, xml_content,
|
||||||
item)
|
item)
|
||||||
|
@ -47,8 +47,8 @@ class ApplicationPutMixin:
|
|||||||
# Prepare before locking
|
# Prepare before locking
|
||||||
parent_path = pathutils.unstrip_path(
|
parent_path = pathutils.unstrip_path(
|
||||||
posixpath.dirname(pathutils.strip_path(path)), True)
|
posixpath.dirname(pathutils.strip_path(path)), True)
|
||||||
permissions = self.rights.authorized(user, path, "Ww")
|
permissions = self._rights.authorized(user, path, "Ww")
|
||||||
parent_permissions = self.rights.authorized(user, parent_path, "w")
|
parent_permissions = self._rights.authorized(user, parent_path, "w")
|
||||||
|
|
||||||
def prepare(vobject_items, tag=None, write_whole_collection=None):
|
def prepare(vobject_items, tag=None, write_whole_collection=None):
|
||||||
if (write_whole_collection or
|
if (write_whole_collection or
|
||||||
@ -149,9 +149,9 @@ class ApplicationPutMixin:
|
|||||||
(prepared_items, prepared_tag, prepared_write_whole_collection,
|
(prepared_items, prepared_tag, prepared_write_whole_collection,
|
||||||
prepared_props, prepared_exc_info) = prepare(vobject_items)
|
prepared_props, prepared_exc_info) = prepare(vobject_items)
|
||||||
|
|
||||||
with self.storage.acquire_lock("w", user):
|
with self._storage.acquire_lock("w", user):
|
||||||
item = next(self.storage.discover(path), None)
|
item = next(self._storage.discover(path), None)
|
||||||
parent_item = next(self.storage.discover(parent_path), None)
|
parent_item = next(self._storage.discover(parent_path), None)
|
||||||
if not parent_item:
|
if not parent_item:
|
||||||
return httputils.CONFLICT
|
return httputils.CONFLICT
|
||||||
|
|
||||||
@ -165,9 +165,10 @@ class ApplicationPutMixin:
|
|||||||
tag = parent_item.get_meta("tag")
|
tag = parent_item.get_meta("tag")
|
||||||
|
|
||||||
if write_whole_collection:
|
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
|
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
|
return httputils.NOT_ALLOWED
|
||||||
|
|
||||||
etag = environ.get("HTTP_IF_MATCH", "")
|
etag = environ.get("HTTP_IF_MATCH", "")
|
||||||
@ -197,7 +198,7 @@ class ApplicationPutMixin:
|
|||||||
|
|
||||||
if write_whole_collection:
|
if write_whole_collection:
|
||||||
try:
|
try:
|
||||||
etag = self.storage.create_collection(
|
etag = self._storage.create_collection(
|
||||||
path, prepared_items, props).etag
|
path, prepared_items, props).etag
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
|
@ -29,7 +29,8 @@ from radicale.item import filter as radicale_filter
|
|||||||
from radicale.log import logger
|
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 and answer REPORT requests.
|
||||||
|
|
||||||
Read rfc3253-3.6 for info.
|
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
|
element.text = item.etag
|
||||||
found_props.append(element)
|
found_props.append(element)
|
||||||
elif tag == xmlutils.make_tag("D", "getcontenttype"):
|
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)
|
found_props.append(element)
|
||||||
elif tag in (
|
elif tag in (
|
||||||
xmlutils.make_tag("C", "calendar-data"),
|
xmlutils.make_tag("C", "calendar-data"),
|
||||||
@ -270,8 +271,8 @@ class ApplicationReportMixin:
|
|||||||
logger.debug("client timed out", exc_info=True)
|
logger.debug("client timed out", exc_info=True)
|
||||||
return httputils.REQUEST_TIMEOUT
|
return httputils.REQUEST_TIMEOUT
|
||||||
with contextlib.ExitStack() as lock_stack:
|
with contextlib.ExitStack() as lock_stack:
|
||||||
lock_stack.enter_context(self.storage.acquire_lock("r", user))
|
lock_stack.enter_context(self._storage.acquire_lock("r", user))
|
||||||
item = next(self.storage.discover(path), None)
|
item = next(self._storage.discover(path), None)
|
||||||
if not item:
|
if not item:
|
||||||
return httputils.NOT_FOUND
|
return httputils.NOT_FOUND
|
||||||
if not self.access(user, path, "r", item):
|
if not self.access(user, path, "r", item):
|
||||||
@ -280,10 +281,10 @@ class ApplicationReportMixin:
|
|||||||
collection = item
|
collection = item
|
||||||
else:
|
else:
|
||||||
collection = item.collection
|
collection = item.collection
|
||||||
headers = {"Content-Type": "text/xml; charset=%s" % self.encoding}
|
headers = {"Content-Type": "text/xml; charset=%s" % self._encoding}
|
||||||
try:
|
try:
|
||||||
status, xml_answer = xml_report(
|
status, xml_answer = xml_report(
|
||||||
base_prefix, path, xml_content, collection,
|
base_prefix, path, xml_content, collection, self._encoding,
|
||||||
lock_stack.close)
|
lock_stack.close)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
|
@ -127,11 +127,10 @@ def webdav_error(namespace, name):
|
|||||||
return root
|
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.
|
"""Get the content-type of an item with charset and component parameters.
|
||||||
"""
|
"""
|
||||||
mimetype = OBJECT_MIMETYPES[item.name]
|
mimetype = OBJECT_MIMETYPES[item.name]
|
||||||
encoding = item.collection.configuration.get("encoding", "request")
|
|
||||||
tag = item.component_name
|
tag = item.component_name
|
||||||
content_type = "%s;charset=%s" % (mimetype, encoding)
|
content_type = "%s;charset=%s" % (mimetype, encoding)
|
||||||
if tag:
|
if tag:
|
||||||
|
Loading…
Reference in New Issue
Block a user