give urllib.urlopen a context parameter (closes #22927)
diff --git a/Lib/httplib.py b/Lib/httplib.py
index 6d2e38d..48fbcb6 100644
--- a/Lib/httplib.py
+++ b/Lib/httplib.py
@@ -1238,14 +1238,15 @@
         _connection_class = HTTPSConnection
 
         def __init__(self, host='', port=None, key_file=None, cert_file=None,
-                     strict=None):
+                     strict=None, context=None):
             # provide a default host, pass the X509 cert info
 
             # urf. compensate for bad input.
             if port == 0:
                 port = None
             self._setup(self._connection_class(host, port, key_file,
-                                               cert_file, strict))
+                                               cert_file, strict,
+                                               context=context))
 
             # we never actually use these for anything, but we keep them
             # here for compatibility with post-1.5.2 CVS.
diff --git a/Lib/test/test_urllibnet.py b/Lib/test/test_urllibnet.py
index 9f24b7a..7c4b1f7 100644
--- a/Lib/test/test_urllibnet.py
+++ b/Lib/test/test_urllibnet.py
@@ -7,6 +7,15 @@
 import os
 import time
 
+try:
+    import ssl
+except ImportError:
+    ssl = None
+
+here = os.path.dirname(__file__)
+# Self-signed cert file for self-signed.pythontest.net
+CERT_selfsigned_pythontestdotnet = os.path.join(here, 'selfsigned_pythontestdotnet.pem')
+
 mimetools = test_support.import_module("mimetools", deprecated=True)
 
 
@@ -195,6 +204,14 @@
             self.fail('Date value not in %r format', dateformat)
 
 
+@unittest.skipIf(ssl is None, "requires ssl")
+class urlopen_HttpsTests(unittest.TestCase):
+
+    def test_context_argument(self):
+        context = ssl.create_default_context(cafile=CERT_selfsigned_pythontestdotnet)
+        response = urllib.urlopen("https://self-signed.pythontest.net", context=context)
+        self.assertIn("Python", response.read())
+
 
 def test_main():
     test_support.requires('network')
@@ -202,7 +219,8 @@
             ("urllib.urlopen.. has been removed", DeprecationWarning)):
         test_support.run_unittest(URLTimeoutTest,
                                   urlopenNetworkTests,
-                                  urlretrieveNetworkTests)
+                                  urlretrieveNetworkTests,
+                                  urlopen_HttpsTests)
 
 if __name__ == "__main__":
     test_main()
diff --git a/Lib/urllib.py b/Lib/urllib.py
index ac5d797..2408cb8 100644
--- a/Lib/urllib.py
+++ b/Lib/urllib.py
@@ -69,15 +69,15 @@
 
 # Shortcut for basic usage
 _urlopener = None
-def urlopen(url, data=None, proxies=None):
+def urlopen(url, data=None, proxies=None, context=None):
     """Create a file-like object for the specified URL to read from."""
     from warnings import warnpy3k
     warnpy3k("urllib.urlopen() has been removed in Python 3.0 in "
              "favor of urllib2.urlopen()", stacklevel=2)
 
     global _urlopener
-    if proxies is not None:
-        opener = FancyURLopener(proxies=proxies)
+    if proxies is not None or context is not None:
+        opener = FancyURLopener(proxies=proxies, context=context)
     elif not _urlopener:
         opener = FancyURLopener()
         _urlopener = opener
@@ -87,11 +87,15 @@
         return opener.open(url)
     else:
         return opener.open(url, data)
-def urlretrieve(url, filename=None, reporthook=None, data=None):
+def urlretrieve(url, filename=None, reporthook=None, data=None, context=None):
     global _urlopener
-    if not _urlopener:
-        _urlopener = FancyURLopener()
-    return _urlopener.retrieve(url, filename, reporthook, data)
+    if context is not None:
+        opener = FancyURLopener(context=context)
+    elif not _urlopener:
+        _urlopener = opener = FancyURLopener()
+    else:
+        opener = _urlopener
+    return opener.retrieve(url, filename, reporthook, data)
 def urlcleanup():
     if _urlopener:
         _urlopener.cleanup()
@@ -126,13 +130,14 @@
     version = "Python-urllib/%s" % __version__
 
     # Constructor
-    def __init__(self, proxies=None, **x509):
+    def __init__(self, proxies=None, context=None, **x509):
         if proxies is None:
             proxies = getproxies()
         assert hasattr(proxies, 'has_key'), "proxies must be a mapping"
         self.proxies = proxies
         self.key_file = x509.get('key_file')
         self.cert_file = x509.get('cert_file')
+        self.context = context
         self.addheaders = [('User-Agent', self.version)]
         self.__tempfiles = []
         self.__unlink = os.unlink # See cleanup()
@@ -422,7 +427,8 @@
                 auth = None
             h = httplib.HTTPS(host, 0,
                               key_file=self.key_file,
-                              cert_file=self.cert_file)
+                              cert_file=self.cert_file,
+                              context=self.context)
             if data is not None:
                 h.putrequest('POST', selector)
                 h.putheader('Content-Type',