summaryrefslogtreecommitdiff
path: root/eventlet
diff options
context:
space:
mode:
authorJakub Stasiak <jakub@stasiak.at>2014-11-02 12:29:13 +0000
committerJakub Stasiak <jakub@stasiak.at>2014-11-04 23:56:59 +0000
commit01093df590b12cc0ee6aa46c2aaf87458cf3ce78 (patch)
tree1fac4642a37bc85e338fc10c184421476e455be7 /eventlet
parent67cde41d03c0bccb12fd7d5f6d7e155d6da95e40 (diff)
downloadeventlet-python3-clean.tar.gz
Python 3 compat; Improve WSGI, WS, threading and testspython3-clean
This includes: * patching more tests to pass * removing few unit tests which I think are redundant * repeating SSL socket reads in a loop to read all data (I suspect this is related to the fact that writelines is used in the server code there and Python 3 writelines calls write/send repeatedly while on Python 2 it calls it once; on one hand there's no guarantee that single recv/read will return all data sent by the server, on the other hand it's quite suspicious that the number of required reads seems to be connected to the number of sends on the other side of the connection) * working through Python 2/Python 3 threading and thread differences; the lock code I used is the simplest way I could make the tests pass but will likely need to be modified in order to match the original This commit includes 6bcb1dc3686f72b0f1af803b46883ce4f5e4b8df and closes GH #153
Diffstat (limited to 'eventlet')
-rw-r--r--eventlet/green/thread.py12
-rw-r--r--eventlet/green/threading.py13
-rw-r--r--eventlet/websocket.py51
-rw-r--r--eventlet/wsgi.py30
4 files changed, 54 insertions, 52 deletions
diff --git a/eventlet/green/thread.py b/eventlet/green/thread.py
index 66bb581..d2d492a 100644
--- a/eventlet/green/thread.py
+++ b/eventlet/green/thread.py
@@ -1,6 +1,6 @@
"""Implements the standard thread module, using greenthreads."""
from eventlet.support.six.moves import _thread as __thread
-from eventlet.support import greenlets as greenlet
+from eventlet.support import greenlets as greenlet, six
from eventlet import greenthread
from eventlet.semaphore import Semaphore as LockType
@@ -13,6 +13,16 @@ error = __thread.error
__threadcount = 0
+if six.PY3:
+ def _set_sentinel():
+ # HACK this is dummy code
+ # TODO possibly reimplement this:
+ # https://hg.python.org/cpython/file/b5e9bc4352e1/Modules/_threadmodule.c#l1203
+ return allocate_lock()
+
+ TIMEOUT_MAX = __thread.TIMEOUT_MAX
+
+
def _count():
return __threadcount
diff --git a/eventlet/green/threading.py b/eventlet/green/threading.py
index 5c56ba1..3176261 100644
--- a/eventlet/green/threading.py
+++ b/eventlet/green/threading.py
@@ -2,12 +2,17 @@
from eventlet import patcher
from eventlet.green import thread
from eventlet.green import time
-from eventlet.support import greenlets as greenlet
+from eventlet.support import greenlets as greenlet, six
-__patched__ = ['_start_new_thread', '_allocate_lock', '_get_ident', '_sleep',
- 'local', 'stack_size', 'Lock', 'currentThread',
+__patched__ = ['_start_new_thread', '_allocate_lock',
+ '_sleep', 'local', 'stack_size', 'Lock', 'currentThread',
'current_thread', '_after_fork', '_shutdown']
+if six.PY2:
+ __patched__ += ['_get_ident']
+else:
+ __patched__ += ['get_ident', '_set_sentinel']
+
__orig_threading = patcher.original('threading')
__threadlocal = __orig_threading.local()
@@ -15,7 +20,7 @@ __threadlocal = __orig_threading.local()
patcher.inject(
'threading',
globals(),
- ('thread', thread),
+ ('thread' if six.PY2 else '_thread', thread),
('time', time))
del patcher
diff --git a/eventlet/websocket.py b/eventlet/websocket.py
index 10c868d..1fb33bb 100644
--- a/eventlet/websocket.py
+++ b/eventlet/websocket.py
@@ -168,25 +168,24 @@ class WebSocketWSGI(object):
if qs is not None:
location += '?' + qs
if self.protocol_version == 75:
- handshake_reply = ("HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
- "Upgrade: WebSocket\r\n"
- "Connection: Upgrade\r\n"
- "WebSocket-Origin: %s\r\n"
- "WebSocket-Location: %s\r\n\r\n" % (
- environ.get('HTTP_ORIGIN'),
- location))
+ handshake_reply = (
+ b"HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
+ b"Upgrade: WebSocket\r\n"
+ b"Connection: Upgrade\r\n"
+ b"WebSocket-Origin: " + environ.get('HTTP_ORIGIN') + b"\r\n"
+ b"WebSocket-Location: " + six.b(location) + b"\r\n\r\n"
+ )
elif self.protocol_version == 76:
- handshake_reply = ("HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
- "Upgrade: WebSocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Origin: %s\r\n"
- "Sec-WebSocket-Protocol: %s\r\n"
- "Sec-WebSocket-Location: %s\r\n"
- "\r\n%s" % (
- environ.get('HTTP_ORIGIN'),
- environ.get('HTTP_SEC_WEBSOCKET_PROTOCOL', 'default'),
- location,
- response))
+ handshake_reply = (
+ b"HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
+ b"Upgrade: WebSocket\r\n"
+ b"Connection: Upgrade\r\n"
+ b"Sec-WebSocket-Origin: " + six.b(environ.get('HTTP_ORIGIN')) + b"\r\n"
+ b"Sec-WebSocket-Protocol: " +
+ six.b(environ.get('HTTP_SEC_WEBSOCKET_PROTOCOL', 'default')) + b"\r\n"
+ b"Sec-WebSocket-Location: " + six.b(location) + b"\r\n"
+ b"\r\n" + response
+ )
else: # pragma NO COVER
raise ValueError("Unknown WebSocket protocol version.")
sock.sendall(handshake_reply)
@@ -244,7 +243,7 @@ class WebSocketWSGI(object):
out += char
elif char == " ":
spaces += 1
- return int(out) / spaces
+ return int(out) // spaces
class WebSocket(object):
@@ -281,7 +280,7 @@ class WebSocket(object):
self.environ = environ
self.version = version
self.websocket_closed = False
- self._buf = ""
+ self._buf = b""
self._msgs = collections.deque()
self._sendlock = semaphore.Semaphore()
@@ -294,8 +293,8 @@ class WebSocket(object):
if isinstance(message, six.text_type):
message = message.encode('utf-8')
elif not isinstance(message, six.binary_type):
- message = b'%s' % (message,)
- packed = b"\x00%s\xFF" % message
+ message = six.b(str(message))
+ packed = b"\x00" + message + b"\xFF"
return packed
def _parse_messages(self):
@@ -309,17 +308,17 @@ class WebSocket(object):
end_idx = 0
buf = self._buf
while buf:
- frame_type = ord(buf[0])
+ frame_type = six.indexbytes(buf, 0)
if frame_type == 0:
# Normal message.
- end_idx = buf.find("\xFF")
+ end_idx = buf.find(b"\xFF")
if end_idx == -1: # pragma NO COVER
break
msgs.append(buf[1:end_idx].decode('utf-8', 'replace'))
buf = buf[end_idx + 1:]
elif frame_type == 255:
# Closing handshake.
- assert ord(buf[1]) == 0, "Unexpected closing handshake: %r" % buf
+ assert six.indexbytes(buf, 1) == 0, "Unexpected closing handshake: %r" % buf
self.websocket_closed = True
break
else:
@@ -355,7 +354,7 @@ class WebSocket(object):
return None
# no parsed messages, must mean buf needs more data
delta = self.socket.recv(8096)
- if delta == '':
+ if delta == b'':
return None
self._buf += delta
msgs = self._parse_messages()
diff --git a/eventlet/wsgi.py b/eventlet/wsgi.py
index a17de17..807b413 100644
--- a/eventlet/wsgi.py
+++ b/eventlet/wsgi.py
@@ -69,11 +69,13 @@ class Input(object):
def __init__(self,
rfile,
content_length,
+ sock,
wfile=None,
wfile_line=None,
chunked_input=False):
self.rfile = rfile
+ self._sock = sock
if content_length is not None:
content_length = int(content_length)
self.content_length = content_length
@@ -193,7 +195,7 @@ class Input(object):
return iter(self.read, b'')
def get_socket(self):
- return self.rfile._sock
+ return self._sock
def set_hundred_continue_response_headers(self, headers,
capitalize_response_headers=True):
@@ -387,24 +389,8 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
towrite.append(six.b("%x" % (len(data),)) + b"\r\n" + data + b"\r\n")
else:
towrite.append(data)
- try:
- _writelines(towrite)
- length[0] = length[0] + sum(map(len, towrite))
- except UnicodeEncodeError:
- self.server.log_message(
- "Encountered non-ascii unicode while attempting to write"
- "wsgi response: %r" %
- [x for x in towrite if isinstance(x, six.text_type)])
- self.server.log_message(traceback.format_exc())
- _writelines(
- ["HTTP/1.1 500 Internal Server Error\r\n",
- "Connection: close\r\n",
- "Content-type: text/plain\r\n",
- "Content-length: 98\r\n",
- "Date: %s\r\n" % format_date_time(time.time()),
- "\r\n",
- ("Internal Server Error: wsgi application passed "
- "a unicode object to the server instead of a string.")])
+ _writelines(towrite)
+ length[0] = length[0] + sum(map(len, towrite))
def start_response(status, response_headers, exc_info=None):
status_code[0] = status.split()[0]
@@ -448,6 +434,8 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
minimum_write_chunk_size = int(self.environ.get(
'eventlet.minimum_write_chunk_size', self.minimum_chunk_size))
for data in result:
+ if not isinstance(data, six.binary_type):
+ raise Exception('The result iterable has to return bytestrings')
towrite.append(data)
towrite_size += len(data)
if towrite_size >= minimum_write_chunk_size:
@@ -464,7 +452,7 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
self.close_connection = 1
tb = traceback.format_exc()
self.server.log_message(tb)
- if not headers_set:
+ if not headers_sent:
err_body =six.b(tb) if self.server.debug else b''
start_response("500 Internal Server Error",
[('Content-type', 'text/plain'),
@@ -564,7 +552,7 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
wfile_line = None
chunked = env.get('HTTP_TRANSFER_ENCODING', '').lower() == 'chunked'
env['wsgi.input'] = env['eventlet.input'] = Input(
- self.rfile, length, wfile=wfile, wfile_line=wfile_line,
+ self.rfile, length, self.connection, wfile=wfile, wfile_line=wfile_line,
chunked_input=chunked)
env['eventlet.posthooks'] = []