Fix MOVE failing with URL-encoded Destination header

Destination header wasn't being decoded before urlparse(), and relative
URLs (empty netloc) failed the host comparison.

Ran into this with email usernames where @ gets encoded as %40."
This commit is contained in:
laurisvr
2026-01-21 16:58:25 +01:00
committed by Lauris
parent 4fb16727f0
commit 9a2bbb589c

View File

@@ -22,7 +22,7 @@ import errno
import posixpath
import re
from http import client
from urllib.parse import urlparse
from urllib.parse import unquote, urlparse
from radicale import httputils, pathutils, storage, types
from radicale.app.base import Access, ApplicationBase
@@ -51,15 +51,22 @@ class ApplicationPartMove(ApplicationBase):
path: str, user: str, remote_host: str, remote_useragent: str) -> types.WSGIResponse:
"""Manage MOVE request."""
raw_dest = environ.get("HTTP_DESTINATION", "")
to_url = urlparse(raw_dest)
to_netloc_with_port = to_url.netloc
if to_url.port is None:
to_netloc_with_port += (":443" if to_url.scheme == "https"
else ":80")
if to_netloc_with_port != get_server_netloc(environ, force_port=True):
logger.info("Unsupported destination address: %r", raw_dest)
# Remote destination server, not supported
return httputils.REMOTE_DESTINATION
# Decode URL-encoded characters (e.g. %40 -> @) before parsing
raw_dest_decoded = unquote(raw_dest)
to_url = urlparse(raw_dest_decoded)
# Only check netloc for absolute URLs
if to_url.netloc:
to_netloc_with_port = to_url.netloc
if to_url.port is None:
to_netloc_with_port += (":443" if to_url.scheme == "https"
else ":80")
if to_netloc_with_port != get_server_netloc(environ, force_port=True):
logger.info("Unsupported destination address: %r", raw_dest)
# Remote destination server, not supported
return httputils.REMOTE_DESTINATION
access = Access(self._rights, user, path)
if not access.check("w"):
return httputils.NOT_ALLOWED