Issue #17107: Test client-side SNI support in urllib.request thanks to the new server-side SNI support in the ssl module.
Initial patch by Daniel Black.
This commit is contained in:
parent
ca4220be1f
commit
da23259f99
|
@ -147,9 +147,11 @@ class HTTPSServerThread(threading.Thread):
|
|||
self.server.shutdown()
|
||||
|
||||
|
||||
def make_https_server(case, certfile=CERTFILE, host=HOST, handler_class=None):
|
||||
# we assume the certfile contains both private key and certificate
|
||||
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
|
||||
def make_https_server(case, *, context=None, certfile=CERTFILE,
|
||||
host=HOST, handler_class=None):
|
||||
if context is None:
|
||||
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
|
||||
# We assume the certfile contains both private key and certificate
|
||||
context.load_cert_chain(certfile)
|
||||
server = HTTPSServerThread(context, host, handler_class)
|
||||
flag = threading.Event()
|
||||
|
|
|
@ -703,7 +703,7 @@ class HTTPSTest(TestCase):
|
|||
|
||||
def make_server(self, certfile):
|
||||
from test.ssl_servers import make_https_server
|
||||
return make_https_server(self, certfile)
|
||||
return make_https_server(self, certfile=certfile)
|
||||
|
||||
def test_attributes(self):
|
||||
# simple test to check it's storing the timeout
|
||||
|
|
|
@ -1637,7 +1637,7 @@ else:
|
|||
|
||||
def test_socketserver(self):
|
||||
"""Using a SocketServer to create and manage SSL connections."""
|
||||
server = make_https_server(self, CERTFILE)
|
||||
server = make_https_server(self, certfile=CERTFILE)
|
||||
# try to connect
|
||||
if support.verbose:
|
||||
sys.stdout.write('\n')
|
||||
|
|
|
@ -9,7 +9,10 @@ import unittest
|
|||
import hashlib
|
||||
from test import support
|
||||
threading = support.import_module('threading')
|
||||
|
||||
try:
|
||||
import ssl
|
||||
except ImportError:
|
||||
ssl = None
|
||||
|
||||
here = os.path.dirname(__file__)
|
||||
# Self-signed cert file for 'localhost'
|
||||
|
@ -17,6 +20,7 @@ CERT_localhost = os.path.join(here, 'keycert.pem')
|
|||
# Self-signed cert file for 'fakehostname'
|
||||
CERT_fakehostname = os.path.join(here, 'keycert2.pem')
|
||||
|
||||
|
||||
# Loopback http server infrastructure
|
||||
|
||||
class LoopbackHttpServer(http.server.HTTPServer):
|
||||
|
@ -353,12 +357,15 @@ class TestUrlopen(unittest.TestCase):
|
|||
def setUp(self):
|
||||
super(TestUrlopen, self).setUp()
|
||||
# Ignore proxies for localhost tests.
|
||||
self.old_environ = os.environ.copy()
|
||||
os.environ['NO_PROXY'] = '*'
|
||||
self.server = None
|
||||
|
||||
def tearDown(self):
|
||||
if self.server is not None:
|
||||
self.server.stop()
|
||||
os.environ.clear()
|
||||
os.environ.update(self.old_environ)
|
||||
super(TestUrlopen, self).tearDown()
|
||||
|
||||
def urlopen(self, url, data=None, **kwargs):
|
||||
|
@ -386,14 +393,14 @@ class TestUrlopen(unittest.TestCase):
|
|||
handler.port = port
|
||||
return handler
|
||||
|
||||
def start_https_server(self, responses=None, certfile=CERT_localhost):
|
||||
def start_https_server(self, responses=None, **kwargs):
|
||||
if not hasattr(urllib.request, 'HTTPSHandler'):
|
||||
self.skipTest('ssl support required')
|
||||
from test.ssl_servers import make_https_server
|
||||
if responses is None:
|
||||
responses = [(200, [], b"we care a bit")]
|
||||
handler = GetRequestHandler(responses)
|
||||
server = make_https_server(self, certfile=certfile, handler_class=handler)
|
||||
server = make_https_server(self, handler_class=handler, **kwargs)
|
||||
handler.port = server.port
|
||||
return handler
|
||||
|
||||
|
@ -483,6 +490,21 @@ class TestUrlopen(unittest.TestCase):
|
|||
self.urlopen("https://localhost:%s/bizarre" % handler.port,
|
||||
cadefault=True)
|
||||
|
||||
def test_https_sni(self):
|
||||
if ssl is None:
|
||||
self.skipTest("ssl module required")
|
||||
if not ssl.HAS_SNI:
|
||||
self.skipTest("SNI support required in OpenSSL")
|
||||
sni_name = None
|
||||
def cb_sni(ssl_sock, server_name, initial_context):
|
||||
nonlocal sni_name
|
||||
sni_name = server_name
|
||||
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
|
||||
context.set_servername_callback(cb_sni)
|
||||
handler = self.start_https_server(context=context, certfile=CERT_localhost)
|
||||
self.urlopen("https://localhost:%s" % handler.port)
|
||||
self.assertEqual(sni_name, "localhost")
|
||||
|
||||
def test_sending_headers(self):
|
||||
handler = self.start_server()
|
||||
req = urllib.request.Request("http://localhost:%s/" % handler.port,
|
||||
|
|
|
@ -330,31 +330,9 @@ class TimeoutTest(unittest.TestCase):
|
|||
self.assertEqual(u.fp.fp.raw._sock.gettimeout(), 60)
|
||||
|
||||
|
||||
@unittest.skipUnless(ssl, "requires SSL support")
|
||||
class HTTPSTests(unittest.TestCase):
|
||||
|
||||
def test_sni(self):
|
||||
self.skipTest("test disabled - test server needed")
|
||||
# Checks that Server Name Indication works, if supported by the
|
||||
# OpenSSL linked to.
|
||||
# The ssl module itself doesn't have server-side support for SNI,
|
||||
# so we rely on a third-party test site.
|
||||
expect_sni = ssl.HAS_SNI
|
||||
with support.transient_internet("XXX"):
|
||||
u = urllib.request.urlopen("XXX")
|
||||
contents = u.readall()
|
||||
if expect_sni:
|
||||
self.assertIn(b"Great", contents)
|
||||
self.assertNotIn(b"Unfortunately", contents)
|
||||
else:
|
||||
self.assertNotIn(b"Great", contents)
|
||||
self.assertIn(b"Unfortunately", contents)
|
||||
|
||||
|
||||
def test_main():
|
||||
support.requires("network")
|
||||
support.run_unittest(AuthTests,
|
||||
HTTPSTests,
|
||||
OtherNetworkTests,
|
||||
CloseSocketTest,
|
||||
TimeoutTest,
|
||||
|
|
|
@ -754,6 +754,10 @@ Extension Modules
|
|||
Tests
|
||||
-----
|
||||
|
||||
- Issue #17107: Test client-side SNI support in urllib.request thanks to
|
||||
the new server-side SNI support in the ssl module. Initial patch by
|
||||
Daniel Black.
|
||||
|
||||
- Issue #17041: Fix testing when Python is configured with the
|
||||
--without-doc-strings.
|
||||
|
||||
|
|
Loading…
Reference in New Issue