Skip to content

Commit

Permalink
Wrap BaseSSLError into SSLError during response reads
Browse files Browse the repository at this point in the history
  • Loading branch information
sethmlarson committed Aug 31, 2020
1 parent 24e540f commit bb862a2
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 3 deletions.
6 changes: 3 additions & 3 deletions src/urllib3/response.py
Expand Up @@ -22,6 +22,7 @@
InvalidChunkLength,
InvalidHeader,
HTTPError,
SSLError,
)
from .packages.six import string_types as basestring, PY3
from .connection import HTTPException, BaseSSLError
Expand Down Expand Up @@ -443,9 +444,8 @@ def _error_catcher(self):
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.")

Expand Down
27 changes: 27 additions & 0 deletions test/test_response.py
@@ -1,7 +1,9 @@
# -*- coding: utf-8 -*-

import contextlib
import re
import socket
import ssl
import zlib

from io import BytesIO, BufferedReader, TextIOWrapper
Expand All @@ -19,6 +21,7 @@
httplib_IncompleteRead,
IncompleteRead,
InvalidChunkLength,
SSLError,
)
from urllib3.packages.six.moves import http_client as httplib
from urllib3.util.retry import Retry, RequestHistory
Expand Down Expand Up @@ -936,6 +939,30 @@ def stream():

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):
Expand Down

0 comments on commit bb862a2

Please sign in to comment.