diff --git a/tests/storage/dav/test_main.py b/tests/storage/dav/test_main.py
index 701512c..27ff141 100644
--- a/tests/storage/dav/test_main.py
+++ b/tests/storage/dav/test_main.py
@@ -20,8 +20,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, \
- _normalize_href
+from vdirsyncer.storage.dav import CaldavStorage, CarddavStorage
from .. import StorageTests, format_item
@@ -183,26 +182,3 @@ class TestCarddavStorage(DavStorageTests):
@pytest.fixture
def item_template(self, request):
return VCARD_TEMPLATE
-
-
-@pytest.mark.parametrize('base,path', [
- ('http://example.com/', ''),
- ('http://example.com/L%C3%98/', '/L%C3%98'),
- ('http://example.com/LØ/', '/L%C3%98'),
-])
-def test_normalize_href(base, path):
- assert _normalize_href(base, 'asdf') == path + '/asdf'
-
- assert _normalize_href(base, 'hahah') == path + '/hahah'
-
- assert _normalize_href(base, 'whoops@vdirsyncer.vcf') == \
- path + '/whoops@vdirsyncer.vcf'
-
- assert _normalize_href(base, 'whoops%40vdirsyncer.vcf') == \
- path + '/whoops@vdirsyncer.vcf'
-
- assert _normalize_href(base, 'wh%C3%98ops@vdirsyncer.vcf') == \
- path + '/wh%C3%98ops@vdirsyncer.vcf'
-
- assert _normalize_href(base, 'whØops@vdirsyncer.vcf') == \
- path + '/wh%C3%98ops@vdirsyncer.vcf'
diff --git a/vdirsyncer/storage/dav.py b/vdirsyncer/storage/dav.py
index 2f18362..528ed8f 100644
--- a/vdirsyncer/storage/dav.py
+++ b/vdirsyncer/storage/dav.py
@@ -23,21 +23,24 @@ dav_logger = log.get(__name__)
CALDAV_DT_FORMAT = '%Y%m%dT%H%M%SZ'
-def _normalize_href(base, href, decoding_rounds=1):
+def _normalize_href(base, href):
'''Normalize the href to be a path only relative to hostname and
schema.'''
if not href:
raise ValueError(href)
x = utils.urlparse.urljoin(base, href)
x = utils.urlparse.urlsplit(x).path
-
- for i in range(decoding_rounds):
- x = utils.compat.urlunquote(x)
-
- x = utils.compat.urlquote(x, '/@')
return x
+def _encode_href(x):
+ return utils.compat.urlquote(x, '/@')
+
+
+def _decode_href(x):
+ return utils.compat.urlunquote(x)
+
+
def _parse_xml(content):
try:
return etree.XML(content)
@@ -293,7 +296,7 @@ class DavStorage(Storage):
for href in hrefs:
if href != self._normalize_href(href):
raise exceptions.NotFoundError(href)
- href_xml.append('{}'.format(href))
+ href_xml.append('{}'.format(_encode_href(href)))
if not href_xml:
return ()
@@ -345,7 +348,7 @@ class DavStorage(Storage):
response = self.session.request(
'PUT',
- href,
+ _encode_href(href),
data=item.raw.encode('utf-8'),
headers=headers
)
@@ -375,7 +378,7 @@ class DavStorage(Storage):
self.session.request(
'DELETE',
- href,
+ _encode_href(href),
headers=headers
)
@@ -388,7 +391,10 @@ class DavStorage(Storage):
dav_logger.error('Skipping response, href is missing.')
continue
- href = self._normalize_href(href, decoding_rounds=decoding_rounds)
+ href = self._normalize_href(href)
+ for i in range(decoding_rounds):
+ href = _decode_href(href)
+
if href in hrefs:
# Servers that send duplicate hrefs:
# - Zimbra
@@ -618,7 +624,6 @@ class CarddavStorage(DavStorage):
# with Zimbra. See https://github.com/untitaker/vdirsyncer/issues/83
response = self.session.request('PROPFIND', '', data=data,
headers=headers)
-
root = _parse_xml(response.content)
# Decode twice because ownCloud encodes twice.