diff --git a/tornado/httputil.py b/tornado/httputil.py index 4bd17786d..4fc12da38 100644 --- a/tornado/httputil.py +++ b/tornado/httputil.py @@ -1321,6 +1321,8 @@ def split_host_and_port(netloc: str) -> tuple[str, int | None]: if match: host = match.group(1) port: int | None = int(match.group(2)) + if port < 0 or port > 65535: + raise HTTPInputError("Invalid port number %r" % port) else: host = netloc port = None diff --git a/tornado/test/httputil_test.py b/tornado/test/httputil_test.py index 4e966eb50..a427bcc8e 100644 --- a/tornado/test/httputil_test.py +++ b/tornado/test/httputil_test.py @@ -19,6 +19,7 @@ parse_multipart_form_data, parse_request_start_line, qs_to_qsl, + split_host_and_port, url_concat, ) from tornado.log import gen_log @@ -623,6 +624,33 @@ def test_parse_request_start_line(self): self.assertEqual(parsed_start_line.version, self.VERSION) +class SplitHostAndPortTest(unittest.TestCase): + def test_host_only(self): + # No colon -> port is None and the whole netloc is the host. + self.assertEqual(split_host_and_port("example.com"), ("example.com", None)) + + def test_host_and_port(self): + self.assertEqual( + split_host_and_port("example.com:8080"), ("example.com", 8080) + ) + + def test_port_at_upper_bound(self): + # 65535 is the highest legal TCP port and must be accepted. + self.assertEqual(split_host_and_port("example.com:65535"), ("example.com", 65535)) + + def test_port_at_lower_bound(self): + # 0 is reserved but is still a valid integer in the port slot. + self.assertEqual(split_host_and_port("example.com:0"), ("example.com", 0)) + + def test_port_above_max_raises(self): + # Anything > 65535 is not a valid TCP port and must raise. + for port in (65536, 70000, 100000): + with self.subTest(port=port): + with self.assertRaises(HTTPInputError) as cm: + split_host_and_port(f"example.com:{port}") + self.assertIn(str(port), str(cm.exception)) + + class ParseCookieTest(unittest.TestCase): # These tests copied from Django: # https://github.com/django/django/pull/6277/commits/da810901ada1cae9fc1f018f879f11a7fb467b28