From: Mike Bayer Date: Wed, 6 Dec 2023 18:57:23 +0000 (-0500) Subject: Revert "Replace custom URL-encoding method with quote_plus" X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1acca3d6c6cf035c36ddfa1f281b4932ace18b24;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Revert "Replace custom URL-encoding method with quote_plus" This reverts commit b80e17c3f3e21059ba1a425d75bf3e0f9384d4d2. our URL parsing does not interpret plus signs as spaces in the password. so we cannot use this function as is --- diff --git a/doc/build/changelog/unreleased_21/10662.rst b/doc/build/changelog/unreleased_21/10662.rst deleted file mode 100644 index c5cc64a602..0000000000 --- a/doc/build/changelog/unreleased_21/10662.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. change:: - :tags: bug, engine - :tickets: 10662 - - Fixed URL-encoding of the username and password components of - :class:`.engine.URL` objects when converting them to string using the - :meth:`_engine.URL.render_as_string` method, by using Python standard - library ``urllib.parse.quote_plus``, rather than the legacy home-grown - routine from many years ago. Pull request courtesy of Xavier NUNN. diff --git a/lib/sqlalchemy/engine/url.py b/lib/sqlalchemy/engine/url.py index bf1471a0fc..5cf5ec7b4b 100644 --- a/lib/sqlalchemy/engine/url.py +++ b/lib/sqlalchemy/engine/url.py @@ -631,7 +631,7 @@ class URL(NamedTuple): s += "@" if self.host is not None: if ":" in self.host: - s += f"[{self.host}]" + s += "[%s]" % self.host else: s += self.host if self.port is not None: @@ -642,7 +642,7 @@ class URL(NamedTuple): keys = list(self.query) keys.sort() s += "?" + "&".join( - f"{_sqla_url_quote(k)}={_sqla_url_quote(element)}" + "%s=%s" % (quote_plus(k), quote_plus(element)) for k in keys for element in util.to_list(self.query[k]) ) @@ -906,7 +906,8 @@ def _parse_url(name: str) -> URL: ) -_sqla_url_quote = quote_plus +def _sqla_url_quote(text: str) -> str: + return re.sub(r"[:@/]", lambda m: "%%%X" % ord(m.group(0)), text) _sqla_url_unquote = unquote diff --git a/test/engine/test_parseconnect.py b/test/engine/test_parseconnect.py index 846cd3b4de..4c144a4a31 100644 --- a/test/engine/test_parseconnect.py +++ b/test/engine/test_parseconnect.py @@ -62,19 +62,13 @@ class URLTest(fixtures.TestBase): "dbtype://username:password@hostspec/test database with@atsign", "dbtype://username:password@hostspec?query=but_no_db", "dbtype://username:password@hostspec:450?query=but_no_db", - "dbtype://user%25%26%7C:pass%25%26%7C@hostspec:499?query=but_no_db", ) def test_rfc1738(self, text): u = url.make_url(text) assert u.drivername in ("dbtype", "dbtype+apitype") - assert u.username in ("username", "user%&|", None) - assert u.password in ( - "password", - "apples/oranges", - "pass%&|", - None, - ) + assert u.username in ("username", None) + assert u.password in ("password", "apples/oranges", None) assert u.host in ( "hostspec", "127.0.0.1", @@ -101,7 +95,7 @@ class URLTest(fixtures.TestBase): eq_(str(u), "dbtype://user:***@host/dbname") eq_( u.render_as_string(hide_password=False), - "dbtype://user:pass+word+%2B+other%3Awords@host/dbname", + "dbtype://user:pass word + other%3Awords@host/dbname", ) u = url.make_url(