Wrap BaseSSLError into SSLError during response reads
MODIFY
src/urllib3/response.py
src/urllib3/response.py
@@ -22,6 +22,7 @@ from .exceptions import (
InvalidChunkLength,
InvalidHeader,
HTTPError,
+ SSLError,
)
from .packages.six import string_types as basestring, PY3
from .connection import HTTPException, BaseSSLError
@@ -443,9 +444,8 @@ class HTTPResponse(io.IOBase):
except BaseSSLError as e:
# FIXME: Is there a better way to differentiate between SSLErrors?
if "read operation timed out" not in str(e): # Defensive:
- # This shouldn't happen but just in case we're missing an edge
- # case, let's avoid swallowing SSL errors.
- raise
+ # SSL errors related to framing/MAC get wrapped and reraised here
+ raise SSLError(e)
raise ReadTimeoutError(self._pool, None, "Read timed out.")

MODIFY
test/test_response.py
test/test_response.py
# -*- coding: utf-8 -*-
+import contextlib
import re
import socket
+import ssl
import zlib
from io import BytesIO, BufferedReader, TextIOWrapper
@@ -19,6 +21,7 @@ from urllib3.exceptions import (
httplib_IncompleteRead,
IncompleteRead,
InvalidChunkLength,
+ SSLError,
)
from urllib3.packages.six.moves import http_client as httplib
from urllib3.util.retry import Retry, RequestHistory
@@ -936,6 +939,30 @@ class TestResponse(object):
assert b"foo\nbar" == data
+ def test_non_timeout_ssl_error_on_read(self):
+ mac_error = ssl.SSLError(
+ "SSL routines", "ssl3_get_record", "decryption failed or bad record mac"
+ )
+
+ @contextlib.contextmanager
+ def make_bad_mac_fp():
+ fp = BytesIO(b"")
+ with mock.patch.object(fp, "read") as fp_read:
+ # mac/decryption error
+ fp_read.side_effect = mac_error
+ yield fp
+
+ with make_bad_mac_fp() as fp:
+ with pytest.raises(SSLError) as e:
+ HTTPResponse(fp)
+ assert e.value.args[0] == mac_error
+
+ with make_bad_mac_fp() as fp:
+ resp = HTTPResponse(fp, preload_content=False)
+ with pytest.raises(SSLError) as e:
+ resp.read()
+ assert e.value.args[0] == mac_error
+
class MockChunkedEncodingResponse(object):
def __init__(self, content):

Wrap BaseSSLError into SSLError during response reads