ClosedPoolError gets shadowed by a false Timeout error

A customer in whose product I used Requests complained that, on Windows, my program would immediately die with a series of `Timeout` exceptions printed to the logs:

```
  ...
    r = session.get(url, headers=headers, stream=True)
  File "...\venv\lib\site-packages\requests\sessions.py", line 310, in get
    return self.request('GET', url, **kwargs)
  File "...\venv\lib\site-packages\requests\sessions.py", line 279, in request
    resp = self.send(prep, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies)
  File "...\venv\lib\site-packages\requests\sessions.py", line 374, in send
    r = adapter.send(request, **kwargs)
  File "...\venv\lib\site-packages\requests\adapters.py", line 217, in send
    raise Timeout('Request timed out.')
Timeout: Request timed out.
```

This seemed odd, since timeouts usually take — well — _time_ to occur, instead of happening immediately when a program starts! So I looked at the code that was raising the `Timeout`, which is in `adapters.py`:

```
    except (_SSLError, _HTTPError) as e:
        if isinstance(e, _SSLError):
            raise SSLError(e)
        elif isinstance(e, TimeoutError):
            raise Timeout(e)
        else:
            raise Timeout('Request timed out.')
```

The last line of this stanza struck me as suspicious: is it _really_ the case that all SSL and HTTP errors can be explained as timeouts? So I had my customer change the last line to simply the statement `raise`, so that I could see the exception that was being hidden by the `Timeout` and this is what we saw:

```
    r = session.get(url, headers=headers, stream=True)
  File "...\venv\lib\site-packages\requests\sessions.py", line 310, in get
    return self.request('GET', url, **kwargs)
  File "...\venv\lib\site-packages\requests\sessions.py", line 279, in request
    resp = self.send(prep, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies)
  File "...\venv\lib\site-packages\requests\sessions.py", line 374, in send
    r = adapter.send(request, **kwargs)
  File "...\venv\lib\site-packages\requests\adapters.py", line 174, in send
    timeout=timeout
  File "...\venv\lib\site-packages\requests\packages\urllib3\connectionpool.py", line
 417, in urlopen
    conn = self._get_conn(timeout=pool_timeout)
  File "...\venv\lib\site-packages\requests\packages\urllib3\connectionpool.py", line
 218, in _get_conn
    raise ClosedPoolError(self, "Pool is closed.")
```

I have no idea what this error means, but it went away when instead of having several threads share the same `Session` we instead had each thread create its own `Session` for its use alone — I suppose that I should open another ticket about that, reporting that session objects are not, in fact, thread-safe in Python under Windows, but give this pool-is-closed exception instead?


I don't think the Session is thread-safe under any OS.

I do think the blanket 'Timeout' exception is pretty unwise, we can probably handle the urllib3 exceptions better. Let me take a look and see.


@Lukasa In that case an update to the documentation is warranted—the front page of the project says “thread-safe” which I assumed meant, you know, the whole project. :)


@brandon-rhodes has a point. I also have to wonder why we mask those exceptions.


Session should absolutely be thread-safe.


I agree it should be, but is it? For instance, Sessions have the `close()` method, which is clearly not thread safe.


Well, close should almost never be used. :)


I agree, but unfortunately both the `HTTPAdapter` and the `HTTPConnectionPool` underlying the Sessions also have close methods.

This key problem, I suspect, is actually in the way `HTTPConnectionPool` objects work. I can take a look into it if you like. =)


@shazow, we need your help!


Actually, looking at this, the only way this could happen is if `PoolManager.clear()` gets called. We only do that from the `HTTPAdapter.close()` method, and we only hit _that_ if you call `Session.close()`. @brandon-rhodes, do you ever call `Session.close()` or use the Session as a context manager?


Sorry I'm off the grid until Tuesday.
- Sent from rogue wilderness wifi
  On Feb 13, 2013 8:34 PM, "Kenneth Reitz" notifications@github.com wrote:

> @shazow https://github.com/shazow, we need your help!
> 
> —
> Reply to this email directly or view it on GitHubhttps://github.com/kennethreitz/requests/issues/1188#issuecomment-13532802.


@brandon-rhodes any updates? Changes made to address this (in part) were included in 1.2.0


This issue is many many months old, so I'm closing unless Brandon comes back and indicates that this is still a problem.


No, I do not have any more information to offer; because Requests could not be used safely in a threaded program on Windows, and because we needed to control pooling ourselves when doing NTLM (since once NTLM authentication has taken place, connections have to be removed from the "host X" pool and added to a "user Y on host X" pool), Requests was not a good fit for our project. Thanks for addressing this issue, though, and I'll certainly comment here if I ever encounter this issue again either way!


FWIW, the root cause of this was most likely the race condition fixed in shazow/urllib3/pull/204. Those changes were included in requests as of 9f119ee420318c113094e15bc5e6d7dbda5c98b0 (v2.0.0).
How do I know? I have still been using v1.2.3 and encountered the same problem.


Many thanks @ddoskind!