1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
|
"""Internal module for Python 2 backwards compatibility."""
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):
# Adapted from https://bugs.python.org/review/23863/patch/14532/54418
import time
# Wrapper for handling interruptable system calls.
def _retryable_call(s, func, *args, **kwargs):
# Some modules (SSL) use the _fileobject wrapper directly and
# implement a smaller portion of the socket interface, thus we
# need to let them continue to do so.
timeout, deadline = None, 0.0
attempted = False
try:
timeout = s.gettimeout()
except AttributeError:
pass
if timeout:
deadline = time.time() + timeout
try:
while True:
if attempted and timeout:
now = time.time()
if now >= deadline:
raise socket.error(errno.EWOULDBLOCK, "timed out")
else:
# Overwrite the timeout on the socket object
# to take into account elapsed time.
s.settimeout(deadline - now)
try:
attempted = True
return func(*args, **kwargs)
except socket.error as e:
if e.args[0] == errno.EINTR:
continue
raise
finally:
# Set the existing timeout back for future
# calls.
if timeout:
s.settimeout(timeout)
def recv(sock, *args, **kwargs):
return _retryable_call(sock, sock.recv, *args, **kwargs)
def recv_into(sock, *args, **kwargs):
return _retryable_call(sock, sock.recv_into, *args, **kwargs)
else: # Python 3.5 and above automatically retry EINTR
def recv(sock, *args, **kwargs):
return sock.recv(*args, **kwargs)
def recv_into(sock, *args, **kwargs):
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.message 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
from string import letters as ascii_letters
from Queue import Queue
# special unicode handling for python2 to avoid UnicodeDecodeError
def safe_unicode(obj, *args):
""" return the unicode representation of obj """
try:
return unicode(obj, *args)
except UnicodeDecodeError:
# obj is byte string
ascii_text = str(obj).encode('string_escape')
return unicode(ascii_text)
def iteritems(x):
return x.iteritems()
def iterkeys(x):
return x.iterkeys()
def itervalues(x):
return x.itervalues()
def nativestr(x):
return x if isinstance(x, str) else x.encode('utf-8', 'replace')
def next(x):
return x.next()
def byte_to_chr(x):
return x
unichr = unichr
xrange = xrange
basestring = basestring
unicode = unicode
long = long
BlockingIOError = socket.error
else:
from urllib.parse import parse_qs, unquote, urlparse
from string import ascii_letters
from queue import Queue
def iteritems(x):
return iter(x.items())
def iterkeys(x):
return iter(x.keys())
def itervalues(x):
return iter(x.values())
def byte_to_chr(x):
return chr(x)
def nativestr(x):
return x if isinstance(x, str) else x.decode('utf-8', 'replace')
next = next
unichr = chr
imap = map
izip = zip
xrange = range
basestring = str
unicode = str
safe_unicode = str
long = int
BlockingIOError = BlockingIOError
try: # Python 3
from queue import LifoQueue, Empty, Full
except ImportError: # Python 2
from Queue import LifoQueue, Empty, Full
|