We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
conn.close() can raise OpenSSL exception after idle timeout
When returning a connection to the pool, urllib3 calls `conn.close()`:

```
        if conn and is_connection_dropped(conn):
            log.info("Resetting dropped connection: %s" % self.host)
            conn.close()
```

This can raise an exception under the following conditions:
- urllib3 is using pyOpenSSL and https
- Remote webserver is running Windows IIS (7.5 and 8 tested)
- KeepAlives are active (default for IIS)
- Connection drops after idle timeout

tcpdump shows that the remote IIS host sends a RST on idle timeout. This appears to be IIS-specific behaviour (Apache2 and haproxy both close the connection normally)

At that point nothing bad happens immediately. However the connection remains in the pool. The next time you send a request to this host, it is reused; some data is sent down it; this then raises an `OpenSSL.SSL.SysCallError` exception. I am guessing that it it is trying to send an SSL shutdown message down the already-closed socket.

More detail at https://github.com/zatosource/zato/issues/465

Proposed patch:

```
--- a/urllib3/connectionpool.py
+++ b/urllib3/connectionpool.py
@@ -239,11 +239,15 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
         # If this is a persistent connection, check if it got disconnected
         if conn and is_connection_dropped(conn):
             log.info("Resetting dropped connection: %s" % self.host)
-            conn.close()
-            if getattr(conn, 'auto_open', 1) == 0:
-                # This is a proxied connection that has been mutated by
-                # httplib._tunnel() and cannot be reused (since it would
-                # attempt to bypass the proxy)
+            try:
+                conn.close()
+                if getattr(conn, 'auto_open', 1) == 0:
+                    # This is a proxied connection that has been mutated by
+                    # httplib._tunnel() and cannot be reused (since it would
+                    # attempt to bypass the proxy)
+                    conn = None
+            except Exception as e:
+                log.info("Closing connection failed: %s, force new connection" % str(e))
                 conn = None

         return conn or self._new_conn()
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `urllib3/contrib/pyopenssl.py`
Content:
```
1 '''SSL with SNI_-support for Python 2. Follow these instructions if you would
2 like to verify SSL certificates in Python 2. Note, the default libraries do
3 *not* do certificate checking; you need to do additional work to validate
4 certificates yourself.
5 
6 This needs the following packages installed:
7 
8 * pyOpenSSL (tested with 0.13)
9 * ndg-httpsclient (tested with 0.3.2)
10 * pyasn1 (tested with 0.1.6)
11 
12 You can install them with the following command:
13 
14     pip install pyopenssl ndg-httpsclient pyasn1
15 
16 To activate certificate checking, call
17 :func:`~urllib3.contrib.pyopenssl.inject_into_urllib3` from your Python code
18 before you begin making HTTP requests. This can be done in a ``sitecustomize``
19 module, or at any other time before your application begins using ``urllib3``,
20 like this::
21 
22     try:
23         import urllib3.contrib.pyopenssl
24         urllib3.contrib.pyopenssl.inject_into_urllib3()
25     except ImportError:
26         pass
27 
28 Now you can use :mod:`urllib3` as you normally would, and it will support SNI
29 when the required modules are installed.
30 
31 Activating this module also has the positive side effect of disabling SSL/TLS
32 compression in Python 2 (see `CRIME attack`_).
33 
34 If you want to configure the default list of supported cipher suites, you can
35 set the ``urllib3.contrib.pyopenssl.DEFAULT_SSL_CIPHER_LIST`` variable.
36 
37 Module Variables
38 ----------------
39 
40 :var DEFAULT_SSL_CIPHER_LIST: The list of supported SSL/TLS cipher suites.
41 
42 .. _sni: https://en.wikipedia.org/wiki/Server_Name_Indication
43 .. _crime attack: https://en.wikipedia.org/wiki/CRIME_(security_exploit)
44 
45 '''
46 
47 try:
48     from ndg.httpsclient.ssl_peer_verification import SUBJ_ALT_NAME_SUPPORT
49     from ndg.httpsclient.subj_alt_name import SubjectAltName as BaseSubjectAltName
50 except SyntaxError as e:
51     raise ImportError(e)
52 
53 import OpenSSL.SSL
54 from pyasn1.codec.der import decoder as der_decoder
55 from pyasn1.type import univ, constraint
56 from socket import _fileobject, timeout
57 import ssl
58 import select
59 
60 from .. import connection
61 from .. import util
62 
63 __all__ = ['inject_into_urllib3', 'extract_from_urllib3']
64 
65 # SNI only *really* works if we can read the subjectAltName of certificates.
66 HAS_SNI = SUBJ_ALT_NAME_SUPPORT
67 
68 # Map from urllib3 to PyOpenSSL compatible parameter-values.
69 _openssl_versions = {
70     ssl.PROTOCOL_SSLv23: OpenSSL.SSL.SSLv23_METHOD,
71     ssl.PROTOCOL_TLSv1: OpenSSL.SSL.TLSv1_METHOD,
72 }
73 
74 try:
75     _openssl_versions.update({ssl.PROTOCOL_SSLv3: OpenSSL.SSL.SSLv3_METHOD})
76 except AttributeError:
77     pass
78 
79 _openssl_verify = {
80     ssl.CERT_NONE: OpenSSL.SSL.VERIFY_NONE,
81     ssl.CERT_OPTIONAL: OpenSSL.SSL.VERIFY_PEER,
82     ssl.CERT_REQUIRED: OpenSSL.SSL.VERIFY_PEER
83                        + OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
84 }
85 
86 DEFAULT_SSL_CIPHER_LIST = util.ssl_.DEFAULT_CIPHERS
87 
88 # OpenSSL will only write 16K at a time
89 SSL_WRITE_BLOCKSIZE = 16384
90 
91 orig_util_HAS_SNI = util.HAS_SNI
92 orig_connection_ssl_wrap_socket = connection.ssl_wrap_socket
93 
94 
95 def inject_into_urllib3():
96     'Monkey-patch urllib3 with PyOpenSSL-backed SSL-support.'
97 
98     connection.ssl_wrap_socket = ssl_wrap_socket
99     util.HAS_SNI = HAS_SNI
100 
101 
102 def extract_from_urllib3():
103     'Undo monkey-patching by :func:`inject_into_urllib3`.'
104 
105     connection.ssl_wrap_socket = orig_connection_ssl_wrap_socket
106     util.HAS_SNI = orig_util_HAS_SNI
107 
108 
109 ### Note: This is a slightly bug-fixed version of same from ndg-httpsclient.
110 class SubjectAltName(BaseSubjectAltName):
111     '''ASN.1 implementation for subjectAltNames support'''
112 
113     # There is no limit to how many SAN certificates a certificate may have,
114     #   however this needs to have some limit so we'll set an arbitrarily high
115     #   limit.
116     sizeSpec = univ.SequenceOf.sizeSpec + \
117         constraint.ValueSizeConstraint(1, 1024)
118 
119 
120 ### Note: This is a slightly bug-fixed version of same from ndg-httpsclient.
121 def get_subj_alt_name(peer_cert):
122     # Search through extensions
123     dns_name = []
124     if not SUBJ_ALT_NAME_SUPPORT:
125         return dns_name
126 
127     general_names = SubjectAltName()
128     for i in range(peer_cert.get_extension_count()):
129         ext = peer_cert.get_extension(i)
130         ext_name = ext.get_short_name()
131         if ext_name != 'subjectAltName':
132             continue
133 
134         # PyOpenSSL returns extension data in ASN.1 encoded form
135         ext_dat = ext.get_data()
136         decoded_dat = der_decoder.decode(ext_dat,
137                                          asn1Spec=general_names)
138 
139         for name in decoded_dat:
140             if not isinstance(name, SubjectAltName):
141                 continue
142             for entry in range(len(name)):
143                 component = name.getComponentByPosition(entry)
144                 if component.getName() != 'dNSName':
145                     continue
146                 dns_name.append(str(component.getComponent()))
147 
148     return dns_name
149 
150 
151 class WrappedSocket(object):
152     '''API-compatibility wrapper for Python OpenSSL's Connection-class.
153 
154     Note: _makefile_refs, _drop() and _reuse() are needed for the garbage
155     collector of pypy.
156     '''
157 
158     def __init__(self, connection, socket, suppress_ragged_eofs=True):
159         self.connection = connection
160         self.socket = socket
161         self.suppress_ragged_eofs = suppress_ragged_eofs
162         self._makefile_refs = 0
163 
164     def fileno(self):
165         return self.socket.fileno()
166 
167     def makefile(self, mode, bufsize=-1):
168         self._makefile_refs += 1
169         return _fileobject(self, mode, bufsize, close=True)
170 
171     def recv(self, *args, **kwargs):
172         try:
173             data = self.connection.recv(*args, **kwargs)
174         except OpenSSL.SSL.SysCallError as e:
175             if self.suppress_ragged_eofs and e.args == (-1, 'Unexpected EOF'):
176                 return b''
177             else:
178                 raise
179         except OpenSSL.SSL.ZeroReturnError as e:
180             if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN:
181                 return b''
182             else:
183                 raise
184         except OpenSSL.SSL.WantReadError:
185             rd, wd, ed = select.select(
186                 [self.socket], [], [], self.socket.gettimeout())
187             if not rd:
188                 raise timeout('The read operation timed out')
189             else:
190                 return self.recv(*args, **kwargs)
191         else:
192             return data
193 
194     def settimeout(self, timeout):
195         return self.socket.settimeout(timeout)
196 
197     def _send_until_done(self, data):
198         while True:
199             try:
200                 return self.connection.send(data)
201             except OpenSSL.SSL.WantWriteError:
202                 _, wlist, _ = select.select([], [self.socket], [],
203                                             self.socket.gettimeout())
204                 if not wlist:
205                     raise timeout()
206                 continue
207 
208     def sendall(self, data):
209         total_sent = 0
210         while total_sent < len(data):
211             sent = self._send_until_done(data[total_sent:total_sent+SSL_WRITE_BLOCKSIZE])
212             total_sent += sent
213 
214     def shutdown(self):
215         # FIXME rethrow compatible exceptions should we ever use this
216         self.connection.shutdown()
217 
218     def close(self):
219         if self._makefile_refs < 1:
220             return self.connection.close()
221         else:
222             self._makefile_refs -= 1
223 
224     def getpeercert(self, binary_form=False):
225         x509 = self.connection.get_peer_certificate()
226 
227         if not x509:
228             return x509
229 
230         if binary_form:
231             return OpenSSL.crypto.dump_certificate(
232                 OpenSSL.crypto.FILETYPE_ASN1,
233                 x509)
234 
235         return {
236             'subject': (
237                 (('commonName', x509.get_subject().CN),),
238             ),
239             'subjectAltName': [
240                 ('DNS', value)
241                 for value in get_subj_alt_name(x509)
242             ]
243         }
244 
245     def _reuse(self):
246         self._makefile_refs += 1
247 
248     def _drop(self):
249         if self._makefile_refs < 1:
250             self.close()
251         else:
252             self._makefile_refs -= 1
253 
254 
255 def _verify_callback(cnx, x509, err_no, err_depth, return_code):
256     return err_no == 0
257 
258 
259 def ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None,
260                     ca_certs=None, server_hostname=None,
261                     ssl_version=None, ca_cert_dir=None):
262     ctx = OpenSSL.SSL.Context(_openssl_versions[ssl_version])
263     if certfile:
264         keyfile = keyfile or certfile  # Match behaviour of the normal python ssl library
265         ctx.use_certificate_file(certfile)
266     if keyfile:
267         ctx.use_privatekey_file(keyfile)
268     if cert_reqs != ssl.CERT_NONE:
269         ctx.set_verify(_openssl_verify[cert_reqs], _verify_callback)
270     if ca_certs or ca_cert_dir:
271         try:
272             ctx.load_verify_locations(ca_certs, ca_cert_dir)
273         except OpenSSL.SSL.Error as e:
274             raise ssl.SSLError('bad ca_certs: %r' % ca_certs, e)
275     else:
276         ctx.set_default_verify_paths()
277 
278     # Disable TLS compression to migitate CRIME attack (issue #309)
279     OP_NO_COMPRESSION = 0x20000
280     ctx.set_options(OP_NO_COMPRESSION)
281 
282     # Set list of supported ciphersuites.
283     ctx.set_cipher_list(DEFAULT_SSL_CIPHER_LIST)
284 
285     cnx = OpenSSL.SSL.Connection(ctx, sock)
286     cnx.set_tlsext_host_name(server_hostname)
287     cnx.set_connect_state()
288     while True:
289         try:
290             cnx.do_handshake()
291         except OpenSSL.SSL.WantReadError:
292             rd, _, _ = select.select([sock], [], [], sock.gettimeout())
293             if not rd:
294                 raise timeout('select timed out')
295             continue
296         except OpenSSL.SSL.Error as e:
297             raise ssl.SSLError('bad handshake: %r' % e)
298         break
299 
300     return WrappedSocket(cnx, sock)
301
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/urllib3/contrib/pyopenssl.py b/urllib3/contrib/pyopenssl.py
--- a/urllib3/contrib/pyopenssl.py
+++ b/urllib3/contrib/pyopenssl.py
@@ -217,7 +217,10 @@
 
     def close(self):
         if self._makefile_refs < 1:
-            return self.connection.close()
+            try:
+                return self.connection.close()
+            except OpenSSL.SSL.Error:
+                return
         else:
             self._makefile_refs -= 1

{"golden_diff": "diff --git a/urllib3/contrib/pyopenssl.py b/urllib3/contrib/pyopenssl.py\n--- a/urllib3/contrib/pyopenssl.py\n+++ b/urllib3/contrib/pyopenssl.py\n@@ -217,7 +217,10 @@\n \n     def close(self):\n         if self._makefile_refs < 1:\n-            return self.connection.close()\n+            try:\n+                return self.connection.close()\n+            except OpenSSL.SSL.Error:\n+                return\n         else:\n             self._makefile_refs -= 1\n", "issue": "conn.close() can raise OpenSSL exception after idle timeout\nWhen returning a connection to the pool, urllib3 calls `conn.close()`:\n\n```\n        if conn and is_connection_dropped(conn):\n            log.info(\"Resetting dropped connection: %s\" % self.host)\n            conn.close()\n```\n\nThis can raise an exception under the following conditions:\n- urllib3 is using pyOpenSSL and https\n- Remote webserver is running Windows IIS (7.5 and 8 tested)\n- KeepAlives are active (default for IIS)\n- Connection drops after idle timeout\n\ntcpdump shows that the remote IIS host sends a RST on idle timeout. This appears to be IIS-specific behaviour (Apache2 and haproxy both close the connection normally)\n\nAt that point nothing bad happens immediately. However the connection remains in the pool. The next time you send a request to this host, it is reused; some data is sent down it; this then raises an `OpenSSL.SSL.SysCallError` exception. I am guessing that it it is trying to send an SSL shutdown message down the already-closed socket.\n\nMore detail at https://github.com/zatosource/zato/issues/465\n\nProposed patch:\n\n```\n--- a/urllib3/connectionpool.py\n+++ b/urllib3/connectionpool.py\n@@ -239,11 +239,15 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):\n         # If this is a persistent connection, check if it got disconnected\n         if conn and is_connection_dropped(conn):\n             log.info(\"Resetting dropped connection: %s\" % self.host)\n-            conn.close()\n-            if getattr(conn, 'auto_open', 1) == 0:\n-                # This is a proxied connection that has been mutated by\n-                # httplib._tunnel() and cannot be reused (since it would\n-                # attempt to bypass the proxy)\n+            try:\n+                conn.close()\n+                if getattr(conn, 'auto_open', 1) == 0:\n+                    # This is a proxied connection that has been mutated by\n+                    # httplib._tunnel() and cannot be reused (since it would\n+                    # attempt to bypass the proxy)\n+                    conn = None\n+            except Exception as e:\n+                log.info(\"Closing connection failed: %s, force new connection\" % str(e))\n                 conn = None\n\n         return conn or self._new_conn()\n```\n\n", "before_files": [{"content": "'''SSL with SNI_-support for Python 2. Follow these instructions if you would\nlike to verify SSL certificates in Python 2. Note, the default libraries do\n*not* do certificate checking; you need to do additional work to validate\ncertificates yourself.\n\nThis needs the following packages installed:\n\n* pyOpenSSL (tested with 0.13)\n* ndg-httpsclient (tested with 0.3.2)\n* pyasn1 (tested with 0.1.6)\n\nYou can install them with the following command:\n\n    pip install pyopenssl ndg-httpsclient pyasn1\n\nTo activate certificate checking, call\n:func:`~urllib3.contrib.pyopenssl.inject_into_urllib3` from your Python code\nbefore you begin making HTTP requests. This can be done in a ``sitecustomize``\nmodule, or at any other time before your application begins using ``urllib3``,\nlike this::\n\n    try:\n        import urllib3.contrib.pyopenssl\n        urllib3.contrib.pyopenssl.inject_into_urllib3()\n    except ImportError:\n        pass\n\nNow you can use :mod:`urllib3` as you normally would, and it will support SNI\nwhen the required modules are installed.\n\nActivating this module also has the positive side effect of disabling SSL/TLS\ncompression in Python 2 (see `CRIME attack`_).\n\nIf you want to configure the default list of supported cipher suites, you can\nset the ``urllib3.contrib.pyopenssl.DEFAULT_SSL_CIPHER_LIST`` variable.\n\nModule Variables\n----------------\n\n:var DEFAULT_SSL_CIPHER_LIST: The list of supported SSL/TLS cipher suites.\n\n.. _sni: https://en.wikipedia.org/wiki/Server_Name_Indication\n.. _crime attack: https://en.wikipedia.org/wiki/CRIME_(security_exploit)\n\n'''\n\ntry:\n    from ndg.httpsclient.ssl_peer_verification import SUBJ_ALT_NAME_SUPPORT\n    from ndg.httpsclient.subj_alt_name import SubjectAltName as BaseSubjectAltName\nexcept SyntaxError as e:\n    raise ImportError(e)\n\nimport OpenSSL.SSL\nfrom pyasn1.codec.der import decoder as der_decoder\nfrom pyasn1.type import univ, constraint\nfrom socket import _fileobject, timeout\nimport ssl\nimport select\n\nfrom .. import connection\nfrom .. import util\n\n__all__ = ['inject_into_urllib3', 'extract_from_urllib3']\n\n# SNI only *really* works if we can read the subjectAltName of certificates.\nHAS_SNI = SUBJ_ALT_NAME_SUPPORT\n\n# Map from urllib3 to PyOpenSSL compatible parameter-values.\n_openssl_versions = {\n    ssl.PROTOCOL_SSLv23: OpenSSL.SSL.SSLv23_METHOD,\n    ssl.PROTOCOL_TLSv1: OpenSSL.SSL.TLSv1_METHOD,\n}\n\ntry:\n    _openssl_versions.update({ssl.PROTOCOL_SSLv3: OpenSSL.SSL.SSLv3_METHOD})\nexcept AttributeError:\n    pass\n\n_openssl_verify = {\n    ssl.CERT_NONE: OpenSSL.SSL.VERIFY_NONE,\n    ssl.CERT_OPTIONAL: OpenSSL.SSL.VERIFY_PEER,\n    ssl.CERT_REQUIRED: OpenSSL.SSL.VERIFY_PEER\n                       + OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,\n}\n\nDEFAULT_SSL_CIPHER_LIST = util.ssl_.DEFAULT_CIPHERS\n\n# OpenSSL will only write 16K at a time\nSSL_WRITE_BLOCKSIZE = 16384\n\norig_util_HAS_SNI = util.HAS_SNI\norig_connection_ssl_wrap_socket = connection.ssl_wrap_socket\n\n\ndef inject_into_urllib3():\n    'Monkey-patch urllib3 with PyOpenSSL-backed SSL-support.'\n\n    connection.ssl_wrap_socket = ssl_wrap_socket\n    util.HAS_SNI = HAS_SNI\n\n\ndef extract_from_urllib3():\n    'Undo monkey-patching by :func:`inject_into_urllib3`.'\n\n    connection.ssl_wrap_socket = orig_connection_ssl_wrap_socket\n    util.HAS_SNI = orig_util_HAS_SNI\n\n\n### Note: This is a slightly bug-fixed version of same from ndg-httpsclient.\nclass SubjectAltName(BaseSubjectAltName):\n    '''ASN.1 implementation for subjectAltNames support'''\n\n    # There is no limit to how many SAN certificates a certificate may have,\n    #   however this needs to have some limit so we'll set an arbitrarily high\n    #   limit.\n    sizeSpec = univ.SequenceOf.sizeSpec + \\\n        constraint.ValueSizeConstraint(1, 1024)\n\n\n### Note: This is a slightly bug-fixed version of same from ndg-httpsclient.\ndef get_subj_alt_name(peer_cert):\n    # Search through extensions\n    dns_name = []\n    if not SUBJ_ALT_NAME_SUPPORT:\n        return dns_name\n\n    general_names = SubjectAltName()\n    for i in range(peer_cert.get_extension_count()):\n        ext = peer_cert.get_extension(i)\n        ext_name = ext.get_short_name()\n        if ext_name != 'subjectAltName':\n            continue\n\n        # PyOpenSSL returns extension data in ASN.1 encoded form\n        ext_dat = ext.get_data()\n        decoded_dat = der_decoder.decode(ext_dat,\n                                         asn1Spec=general_names)\n\n        for name in decoded_dat:\n            if not isinstance(name, SubjectAltName):\n                continue\n            for entry in range(len(name)):\n                component = name.getComponentByPosition(entry)\n                if component.getName() != 'dNSName':\n                    continue\n                dns_name.append(str(component.getComponent()))\n\n    return dns_name\n\n\nclass WrappedSocket(object):\n    '''API-compatibility wrapper for Python OpenSSL's Connection-class.\n\n    Note: _makefile_refs, _drop() and _reuse() are needed for the garbage\n    collector of pypy.\n    '''\n\n    def __init__(self, connection, socket, suppress_ragged_eofs=True):\n        self.connection = connection\n        self.socket = socket\n        self.suppress_ragged_eofs = suppress_ragged_eofs\n        self._makefile_refs = 0\n\n    def fileno(self):\n        return self.socket.fileno()\n\n    def makefile(self, mode, bufsize=-1):\n        self._makefile_refs += 1\n        return _fileobject(self, mode, bufsize, close=True)\n\n    def recv(self, *args, **kwargs):\n        try:\n            data = self.connection.recv(*args, **kwargs)\n        except OpenSSL.SSL.SysCallError as e:\n            if self.suppress_ragged_eofs and e.args == (-1, 'Unexpected EOF'):\n                return b''\n            else:\n                raise\n        except OpenSSL.SSL.ZeroReturnError as e:\n            if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN:\n                return b''\n            else:\n                raise\n        except OpenSSL.SSL.WantReadError:\n            rd, wd, ed = select.select(\n                [self.socket], [], [], self.socket.gettimeout())\n            if not rd:\n                raise timeout('The read operation timed out')\n            else:\n                return self.recv(*args, **kwargs)\n        else:\n            return data\n\n    def settimeout(self, timeout):\n        return self.socket.settimeout(timeout)\n\n    def _send_until_done(self, data):\n        while True:\n            try:\n                return self.connection.send(data)\n            except OpenSSL.SSL.WantWriteError:\n                _, wlist, _ = select.select([], [self.socket], [],\n                                            self.socket.gettimeout())\n                if not wlist:\n                    raise timeout()\n                continue\n\n    def sendall(self, data):\n        total_sent = 0\n        while total_sent < len(data):\n            sent = self._send_until_done(data[total_sent:total_sent+SSL_WRITE_BLOCKSIZE])\n            total_sent += sent\n\n    def shutdown(self):\n        # FIXME rethrow compatible exceptions should we ever use this\n        self.connection.shutdown()\n\n    def close(self):\n        if self._makefile_refs < 1:\n            return self.connection.close()\n        else:\n            self._makefile_refs -= 1\n\n    def getpeercert(self, binary_form=False):\n        x509 = self.connection.get_peer_certificate()\n\n        if not x509:\n            return x509\n\n        if binary_form:\n            return OpenSSL.crypto.dump_certificate(\n                OpenSSL.crypto.FILETYPE_ASN1,\n                x509)\n\n        return {\n            'subject': (\n                (('commonName', x509.get_subject().CN),),\n            ),\n            'subjectAltName': [\n                ('DNS', value)\n                for value in get_subj_alt_name(x509)\n            ]\n        }\n\n    def _reuse(self):\n        self._makefile_refs += 1\n\n    def _drop(self):\n        if self._makefile_refs < 1:\n            self.close()\n        else:\n            self._makefile_refs -= 1\n\n\ndef _verify_callback(cnx, x509, err_no, err_depth, return_code):\n    return err_no == 0\n\n\ndef ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None,\n                    ca_certs=None, server_hostname=None,\n                    ssl_version=None, ca_cert_dir=None):\n    ctx = OpenSSL.SSL.Context(_openssl_versions[ssl_version])\n    if certfile:\n        keyfile = keyfile or certfile  # Match behaviour of the normal python ssl library\n        ctx.use_certificate_file(certfile)\n    if keyfile:\n        ctx.use_privatekey_file(keyfile)\n    if cert_reqs != ssl.CERT_NONE:\n        ctx.set_verify(_openssl_verify[cert_reqs], _verify_callback)\n    if ca_certs or ca_cert_dir:\n        try:\n            ctx.load_verify_locations(ca_certs, ca_cert_dir)\n        except OpenSSL.SSL.Error as e:\n            raise ssl.SSLError('bad ca_certs: %r' % ca_certs, e)\n    else:\n        ctx.set_default_verify_paths()\n\n    # Disable TLS compression to migitate CRIME attack (issue #309)\n    OP_NO_COMPRESSION = 0x20000\n    ctx.set_options(OP_NO_COMPRESSION)\n\n    # Set list of supported ciphersuites.\n    ctx.set_cipher_list(DEFAULT_SSL_CIPHER_LIST)\n\n    cnx = OpenSSL.SSL.Connection(ctx, sock)\n    cnx.set_tlsext_host_name(server_hostname)\n    cnx.set_connect_state()\n    while True:\n        try:\n            cnx.do_handshake()\n        except OpenSSL.SSL.WantReadError:\n            rd, _, _ = select.select([sock], [], [], sock.gettimeout())\n            if not rd:\n                raise timeout('select timed out')\n            continue\n        except OpenSSL.SSL.Error as e:\n            raise ssl.SSLError('bad handshake: %r' % e)\n        break\n\n    return WrappedSocket(cnx, sock)\n", "path": "urllib3/contrib/pyopenssl.py"}], "after_files": [{"content": "'''SSL with SNI_-support for Python 2. Follow these instructions if you would\nlike to verify SSL certificates in Python 2. Note, the default libraries do\n*not* do certificate checking; you need to do additional work to validate\ncertificates yourself.\n\nThis needs the following packages installed:\n\n* pyOpenSSL (tested with 0.13)\n* ndg-httpsclient (tested with 0.3.2)\n* pyasn1 (tested with 0.1.6)\n\nYou can install them with the following command:\n\n    pip install pyopenssl ndg-httpsclient pyasn1\n\nTo activate certificate checking, call\n:func:`~urllib3.contrib.pyopenssl.inject_into_urllib3` from your Python code\nbefore you begin making HTTP requests. This can be done in a ``sitecustomize``\nmodule, or at any other time before your application begins using ``urllib3``,\nlike this::\n\n    try:\n        import urllib3.contrib.pyopenssl\n        urllib3.contrib.pyopenssl.inject_into_urllib3()\n    except ImportError:\n        pass\n\nNow you can use :mod:`urllib3` as you normally would, and it will support SNI\nwhen the required modules are installed.\n\nActivating this module also has the positive side effect of disabling SSL/TLS\ncompression in Python 2 (see `CRIME attack`_).\n\nIf you want to configure the default list of supported cipher suites, you can\nset the ``urllib3.contrib.pyopenssl.DEFAULT_SSL_CIPHER_LIST`` variable.\n\nModule Variables\n----------------\n\n:var DEFAULT_SSL_CIPHER_LIST: The list of supported SSL/TLS cipher suites.\n\n.. _sni: https://en.wikipedia.org/wiki/Server_Name_Indication\n.. _crime attack: https://en.wikipedia.org/wiki/CRIME_(security_exploit)\n\n'''\n\ntry:\n    from ndg.httpsclient.ssl_peer_verification import SUBJ_ALT_NAME_SUPPORT\n    from ndg.httpsclient.subj_alt_name import SubjectAltName as BaseSubjectAltName\nexcept SyntaxError as e:\n    raise ImportError(e)\n\nimport OpenSSL.SSL\nfrom pyasn1.codec.der import decoder as der_decoder\nfrom pyasn1.type import univ, constraint\nfrom socket import _fileobject, timeout\nimport ssl\nimport select\n\nfrom .. import connection\nfrom .. import util\n\n__all__ = ['inject_into_urllib3', 'extract_from_urllib3']\n\n# SNI only *really* works if we can read the subjectAltName of certificates.\nHAS_SNI = SUBJ_ALT_NAME_SUPPORT\n\n# Map from urllib3 to PyOpenSSL compatible parameter-values.\n_openssl_versions = {\n    ssl.PROTOCOL_SSLv23: OpenSSL.SSL.SSLv23_METHOD,\n    ssl.PROTOCOL_TLSv1: OpenSSL.SSL.TLSv1_METHOD,\n}\n\ntry:\n    _openssl_versions.update({ssl.PROTOCOL_SSLv3: OpenSSL.SSL.SSLv3_METHOD})\nexcept AttributeError:\n    pass\n\n_openssl_verify = {\n    ssl.CERT_NONE: OpenSSL.SSL.VERIFY_NONE,\n    ssl.CERT_OPTIONAL: OpenSSL.SSL.VERIFY_PEER,\n    ssl.CERT_REQUIRED: OpenSSL.SSL.VERIFY_PEER\n                       + OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,\n}\n\nDEFAULT_SSL_CIPHER_LIST = util.ssl_.DEFAULT_CIPHERS\n\n# OpenSSL will only write 16K at a time\nSSL_WRITE_BLOCKSIZE = 16384\n\norig_util_HAS_SNI = util.HAS_SNI\norig_connection_ssl_wrap_socket = connection.ssl_wrap_socket\n\n\ndef inject_into_urllib3():\n    'Monkey-patch urllib3 with PyOpenSSL-backed SSL-support.'\n\n    connection.ssl_wrap_socket = ssl_wrap_socket\n    util.HAS_SNI = HAS_SNI\n\n\ndef extract_from_urllib3():\n    'Undo monkey-patching by :func:`inject_into_urllib3`.'\n\n    connection.ssl_wrap_socket = orig_connection_ssl_wrap_socket\n    util.HAS_SNI = orig_util_HAS_SNI\n\n\n### Note: This is a slightly bug-fixed version of same from ndg-httpsclient.\nclass SubjectAltName(BaseSubjectAltName):\n    '''ASN.1 implementation for subjectAltNames support'''\n\n    # There is no limit to how many SAN certificates a certificate may have,\n    #   however this needs to have some limit so we'll set an arbitrarily high\n    #   limit.\n    sizeSpec = univ.SequenceOf.sizeSpec + \\\n        constraint.ValueSizeConstraint(1, 1024)\n\n\n### Note: This is a slightly bug-fixed version of same from ndg-httpsclient.\ndef get_subj_alt_name(peer_cert):\n    # Search through extensions\n    dns_name = []\n    if not SUBJ_ALT_NAME_SUPPORT:\n        return dns_name\n\n    general_names = SubjectAltName()\n    for i in range(peer_cert.get_extension_count()):\n        ext = peer_cert.get_extension(i)\n        ext_name = ext.get_short_name()\n        if ext_name != 'subjectAltName':\n            continue\n\n        # PyOpenSSL returns extension data in ASN.1 encoded form\n        ext_dat = ext.get_data()\n        decoded_dat = der_decoder.decode(ext_dat,\n                                         asn1Spec=general_names)\n\n        for name in decoded_dat:\n            if not isinstance(name, SubjectAltName):\n                continue\n            for entry in range(len(name)):\n                component = name.getComponentByPosition(entry)\n                if component.getName() != 'dNSName':\n                    continue\n                dns_name.append(str(component.getComponent()))\n\n    return dns_name\n\n\nclass WrappedSocket(object):\n    '''API-compatibility wrapper for Python OpenSSL's Connection-class.\n\n    Note: _makefile_refs, _drop() and _reuse() are needed for the garbage\n    collector of pypy.\n    '''\n\n    def __init__(self, connection, socket, suppress_ragged_eofs=True):\n        self.connection = connection\n        self.socket = socket\n        self.suppress_ragged_eofs = suppress_ragged_eofs\n        self._makefile_refs = 0\n\n    def fileno(self):\n        return self.socket.fileno()\n\n    def makefile(self, mode, bufsize=-1):\n        self._makefile_refs += 1\n        return _fileobject(self, mode, bufsize, close=True)\n\n    def recv(self, *args, **kwargs):\n        try:\n            data = self.connection.recv(*args, **kwargs)\n        except OpenSSL.SSL.SysCallError as e:\n            if self.suppress_ragged_eofs and e.args == (-1, 'Unexpected EOF'):\n                return b''\n            else:\n                raise\n        except OpenSSL.SSL.ZeroReturnError as e:\n            if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN:\n                return b''\n            else:\n                raise\n        except OpenSSL.SSL.WantReadError:\n            rd, wd, ed = select.select(\n                [self.socket], [], [], self.socket.gettimeout())\n            if not rd:\n                raise timeout('The read operation timed out')\n            else:\n                return self.recv(*args, **kwargs)\n        else:\n            return data\n\n    def settimeout(self, timeout):\n        return self.socket.settimeout(timeout)\n\n    def _send_until_done(self, data):\n        while True:\n            try:\n                return self.connection.send(data)\n            except OpenSSL.SSL.WantWriteError:\n                _, wlist, _ = select.select([], [self.socket], [],\n                                            self.socket.gettimeout())\n                if not wlist:\n                    raise timeout()\n                continue\n\n    def sendall(self, data):\n        total_sent = 0\n        while total_sent < len(data):\n            sent = self._send_until_done(data[total_sent:total_sent+SSL_WRITE_BLOCKSIZE])\n            total_sent += sent\n\n    def shutdown(self):\n        # FIXME rethrow compatible exceptions should we ever use this\n        self.connection.shutdown()\n\n    def close(self):\n        if self._makefile_refs < 1:\n            try:\n                return self.connection.close()\n            except OpenSSL.SSL.Error:\n                return\n        else:\n            self._makefile_refs -= 1\n\n    def getpeercert(self, binary_form=False):\n        x509 = self.connection.get_peer_certificate()\n\n        if not x509:\n            return x509\n\n        if binary_form:\n            return OpenSSL.crypto.dump_certificate(\n                OpenSSL.crypto.FILETYPE_ASN1,\n                x509)\n\n        return {\n            'subject': (\n                (('commonName', x509.get_subject().CN),),\n            ),\n            'subjectAltName': [\n                ('DNS', value)\n                for value in get_subj_alt_name(x509)\n            ]\n        }\n\n    def _reuse(self):\n        self._makefile_refs += 1\n\n    def _drop(self):\n        if self._makefile_refs < 1:\n            self.close()\n        else:\n            self._makefile_refs -= 1\n\n\ndef _verify_callback(cnx, x509, err_no, err_depth, return_code):\n    return err_no == 0\n\n\ndef ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None,\n                    ca_certs=None, server_hostname=None,\n                    ssl_version=None, ca_cert_dir=None):\n    ctx = OpenSSL.SSL.Context(_openssl_versions[ssl_version])\n    if certfile:\n        keyfile = keyfile or certfile  # Match behaviour of the normal python ssl library\n        ctx.use_certificate_file(certfile)\n    if keyfile:\n        ctx.use_privatekey_file(keyfile)\n    if cert_reqs != ssl.CERT_NONE:\n        ctx.set_verify(_openssl_verify[cert_reqs], _verify_callback)\n    if ca_certs or ca_cert_dir:\n        try:\n            ctx.load_verify_locations(ca_certs, ca_cert_dir)\n        except OpenSSL.SSL.Error as e:\n            raise ssl.SSLError('bad ca_certs: %r' % ca_certs, e)\n    else:\n        ctx.set_default_verify_paths()\n\n    # Disable TLS compression to migitate CRIME attack (issue #309)\n    OP_NO_COMPRESSION = 0x20000\n    ctx.set_options(OP_NO_COMPRESSION)\n\n    # Set list of supported ciphersuites.\n    ctx.set_cipher_list(DEFAULT_SSL_CIPHER_LIST)\n\n    cnx = OpenSSL.SSL.Connection(ctx, sock)\n    cnx.set_tlsext_host_name(server_hostname)\n    cnx.set_connect_state()\n    while True:\n        try:\n            cnx.do_handshake()\n        except OpenSSL.SSL.WantReadError:\n            rd, _, _ = select.select([sock], [], [], sock.gettimeout())\n            if not rd:\n                raise timeout('select timed out')\n            continue\n        except OpenSSL.SSL.Error as e:\n            raise ssl.SSLError('bad handshake: %r' % e)\n        break\n\n    return WrappedSocket(cnx, sock)\n", "path": "urllib3/contrib/pyopenssl.py"}]}