Skip to content

Commit 09eb375

Browse files
author
Hugo Osvaldo Barrera
authored
Merge pull request #929 from pimutils/fix-918
Fix 918
2 parents dff48f1 + 4874746 commit 09eb375

File tree

3 files changed

+36
-34
lines changed

3 files changed

+36
-34
lines changed

tests/storage/__init__.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,6 @@ async def test_case_sensitive_uids(self, s, get_item):
282282
async def test_specialchars(
283283
self, monkeypatch, requires_collections, get_storage_args, get_item
284284
):
285-
if getattr(self, "dav_server", "") == "radicale":
286-
pytest.skip("Radicale is fundamentally broken.")
287285
if getattr(self, "dav_server", "") in ("icloud", "fastmail"):
288286
pytest.skip("iCloud and FastMail reject this name.")
289287

@@ -312,6 +310,26 @@ async def test_specialchars(
312310
if self.storage_class.storage_name.endswith("dav"):
313311
assert urlquote(uid, "/@:") in href
314312

313+
@pytest.mark.asyncio
314+
async def test_newline_in_uid(
315+
self, monkeypatch, requires_collections, get_storage_args, get_item
316+
):
317+
monkeypatch.setattr("vdirsyncer.utils.generate_href", lambda x: x)
318+
319+
uid = "UID:20210609T084907Z-@synaps-web-54fddfdf7-7kcfm%0A.ics"
320+
321+
s = self.storage_class(**await get_storage_args())
322+
item = get_item(uid=uid)
323+
324+
href, etag = await s.upload(item)
325+
item2, etag2 = await s.get(href)
326+
if etag is not None:
327+
assert etag2 == etag
328+
assert_item_equals(item2, item)
329+
330+
((_, etag3),) = await aiostream.stream.list(s.list())
331+
assert etag2 == etag3
332+
315333
@pytest.mark.asyncio
316334
async def test_empty_metadata(self, requires_metadata, s):
317335
if getattr(self, "dav_server", ""):

tests/storage/dav/test_main.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from vdirsyncer.storage.dav import _BAD_XML_CHARS
44
from vdirsyncer.storage.dav import _merge_xml
5+
from vdirsyncer.storage.dav import _normalize_href
56
from vdirsyncer.storage.dav import _parse_xml
67

78

@@ -44,3 +45,13 @@ def test_xml_specialchars(char):
4445

4546
if char in _BAD_XML_CHARS:
4647
assert x.text == "yes\nhello"
48+
49+
50+
@pytest.mark.parametrize(
51+
"href",
52+
[
53+
"/dav/calendars/user/testuser/123/UID%253A20210609T084907Z-@synaps-web-54fddfdf7-7kcfm%250A.ics", # noqa: E501
54+
],
55+
)
56+
def test_normalize_href(href):
57+
assert href == _normalize_href("https://example.com", href)

vdirsyncer/storage/dav.py

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -29,25 +29,6 @@
2929
CALDAV_DT_FORMAT = "%Y%m%dT%H%M%SZ"
3030

3131

32-
def _generate_path_reserved_chars():
33-
for x in "/?#[]!$&'()*+,;":
34-
x = urlparse.quote(x, "")
35-
yield x.upper()
36-
yield x.lower()
37-
38-
39-
_path_reserved_chars = frozenset(_generate_path_reserved_chars())
40-
del _generate_path_reserved_chars
41-
42-
43-
def _contains_quoted_reserved_chars(x):
44-
for y in _path_reserved_chars:
45-
if y in x:
46-
dav_logger.debug(f"Unsafe character: {y!r}")
47-
return True
48-
return False
49-
50-
5132
async def _assert_multistatus_success(r):
5233
# Xandikos returns a multistatus on PUT.
5334
try:
@@ -65,26 +46,18 @@ async def _assert_multistatus_success(r):
6546

6647

6748
def _normalize_href(base, href):
68-
"""Normalize the href to be a path only relative to hostname and
69-
schema."""
49+
"""Normalize the href to be a path only relative to hostname and schema."""
7050
orig_href = href
7151
if not href:
7252
raise ValueError(href)
7353

7454
x = urlparse.urljoin(base, href)
7555
x = urlparse.urlsplit(x).path
7656

77-
# Encoding issues:
78-
# - https://github.com/owncloud/contacts/issues/581
79-
# - https://github.com/Kozea/Radicale/issues/298
80-
old_x = None
81-
while old_x is None or x != old_x:
82-
if _contains_quoted_reserved_chars(x):
83-
break
84-
old_x = x
85-
x = urlparse.unquote(x)
86-
87-
x = urlparse.quote(x, "/@%:")
57+
# We unquote and quote again, but want to make sure we
58+
# keep around the "@" character.
59+
x = urlparse.unquote(x)
60+
x = urlparse.quote(x, "/@")
8861

8962
if orig_href == x:
9063
dav_logger.debug(f"Already normalized: {x!r}")

0 commit comments

Comments
 (0)