summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy McCurdy <andy@andymccurdy.com>2019-07-30 15:14:32 -0700
committerAndy McCurdy <andy@andymccurdy.com>2019-07-30 15:14:32 -0700
commit885ce770856a1ee5ebc51d7c5390c88fb62bc93e (patch)
treeea1f83c8382f289f96cdf7007c891d2835ff0699
parent6b6e394ccb7199cb5e0d2e8192dc904aa0a8b347 (diff)
downloadredis-py-885ce770856a1ee5ebc51d7c5390c88fb62bc93e.tar.gz
version 3.3.4, more specifically identify nonblocking read errors
versions 3.3.1, 3.3.2 and 3.3.3 could potentially hide ConnectionErrors on Python 2.7. This change accurately identifies errors by both exception class and errno to determine whether a nonblocking socket can be read
-rw-r--r--CHANGES4
-rw-r--r--redis/__init__.py2
-rwxr-xr-xredis/connection.py31
3 files changed, 22 insertions, 15 deletions
diff --git a/CHANGES b/CHANGES
index 924c88a..7b53f9c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,7 @@
+* 3.3.4
+ * More specifically identify nonblocking read errors for both SSL and
+ non-SSL connections. 3.3.1, 3.3.2 and 3.3.3 on Python 2.7 could
+ potentially mask a ConnectionError. #1197
* 3.3.3
* The SSL module in Python < 2.7.9 handles non-blocking sockets
differently than 2.7.9+. This patch accommodates older versions. #1197
diff --git a/redis/__init__.py b/redis/__init__.py
index 2d586c6..71bc217 100644
--- a/redis/__init__.py
+++ b/redis/__init__.py
@@ -29,7 +29,7 @@ def int_or_str(value):
return value
-__version__ = '3.3.3'
+__version__ = '3.3.4'
VERSION = tuple(map(int_or_str, __version__.split('.')))
__all__ = [
diff --git a/redis/connection.py b/redis/connection.py
index e753bcb..8b87ead 100755
--- a/redis/connection.py
+++ b/redis/connection.py
@@ -34,17 +34,18 @@ try:
except ImportError:
ssl_available = False
-if ssl_available and hasattr(ssl, 'SSLWantReadError'):
- # note that when using nonblocking sockets over ssl, the ssl module
- # in python > 2.7.9 raises its own exceptions rather than BlockingIOError
- blocking_exceptions = (
- BlockingIOError,
- ssl.SSLWantReadError,
- ssl.SSLWantWriteError
- )
-else:
- blocking_exceptions = (BlockingIOError,)
+NONBLOCKING_EXCEPTION_ERROR_NUMBERS = {
+ BlockingIOError: 35,
+}
+
+if ssl_available:
+ if hasattr(ssl, 'SSLWantReadError'):
+ NONBLOCKING_EXCEPTION_ERROR_NUMBERS[ssl.SSLWantReadError] = 2
+ NONBLOCKING_EXCEPTION_ERROR_NUMBERS[ssl.SSLWantWriteError] = 2
+ else:
+ NONBLOCKING_EXCEPTION_ERROR_NUMBERS[ssl.SSLError] = 2
+NONBLOCKING_EXCEPTIONS = tuple(NONBLOCKING_EXCEPTION_ERROR_NUMBERS.keys())
if HIREDIS_AVAILABLE:
import hiredis
@@ -180,12 +181,13 @@ class SocketBuffer(object):
if length is not None and length > marker:
continue
return True
- except blocking_exceptions as ex:
+ except NONBLOCKING_EXCEPTIONS as ex:
# if we're in nonblocking mode and the recv raises a
# blocking error, simply return False indicating that
# there's no data to be read. otherwise raise the
# original exception.
- if raise_on_timeout:
+ allowed_errno = NONBLOCKING_EXCEPTION_ERROR_NUMBERS[ex.__class__]
+ if raise_on_timeout or ex.errno != allowed_errno:
raise
return False
except socket.timeout:
@@ -409,12 +411,13 @@ class HiredisParser(BaseParser):
# data was read from the socket and added to the buffer.
# return True to indicate that data was read.
return True
- except blocking_exceptions as ex:
+ except NONBLOCKING_EXCEPTIONS as ex:
# if we're in nonblocking mode and the recv raises a
# blocking error, simply return False indicating that
# there's no data to be read. otherwise raise the
# original exception.
- if raise_on_timeout:
+ allowed_errno = NONBLOCKING_EXCEPTION_ERROR_NUMBERS[ex.__class__]
+ if raise_on_timeout or ex.errno != allowed_errno:
raise
return False
except socket.timeout: