diff --git a/doc/modules/websocket.rst b/doc/modules/websocket.rst
index 7405e8c..b42a25f 100644
--- a/doc/modules/websocket.rst
+++ b/doc/modules/websocket.rst
@@ -2,7 +2,7 @@
=====================================
This module provides a simple way to create a `websocket
-` server. It works with a few
+`_ server. It works with a few
tweaks in the :mod:`~eventlet.wsgi` module that allow websockets to
coexist with other WSGI applications.
diff --git a/eventlet/websocket.py b/eventlet/websocket.py
index b2f783f..194e984 100644
--- a/eventlet/websocket.py
+++ b/eventlet/websocket.py
@@ -81,7 +81,7 @@ class WebSocketWSGI(object):
environ.get('PATH_INFO')
)
qs = environ.get('QUERY_STRING')
- if qs:
+ if qs is not None:
location += '?' + qs
if self.protocol_version == 75:
handshake_reply = ("HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
@@ -212,9 +212,11 @@ class WebSocket(object):
return msgs
def send(self, message):
- """Send a message to the browser. *message* should be
- convertable to a string; unicode objects should be encodable
- as utf-8."""
+ """Send a message to the browser.
+
+ *message* should be convertable to a string; unicode objects should be
+ encodable as utf-8. Raises socket.error with errno of 32
+ (broken pipe) if the socket has already been closed by the client."""
packed = self._pack_message(message)
# if two greenthreads are trying to send at the same time
# on the same socket, sendlock prevents interleaving and corruption
@@ -225,8 +227,12 @@ class WebSocket(object):
self._sendlock.release()
def wait(self):
- """Waits for and deserializes messages. Returns a single
- message; the oldest not yet processed."""
+ """Waits for and deserializes messages.
+
+ Returns a single message; the oldest not yet processed. If the client
+ has already closed the connection, returns None. This is different
+ from normal socket behavior because the empty string is a valid
+ websocket message."""
while not self._msgs:
# Websocket might be closed already.
if self.websocket_closed:
diff --git a/eventlet/wsgi.py b/eventlet/wsgi.py
index a5ea4ff..54adf02 100644
--- a/eventlet/wsgi.py
+++ b/eventlet/wsgi.py
@@ -402,12 +402,10 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
env['REQUEST_METHOD'] = self.command
env['SCRIPT_NAME'] = ''
- if '?' in self.path:
- path, query = self.path.split('?', 1)
- else:
- path, query = self.path, ''
- env['PATH_INFO'] = urllib.unquote(path)
- env['QUERY_STRING'] = query
+ pq = self.path.split('?', 1)
+ env['PATH_INFO'] = urllib.unquote(pq[0])
+ if len(pq) > 1:
+ env['QUERY_STRING'] = pq[1]
if self.headers.typeheader is None:
env['CONTENT_TYPE'] = self.headers.type
diff --git a/tests/websocket_test.py b/tests/websocket_test.py
index 4e16ad4..f8bb45f 100644
--- a/tests/websocket_test.py
+++ b/tests/websocket_test.py
@@ -145,6 +145,58 @@ class TestWebSocket(_TestBase):
'Sec-WebSocket-Origin: http://localhost:%s' % self.port,
'Sec-WebSocket-Protocol: ws',
'Sec-WebSocket-Location: ws://localhost:%s/echo\r\n\r\n8jKS\'y:G*Co,Wxa-' % self.port]))
+
+
+ def test_query_string(self):
+ # verify that the query string comes out the other side unscathed
+ connect = [
+ "GET /echo?query_string HTTP/1.1",
+ "Upgrade: WebSocket",
+ "Connection: Upgrade",
+ "Host: localhost:%s" % self.port,
+ "Origin: http://localhost:%s" % self.port,
+ "Sec-WebSocket-Protocol: ws",
+ "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5",
+ "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00",
+ ]
+ sock = eventlet.connect(
+ ('localhost', self.port))
+
+ sock.sendall('\r\n'.join(connect) + '\r\n\r\n^n:ds[4U')
+ result = sock.recv(1024)
+ self.assertEqual(result,
+ '\r\n'.join(['HTTP/1.1 101 WebSocket Protocol Handshake',
+ 'Upgrade: WebSocket',
+ 'Connection: Upgrade',
+ 'Sec-WebSocket-Origin: http://localhost:%s' % self.port,
+ 'Sec-WebSocket-Protocol: ws',
+ 'Sec-WebSocket-Location: ws://localhost:%s/echo?query_string\r\n\r\n8jKS\'y:G*Co,Wxa-' % self.port]))
+
+ def test_empty_query_string(self):
+ # verify that a single trailing ? doesn't get nuked
+ connect = [
+ "GET /echo? HTTP/1.1",
+ "Upgrade: WebSocket",
+ "Connection: Upgrade",
+ "Host: localhost:%s" % self.port,
+ "Origin: http://localhost:%s" % self.port,
+ "Sec-WebSocket-Protocol: ws",
+ "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5",
+ "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00",
+ ]
+ sock = eventlet.connect(
+ ('localhost', self.port))
+
+ sock.sendall('\r\n'.join(connect) + '\r\n\r\n^n:ds[4U')
+ result = sock.recv(1024)
+ self.assertEqual(result,
+ '\r\n'.join(['HTTP/1.1 101 WebSocket Protocol Handshake',
+ 'Upgrade: WebSocket',
+ 'Connection: Upgrade',
+ 'Sec-WebSocket-Origin: http://localhost:%s' % self.port,
+ 'Sec-WebSocket-Protocol: ws',
+ 'Sec-WebSocket-Location: ws://localhost:%s/echo?\r\n\r\n8jKS\'y:G*Co,Wxa-' % self.port]))
+
def test_sending_messages_to_websocket_75(self):
connect = [