[Python-checkins] gh-94172: urllib.request avoids deprecated check_hostname (#94193)

vstinner webhook-mailer at python.org
Fri Jun 24 11:45:40 EDT 2022


https://github.com/python/cpython/commit/f0b234e6ed83e810bd9844e744f5e22aa538a356
commit: f0b234e6ed83e810bd9844e744f5e22aa538a356
branch: main
author: Victor Stinner <vstinner at python.org>
committer: vstinner <vstinner at python.org>
date: 2022-06-24T17:45:28+02:00
summary:

gh-94172: urllib.request avoids deprecated check_hostname (#94193)

The urllib.request no longer uses the deprecated check_hostname
parameter of the http.client module.

Add private http.client._create_https_context() helper to http.client,
used by urllib.request.

Remove the now redundant check on check_hostname and verify_mode in
http.client: the SSLContext.check_hostname setter already implements
the check.

files:
M Lib/http/client.py
M Lib/urllib/request.py

diff --git a/Lib/http/client.py b/Lib/http/client.py
index f54172fd0deea..4bef50e6474d4 100644
--- a/Lib/http/client.py
+++ b/Lib/http/client.py
@@ -786,6 +786,20 @@ def getcode(self):
         '''
         return self.status
 
+
+def _create_https_context(http_version):
+    # Function also used by urllib.request to be able to set the check_hostname
+    # attribute on a context object.
+    context = ssl._create_default_https_context()
+    # send ALPN extension to indicate HTTP/1.1 protocol
+    if http_version == 11:
+        context.set_alpn_protocols(['http/1.1'])
+    # enable PHA for TLS 1.3 connections if available
+    if context.post_handshake_auth is not None:
+        context.post_handshake_auth = True
+    return context
+
+
 class HTTPConnection:
 
     _http_vsn = 11
@@ -1418,19 +1432,9 @@ def __init__(self, host, port=None, key_file=None, cert_file=None,
             self.key_file = key_file
             self.cert_file = cert_file
             if context is None:
-                context = ssl._create_default_https_context()
-                # send ALPN extension to indicate HTTP/1.1 protocol
-                if self._http_vsn == 11:
-                    context.set_alpn_protocols(['http/1.1'])
-                # enable PHA for TLS 1.3 connections if available
-                if context.post_handshake_auth is not None:
-                    context.post_handshake_auth = True
-            will_verify = context.verify_mode != ssl.CERT_NONE
-            if check_hostname is None:
-                check_hostname = context.check_hostname
-            if check_hostname and not will_verify:
-                raise ValueError("check_hostname needs a SSL context with "
-                                 "either CERT_OPTIONAL or CERT_REQUIRED")
+                context = _create_https_context(self._http_vsn)
+            if check_hostname is not None:
+                context.check_hostname = check_hostname
             if key_file or cert_file:
                 context.load_cert_chain(cert_file, key_file)
                 # cert and key file means the user wants to authenticate.
@@ -1438,8 +1442,6 @@ def __init__(self, host, port=None, key_file=None, cert_file=None,
                 if context.post_handshake_auth is not None:
                     context.post_handshake_auth = True
             self._context = context
-            if check_hostname is not None:
-                self._context.check_hostname = check_hostname
 
         def connect(self):
             "Connect to a host on a given (SSL) port."
diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py
index c352fb25ae2bc..7878daacb52d0 100644
--- a/Lib/urllib/request.py
+++ b/Lib/urllib/request.py
@@ -1383,12 +1383,16 @@ class HTTPSHandler(AbstractHTTPHandler):
 
         def __init__(self, debuglevel=0, context=None, check_hostname=None):
             AbstractHTTPHandler.__init__(self, debuglevel)
+            if context is None:
+                http_version = http.client.HTTPSConnection._http_vsn
+                context = http.client._create_https_context(http_version)
+            if check_hostname is not None:
+                context.check_hostname = check_hostname
             self._context = context
-            self._check_hostname = check_hostname
 
         def https_open(self, req):
             return self.do_open(http.client.HTTPSConnection, req,
-                context=self._context, check_hostname=self._check_hostname)
+                                context=self._context)
 
         https_request = AbstractHTTPHandler.do_request_
 



More information about the Python-checkins mailing list