michael@0: # Copyright 2011, Google Inc. michael@0: # All rights reserved. michael@0: # michael@0: # Redistribution and use in source and binary forms, with or without michael@0: # modification, are permitted provided that the following conditions are michael@0: # met: michael@0: # michael@0: # * Redistributions of source code must retain the above copyright michael@0: # notice, this list of conditions and the following disclaimer. michael@0: # * Redistributions in binary form must reproduce the above michael@0: # copyright notice, this list of conditions and the following disclaimer michael@0: # in the documentation and/or other materials provided with the michael@0: # distribution. michael@0: # * Neither the name of Google Inc. nor the names of its michael@0: # contributors may be used to endorse or promote products derived from michael@0: # this software without specific prior written permission. michael@0: # michael@0: # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: michael@0: """WebSocket extension for Apache HTTP Server. michael@0: michael@0: mod_pywebsocket is a WebSocket extension for Apache HTTP Server michael@0: intended for testing or experimental purposes. mod_python is required. michael@0: michael@0: michael@0: Installation: michael@0: michael@0: 0. Prepare an Apache HTTP Server for which mod_python is enabled. michael@0: michael@0: 1. Specify the following Apache HTTP Server directives to suit your michael@0: configuration. michael@0: michael@0: If mod_pywebsocket is not in the Python path, specify the following. michael@0: is the directory where mod_pywebsocket is installed. michael@0: michael@0: PythonPath "sys.path+['']" michael@0: michael@0: Always specify the following. is the directory where michael@0: user-written WebSocket handlers are placed. michael@0: michael@0: PythonOption mod_pywebsocket.handler_root michael@0: PythonHeaderParserHandler mod_pywebsocket.headerparserhandler michael@0: michael@0: To limit the search for WebSocket handlers to a directory michael@0: under , configure as follows: michael@0: michael@0: PythonOption mod_pywebsocket.handler_scan michael@0: michael@0: is useful in saving scan time when michael@0: contains many non-WebSocket handler files. michael@0: michael@0: If you want to support old handshake based on michael@0: draft-hixie-thewebsocketprotocol-75: michael@0: michael@0: PythonOption mod_pywebsocket.allow_draft75 On michael@0: michael@0: If you want to allow handlers whose canonical path is not under the root michael@0: directory (i.e. symbolic link is in root directory but its target is not), michael@0: configure as follows: michael@0: michael@0: PythonOption mod_pywebsocket.allow_handlers_outside_root_dir On michael@0: michael@0: Example snippet of httpd.conf: michael@0: (mod_pywebsocket is in /websock_lib, WebSocket handlers are in michael@0: /websock_handlers, port is 80 for ws, 443 for wss.) michael@0: michael@0: michael@0: PythonPath "sys.path+['/websock_lib']" michael@0: PythonOption mod_pywebsocket.handler_root /websock_handlers michael@0: PythonHeaderParserHandler mod_pywebsocket.headerparserhandler michael@0: michael@0: michael@0: 2. Tune Apache parameters for serving WebSocket. We'd like to note that at michael@0: least TimeOut directive from core features and RequestReadTimeout michael@0: directive from mod_reqtimeout should be modified not to kill connections michael@0: in only a few seconds of idle time. michael@0: michael@0: 3. Verify installation. You can use example/console.html to poke the server. michael@0: michael@0: michael@0: Writing WebSocket handlers: michael@0: michael@0: When a WebSocket request comes in, the resource name michael@0: specified in the handshake is considered as if it is a file path under michael@0: and the handler defined in michael@0: /_wsh.py is invoked. michael@0: michael@0: For example, if the resource name is /example/chat, the handler defined in michael@0: /example/chat_wsh.py is invoked. michael@0: michael@0: A WebSocket handler is composed of the following three functions: michael@0: michael@0: web_socket_do_extra_handshake(request) michael@0: web_socket_transfer_data(request) michael@0: web_socket_passive_closing_handshake(request) michael@0: michael@0: where: michael@0: request: mod_python request. michael@0: michael@0: web_socket_do_extra_handshake is called during the handshake after the michael@0: headers are successfully parsed and WebSocket properties (ws_location, michael@0: ws_origin, and ws_resource) are added to request. A handler michael@0: can reject the request by raising an exception. michael@0: michael@0: A request object has the following properties that you can use during the michael@0: extra handshake (web_socket_do_extra_handshake): michael@0: - ws_resource michael@0: - ws_origin michael@0: - ws_version michael@0: - ws_location (Hixie 75 and HyBi 00 only) michael@0: - ws_extensions (Hybi 06 and later) michael@0: - ws_deflate (HyBi 06 and later) michael@0: - ws_protocol michael@0: - ws_requested_protocols (HyBi 06 and later) michael@0: michael@0: The last two are a bit tricky. michael@0: michael@0: For HyBi 06 and later, ws_protocol is always set to None when michael@0: web_socket_do_extra_handshake is called. If ws_requested_protocols is not michael@0: None, you must choose one subprotocol from this list and set it to michael@0: ws_protocol. michael@0: michael@0: For Hixie 75 and HyBi 00, when web_socket_do_extra_handshake is called, michael@0: ws_protocol is set to the value given by the client in michael@0: Sec-WebSocket-Protocol (WebSocket-Protocol for Hixie 75) header or None if michael@0: such header was not found in the opening handshake request. Finish extra michael@0: handshake with ws_protocol untouched to accept the request subprotocol. michael@0: Then, Sec-WebSocket-Protocol (or WebSocket-Protocol) header will be sent to michael@0: the client in response with the same value as requested. Raise an exception michael@0: in web_socket_do_extra_handshake to reject the requested subprotocol. michael@0: michael@0: web_socket_transfer_data is called after the handshake completed michael@0: successfully. A handler can receive/send messages from/to the client michael@0: using request. mod_pywebsocket.msgutil module provides utilities michael@0: for data transfer. michael@0: michael@0: You can receive a message by the following statement. michael@0: michael@0: message = request.ws_stream.receive_message() michael@0: michael@0: This call blocks until any complete text frame arrives, and the payload data michael@0: of the incoming frame will be stored into message. When you're using IETF michael@0: HyBi 00 or later protocol, receive_message() will return None on receiving michael@0: client-initiated closing handshake. When any error occurs, receive_message() michael@0: will raise some exception. michael@0: michael@0: You can send a message by the following statement. michael@0: michael@0: request.ws_stream.send_message(message) michael@0: michael@0: Executing the following statement or just return-ing from michael@0: web_socket_transfer_data cause connection close. michael@0: michael@0: request.ws_stream.close_connection() michael@0: michael@0: When you're using IETF HyBi 00 or later protocol, close_connection will wait michael@0: for closing handshake acknowledgement coming from the client. When it michael@0: couldn't receive a valid acknowledgement, raises an exception. michael@0: michael@0: web_socket_passive_closing_handshake is called after the server receives michael@0: incoming closing frame from the client peer immediately. You can specify michael@0: code and reason by return values. They are sent as a outgoing closing frame michael@0: from the server. A request object has the following properties that you can michael@0: use in web_socket_passive_closing_handshake. michael@0: - ws_close_code michael@0: - ws_close_reason michael@0: michael@0: A WebSocket handler must be thread-safe if the server (Apache or michael@0: standalone.py) is configured to use threads. michael@0: """ michael@0: michael@0: michael@0: # vi:sts=4 sw=4 et tw=72