summaryrefslogtreecommitdiff
path: root/redis/_compat.py
diff options
context:
space:
mode:
authorZac Bristow <zbristow@codeaurora.org>2019-09-20 15:20:08 -0700
committerAndy McCurdy <andy@andymccurdy.com>2019-10-10 14:10:16 -0700
commita03c12e5869469aeaf4016d75a883a1fceb992fd (patch)
treece24ae73f68ba2554798f6dd744f2a582fb7f0e5 /redis/_compat.py
parent29a5259f644da35baee25342dc097782527d854b (diff)
downloadredis-py-a03c12e5869469aeaf4016d75a883a1fceb992fd.tar.gz
Version 3.3.93.3.9
Fixes SSL read timeouts in Python 2.7 The ssl module in Python 2.7 raises timeouts as ssl.SSLError instead of socket.timeout. When these timeouts are encountered, the error will be re-raised as socket.timeout so it is handled appropriately by the connection.
Diffstat (limited to 'redis/_compat.py')
-rw-r--r--redis/_compat.py50
1 files changed, 50 insertions, 0 deletions
diff --git a/redis/_compat.py b/redis/_compat.py
index d70af2a..39b6619 100644
--- a/redis/_compat.py
+++ b/redis/_compat.py
@@ -3,6 +3,19 @@ import errno
import socket
import sys
+
+def sendall(sock, *args, **kwargs):
+ return sock.sendall(*args, **kwargs)
+
+
+def shutdown(sock, *args, **kwargs):
+ return sock.shutdown(*args, **kwargs)
+
+
+def ssl_wrap_socket(context, sock, *args, **kwargs):
+ return context.wrap_socket(sock, *args, **kwargs)
+
+
# For Python older than 3.5, retry EINTR.
if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and
sys.version_info[1] < 5):
@@ -61,6 +74,43 @@ else: # Python 3.5 and above automatically retry EINTR
return sock.recv_into(*args, **kwargs)
if sys.version_info[0] < 3:
+ # In Python 3, the ssl module raises socket.timeout whereas it raises
+ # SSLError in Python 2. For compatibility between versions, ensure
+ # socket.timeout is raised for both.
+ import functools
+
+ try:
+ from ssl import SSLError as _SSLError
+ except ImportError:
+ class _SSLError(Exception):
+ """A replacement in case ssl.SSLError is not available."""
+ pass
+
+ _EXPECTED_SSL_TIMEOUT_MESSAGES = (
+ "The handshake operation timed out",
+ "The read operation timed out",
+ "The write operation timed out",
+ )
+
+ def _handle_ssl_timeout(func):
+ @functools.wraps(func)
+ def wrapper(*args, **kwargs):
+ try:
+ return func(*args, **kwargs)
+ except _SSLError as e:
+ if any(x in e.args[0] for x in _EXPECTED_SSL_TIMEOUT_MESSAGES):
+ # Raise socket.timeout for compatibility with Python 3.
+ raise socket.timeout(*e.args)
+ raise
+ return wrapper
+
+ recv = _handle_ssl_timeout(recv)
+ recv_into = _handle_ssl_timeout(recv_into)
+ sendall = _handle_ssl_timeout(sendall)
+ shutdown = _handle_ssl_timeout(shutdown)
+ ssl_wrap_socket = _handle_ssl_timeout(ssl_wrap_socket)
+
+if sys.version_info[0] < 3:
from urllib import unquote
from urlparse import parse_qs, urlparse
from itertools import imap, izip