Session.close() doesn't work with proxies

I have an upstream server that supports both basic authentication and SSL client certificates for authenticating a client.

I have the following contrived requests client (with a session object) that hits the upstream server using basic auth and then switches to using SSL client certificates and repeats the request:

``` python
#!/usr/bin/env python

import requests

session = requests.Session()
session.verify = './cacert.pem'
session.auth = ('bob', 'password')

response = session.get('https://1.2.3.4/')

session.auth = None
session.cert = ('./cert.pem', './key.pem')
session.close()

response = session.get('https://1.2.3.4/')
```

Because the client certificates need to be presented at the beginning of the connection I use `session.close()` to tear down any active connections before attempting the second request. If I don't do this, the session connection pooling kicks in and reuses the existing connection from the first request which won't have presented any certificates and so the second request is unauthorised.

This is all understood however I then had a need for the client to access the server through a proxy so the code is updated to just add the proxy configuration:

``` python
#!/usr/bin/env python

import requests

session = requests.Session()
session.verify = False
session.auth = ('bob', 'password')

session.proxies = {
  'https': 'http://alice:secret@5.6.7.8:3128/',
}

response = session.get('https://1.2.3.4/')

session.auth = None
session.cert = ('./cert.pem', './key.pem')
session.close()

response = session.get('https://1.2.3.4/')
```

Now the second request is unauthorised; `session.close()` seems to have no effect and doesn't tear down the connections through the proxy; there are no TCP FIN packets initiated from the client which I do see when no proxy is used.

The upstream server has keepalives enabled so if I add a sleep for longer than the idle timeout then the server terminates the connection between itself and the proxy, then the proxy terminates the connection to the client and then the second request is successful.

I appreciate this is probably a corner case but any ideas here? I would expect `session.close()` to correctly tear down the connections to the proxy. I've reproduced this against version 2.9.1.


Great spot, this is definitely a bug!

The bug is in `HTTPAdapter.close`: this currently clears the basic `PoolManager`, but doesn't clear any instantiated `ProxyManager` objects. That means that they inadvertently get preserved, which makes using them for this use-case untenable.

This bug is easily fixed, though: clearing out `HTTPAdapter.proxy_manager` is going to be the way to go.

In the meantime @bodgit, to work around this problem you can not just close the Session but actively mount new `HTTPAdapters`:

``` python
session.close()

session.mount('http://', requests.adapters.HTTPAdapter())
session.mount('https://', requests.adapters.HTTPAdapter())
```

This will hopefully all become needless in a future version of requests which will include TLS information in the connection pooling, but we're not there yet.


Brilliant, I've just confirmed adding those two `session.mount()` calls gets things working again. I noticed it doesn't cause any previous connections to be immediately torn down but that shouldn't be a massive problem.


I've submitted the following diff as a PR which seems to fix the issue for me:

``` diff
diff --git a/requests/adapters.py b/requests/adapters.py
index fe9f533..db62c09 100644
--- a/requests/adapters.py
+++ b/requests/adapters.py
@@ -264,10 +264,12 @@ class HTTPAdapter(BaseAdapter):
     def close(self):
         """Disposes of any internal state.

-        Currently, this just closes the PoolManager, which closes pooled
-        connections.
+        Currently, this closes the PoolManager and any active ProxyManager,
+        which closes any pooled connections.
         """
         self.poolmanager.clear()
+        for proxy in self.proxy_manager.values():
+            proxy.clear()

     def request_url(self, request, proxies):
         """Obtain the url to use when making the final request.

```


Closed this as #3091 has been merged. Thanks @Lukasa for the workaround and the explanation of the bug.