diff --git a/tests/storage/dav/test_main.py b/tests/storage/dav/test_main.py
index e48d5d5..1ac356f 100644
--- a/tests/storage/dav/test_main.py
+++ b/tests/storage/dav/test_main.py
@@ -13,7 +13,7 @@ from tests import EVENT_TEMPLATE, TASK_TEMPLATE, VCARD_TEMPLATE
import vdirsyncer.exceptions as exceptions
from vdirsyncer.storage.base import Item
-from vdirsyncer.storage.dav import CaldavStorage, CarddavStorage
+from vdirsyncer.storage.dav import CaldavStorage, CarddavStorage, _parse_xml
from .. import StorageTests, format_item
@@ -183,3 +183,10 @@ class TestCarddavStorage(DavStorageTests):
@pytest.fixture(params=['VCARD'])
def item_type(self, request):
return request.param
+
+
+def test_broken_xml(capsys):
+ rv = _parse_xml(b'
\x10haha
')
+ assert rv.text == 'haha'
+ warnings = capsys.readouterr()[1]
+ assert 'partially invalid xml' in warnings.lower()
diff --git a/vdirsyncer/storage/dav.py b/vdirsyncer/storage/dav.py
index a5136ed..640c062 100644
--- a/vdirsyncer/storage/dav.py
+++ b/vdirsyncer/storage/dav.py
@@ -42,12 +42,18 @@ class InvalidXMLResponse(exceptions.InvalidResponse):
def _parse_xml(content):
- try:
- return etree.XML(content)
- except etree.Error as e:
+ p = etree.XMLParser(recover=True)
+ rv = etree.XML(content, parser=p)
+ if rv is None:
raise InvalidXMLResponse('Invalid XML encountered: {}\n'
'Double-check the URLs in your config.'
- .format(e))
+ .format(p.error_log))
+ if p.error_log:
+ dav_logger.warning('Partially invalid XML response, some of your '
+ 'items may be corrupted. Check the debug log and '
+ 'consider switching servers. ({})'
+ .format(p.error_log))
+ return rv
def _merge_xml(items):