diff options
author | Ashwin Ramaswami <aramaswamis@gmail.com> | 2020-03-14 18:56:06 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-14 18:56:06 (GMT) |
commit | 9165addc22d05e776a54319a8531ebd0b2fe01ef (patch) | |
tree | 288869da768bf6c9c5c930bf50e58a36114b04e6 /Lib/test/test_urllib.py | |
parent | 6672c16b1d7f83789bf3a2016bd19edfd3568e71 (diff) | |
download | cpython-9165addc22d05e776a54319a8531ebd0b2fe01ef.zip cpython-9165addc22d05e776a54319a8531ebd0b2fe01ef.tar.gz cpython-9165addc22d05e776a54319a8531ebd0b2fe01ef.tar.bz2 |
bpo-38576: Disallow control characters in hostnames in http.client (GH-18995)
Add host validation for control characters for more CVE-2019-18348 protection.
Diffstat (limited to 'Lib/test/test_urllib.py')
-rw-r--r-- | Lib/test/test_urllib.py | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py index 2e82fc7..ebeb9a0 100644 --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -370,7 +370,7 @@ class urlopen_HttpTests(unittest.TestCase, FakeHTTPMixin, FakeFTPMixin): self.unfakehttp() @unittest.skipUnless(ssl, "ssl module required") - def test_url_with_control_char_rejected(self): + def test_url_path_with_control_char_rejected(self): for char_no in list(range(0, 0x21)) + [0x7f]: char = chr(char_no) schemeless_url = f"//localhost:7777/test{char}/" @@ -397,7 +397,7 @@ class urlopen_HttpTests(unittest.TestCase, FakeHTTPMixin, FakeFTPMixin): self.unfakehttp() @unittest.skipUnless(ssl, "ssl module required") - def test_url_with_newline_header_injection_rejected(self): + def test_url_path_with_newline_header_injection_rejected(self): self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello.") host = "localhost:7777?a=1 HTTP/1.1\r\nX-injected: header\r\nTEST: 123" schemeless_url = "//" + host + ":8080/test/?test=a" @@ -422,6 +422,38 @@ class urlopen_HttpTests(unittest.TestCase, FakeHTTPMixin, FakeFTPMixin): finally: self.unfakehttp() + @unittest.skipUnless(ssl, "ssl module required") + def test_url_host_with_control_char_rejected(self): + for char_no in list(range(0, 0x21)) + [0x7f]: + char = chr(char_no) + schemeless_url = f"//localhost{char}/test/" + self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello.") + try: + escaped_char_repr = repr(char).replace('\\', r'\\') + InvalidURL = http.client.InvalidURL + with self.assertRaisesRegex( + InvalidURL, f"contain control.*{escaped_char_repr}"): + urlopen(f"http:{schemeless_url}") + with self.assertRaisesRegex(InvalidURL, f"contain control.*{escaped_char_repr}"): + urlopen(f"https:{schemeless_url}") + finally: + self.unfakehttp() + + @unittest.skipUnless(ssl, "ssl module required") + def test_url_host_with_newline_header_injection_rejected(self): + self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello.") + host = "localhost\r\nX-injected: header\r\n" + schemeless_url = "//" + host + ":8080/test/?test=a" + try: + InvalidURL = http.client.InvalidURL + with self.assertRaisesRegex( + InvalidURL, r"contain control.*\\r"): + urlopen(f"http:{schemeless_url}") + with self.assertRaisesRegex(InvalidURL, r"contain control.*\\n"): + urlopen(f"https:{schemeless_url}") + finally: + self.unfakehttp() + def test_read_0_9(self): # "0.9" response accepted (but not "simple responses" without # a status line) |