From 1126f318af42e177cb930366e8480a1e384a698d Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Sun, 8 Feb 2015 17:52:55 +0100 Subject: [PATCH] Fully fix #258 If I do REPORT requests, the following line would raise a KeyError: items = [collection.items[name]] Wrapping it with a try-except block obviously fixes that issue. At least for REPORT requests, Radicale now also returns proper HTTP status codes when items or just its properties couldn't be found. --- radicale/xmlutils.py | 72 +++++++++++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 17 deletions(-) diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index 7f1573b..a1ccb2d 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -504,46 +504,84 @@ def report(path, xml_request, collection): if name: # Reference is an item path = "/".join(hreference.split("/")[:-1]) + "/" - items = [collection.items[name]] + try: + items = [collection.items[name]] + except KeyError: + multistatus.append(_item_response(hreference, + found_item=False)) + continue + else: # Reference is a collection path = hreference items = collection.components for item in items: + href = _href("%s/%s" % (path.rstrip("/"), item.name)) if tag_filters and item.tag not in tag_filters: continue - response = ET.Element(_tag("D", "response")) - multistatus.append(response) - - href = ET.Element(_tag("D", "href")) - href.text = _href("%s/%s" % (path.rstrip("/"), item.name)) - response.append(href) - - propstat = ET.Element(_tag("D", "propstat")) - response.append(propstat) - - prop = ET.Element(_tag("D", "prop")) - propstat.append(prop) + found_props = [] + not_found_props = [] for tag in props: element = ET.Element(tag) if tag == _tag("D", "getetag"): element.text = item.etag + found_props.append(element) elif tag == _tag("D", "getcontenttype"): element.text = "%s; component=%s" % ( item.mimetype, item.tag.lower()) + found_props.append(element) elif tag in (_tag("C", "calendar-data"), _tag("CR", "address-data")): if isinstance(item, ical.Component): element.text = ical.serialize( collection_tag, collection_headers, collection_timezones + [item]) - prop.append(element) + found_props.append(element) + else: + not_found_props.append(element) - status = ET.Element(_tag("D", "status")) - status.text = _response(200) - propstat.append(status) + multistatus.append(_item_response(href, found_props=found_props, + not_found_props=not_found_props, + found_item=True)) return _pretty_xml(multistatus) + + +def _item_response(href, found_props=(), not_found_props=(), found_item=True): + response = ET.Element(_tag("D", "response")) + + href_tag = ET.Element(_tag("D", "href")) + href_tag.text = href + response.append(href_tag) + + if found_item: + if found_props: + propstat = ET.Element(_tag("D", "propstat")) + status = ET.Element(_tag("D", "status")) + status.text = _response(200) + prop = ET.Element(_tag("D", "prop")) + for p in found_props: + prop.append(p) + propstat.append(prop) + propstat.append(status) + response.append(propstat) + + if not_found_props: + propstat = ET.Element(_tag("D", "propstat")) + status = ET.Element(_tag("D", "status")) + status.text = _response(404) + prop = ET.Element(_Tag("D", "prop")) + for p in not_found_props: + prop.append(p) + propstat.append(prop) + propstat.append(status) + response.append(propstat) + else: + status = ET.Element(_tag("D", "status")) + status.text = _response(404) + response.append(status) + + return response