Skip to content

Commit bf12e97

Browse files
authored
PYTHON-4588 Don't include invalid port in URI parsing error message (mongodb#1753)
1 parent a3cd704 commit bf12e97

File tree

2 files changed

+37
-6
lines changed

2 files changed

+37
-6
lines changed

pymongo/uri_parser.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,21 @@ def parse_host(entity: str, default_port: Optional[int] = DEFAULT_PORT) -> _Addr
146146
)
147147
host, port = host.split(":", 1)
148148
if isinstance(port, str):
149-
if not port.isdigit() or int(port) > 65535 or int(port) <= 0:
150-
raise ValueError(f"Port must be an integer between 0 and 65535: {port!r}")
149+
if not port.isdigit():
150+
# Special case check for mistakes like "mongodb://localhost:27017 ".
151+
if all(c.isspace() or c.isdigit() for c in port):
152+
for c in port:
153+
if c.isspace():
154+
raise ValueError(f"Port contains whitespace character: {c!r}")
155+
156+
# A non-digit port indicates that the URI is invalid, likely because the password
157+
# or username were not escaped.
158+
raise ValueError(
159+
"Port contains non-digit characters. Hint: username and password must be escaped according to "
160+
"RFC 3986, use urllib.parse.quote_plus"
161+
)
162+
if int(port) > 65535 or int(port) <= 0:
163+
raise ValueError("Port must be an integer between 0 and 65535")
151164
port = int(port)
152165

153166
# Normalize hostname to lowercase, since DNS is case-insensitive:

test/test_uri_parser.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,6 @@ def test_parse_uri(self):
160160
self.assertRaises(InvalidURI, parse_uri, "http://[email protected]")
161161
self.assertRaises(ValueError, parse_uri, "mongodb://::1", 27017)
162162

163-
# Extra whitespace should be visible in error message.
164-
with self.assertRaisesRegex(ValueError, "'27017 '"):
165-
parse_uri("mongodb://localhost:27017 ")
166-
167163
orig: dict = {
168164
"nodelist": [("localhost", 27017)],
169165
"username": None,
@@ -536,6 +532,28 @@ def test_special_chars(self):
536532
self.assertEqual(user, res["username"])
537533
self.assertEqual(pwd, res["password"])
538534

535+
def test_do_not_include_password_in_port_message(self):
536+
with self.assertRaisesRegex(ValueError, "Port must be an integer between 0 and 65535"):
537+
parse_uri("mongodb://localhost:65536")
538+
with self.assertRaisesRegex(
539+
ValueError, "Port contains non-digit characters. Hint: username "
540+
) as ctx:
541+
parse_uri("mongodb://user:PASS /@localhost:27017")
542+
self.assertNotIn("PASS", str(ctx.exception))
543+
544+
# This "invalid" case is technically a valid URI:
545+
res = parse_uri("mongodb://user:1234/@localhost:27017")
546+
self.assertEqual([("user", 1234)], res["nodelist"])
547+
self.assertEqual("@localhost:27017", res["database"])
548+
549+
def test_port_with_whitespace(self):
550+
with self.assertRaisesRegex(ValueError, "Port contains whitespace character: ' '"):
551+
parse_uri("mongodb://localhost:27017 ")
552+
with self.assertRaisesRegex(ValueError, "Port contains whitespace character: ' '"):
553+
parse_uri("mongodb://localhost: 27017")
554+
with self.assertRaisesRegex(ValueError, r"Port contains whitespace character: '\\n'"):
555+
parse_uri("mongodb://localhost:27\n017")
556+
539557

540558
if __name__ == "__main__":
541559
unittest.main()

0 commit comments

Comments
 (0)