SSLError exception leak while reading content stream

This system is on requests 2.7.0.  Traceback below:

```
.....File "/usr/local/lib/python2.7/site-packages/requests-2.7.0-py2.7.egg/requests/sessions.py", line 508, in post    return self.request(\'POST\', url, data=data, json=json, **kwargs)
File "/usr/local/lib/python2.7/site-packages/requests-2.7.0-py2.7.egg/requests/sessions.py", line 465, in request    resp = self.send(prep, **send_kwargs),
File "/usr/local/lib/python2.7/site-packages/requests-2.7.0-py2.7.egg/requests/sessions.py", line 605, in send    r.content,
File "/usr/local/lib/python2.7/site-packages/requests-2.7.0-py2.7.egg/requests/models.py", line 750, in content    self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes(),
File "/usr/local/lib/python2.7/site-packages/requests-2.7.0-py2.7.egg/requests/models.py", line 673, in generate    for chunk in self.raw.stream(chunk_size, decode_content=True):,
File "/usr/local/lib/python2.7/site-packages/requests-2.7.0-py2.7.egg/requests/packages/urllib3/response.py", line 303, in stream    for line in self.read_chunked(amt, decode_content=decode_content):,
File "/usr/local/lib/python2.7/site-packages/requests-2.7.0-py2.7.egg/requests/packages/urllib3/response.py", line 450, in read_chunked    chunk = self._handle_chunk(amt),
File "/usr/local/lib/python2.7/site-packages/requests-2.7.0-py2.7.egg/requests/packages/urllib3/response.py", line 420, in _handle_chunk    returned_chunk = self._fp._safe_read(self.chunk_left),
File "/usr/local/lib/python2.7/httplib.py", line 647, in _safe_read    chunk = self.fp.read(min(amt, MAXAMOUNT)),
File "/usr/local/lib/python2.7/socket.py", line 380, in read    data = self._sock.recv(left),
File "/usr/local/lib/python2.7/ssl.py", line 241, in recv    return self.read(buflen),
File "/usr/local/lib/python2.7/ssl.py", line 160, in read    return self._sslobj.read(len)
SSLError: The read operation timed out
```

Seems similar to #1826


@fredthomsen Can you please check with 2.9.0? I believe we fixed this already.


On the system I am able to reproduce this on, it's only occurring occasionally, but has almost always been happening daily.  I put 2.9.0 on there, and I'll let it run overnight.


Determined a better way of reproducing the issue consistently. @Lukasa looks fine on 2.9.0.  Move along nothing to see here.


Thanks for the report and for clearing it up @fredthomsen! :sparkles:


I'm having this problem on 2.9.1 (with eventlet monkey-patched urllib, if it matters). Backtrace:

```
Traceback (most recent call last):
  <snip...>
  File "/app/.heroku/python/lib/python3.3/site-packages/requests/api.py", line 107, in post 
    return request('post', url, data=data, json=json, **kwargs) 
  File "/app/.heroku/python/lib/python3.3/site-packages/requests/api.py", line 53, in request 
    return session.request(method=method, url=url, **kwargs) 
  File "/app/.heroku/python/lib/python3.3/site-packages/requests/sessions.py", line 468, in request 
    resp = self.send(prep, **send_kwargs) 
  File "/app/.heroku/python/lib/python3.3/site-packages/requests/sessions.py", line 608, in send 
    r.content 
  File "/app/.heroku/python/lib/python3.3/site-packages/requests/models.py", line 737, in content 
    self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes() 
  File "/app/.heroku/python/lib/python3.3/site-packages/requests/models.py", line 660, in generate 
    for chunk in self.raw.stream(chunk_size, decode_content=True): 
  File "/app/.heroku/python/lib/python3.3/site-packages/requests/packages/urllib3/response.py", line 344, in stream 
    data = self.read(amt=amt, decode_content=decode_content) 
  File "/app/.heroku/python/lib/python3.3/site-packages/requests/packages/urllib3/response.py", line 301, in read 
    data = self._fp.read(amt) 
  File "/app/.heroku/python/lib/python3.3/http/client.py", line 507, in read 
    return super(HTTPResponse, self).read(amt) 
  File "/app/.heroku/python/lib/python3.3/http/client.py", line 546, in readinto 
    n = self.fp.readinto(b) 
  File "/app/.heroku/python/lib/python3.3/socket.py", line 297, in readinto 
    return self._sock.recv_into(b) 
  File "/app/.heroku/python/lib/python3.3/site-packages/eventlet/green/ssl.py", line 221, in recv_into 
    timeout_exc=timeout_exc('timed out')) 
  File "/app/.heroku/python/lib/python3.3/site-packages/eventlet/hubs/__init__.py", line 162, in trampoline 
    return hub.switch() 
  File "/app/.heroku/python/lib/python3.3/site-packages/eventlet/hubs/hub.py", line 294, in switch 
    return self.greenlet.switch() 
ssl.SSLError: ('timed out',) 
```


The eventlet monkeypatching does appear to be a problem, mostly because it seems to be causing a `from` import to be binding the wrong object. If you move the monkeypatch to ensure that it occurs _before_ `requests` is imported your problem should go away.


Edit: thanks for the awesomely fast response!

Unfortunately, this is running under celery and gunicorn which both automatically monkey patch, so we don't have control over when that happens :(


Do you have control over when the import occurs? If so, you should be able to delay it until a point well after the monkeypatch.


Oh, duh, sorry.

When I run this locally (having edited eventlet to print when monkey patched and requests to print when imported), I see that eventlet _is_ monkey patching before requests is imported... It's possible that the import order is different on prod, but I don't have a good way to check the import order on prod since I can't edit the libraries and they don't log.

Do you have a suggestion for a requests call that would reliably repro the `ssl.SSLError` if the monkey patching was happening in the wrong order? That way I can test locally if the problem was persisting despite the fact that locally my imports are in the correct order. (The request that's failing on prod unfortunately works fine from my localhost, so I can't use it to test.)


Any idea of how I could get a consistent repro on this so that I can test the import-order stuff? I'm not sure what's causing the SSLError, so I'm not sure how to set up a request that consistently raises it.


@benkuhn The SSL error seems to be caused by a failure to deliver the response, so a server that sends a content-length but then stops sending halfway through the body (without closing the socket) should be enough to trigger this.


OK, sorry for the extremely long delay, but I have a minimal repro that shows the problem occurs even when `eventlet.monkey_patch()` is called before `requests` is imported. Sorry for the copy-paste; Github apparently doesn't want to upload my .py files?

``` python
# server.py
from flask import Flask, Response
import time

app = Flask(__name__)

@app.route('/')
def root():
    return 'hello world'

@app.route('/fail')
def fail():
    def generate():
        yield 'hello\n'
        time.sleep(5)
        yield 'world'
    return Response(generate())

app.run('0.0.0.0', debug=True, port=8100, ssl_context='adhoc')
```

``` python
# client.py
import eventlet
eventlet.monkey_patch()

import requests

requests.get('https://localhost:8100/fail', timeout=4, verify=False)
```

Install `flask`, `requests==2.11.1` and `pyopenssl`, then run `python server.py` and `python client.py`. You should see the following output:

``````
/Users/ben/.virtualenvs/remit/lib/python3.5/site-packages/requests/packages/urllib3/connectionpool.py:838: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/security.html
  InsecureRequestWarning)
Traceback (most recent call last):
  File "client.py", line 6, in <module>
    requests.get('https://localhost:8100/fail', timeout=4, verify=False)
  File "/Users/ben/.virtualenvs/remit/lib/python3.5/site-packages/requests/api.py", line 70, in get
    return request('get', url, params=params, **kwargs)
  File "/Users/ben/.virtualenvs/remit/lib/python3.5/site-packages/requests/api.py", line 56, in request
    return session.request(method=method, url=url, **kwargs)
  File "/Users/ben/.virtualenvs/remit/lib/python3.5/site-packages/requests/sessions.py", line 475, in request
    resp = self.send(prep, **send_kwargs)
  File "/Users/ben/.virtualenvs/remit/lib/python3.5/site-packages/requests/sessions.py", line 628, in send
    r.content
  File "/Users/ben/.virtualenvs/remit/lib/python3.5/site-packages/requests/models.py", line 755, in content
    self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()
  File "/Users/ben/.virtualenvs/remit/lib/python3.5/site-packages/requests/models.py", line 676, in generate
    for chunk in self.raw.stream(chunk_size, decode_content=True):
  File "/Users/ben/.virtualenvs/remit/lib/python3.5/site-packages/requests/packages/urllib3/response.py", line 357, in stream
    data = self.read(amt=amt, decode_content=decode_content)
  File "/Users/ben/.virtualenvs/remit/lib/python3.5/site-packages/requests/packages/urllib3/response.py", line 314, in read
    data = self._fp.read(amt)
  File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 433, in read
    n = self.readinto(b)
  File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 473, in readinto
    n = self.fp.readinto(b)
  File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/socket.py", line 575, in readinto
    return self._sock.recv_into(b)
  File "/Users/ben/.virtualenvs/remit/lib/python3.5/site-packages/eventlet/green/ssl.py", line 224, in recv_into
    timeout_exc=timeout_exc('timed out'))
  File "/Users/ben/.virtualenvs/remit/lib/python3.5/site-packages/eventlet/hubs/__init__.py", line 162, in trampoline
    return hub.switch()
  File "/Users/ben/.virtualenvs/remit/lib/python3.5/site-packages/eventlet/hubs/hub.py", line 294, in switch
    return self.greenlet.switch()
ssl.SSLError: ('timed out',)```
``````