Support for SSL websockets, which also happens to improve our SSL support in WSGI generally. Fixes #62.
This commit is contained in:
@@ -300,7 +300,9 @@ class GreenSSLSocket(__ssl.SSLSocket):
|
||||
do_handshake_on_connect=self.do_handshake_on_connect,
|
||||
suppress_ragged_eofs=self.suppress_ragged_eofs)
|
||||
return (new_ssl, addr)
|
||||
|
||||
|
||||
def dup(self):
|
||||
raise NotImplementedError("Can't dup an ssl object")
|
||||
|
||||
SSLSocket = GreenSSLSocket
|
||||
|
||||
|
||||
@@ -71,7 +71,11 @@ class WebSocketWSGI(object):
|
||||
response = md5(key).digest()
|
||||
|
||||
# Start building the response
|
||||
location = 'ws://%s%s%s' % (
|
||||
scheme = 'ws'
|
||||
if environ.get('wsgi.url_scheme') == 'https':
|
||||
scheme = 'wss'
|
||||
location = '%s://%s%s%s' % (
|
||||
scheme,
|
||||
environ.get('HTTP_HOST'),
|
||||
environ.get('SCRIPT_NAME'),
|
||||
environ.get('PATH_INFO')
|
||||
|
||||
@@ -160,7 +160,7 @@ class Input(object):
|
||||
return iter(self.read())
|
||||
|
||||
def get_socket(self):
|
||||
return self.rfile._sock.dup()
|
||||
return self.rfile._sock
|
||||
|
||||
|
||||
class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
@@ -498,6 +498,10 @@ class Server(BaseHTTPServer.HTTPServer):
|
||||
'wsgi.run_once': False,
|
||||
'wsgi.url_scheme': 'http',
|
||||
}
|
||||
# detect secure socket
|
||||
if hasattr(self.socket, 'do_handshake'):
|
||||
d['wsgi.url_scheme'] = 'https'
|
||||
d['HTTPS'] = 'on'
|
||||
if self.environ is not None:
|
||||
d.update(self.environ)
|
||||
return d
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import os
|
||||
|
||||
import eventlet
|
||||
from eventlet import wsgi
|
||||
from eventlet import websocket
|
||||
|
||||
@@ -224,3 +224,6 @@ def get_database_auth():
|
||||
except IOError:
|
||||
pass
|
||||
return retval
|
||||
|
||||
certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt')
|
||||
private_key_file = os.path.join(os.path.dirname(__file__), 'test_server.key')
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
from tests import skipped, LimitedTestCase, skip_unless
|
||||
from tests import skipped, LimitedTestCase, skip_unless, certificate_file, private_key_file
|
||||
from unittest import main
|
||||
import eventlet
|
||||
from eventlet import util, coros, greenio
|
||||
import socket
|
||||
import os
|
||||
|
||||
certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt')
|
||||
private_key_file = os.path.join(os.path.dirname(__file__), 'test_server.key')
|
||||
|
||||
def listen_ssl_socket(address=('127.0.0.1', 0)):
|
||||
sock = util.wrap_ssl(socket.socket(), certificate_file,
|
||||
private_key_file, True)
|
||||
|
||||
@@ -8,7 +8,7 @@ from eventlet.websocket import WebSocket, WebSocketWSGI
|
||||
from eventlet import wsgi
|
||||
from eventlet import event
|
||||
|
||||
from tests import mock, LimitedTestCase
|
||||
from tests import mock, LimitedTestCase, certificate_file, private_key_file
|
||||
from tests.wsgi_test import _TestBase
|
||||
|
||||
|
||||
@@ -460,6 +460,50 @@ class TestWebSocket(_TestBase):
|
||||
self.assert_(error_detected[0])
|
||||
|
||||
|
||||
class TestWebSocketSSL(_TestBase):
|
||||
def set_site(self):
|
||||
self.site = wsapp
|
||||
|
||||
def test_ssl_sending_messages(self):
|
||||
s = eventlet.wrap_ssl(eventlet.listen(('localhost', 0)),
|
||||
certfile=certificate_file,
|
||||
keyfile=private_key_file,
|
||||
server_side=True)
|
||||
self.spawn_server(sock=s)
|
||||
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.wrap_ssl(eventlet.connect(
|
||||
('localhost', self.port)))
|
||||
|
||||
sock.sendall('\r\n'.join(connect) + '\r\n\r\n^n:ds[4U')
|
||||
first_resp = sock.recv(1024)
|
||||
# make sure it sets the wss: protocol on the location header
|
||||
loc_line = [x for x in first_resp.split("\r\n")
|
||||
if x.lower().startswith('sec-websocket-location')][0]
|
||||
self.assert_("wss://localhost" in loc_line,
|
||||
"Expecting wss protocol in location: %s" % loc_line)
|
||||
sock.sendall('\x00hello\xFF')
|
||||
result = sock.recv(1024)
|
||||
self.assertEqual(result, '\x00hello\xff')
|
||||
sock.sendall('\x00start')
|
||||
eventlet.sleep(0.001)
|
||||
sock.sendall(' end\xff')
|
||||
result = sock.recv(1024)
|
||||
self.assertEqual(result, '\x00start end\xff')
|
||||
sock.shutdown(socket.SHUT_RDWR)
|
||||
sock.close()
|
||||
eventlet.sleep(0.01)
|
||||
|
||||
|
||||
|
||||
class TestWebSocketObject(LimitedTestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
||||
Reference in New Issue
Block a user