Sfoglia il codice sorgente

Merge pull request #1968 from laurisvr/fix-move-urlencode-destination

Fix MOVE failing with URL-encoded Destination header
Peter Bieringer 1 mese fa
parent
commit
1a2f5e85f1
1 ha cambiato i file con 17 aggiunte e 10 eliminazioni
  1. 17 10
      radicale/app/move.py

+ 17 - 10
radicale/app/move.py

@@ -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