Improve rights checking and request handlers
* Access rights are checked before the storage is locked and
collections are loaded.
* DELETE sends 410 instead of doing nothing or crashing if the target
doesn't exist.
* GET always returns 404 if the target doesn't exist.
* GET doesn't crash if a collection without tag property is requested.
* MKCOL and MKCALENDAR send 409 if the target already exists.
* MOVE checks if the target collection of an item actually exists and
sends 409 otherwise.
* PUT doesn't crash if a whole collection that doesn't exist yet is
uploaded and ``content-type`` is ``text/vcard`` or
``text/calendar``.
* PUT distinguishes between simple items and whole collections by the
following criteria: Target is a collection; Parent exists; Parent
has the tag property set; Parent contains other items. Before only
the first two criteria where used, which was very unrelieable. #384
* PROPPATCH is only allowed on collections and 409 is send otherwise.
* ``Rights.authorized`` takes a path instead of a collection.
* ``Collection.discover`` only returns items in ``path``, that
actually exist. #442
This commit is contained in:
@@ -211,9 +211,7 @@ class BaseCollection:
|
||||
returned.
|
||||
|
||||
If ``depth`` is anything but "0", it is considered as "1" and direct
|
||||
children are included in the result. If ``include_container`` is
|
||||
``True`` (the default), the containing object is included in the
|
||||
result.
|
||||
children are included in the result.
|
||||
|
||||
The ``path`` is relative.
|
||||
|
||||
@@ -368,41 +366,39 @@ class Collection(BaseCollection):
|
||||
attributes = sane_path.split("/")
|
||||
if not attributes[0]:
|
||||
attributes.pop()
|
||||
|
||||
# Try to guess if the path leads to a collection or an item
|
||||
folder = os.path.expanduser(
|
||||
cls.configuration.get("storage", "filesystem_folder"))
|
||||
if not os.path.isdir(path_to_filesystem(folder, sane_path)):
|
||||
# path is not a collection
|
||||
if attributes and os.path.isfile(path_to_filesystem(folder,
|
||||
sane_path)):
|
||||
# path is an item
|
||||
attributes.pop()
|
||||
elif attributes and os.path.isdir(path_to_filesystem(
|
||||
folder, *attributes[:-1])):
|
||||
# path parent is a collection
|
||||
attributes.pop()
|
||||
# TODO: else: return?
|
||||
try:
|
||||
filesystem_path = path_to_filesystem(folder, sane_path)
|
||||
except ValueError:
|
||||
# Path is unsafe
|
||||
return
|
||||
href = None
|
||||
if not os.path.isdir(filesystem_path):
|
||||
if attributes and os.path.isfile(filesystem_path):
|
||||
href = attributes.pop()
|
||||
else:
|
||||
return
|
||||
|
||||
path = "/".join(attributes)
|
||||
|
||||
principal = len(attributes) == 1
|
||||
collection = cls(path, principal)
|
||||
if href:
|
||||
yield collection.get(href)
|
||||
return
|
||||
yield collection
|
||||
if depth != "0":
|
||||
# TODO: fix this
|
||||
items = list(collection.list())
|
||||
if items:
|
||||
for item in items:
|
||||
yield collection.get(item[0])
|
||||
_, directories, _ = next(os.walk(collection._filesystem_path))
|
||||
for sub_path in directories:
|
||||
if not is_safe_filesystem_path_component(sub_path):
|
||||
cls.logger.debug("Skipping collection: %s", sub_path)
|
||||
continue
|
||||
full_path = os.path.join(collection._filesystem_path, sub_path)
|
||||
if os.path.exists(full_path):
|
||||
yield cls(posixpath.join(path, sub_path))
|
||||
if depth == "0":
|
||||
return
|
||||
for item in collection.list():
|
||||
yield collection.get(item[0])
|
||||
for href in os.listdir(filesystem_path):
|
||||
if not is_safe_filesystem_path_component(href):
|
||||
cls.logger.debug("Skipping collection: %s", href)
|
||||
continue
|
||||
child_filesystem_path = path_to_filesystem(filesystem_path, href)
|
||||
if os.path.isdir(child_filesystem_path):
|
||||
child_principal = len(attributes) == 0
|
||||
yield cls(child_filesystem_path, child_principal)
|
||||
|
||||
@classmethod
|
||||
def create_collection(cls, href, collection=None, tag=None):
|
||||
|
||||
Reference in New Issue
Block a user