Skip to content

Commit

Permalink
Wrap urllib3's SSLError as requests' SSLError (#6057)
Browse files Browse the repository at this point in the history
  • Loading branch information
nateprewitt committed Feb 5, 2022
1 parent 7ae3887 commit 95f4567
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 5 deletions.
5 changes: 5 additions & 0 deletions HISTORY.md
Expand Up @@ -6,6 +6,11 @@ dev

- \[Short description of non-trivial change.\]

**Bugfixes**

- Fixed urllib3 exception leak, wrapping `urllib3.exceptions.SSLError` with
`requests.exceptions.SSLError` for `content` and `iter_content`.

2.27.1 (2022-01-05)
-------------------

Expand Down
10 changes: 9 additions & 1 deletion requests/models.py
Expand Up @@ -19,7 +19,12 @@
from urllib3.filepost import encode_multipart_formdata
from urllib3.util import parse_url
from urllib3.exceptions import (
DecodeError, ReadTimeoutError, ProtocolError, LocationParseError)
DecodeError,
LocationParseError,
ProtocolError,
ReadTimeoutError,
SSLError,
)

from io import UnsupportedOperation
from .hooks import default_hooks
Expand All @@ -32,6 +37,7 @@
ContentDecodingError, ConnectionError, StreamConsumedError,
InvalidJSONError)
from .exceptions import JSONDecodeError as RequestsJSONDecodeError
from .exceptions import SSLError as RequestsSSLError
from ._internal_utils import to_native_string, unicode_is_ascii
from .utils import (
guess_filename, get_auth_from_url, requote_uri,
Expand Down Expand Up @@ -765,6 +771,8 @@ def generate():
raise ContentDecodingError(e)
except ReadTimeoutError as e:
raise ConnectionError(e)
except SSLError as e:
raise RequestsSSLError(e)
else:
# Standard file-like object.
while True:
Expand Down
45 changes: 41 additions & 4 deletions tests/test_requests.py
Expand Up @@ -14,6 +14,7 @@
import io
import requests
import pytest
import urllib3
from requests.adapters import HTTPAdapter
from requests.auth import HTTPDigestAuth, _basic_auth_str
from requests.compat import (
Expand All @@ -22,9 +23,25 @@
from requests.cookies import (
cookiejar_from_dict, morsel_to_cookie)
from requests.exceptions import (
ConnectionError, ConnectTimeout, InvalidSchema, InvalidURL,
MissingSchema, ReadTimeout, Timeout, RetryError, RequestException, TooManyRedirects,
ProxyError, InvalidHeader, UnrewindableBodyError, SSLError, InvalidProxyURL, InvalidJSONError)
ChunkedEncodingError,
ConnectionError,
ConnectTimeout,
ContentDecodingError,
InvalidHeader,
InvalidJSONError,
InvalidProxyURL,
InvalidSchema,
InvalidURL,
MissingSchema,
ProxyError,
ReadTimeout,
RequestException,
RetryError,
Timeout,
TooManyRedirects,
UnrewindableBodyError,
)
from requests.exceptions import SSLError as RequestsSSLError
from requests.models import PreparedRequest
from requests.structures import CaseInsensitiveDict
from requests.sessions import SessionRedirectMixin
Expand Down Expand Up @@ -910,7 +927,7 @@ def test_certificate_failure(self, httpbin_secure):
"""
When underlying SSL problems occur, an SSLError is raised.
"""
with pytest.raises(SSLError):
with pytest.raises(RequestsSSLError):
# Our local httpbin does not have a trusted CA, so this call will
# fail if we use our default trust bundle.
requests.get(httpbin_secure('status', '200'))
Expand Down Expand Up @@ -1320,6 +1337,26 @@ def test_response_chunk_size_type(self):
with pytest.raises(TypeError):
chunks = r.iter_content("1024")

@pytest.mark.parametrize(
'exception, args, expected', (
(urllib3.exceptions.ProtocolError, tuple(), ChunkedEncodingError),
(urllib3.exceptions.DecodeError, tuple(), ContentDecodingError),
(urllib3.exceptions.ReadTimeoutError, (None, '', ''), ConnectionError),
(urllib3.exceptions.SSLError, tuple(), RequestsSSLError),
)
)
def test_iter_content_wraps_exceptions(
self, httpbin, mocker, exception, args, expected
):
r = requests.Response()
r.raw = mocker.Mock()
# ReadTimeoutError can't be initialized by mock
# so we'll manually create the instance with args
r.raw.stream.side_effect = exception(*args)

with pytest.raises(expected):
next(r.iter_content(1024))

def test_request_and_response_are_pickleable(self, httpbin):
r = requests.get(httpbin('get'))

Expand Down

0 comments on commit 95f4567

Please sign in to comment.