44
55Its usage is rather simple:
66
7- >>> from gevent import monkey; monkey.patch_all()
8- >>> from ws4py.websocket import EchoWebSocket
9- >>> from ws4py.server.geventserver import WebSocketWSGIApplication, WSGIServer
7+ .. code-block: python
108
11- >>> server = WSGIServer(('localhost', 9000), WebSocketWSGIApplication(handler_cls=EchoWebSocket))
12- >>> server.serve_forever()
9+ from gevent import monkey; monkey.patch_all()
10+ from ws4py.websocket import EchoWebSocket
11+ from ws4py.server.geventserver import WSGIServer
12+ from ws4py.server.wsgiutils import WebSocketWSGIApplication
13+
14+ server = WSGIServer(('localhost', 9000), WebSocketWSGIApplication(handler_cls=EchoWebSocket))
15+ server.serve_forever()
1316
1417"""
15- import base64
16- from hashlib import sha1
1718import logging
18- import signal
1919import sys
2020
2121import gevent
2222from gevent .pywsgi import WSGIHandler , WSGIServer as _WSGIServer
2323from gevent .pool import Group
2424
25- from ws4py .websocket import WebSocket
26- from ws4py .exc import HandshakeError
27- from ws4py .compat import enc
28- from ws4py import WS_VERSION , WS_KEY , format_addresses
25+ from ws4py import format_addresses
26+ from ws4py .server .wsgiutils import WebSocketWSGIApplication
2927
3028logger = logging .getLogger ('ws4py' )
3129
32- __all__ = ['WebSocketWSGIHandler' , 'WebSocketWSGIApplication' , ' WSGIServer' ]
30+ __all__ = ['WebSocketWSGIHandler' , 'WSGIServer' ]
3331
3432class WebSocketWSGIHandler (WSGIHandler ):
3533 """
@@ -45,19 +43,6 @@ def run_application(self):
4543 upgrade_header = self .environ .get ('HTTP_UPGRADE' , '' ).lower ()
4644 if upgrade_header :
4745 try :
48- # A couple of dummy validations
49- if self .environ .get ('REQUEST_METHOD' ) != 'GET' :
50- raise HandshakeError ('HTTP method must be a GET' )
51-
52- for key , expected_value in [('HTTP_UPGRADE' , 'websocket' ),
53- ('HTTP_CONNECTION' , 'upgrade' )]:
54- actual_value = self .environ .get (key , '' ).lower ()
55- if not actual_value :
56- raise HandshakeError ('Header %s is not defined' % key )
57- if expected_value not in actual_value :
58- raise HandshakeError ('Illegal value for header %s: %s' %
59- (key , actual_value ))
60-
6146 # Build and start the HTTP response
6247 self .environ ['ws4py.socket' ] = self .socket or self .environ ['wsgi.input' ].rfile ._sock
6348 self .result = self .application (self .environ , self .start_response ) or []
@@ -75,95 +60,6 @@ def run_application(self):
7560 else :
7661 gevent .pywsgi .WSGIHandler .run_application (self )
7762
78- class WebSocketWSGIApplication (object ):
79- def __init__ (self , protocols = None , extensions = None ,
80- version = WS_VERSION , handler_cls = WebSocket ):
81- """
82- WSGI application usable to complete the upgrade handshake
83- by validating the requested protocols and extensions as
84- well as the websocket version.
85-
86- If the upgrade validates, the `handler_cls` class
87- is instanciated and stored inside the WSGI `environ`
88- under the `'ws4y.websocket'` key to make it
89- available to the WSGI handler.
90-
91- Note that the key and its associated value will be removed
92- from the environ dictionary from within the
93- WSGI handler.
94- """
95- self .protocols = protocols
96- self .extensions = extensions
97- self .version = version
98- self .handler_cls = handler_cls
99-
100- def build_websocket (self , sock , protocols , extensions , environ ):
101- """
102- Initialize the `handler_cls` instance with the given
103- negociated sets of protocols and extensions as well as
104- the `environ` and `sock`.
105-
106- Stores then the instance in the `environ` dict
107- under the `'ws4y.websocket'` key.
108- """
109- websocket = self .handler_cls (sock , protocols , extensions ,
110- environ .copy ())
111- environ ['ws4y.websocket' ] = websocket
112- return websocket
113-
114- def __call__ (self , environ , start_response ):
115- key = environ .get ('HTTP_SEC_WEBSOCKET_KEY' )
116- if key :
117- ws_key = base64 .b64decode (enc (key ))
118- if len (ws_key ) != 16 :
119- raise HandshakeError ("WebSocket key's length is invalid" )
120-
121- version = environ .get ('HTTP_SEC_WEBSOCKET_VERSION' )
122- supported_versions = ', ' .join ([str (v ) for v in self .version ])
123- version_is_valid = False
124- if version :
125- try : version = int (version )
126- except : pass
127- else : version_is_valid = version in WS_VERSION
128-
129- if not version_is_valid :
130- environ ['websocket.version' ] = str (version )
131- raise HandshakeError ('Unhandled or missing WebSocket version' )
132-
133- ws_protocols = []
134- protocols = self .protocols or []
135- subprotocols = environ .get ('HTTP_SEC_WEBSOCKET_PROTOCOL' )
136- if subprotocols :
137- for s in subprotocols .split (',' ):
138- s = s .strip ()
139- if s in protocols :
140- ws_protocols .append (s )
141-
142- ws_extensions = []
143- exts = self .extensions or []
144- extensions = environ .get ('HTTP_SEC_WEBSOCKET_EXTENSIONS' )
145- if extensions :
146- for ext in extensions .split (',' ):
147- ext = ext .strip ()
148- if ext in exts :
149- ws_extensions .append (ext )
150-
151- upgrade_headers = [
152- ('Upgrade' , 'websocket' ),
153- ('Connection' , 'Upgrade' ),
154- ('Sec-WebSocket-Version' , str (version )),
155- ('Sec-WebSocket-Accept' , base64 .b64encode (sha1 (key + WS_KEY ).digest ())),
156- ]
157- if ws_protocols :
158- upgrade_headers .append (('Sec-WebSocket-Protocol' , ', ' .join (ws_protocols )))
159- if ws_extensions :
160- upgrade_headers .append (('Sec-WebSocket-Extensions' , ',' .join (ws_extensions )))
161-
162- start_response ("101 Switching Protocols" , upgrade_headers )
163-
164- self .build_websocket (environ ['ws4py.socket' ], ws_protocols ,
165- ws_extensions , environ )
166-
16763class WSGIServer (_WSGIServer ):
16864 handler_class = WebSocketWSGIHandler
16965
@@ -200,6 +96,6 @@ def stop(self, *args, **kwargs):
20096 configure_logger ()
20197
20298 from ws4py .websocket import EchoWebSocket
203- server = WSGIServer (('127.0.0.1' , 9001 ),
99+ server = WSGIServer (('127.0.0.1' , 9000 ),
204100 WebSocketWSGIApplication (handler_cls = EchoWebSocket ))
205101 server .serve_forever ()
0 commit comments