(optionally) Prevent exceptions from iter_content()

It should be possible to suppress exceptions, like when the server closes the connection on us, from `iter_content()`. Catching exceptions from iterators is notoriously difficult, and they are often passed on to other libraries which are outside the control of the programmer.

A typical example (and the case I ran into) is proxying large files; see the example below.

Preventing exceptions should probably be opt-in, e.g. using an argument like this: `r.iter_content(chunk_size=None, prevent_exceptions=True)`.

## Expected Result

Given the hypothetical `prevent_exceptions` parameter, the iterator should just end instead of raising the urllib error.

## Actual Result

When e.g. the server closes the connection on us, a ConnectionResetError is raised.

```
requests.exceptions.ChunkedEncodingError: ("Connection broken: ConnectionResetError(104, 'Connection reset by peer')", ConnectionResetError(104, 'Connection reset by peer'))
```

<details><summary>full trace</summary>

```
[2020-10-01 06:13:09 +0200] [30794] [ERROR] Socket error processing request.
Traceback (most recent call last):
  File "/opt/venv/lib64/python3.6/site-packages/urllib3/response.py", line 437, in _error_catcher
    yield
  File "/opt/venv/lib64/python3.6/site-packages/urllib3/response.py", line 519, in read
    data = self._fp.read(amt) if not fp_closed else b""
  File "/usr/lib64/python3.6/http/client.py", line 459, in read
    n = self.readinto(b)
  File "/usr/lib64/python3.6/http/client.py", line 503, in readinto
    n = self.fp.readinto(b)
  File "/usr/lib64/python3.6/socket.py", line 586, in readinto
    return self._sock.recv_into(b)
  File "/opt/venv/lib64/python3.6/site-packages/eventlet/green/ssl.py", line 241, in recv_into
    return self._base_recv(nbytes, flags, into=True, buffer_=buffer)
  File "/opt/venv/lib64/python3.6/site-packages/eventlet/green/ssl.py", line 256, in _base_recv
    read = self.read(nbytes, buffer_)
  File "/opt/venv/lib64/python3.6/site-packages/eventlet/green/ssl.py", line 176, in read
    super(GreenSSLSocket, self).read, *args, **kwargs)
  File "/opt/venv/lib64/python3.6/site-packages/eventlet/green/ssl.py", line 150, in _call_trampolining
    return func(*a, **kw)
  File "/usr/lib64/python3.6/ssl.py", line 830, in read
    return self._sslobj.read(len, buffer)
  File "/usr/lib64/python3.6/ssl.py", line 587, in read
    v = self._sslobj.read(len, buffer)
ConnectionResetError: [Errno 104] Connection reset by peer

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/venv/lib64/python3.6/site-packages/requests/models.py", line 751, in generate
    for chunk in self.raw.stream(chunk_size, decode_content=True):
  File "/opt/venv/lib64/python3.6/site-packages/urllib3/response.py", line 576, in stream
    data = self.read(amt=amt, decode_content=decode_content)
  File "/opt/venv/lib64/python3.6/site-packages/urllib3/response.py", line 541, in read
    raise IncompleteRead(self._fp_bytes_read, self.length_remaining)
  File "/usr/lib64/python3.6/contextlib.py", line 99, in __exit__
    self.gen.throw(type, value, traceback)
  File "/opt/venv/lib64/python3.6/site-packages/urllib3/response.py", line 455, in _error_catcher
    raise ProtocolError("Connection broken: %r" % e, e)
urllib3.exceptions.ProtocolError: ("Connection broken: ConnectionResetError(104, 'Connection reset by peer')", ConnectionResetError(104, 'Connection reset by peer'))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/venv/lib64/python3.6/site-packages/gunicorn/workers/base_async.py", line 65, in handle
    util.reraise(*sys.exc_info())
  File "/opt/venv/lib64/python3.6/site-packages/gunicorn/util.py", line 625, in reraise
    raise value
  File "/opt/venv/lib64/python3.6/site-packages/gunicorn/workers/base_async.py", line 55, in handle
    self.handle_request(listener_name, req, client, addr)
  File "/opt/venv/lib64/python3.6/site-packages/gunicorn/workers/base_async.py", line 128, in handle_request
    util.reraise(*sys.exc_info())
  File "/opt/venv/lib64/python3.6/site-packages/gunicorn/util.py", line 625, in reraise
    raise value
  File "/opt/venv/lib64/python3.6/site-packages/gunicorn/workers/base_async.py", line 113, in handle_request
    for item in respiter:
  File "/opt/venv/lib64/python3.6/site-packages/werkzeug/wsgi.py", line 506, in __next__
    return self._next()
  File "/opt/venv/lib64/python3.6/site-packages/werkzeug/wrappers/base_response.py", line 45, in _iter_encoded
    for item in iterable:
  File "/opt/venv/lib64/python3.6/site-packages/requests/models.py", line 754, in generate
    raise ChunkedEncodingError(e)
requests.exceptions.ChunkedEncodingError: ("Connection broken: ConnectionResetError(104, 'Connection reset by peer')", ConnectionResetError(104, 'Connection reset by peer'))
```

</details>


## Reproduction Steps

```python
import requests
from flask import Flask, Response
app = Flask(__name__)
@app.route("/")
def proxy():
    r = requests.get("https://httpbin.org/stream-bytes/99999999", stream=True)
    return Response(r.iter_content(chunk_size=8192), status=r.status_code)
app.run(port=8080)
```

## System Information

    $ python -m requests.help

```
{
  "chardet": {
    "version": "3.0.4"
  },
  "cryptography": {
    "version": "2.6.1"
  },
  "idna": {
    "version": "2.8"
  },
  "implementation": {
    "name": "CPython",
    "version": "3.7.9"
  },
  "platform": {
    "release": "5.8.11-100.fc31.x86_64",
    "system": "Linux"
  },
  "pyOpenSSL": {
    "openssl_version": "1010104f",
    "version": "19.0.0"
  },
  "requests": {
    "version": "2.22.0"
  },
  "system_ssl": {
    "version": "1010107f"
  },
  "urllib3": {
    "version": "1.25.7"
  },
  "using_pyopenssl": true
}

```


You're on python 3, and given this is a library in feature freeze. You're going to get to a better solution with:

```py
import requests
from flask import Flask, Response

def silence_errors(generator):
    try:
         yield from generator
    except requests.exceptions.RequestsException:
         return None

app = Flask(__name__)
@app.route("/")
def proxy():
    r = requests.get("https://httpbin.org/stream-bytes/99999999", stream=True)
    return Response(silence_errors(r.iter_content(chunk_size=8192)), status=r.status_code)
app.run(port=8080)

```

And this would fit in the requests-toolbelt which isn't feature frozen

On Thu, Oct 01, 2020 at 04:29:25PM -0700, Ian Stapleton Cordasco wrote:
>You're on python 3, and given this is a library in feature freeze.

Apologies; I was unaware of that. I appreciate the workaround you have 
provided, thanks!