summaryrefslogtreecommitdiffstats
path: root/WebKitTools/pywebsocket/mod_pywebsocket/standalone.py
diff options
context:
space:
mode:
Diffstat (limited to 'WebKitTools/pywebsocket/mod_pywebsocket/standalone.py')
-rw-r--r--WebKitTools/pywebsocket/mod_pywebsocket/standalone.py254
1 files changed, 254 insertions, 0 deletions
diff --git a/WebKitTools/pywebsocket/mod_pywebsocket/standalone.py b/WebKitTools/pywebsocket/mod_pywebsocket/standalone.py
new file mode 100644
index 0000000..a4c142b
--- /dev/null
+++ b/WebKitTools/pywebsocket/mod_pywebsocket/standalone.py
@@ -0,0 +1,254 @@
+#!/usr/bin/env python
+#
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+"""Standalone Web Socket server.
+
+Use this server to run mod_pywebsocket without Apache HTTP Server.
+
+Usage:
+ python standalone.py [-p <ws_port>] [-w <websock_handlers>]
+ [-s <scan_dir>]
+ [-d <document_root>]
+
+<ws_port> is the port number to use for ws:// connection.
+
+<document_root> is the path to the root directory of HTML files.
+
+<websock_handlers> is the path to the root directory of Web Socket handlers.
+See __init__.py for details of <websock_handlers> and how to write Web Socket
+handlers. If this path is relative, <document_root> is used as the base.
+
+<scan_dir> is a path under the root directory. If specified, only the handlers
+under scan_dir are scanned. This is useful in saving scan time.
+
+Note:
+This server is derived from SocketServer.ThreadingMixIn. Hence a thread is
+used for each request.
+"""
+
+import BaseHTTPServer
+import SimpleHTTPServer
+import SocketServer
+import logging
+import optparse
+import os
+import socket
+import sys
+
+_HAS_OPEN_SSL = False
+try:
+ import OpenSSL.SSL
+ _HAS_OPEN_SSL = True
+except ImportError:
+ pass
+
+import dispatch
+import handshake
+
+
+class _StandaloneConnection(object):
+ """Mimic mod_python mp_conn."""
+
+ def __init__(self, request_handler):
+ """Construct an instance.
+
+ Args:
+ request_handler: A WebSocketRequestHandler instance.
+ """
+ self._request_handler = request_handler
+
+ def get_local_addr(self):
+ """Getter to mimic mp_conn.local_addr."""
+ return (self._request_handler.server.server_name,
+ self._request_handler.server.server_port)
+ local_addr = property(get_local_addr)
+
+ def write(self, data):
+ """Mimic mp_conn.write()."""
+ return self._request_handler.wfile.write(data)
+
+ def read(self, length):
+ """Mimic mp_conn.read()."""
+ return self._request_handler.rfile.read(length)
+
+
+class _StandaloneRequest(object):
+ """Mimic mod_python request."""
+
+ def __init__(self, request_handler, use_tls):
+ """Construct an instance.
+
+ Args:
+ request_handler: A WebSocketRequestHandler instance.
+ """
+ self._request_handler = request_handler
+ self.connection = _StandaloneConnection(request_handler)
+ self._use_tls = use_tls
+
+ def get_uri(self):
+ """Getter to mimic request.uri."""
+ return self._request_handler.path
+ uri = property(get_uri)
+
+ def get_headers_in(self):
+ """Getter to mimic request.headers_in."""
+ return self._request_handler.headers
+ headers_in = property(get_headers_in)
+
+ def is_https(self):
+ """Mimic request.is_https()."""
+ return self._use_tls
+
+
+class WebSocketServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
+ """HTTPServer specialized for Web Socket."""
+
+ SocketServer.ThreadingMixIn.daemon_threads = True
+
+ def __init__(self, server_address, RequestHandlerClass):
+ """Override SocketServer.BaseServer.__init__."""
+
+ SocketServer.BaseServer.__init__(
+ self, server_address, RequestHandlerClass)
+ self.socket = self._create_socket()
+ self.server_bind()
+ self.server_activate()
+
+ def _create_socket(self):
+ socket_ = socket.socket(self.address_family, self.socket_type)
+ if WebSocketServer.options.use_tls:
+ ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
+ ctx.use_privatekey_file(WebSocketServer.options.private_key)
+ ctx.use_certificate_file(WebSocketServer.options.certificate)
+ socket_ = OpenSSL.SSL.Connection(ctx, socket_)
+ return socket_
+
+class WebSocketRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
+ """SimpleHTTPRequestHandler specialized for Web Socket."""
+
+ def setup(self):
+ """Override SocketServer.StreamRequestHandler.setup."""
+
+ self.connection = self.request
+ self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
+ self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
+
+ def __init__(self, *args, **keywords):
+ self._request = _StandaloneRequest(
+ self, WebSocketRequestHandler.options.use_tls)
+ self._dispatcher = dispatch.Dispatcher(
+ WebSocketRequestHandler.options.websock_handlers,
+ WebSocketRequestHandler.options.scan_dir)
+ self._print_warnings_if_any()
+ self._handshaker = handshake.Handshaker(self._request,
+ self._dispatcher)
+ SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(
+ self, *args, **keywords)
+
+ def _print_warnings_if_any(self):
+ warnings = self._dispatcher.source_warnings()
+ if warnings:
+ for warning in warnings:
+ logging.warning('mod_pywebsocket: %s' % warning)
+
+ def parse_request(self):
+ """Override BaseHTTPServer.BaseHTTPRequestHandler.parse_request.
+
+ Return True to continue processing for HTTP(S), False otherwise.
+ """
+ result = SimpleHTTPServer.SimpleHTTPRequestHandler.parse_request(self)
+ if result:
+ try:
+ self._handshaker.do_handshake()
+ self._dispatcher.transfer_data(self._request)
+ return False
+ except handshake.HandshakeError, e:
+ # Handshake for ws(s) failed. Assume http(s).
+ logging.info('mod_pywebsocket: %s' % e)
+ return True
+ except dispatch.DispatchError, e:
+ logging.warning('mod_pywebsocket: %s' % e)
+ return False
+ return result
+
+
+def _main():
+ logging.basicConfig()
+
+ parser = optparse.OptionParser()
+ parser.add_option('-p', '--port', dest='port', type='int',
+ default=handshake._DEFAULT_WEB_SOCKET_PORT,
+ help='port to listen to')
+ parser.add_option('-w', '--websock_handlers', dest='websock_handlers',
+ default='.',
+ help='Web Socket handlers root directory.')
+ parser.add_option('-s', '--scan_dir', dest='scan_dir',
+ default=None,
+ help=('Web Socket handlers scan directory. '
+ 'Must be a directory under websock_handlers.'))
+ parser.add_option('-d', '--document_root', dest='document_root',
+ default='.',
+ help='Document root directory.')
+ parser.add_option('-t', '--tls', dest='use_tls', action='store_true',
+ default=False, help='use TLS (wss://)')
+ parser.add_option('-k', '--private_key', dest='private_key',
+ default='', help='TLS private key file.')
+ parser.add_option('-c', '--certificate', dest='certificate',
+ default='', help='TLS certificate file.')
+ options = parser.parse_args()[0]
+
+ if options.use_tls:
+ if not _HAS_OPEN_SSL:
+ print >>sys.stderr, 'To use TLS, install pyOpenSSL.'
+ sys.exit(1)
+ if not options.private_key or not options.certificate:
+ print >>sys.stderr, ('To use TLS, specify private_key and '
+ 'certificate.')
+ sys.exit(1)
+
+ if not options.scan_dir:
+ options.scan_dir = options.websock_handlers
+
+ WebSocketRequestHandler.options = options
+ WebSocketServer.options = options
+
+ os.chdir(options.document_root)
+
+ server = WebSocketServer(('', options.port), WebSocketRequestHandler)
+ server.serve_forever()
+
+
+if __name__ == '__main__':
+ _main()
+
+
+# vi:sts=4 sw=4 et