You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

190 regels
5.5 KiB

  1. """Internal module for Python 2 backwards compatibility."""
  2. import errno
  3. import socket
  4. import sys
  5. def sendall(sock, *args, **kwargs):
  6. return sock.sendall(*args, **kwargs)
  7. def shutdown(sock, *args, **kwargs):
  8. return sock.shutdown(*args, **kwargs)
  9. def ssl_wrap_socket(context, sock, *args, **kwargs):
  10. return context.wrap_socket(sock, *args, **kwargs)
  11. # For Python older than 3.5, retry EINTR.
  12. if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and
  13. sys.version_info[1] < 5):
  14. # Adapted from https://bugs.python.org/review/23863/patch/14532/54418
  15. import time
  16. # Wrapper for handling interruptable system calls.
  17. def _retryable_call(s, func, *args, **kwargs):
  18. # Some modules (SSL) use the _fileobject wrapper directly and
  19. # implement a smaller portion of the socket interface, thus we
  20. # need to let them continue to do so.
  21. timeout, deadline = None, 0.0
  22. attempted = False
  23. try:
  24. timeout = s.gettimeout()
  25. except AttributeError:
  26. pass
  27. if timeout:
  28. deadline = time.time() + timeout
  29. try:
  30. while True:
  31. if attempted and timeout:
  32. now = time.time()
  33. if now >= deadline:
  34. raise socket.error(errno.EWOULDBLOCK, "timed out")
  35. else:
  36. # Overwrite the timeout on the socket object
  37. # to take into account elapsed time.
  38. s.settimeout(deadline - now)
  39. try:
  40. attempted = True
  41. return func(*args, **kwargs)
  42. except socket.error as e:
  43. if e.args[0] == errno.EINTR:
  44. continue
  45. raise
  46. finally:
  47. # Set the existing timeout back for future
  48. # calls.
  49. if timeout:
  50. s.settimeout(timeout)
  51. def recv(sock, *args, **kwargs):
  52. return _retryable_call(sock, sock.recv, *args, **kwargs)
  53. def recv_into(sock, *args, **kwargs):
  54. return _retryable_call(sock, sock.recv_into, *args, **kwargs)
  55. else: # Python 3.5 and above automatically retry EINTR
  56. def recv(sock, *args, **kwargs):
  57. return sock.recv(*args, **kwargs)
  58. def recv_into(sock, *args, **kwargs):
  59. return sock.recv_into(*args, **kwargs)
  60. if sys.version_info[0] < 3:
  61. # In Python 3, the ssl module raises socket.timeout whereas it raises
  62. # SSLError in Python 2. For compatibility between versions, ensure
  63. # socket.timeout is raised for both.
  64. import functools
  65. try:
  66. from ssl import SSLError as _SSLError
  67. except ImportError:
  68. class _SSLError(Exception):
  69. """A replacement in case ssl.SSLError is not available."""
  70. pass
  71. _EXPECTED_SSL_TIMEOUT_MESSAGES = (
  72. "The handshake operation timed out",
  73. "The read operation timed out",
  74. "The write operation timed out",
  75. )
  76. def _handle_ssl_timeout(func):
  77. @functools.wraps(func)
  78. def wrapper(*args, **kwargs):
  79. try:
  80. return func(*args, **kwargs)
  81. except _SSLError as e:
  82. message = len(e.args) == 1 and unicode(e.args[0]) or ''
  83. if any(x in message for x in _EXPECTED_SSL_TIMEOUT_MESSAGES):
  84. # Raise socket.timeout for compatibility with Python 3.
  85. raise socket.timeout(*e.args)
  86. raise
  87. return wrapper
  88. recv = _handle_ssl_timeout(recv)
  89. recv_into = _handle_ssl_timeout(recv_into)
  90. sendall = _handle_ssl_timeout(sendall)
  91. shutdown = _handle_ssl_timeout(shutdown)
  92. ssl_wrap_socket = _handle_ssl_timeout(ssl_wrap_socket)
  93. if sys.version_info[0] < 3:
  94. from urllib import unquote
  95. from urlparse import parse_qs, urlparse
  96. from itertools import imap, izip
  97. from string import letters as ascii_letters
  98. from Queue import Queue
  99. # special unicode handling for python2 to avoid UnicodeDecodeError
  100. def safe_unicode(obj, *args):
  101. """ return the unicode representation of obj """
  102. try:
  103. return unicode(obj, *args)
  104. except UnicodeDecodeError:
  105. # obj is byte string
  106. ascii_text = str(obj).encode('string_escape')
  107. return unicode(ascii_text)
  108. def iteritems(x):
  109. return x.iteritems()
  110. def iterkeys(x):
  111. return x.iterkeys()
  112. def itervalues(x):
  113. return x.itervalues()
  114. def nativestr(x):
  115. return x if isinstance(x, str) else x.encode('utf-8', 'replace')
  116. def next(x):
  117. return x.next()
  118. def byte_to_chr(x):
  119. return x
  120. unichr = unichr
  121. xrange = xrange
  122. basestring = basestring
  123. unicode = unicode
  124. long = long
  125. BlockingIOError = socket.error
  126. else:
  127. from urllib.parse import parse_qs, unquote, urlparse
  128. from string import ascii_letters
  129. from queue import Queue
  130. def iteritems(x):
  131. return iter(x.items())
  132. def iterkeys(x):
  133. return iter(x.keys())
  134. def itervalues(x):
  135. return iter(x.values())
  136. def byte_to_chr(x):
  137. return chr(x)
  138. def nativestr(x):
  139. return x if isinstance(x, str) else x.decode('utf-8', 'replace')
  140. next = next
  141. unichr = chr
  142. imap = map
  143. izip = zip
  144. xrange = range
  145. basestring = str
  146. unicode = str
  147. safe_unicode = str
  148. long = int
  149. BlockingIOError = BlockingIOError
  150. try: # Python 3
  151. from queue import LifoQueue, Empty, Full
  152. except ImportError: # Python 2
  153. from Queue import LifoQueue, Empty, Full