Connection reset by peer with AWS NAT Gateway and Keep Alive

Set up following scenario to reproduce the issue:

backend side:
CloudFlare is proxying to AWS ELB.
ELB is proxying to Nginx.

client side:
Create private subnet and attach AWS NAT Gateway to it.
Launch EC2 instance in private subnet and use a script below to reproduce the issue.

Request path is:

EC2 instance(originating) -> AWS NAT Gateway -> CloudFlare -> AWS ELB -> Nginx.

I created a script which reproduces the issue:

```python
import requests
import time


def request_with_timeout(url, minutes):
    session = requests.Session()
    session.get(url, allow_redirects=False)
    time.sleep(minutes * 60)
    session.get(url, allow_redirects=False)


request_with_timeout('https://coins.ph', 6)
```

After executing - requests raises an exception:

```
>>> request_with_timeout('https://coins.ph', 6)
/opt/app/accounting/venv/local/lib/python2.7/site-packages/requests/packages/urllib3/util/ssl_.py:315: SNIMissingWarning: An HTTPS request has been made, but the SNI (Subject Name Indication) extension to TLS is not available on this platform. This may cause the server to present an incorrect TLS certificate, which can cause validation failures. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#snimissingwarning.
  SNIMissingWarning
/opt/app/accounting/venv/local/lib/python2.7/site-packages/requests/packages/urllib3/util/ssl_.py:120: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
  InsecurePlatformWarning
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in request_with_timeout
  File "/opt/app/accounting/venv/local/lib/python2.7/site-packages/requests/sessions.py", line 480, in get
    return self.request('GET', url, **kwargs)
  File "/opt/app/accounting/venv/local/lib/python2.7/site-packages/requests/sessions.py", line 468, in request
    resp = self.send(prep, **send_kwargs)
  File "/opt/app/accounting/venv/local/lib/python2.7/site-packages/requests/sessions.py", line 576, in send
    r = adapter.send(request, **kwargs)
  File "/opt/app/accounting/venv/local/lib/python2.7/site-packages/requests/adapters.py", line 426, in send
    raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', error(104, 'Connection reset by peer'))
```

Software versions:
```
Python 2.7.6
requests==2.9.1
```

But also reproduced on Python 2.7.12 and requests 2.12.4

Attaching tcpdump

[tcpdump-log.txt](https://github.com/kennethreitz/requests/files/698100/tcpdump-log.txt)


The issue does not appear when URL has `http` scheme.

Also everything works fine when there's no AWS NAT Gateway on the traffic path.

This can be a result of AWS NAT Gateway behavior. http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/vpc-nat-comparison.html

<img width="769" alt="screen shot 2017-01-10 at 16 14 36" src="https://cloud.githubusercontent.com/assets/892861/21838818/60012a24-d7e5-11e6-8859-ac504780771b.png">


I also noticed that error does not happen if requests are passing-by cloudflare.

So, this looks like you're encountering a race condition.

It seems like, one way or another, there is a server or CDN that has a 6-minute timeout on their connection, such that when it is idle for 6 minutes they will close it. If you start another request while the RST packet is in-flight, requests will see the RST as a connection abort. This is indistinguishable from the server closing the connection in our face, so we have to report it as an error condition.

To resolve this, I recommend adding retry logic. Your code should, in general, be resilient to failure in the face of network instability. You can do this either by mounting custom transport adapters, or by changing the value of `requests.adapters.DEFAULT_RETRIES` to something other than zero before you create your session.

I also stumbled upon this behaviour recently.
Being resilient to failure in the face of network instability is good advice, but sometimes it may be expensive to implement this.
After some research I found that turning on TCP keepalive helps preventing reset errors.
For example like this:

    class KeepaliveAdapter(requests.adapters.HTTPAdapter):
        def init_poolmanager(self, *args, **kwargs):
            kwargs['socket_options'] = HTTPConnection.default_socket_options + [
                (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),
            ]
            super(KeepaliveAdapter, self).init_poolmanager(*args, **kwargs)

    keepalive_aware_session = requests.Session()

    adapter = KeepaliveAdapter()
    keepalive_aware_session.mount('http://', adapter)
    keepalive_aware_session.mount('https://', adapter)

And then use session as usual.
But for this to work it is also neccesary to tune keepalive timers (i.e. set it less than 6 min, I used 180 seconds):

    sysctl -w net.ipv4.tcp_keepalive_time=180

Default value for this param on Ubuntu is **two hours**.