15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#!/usr/bin/env python
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Copyright 2012, Google Inc.
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# All rights reserved.
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Redistribution and use in source and binary forms, with or without
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# modification, are permitted provided that the following conditions are
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# met:
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#     * Redistributions of source code must retain the above copyright
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# notice, this list of conditions and the following disclaimer.
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#     * Redistributions in binary form must reproduce the above
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# copyright notice, this list of conditions and the following disclaimer
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# in the documentation and/or other materials provided with the
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# distribution.
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#     * Neither the name of Google Inc. nor the names of its
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# contributors may be used to endorse or promote products derived from
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# this software without specific prior written permission.
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)"""Standalone WebSocket server.
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Use this file to launch pywebsocket without Apache HTTP Server.
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)BASIC USAGE
39f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)===========
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Go to the src directory and run
425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  $ python mod_pywebsocket/standalone.py [-p <ws_port>]
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                         [-w <websock_handlers>]
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                         [-d <document_root>]
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)<ws_port> is the port number to use for ws:// connection.
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)<document_root> is the path to the root directory of HTML files.
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)<websock_handlers> is the path to the root directory of WebSocket handlers.
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)If not specified, <document_root> will be used. See __init__.py (or
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)run $ pydoc mod_pywebsocket) for how to write WebSocket handlers.
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)For more detail and other options, run
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  $ python mod_pywebsocket/standalone.py --help
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)or see _build_option_parser method below.
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)For trouble shooting, adding "--log_level debug" might help you.
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TRY DEMO
65f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)========
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
67f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)Go to the src directory and run standalone.py with -d option to set the
68f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)document root to the directory containing example HTMLs and handlers like this:
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
70f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)  $ cd src
71f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)  $ PYTHONPATH=. python mod_pywebsocket/standalone.py -d example
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)to launch pywebsocket with the sample handler and html on port 80. Open
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)http://localhost/console.html, click the connect button, type something into
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)the text box next to the send button and click the send button. If everything
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)is working, you'll see the message you typed echoed by the server.
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
79f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)USING TLS
80f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)=========
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
82f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)To run the standalone server with TLS support, run it with -t, -k, and -c
83f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)options. When TLS is enabled, the standalone server accepts only TLS connection.
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)Note that when ssl module is used and the key/cert location is incorrect,
8653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)TLS connection silently fails while pyOpenSSL fails on startup.
8753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
88f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)Example:
89f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
90f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)  $ PYTHONPATH=. python mod_pywebsocket/standalone.py \
91f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        -d example \
92f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        -p 10443 \
93f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        -t \
94f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        -c ../test/cert/cert.pem \
95f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        -k ../test/cert/key.pem \
96f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
97f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)Note that when passing a relative path to -c and -k option, it will be resolved
98f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)using the document root directory as the base.
99f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
101f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)USING CLIENT AUTHENTICATION
102f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)===========================
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
104f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)To run the standalone server with TLS client authentication support, run it with
105f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)--tls-client-auth and --tls-client-ca options in addition to ones required for
106f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)TLS support.
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
108f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)Example:
109f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
110f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)  $ PYTHONPATH=. python mod_pywebsocket/standalone.py -d example -p 10443 -t \
111f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        -c ../test/cert/cert.pem -k ../test/cert/key.pem \
112f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        --tls-client-auth \
113f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        --tls-client-ca=../test/cert/cacert.pem
114f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
115f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)Note that when passing a relative path to --tls-client-ca option, it will be
116f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)resolved using the document root directory as the base.
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)CONFIGURATION FILE
120f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)==================
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)You can also write a configuration file and use it by specifying the path to
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)the configuration file by --config option. Please write a configuration file
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)following the documentation of the Python ConfigParser library. Name of each
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)entry must be the long version argument name. E.g. to set log level to debug,
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)add the following line:
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)log_level=debug
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)For options which doesn't take value, please add some fake value. E.g. for
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)--tls option, add the following line:
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)tls=True
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Note that tls will be enabled even if you write tls=False as the value part is
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)fake.
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)When both a command line argument and a configuration file entry are set for
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)the same configuration item, the command line value will override one in the
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)configuration file.
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)THREADING
144f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)=========
1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)This server is derived from SocketServer.ThreadingMixIn. Hence a thread is
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)used for each request.
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)SECURITY WARNING
151f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)================
1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)This uses CGIHTTPServer and CGIHTTPServer is not secure.
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)It may execute arbitrary Python code or external programs. It should not be
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)used outside a firewall.
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)"""
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import BaseHTTPServer
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import CGIHTTPServer
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import SimpleHTTPServer
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import SocketServer
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import ConfigParser
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import base64
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import httplib
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import logging
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import logging.handlers
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import optparse
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import os
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import re
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import select
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import socket
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import sys
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import threading
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import time
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from mod_pywebsocket import common
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from mod_pywebsocket import dispatch
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from mod_pywebsocket import handshake
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from mod_pywebsocket import http_header_util
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from mod_pywebsocket import memorizingfile
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from mod_pywebsocket import util
182f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)from mod_pywebsocket.xhr_benchmark_handler import XHRBenchmarkHandler
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_DEFAULT_LOG_MAX_BYTES = 1024 * 256
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_DEFAULT_LOG_BACKUP_COUNT = 5
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_DEFAULT_REQUEST_QUEUE_SIZE = 128
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# 1024 is practically large enough to contain WebSocket handshake lines.
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_MAX_MEMORIZED_LINES = 1024
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
19353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)# Constants for the --tls_module flag.
19453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)_TLS_BY_STANDARD_MODULE = 'ssl'
19553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)_TLS_BY_PYOPENSSL = 'pyopenssl'
19653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class _StandaloneConnection(object):
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """Mimic mod_python mp_conn."""
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __init__(self, request_handler):
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Construct an instance.
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Args:
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            request_handler: A WebSocketRequestHandler instance.
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._request_handler = request_handler
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def get_local_addr(self):
2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Getter to mimic mp_conn.local_addr."""
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return (self._request_handler.server.server_name,
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._request_handler.server.server_port)
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    local_addr = property(get_local_addr)
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def get_remote_addr(self):
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Getter to mimic mp_conn.remote_addr.
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Setting the property in __init__ won't work because the request
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        handler is not initialized yet there."""
2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._request_handler.client_address
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    remote_addr = property(get_remote_addr)
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def write(self, data):
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Mimic mp_conn.write()."""
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._request_handler.wfile.write(data)
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def read(self, length):
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Mimic mp_conn.read()."""
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._request_handler.rfile.read(length)
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def get_memorized_lines(self):
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Get memorized lines."""
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._request_handler.rfile.get_memorized_lines()
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class _StandaloneRequest(object):
2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """Mimic mod_python request."""
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __init__(self, request_handler, use_tls):
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Construct an instance.
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Args:
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            request_handler: A WebSocketRequestHandler instance.
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._logger = util.get_class_logger(self)
2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._request_handler = request_handler
2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.connection = _StandaloneConnection(request_handler)
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._use_tls = use_tls
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.headers_in = request_handler.headers
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def get_uri(self):
26053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        """Getter to mimic request.uri.
26153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
26253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        This method returns the raw data at the Request-URI part of the
26353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        Request-Line, while the uri method on the request object of mod_python
26453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        returns the path portion after parsing the raw data. This behavior is
26553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        kept for compatibility.
26653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        """
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._request_handler.path
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    uri = property(get_uri)
2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
27153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    def get_unparsed_uri(self):
27253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        """Getter to mimic request.unparsed_uri."""
27353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
27453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        return self._request_handler.path
27553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    unparsed_uri = property(get_unparsed_uri)
27653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def get_method(self):
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Getter to mimic request.method."""
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._request_handler.command
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    method = property(get_method)
2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def get_protocol(self):
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Getter to mimic request.protocol."""
2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._request_handler.request_version
2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    protocol = property(get_protocol)
2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def is_https(self):
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Mimic request.is_https()."""
2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._use_tls
2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
29553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)def _import_ssl():
29653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    global ssl
29753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    try:
29853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        import ssl
29953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        return True
30053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    except ImportError:
30153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        return False
30253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
3035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
30453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)def _import_pyopenssl():
30553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    global OpenSSL
30653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    try:
30753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        import OpenSSL.SSL
30853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        return True
30953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    except ImportError:
31053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        return False
3115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class _StandaloneSSLConnection(object):
31453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    """A wrapper class for OpenSSL.SSL.Connection to
31553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    - provide makefile method which is not supported by the class
31653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    - tweak shutdown method since OpenSSL.SSL.Connection.shutdown doesn't
31753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)      accept the "how" argument.
31853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    - convert SysCallError exceptions that its recv method may raise into a
31953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)      return value of '', meaning EOF. We cannot overwrite the recv method on
32053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)      self._connection since it's immutable.
3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """
3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
32353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    _OVERRIDDEN_ATTRIBUTES = ['_connection', 'makefile', 'shutdown', 'recv']
32453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __init__(self, connection):
3265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._connection = connection
3275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __getattribute__(self, name):
32953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        if name in _StandaloneSSLConnection._OVERRIDDEN_ATTRIBUTES:
3305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return object.__getattribute__(self, name)
3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._connection.__getattribute__(name)
3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __setattr__(self, name, value):
33453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        if name in _StandaloneSSLConnection._OVERRIDDEN_ATTRIBUTES:
3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return object.__setattr__(self, name, value)
3365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._connection.__setattr__(name, value)
3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def makefile(self, mode='r', bufsize=-1):
33953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        return socket._fileobject(self, mode, bufsize)
34053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
34153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    def shutdown(self, unused_how):
34253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        self._connection.shutdown()
34353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
34453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    def recv(self, bufsize, flags=0):
34553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        if flags != 0:
34653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            raise ValueError('Non-zero flags not allowed')
34753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
34853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        try:
34953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            return self._connection.recv(bufsize)
35053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        except OpenSSL.SSL.SysCallError, (err, message):
35153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            if err == -1:
35253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                # Suppress "unexpected EOF" exception. See the OpenSSL document
35353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                # for SSL_get_error.
35453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                return ''
35553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            raise
3565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def _alias_handlers(dispatcher, websock_handlers_map_file):
3595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """Set aliases specified in websock_handler_map_file in dispatcher.
3605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Args:
3625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        dispatcher: dispatch.Dispatcher instance
3635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        websock_handler_map_file: alias map file
3645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """
3655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    fp = open(websock_handlers_map_file)
3675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    try:
3685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for line in fp:
3695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if line[0] == '#' or line.isspace():
3705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                continue
3715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            m = re.match('(\S+)\s+(\S+)', line)
3725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if not m:
3735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                logging.warning('Wrong format in map file:' + line)
3745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                continue
3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            try:
3765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                dispatcher.add_resource_path_alias(
3775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    m.group(1), m.group(2))
3785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            except dispatch.DispatchException, e:
3795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                logging.error(str(e))
3805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    finally:
3815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        fp.close()
3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class WebSocketServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
3855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """HTTPServer specialized for WebSocket."""
3865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # Overrides SocketServer.ThreadingMixIn.daemon_threads
3885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    daemon_threads = True
3895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # Overrides BaseHTTPServer.HTTPServer.allow_reuse_address
3905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    allow_reuse_address = True
3915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __init__(self, options):
3935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Override SocketServer.TCPServer.__init__ to set SSL enabled
3945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        socket object to self.socket before server_bind and server_activate,
3955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if necessary.
3965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """
3975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # Share a Dispatcher among request handlers to save time for
3995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # instantiation.  Dispatcher can be shared because it is thread-safe.
4005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        options.dispatcher = dispatch.Dispatcher(
4015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            options.websock_handlers,
4025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            options.scan_dir,
4035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            options.allow_handlers_outside_root_dir)
4045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if options.websock_handlers_map_file:
4055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            _alias_handlers(options.dispatcher,
4065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            options.websock_handlers_map_file)
4075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        warnings = options.dispatcher.source_warnings()
4085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if warnings:
4095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            for warning in warnings:
41053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                logging.warning('Warning in source loading: %s' % warning)
4115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._logger = util.get_class_logger(self)
4135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.request_queue_size = options.request_queue_size
4155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.__ws_is_shut_down = threading.Event()
4165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.__ws_serving = False
4175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        SocketServer.BaseServer.__init__(
4195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self, (options.server_host, options.port), WebSocketRequestHandler)
4205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # Expose the options object to allow handler objects access it. We name
4225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # it with websocket_ prefix to avoid conflict.
4235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.websocket_server_options = options
4245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._create_sockets()
4265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.server_bind()
4275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.server_activate()
4285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def _create_sockets(self):
4305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.server_name, self.server_port = self.server_address
4315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._sockets = []
4325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if not self.server_name:
4335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # On platforms that doesn't support IPv6, the first bind fails.
4345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # On platforms that supports IPv6
4355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # - If it binds both IPv4 and IPv6 on call with AF_INET6, the
4365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            #   first bind succeeds and the second fails (we'll see 'Address
4375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            #   already in use' error).
4385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # - If it binds only IPv6 on call with AF_INET6, both call are
4395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            #   expected to succeed to listen both protocol.
4405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            addrinfo_array = [
4415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                (socket.AF_INET6, socket.SOCK_STREAM, '', '', ''),
4425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                (socket.AF_INET, socket.SOCK_STREAM, '', '', '')]
4435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else:
4445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            addrinfo_array = socket.getaddrinfo(self.server_name,
4455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                                self.server_port,
4465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                                socket.AF_UNSPEC,
4475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                                socket.SOCK_STREAM,
4485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                                socket.IPPROTO_TCP)
4495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for addrinfo in addrinfo_array:
4505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._logger.info('Create socket on: %r', addrinfo)
4515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            family, socktype, proto, canonname, sockaddr = addrinfo
4525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            try:
4535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                socket_ = socket.socket(family, socktype)
4545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            except Exception, e:
4555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._logger.info('Skip by failure: %r', e)
4565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                continue
45753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            server_options = self.websocket_server_options
45853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            if server_options.use_tls:
45953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                # For the case of _HAS_OPEN_SSL, we do wrapper setup after
46053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                # accept.
46153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                if server_options.tls_module == _TLS_BY_STANDARD_MODULE:
46253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                    if server_options.tls_client_auth:
46353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                        if server_options.tls_client_cert_optional:
46453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                            client_cert_ = ssl.CERT_OPTIONAL
46553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                        else:
46653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                            client_cert_ = ssl.CERT_REQUIRED
4675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    else:
4685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        client_cert_ = ssl.CERT_NONE
4695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    socket_ = ssl.wrap_socket(socket_,
47053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                        keyfile=server_options.private_key,
47153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                        certfile=server_options.certificate,
4725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        ssl_version=ssl.PROTOCOL_SSLv23,
47353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                        ca_certs=server_options.tls_client_ca,
47453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                        cert_reqs=client_cert_,
47553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                        do_handshake_on_connect=False)
4765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._sockets.append((socket_, addrinfo))
4775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def server_bind(self):
4795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Override SocketServer.TCPServer.server_bind to enable multiple
4805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        sockets bind.
4815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """
4825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        failed_sockets = []
4845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for socketinfo in self._sockets:
4865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            socket_, addrinfo = socketinfo
4875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._logger.info('Bind on: %r', addrinfo)
4885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if self.allow_reuse_address:
4895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                socket_.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
4905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            try:
4915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                socket_.bind(self.server_address)
4925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            except Exception, e:
4935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._logger.info('Skip by failure: %r', e)
4945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                socket_.close()
4955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                failed_sockets.append(socketinfo)
4965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if self.server_address[1] == 0:
4975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                # The operating system assigns the actual port number for port
4985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                # number 0. This case, the second and later sockets should use
4995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                # the same port number. Also self.server_port is rewritten
5005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                # because it is exported, and will be used by external code.
5015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self.server_address = (
5025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    self.server_name, socket_.getsockname()[1])
5035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self.server_port = self.server_address[1]
5045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._logger.info('Port %r is assigned', self.server_port)
5055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for socketinfo in failed_sockets:
5075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._sockets.remove(socketinfo)
5085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def server_activate(self):
5105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Override SocketServer.TCPServer.server_activate to enable multiple
5115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        sockets listen.
5125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """
5135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        failed_sockets = []
5155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for socketinfo in self._sockets:
5175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            socket_, addrinfo = socketinfo
5185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._logger.info('Listen on: %r', addrinfo)
5195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            try:
5205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                socket_.listen(self.request_queue_size)
5215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            except Exception, e:
5225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._logger.info('Skip by failure: %r', e)
5235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                socket_.close()
5245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                failed_sockets.append(socketinfo)
5255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for socketinfo in failed_sockets:
5275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._sockets.remove(socketinfo)
5285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if len(self._sockets) == 0:
5305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._logger.critical(
5315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                'No sockets activated. Use info log level to see the reason.')
5325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def server_close(self):
5345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Override SocketServer.TCPServer.server_close to enable multiple
5355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        sockets close.
5365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """
5375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for socketinfo in self._sockets:
5395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            socket_, addrinfo = socketinfo
5405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._logger.info('Close on: %r', addrinfo)
5415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            socket_.close()
5425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def fileno(self):
5445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Override SocketServer.TCPServer.fileno."""
5455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._logger.critical('Not supported: fileno')
5475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._sockets[0][0].fileno()
5485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
54953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    def handle_error(self, request, client_address):
5505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Override SocketServer.handle_error."""
5515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._logger.error(
5535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            'Exception in processing request from: %r\n%s',
5545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            client_address,
5555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            util.get_stack_trace())
5565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # Note: client_address is a tuple.
5575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def get_request(self):
5595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Override TCPServer.get_request to wrap OpenSSL.SSL.Connection
5605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        object with _StandaloneSSLConnection to provide makefile method. We
5615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        cannot substitute OpenSSL.SSL.Connection.makefile since it's readonly
5625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        attribute.
5635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """
5645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        accepted_socket, client_address = self.socket.accept()
56653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
56753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        server_options = self.websocket_server_options
56853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        if server_options.use_tls:
56953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            if server_options.tls_module == _TLS_BY_STANDARD_MODULE:
57053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                try:
57153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                    accepted_socket.do_handshake()
57253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                except ssl.SSLError, e:
57353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                    self._logger.debug('%r', e)
57453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                    raise
57553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
57653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                # Print cipher in use. Handshake is done on accept.
57753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                self._logger.debug('Cipher: %s', accepted_socket.cipher())
57853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                self._logger.debug('Client cert: %r',
57953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                                   accepted_socket.getpeercert())
58053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            elif server_options.tls_module == _TLS_BY_PYOPENSSL:
58153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                # We cannot print the cipher in use. pyOpenSSL doesn't provide
58253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                # any method to fetch that.
58353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
58453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
58553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                ctx.use_privatekey_file(server_options.private_key)
58653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                ctx.use_certificate_file(server_options.certificate)
58753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
58853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                def default_callback(conn, cert, errnum, errdepth, ok):
58953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                    return ok == 1
59053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
59153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                # See the OpenSSL document for SSL_CTX_set_verify.
59253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                if server_options.tls_client_auth:
59353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                    verify_mode = OpenSSL.SSL.VERIFY_PEER
59453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                    if not server_options.tls_client_cert_optional:
59553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                        verify_mode |= OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT
59653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                    ctx.set_verify(verify_mode, default_callback)
59753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                    ctx.load_verify_locations(server_options.tls_client_ca,
59853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                                              None)
59953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                else:
60053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                    ctx.set_verify(OpenSSL.SSL.VERIFY_NONE, default_callback)
60153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
60253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                accepted_socket = OpenSSL.SSL.Connection(ctx, accepted_socket)
60353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                accepted_socket.set_accept_state()
60453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
60553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                # Convert SSL related error into socket.error so that
60653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                # SocketServer ignores them and keeps running.
60753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                #
60853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                # TODO(tyoshino): Convert all kinds of errors.
60953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                try:
61053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                    accepted_socket.do_handshake()
61153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                except OpenSSL.SSL.Error, e:
61253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                    # Set errno part to 1 (SSL_ERROR_SSL) like the ssl module
61353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                    # does.
61453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                    self._logger.debug('%r', e)
61553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                    raise socket.error(1, '%r' % e)
61653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                cert = accepted_socket.get_peer_certificate()
617bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)                if cert is not None:
618bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)                    self._logger.debug('Client cert subject: %r',
619bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)                                       cert.get_subject().get_components())
62053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                accepted_socket = _StandaloneSSLConnection(accepted_socket)
62153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            else:
62253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                raise ValueError('No TLS support module is available')
62353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
6245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return accepted_socket, client_address
6255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def serve_forever(self, poll_interval=0.5):
6275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Override SocketServer.BaseServer.serve_forever."""
6285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.__ws_serving = True
6305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.__ws_is_shut_down.clear()
6315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        handle_request = self.handle_request
6325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if hasattr(self, '_handle_request_noblock'):
6335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            handle_request = self._handle_request_noblock
6345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else:
6355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._logger.warning('Fallback to blocking request handler')
6365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        try:
6375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            while self.__ws_serving:
6385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                r, w, e = select.select(
6395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    [socket_[0] for socket_ in self._sockets],
6405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    [], [], poll_interval)
6415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                for socket_ in r:
6425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    self.socket = socket_
6435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    handle_request()
6445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self.socket = None
6455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        finally:
6465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self.__ws_is_shut_down.set()
6475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def shutdown(self):
6495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Override SocketServer.BaseServer.shutdown."""
6505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.__ws_serving = False
6525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.__ws_is_shut_down.wait()
6535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class WebSocketRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler):
6565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """CGIHTTPRequestHandler specialized for WebSocket."""
6575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # Use httplib.HTTPMessage instead of mimetools.Message.
6595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    MessageClass = httplib.HTTPMessage
6605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def setup(self):
6625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Override SocketServer.StreamRequestHandler.setup to wrap rfile
6635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        with MemorizingFile.
6645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        This method will be called by BaseRequestHandler's constructor
6665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        before calling BaseHTTPRequestHandler.handle.
6675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        BaseHTTPRequestHandler.handle will call
6685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        BaseHTTPRequestHandler.handle_one_request and it will call
6695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        WebSocketRequestHandler.parse_request.
6705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """
6715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # Call superclass's setup to prepare rfile, wfile, etc. See setup
6735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # definition on the root class SocketServer.StreamRequestHandler to
6745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # understand what this does.
6755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        CGIHTTPServer.CGIHTTPRequestHandler.setup(self)
6765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.rfile = memorizingfile.MemorizingFile(
6785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self.rfile,
6795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            max_memorized_lines=_MAX_MEMORIZED_LINES)
6805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __init__(self, request, client_address, server):
6825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._logger = util.get_class_logger(self)
6835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._options = server.websocket_server_options
6855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # Overrides CGIHTTPServerRequestHandler.cgi_directories.
6875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.cgi_directories = self._options.cgi_directories
6885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # Replace CGIHTTPRequestHandler.is_executable method.
6895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if self._options.is_executable_method is not None:
6905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self.is_executable = self._options.is_executable_method
6915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # This actually calls BaseRequestHandler.__init__.
6935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        CGIHTTPServer.CGIHTTPRequestHandler.__init__(
6945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self, request, client_address, server)
6955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def parse_request(self):
6975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Override BaseHTTPServer.BaseHTTPRequestHandler.parse_request.
6985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Return True to continue processing for HTTP(S), False otherwise.
7005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        See BaseHTTPRequestHandler.handle_one_request method which calls
7025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this method to understand how the return value will be handled.
7035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """
7045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # We hook parse_request method, but also call the original
7065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # CGIHTTPRequestHandler.parse_request since when we return False,
7075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # CGIHTTPRequestHandler.handle_one_request continues processing and
7085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # it needs variables set by CGIHTTPRequestHandler.parse_request.
7095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        #
7105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # Variables set by this method will be also used by WebSocket request
7115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # handling (self.path, self.command, self.requestline, etc. See also
7125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # how _StandaloneRequest's members are implemented using these
7135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # attributes).
7145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if not CGIHTTPServer.CGIHTTPRequestHandler.parse_request(self):
7155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return False
7165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if self._options.use_basic_auth:
7185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            auth = self.headers.getheader('Authorization')
7195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if auth != self._options.basic_auth_credential:
7205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self.send_response(401)
7215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self.send_header('WWW-Authenticate',
7225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                 'Basic realm="Pywebsocket"')
7235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self.end_headers()
7245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._logger.info('Request basic authentication')
7255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return True
7265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        host, port, resource = http_header_util.parse_uri(self.path)
728bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)
729bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)        # Special paths for XMLHttpRequest benchmark
730bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)        xhr_benchmark_helper_prefix = '/073be001e10950692ccbf3a2ad21c245'
731bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)        if resource == (xhr_benchmark_helper_prefix + '_send'):
732f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            xhr_benchmark_handler = XHRBenchmarkHandler(
733f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                self.headers, self.rfile, self.wfile)
734f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            xhr_benchmark_handler.do_send()
735bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)            return False
736bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)        if resource == (xhr_benchmark_helper_prefix + '_receive'):
737f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            xhr_benchmark_handler = XHRBenchmarkHandler(
738f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                self.headers, self.rfile, self.wfile)
739f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            xhr_benchmark_handler.do_receive()
740bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)            return False
741bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)
7425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if resource is None:
7435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._logger.info('Invalid URI: %r', self.path)
7445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._logger.info('Fallback to CGIHTTPRequestHandler')
7455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return True
7465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        server_options = self.server.websocket_server_options
7475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if host is not None:
7485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            validation_host = server_options.validation_host
7495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if validation_host is not None and host != validation_host:
7505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._logger.info('Invalid host: %r (expected: %r)',
7515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                  host,
7525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                  validation_host)
7535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._logger.info('Fallback to CGIHTTPRequestHandler')
7545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return True
7555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if port is not None:
7565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            validation_port = server_options.validation_port
7575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if validation_port is not None and port != validation_port:
7585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._logger.info('Invalid port: %r (expected: %r)',
7595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                  port,
7605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                  validation_port)
7615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._logger.info('Fallback to CGIHTTPRequestHandler')
7625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return True
7635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.path = resource
7645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        request = _StandaloneRequest(self, self._options.use_tls)
7665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        try:
7685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # Fallback to default http handler for request paths for which
7695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # we don't have request handlers.
7705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if not self._options.dispatcher.get_handler_suite(self.path):
7715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._logger.info('No handler for resource: %r',
7725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                  self.path)
7735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._logger.info('Fallback to CGIHTTPRequestHandler')
7745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return True
7755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        except dispatch.DispatchException, e:
77653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            self._logger.info('Dispatch failed for error: %s', e)
7775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self.send_error(e.status)
7785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return False
7795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # If any Exceptions without except clause setup (including
7815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # DispatchException) is raised below this point, it will be caught
7825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # and logged by WebSocketServer.
7835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        try:
7855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            try:
7865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                handshake.do_handshake(
7875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    request,
7885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    self._options.dispatcher,
7895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    allowDraft75=self._options.allow_draft75,
7905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    strict=self._options.strict)
7915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            except handshake.VersionException, e:
79253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                self._logger.info('Handshake failed for version error: %s', e)
7935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self.send_response(common.HTTP_STATUS_BAD_REQUEST)
7945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self.send_header(common.SEC_WEBSOCKET_VERSION_HEADER,
7955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                 e.supported_versions)
7965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self.end_headers()
7975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return False
7985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            except handshake.HandshakeException, e:
7995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                # Handshake for ws(s) failed.
80053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                self._logger.info('Handshake failed for error: %s', e)
8015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self.send_error(e.status)
8025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return False
8035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            request._dispatcher = self._options.dispatcher
8055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._options.dispatcher.transfer_data(request)
8065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        except handshake.AbortedByUserException, e:
80753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            self._logger.info('Aborted: %s', e)
8085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return False
8095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def log_request(self, code='-', size='-'):
8115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Override BaseHTTPServer.log_request."""
8125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._logger.info('"%s" %s %s',
8145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                          self.requestline, str(code), str(size))
8155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def log_error(self, *args):
8175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Override BaseHTTPServer.log_error."""
8185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # Despite the name, this method is for warnings than for errors.
8205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # For example, HTTP status code is logged by this method.
8215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._logger.warning('%s - %s',
8225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                             self.address_string(),
8235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                             args[0] % args[1:])
8245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def is_cgi(self):
8265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Test whether self.path corresponds to a CGI script.
8275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Add extra check that self.path doesn't contains ..
8295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Also check if the file is a executable file or not.
8305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        If the file is not executable, it is handled as static file or dir
8315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        rather than a CGI script.
8325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """
8335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if CGIHTTPServer.CGIHTTPRequestHandler.is_cgi(self):
8355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if '..' in self.path:
8365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return False
8375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # strip query parameter from request path
8385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            resource_name = self.path.split('?', 2)[0]
8395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # convert resource_name into real path name in filesystem.
8405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            scriptfile = self.translate_path(resource_name)
8415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if not os.path.isfile(scriptfile):
8425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return False
8435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if not self.is_executable(scriptfile):
8445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return False
8455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return True
8465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return False
8475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def _get_logger_from_class(c):
8505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return logging.getLogger('%s.%s' % (c.__module__, c.__name__))
8515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def _configure_logging(options):
8545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    logging.addLevelName(common.LOGLEVEL_FINE, 'FINE')
8555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    logger = logging.getLogger()
8575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    logger.setLevel(logging.getLevelName(options.log_level.upper()))
8585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if options.log_file:
8595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        handler = logging.handlers.RotatingFileHandler(
8605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                options.log_file, 'a', options.log_max, options.log_count)
8615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    else:
8625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        handler = logging.StreamHandler()
8635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    formatter = logging.Formatter(
8645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            '[%(asctime)s] [%(levelname)s] %(name)s: %(message)s')
8655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    handler.setFormatter(formatter)
8665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    logger.addHandler(handler)
8675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    deflate_log_level_name = logging.getLevelName(
8695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        options.deflate_log_level.upper())
8705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _get_logger_from_class(util._Deflater).setLevel(
8715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        deflate_log_level_name)
8725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _get_logger_from_class(util._Inflater).setLevel(
8735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        deflate_log_level_name)
8745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def _build_option_parser():
8775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser = optparse.OptionParser()
8785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('--config', dest='config_file', type='string',
8805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      default=None,
8815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help=('Path to configuration file. See the file comment '
8825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'at the top of this file for the configuration '
8835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'file format'))
8845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('-H', '--server-host', '--server_host',
8855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      dest='server_host',
8865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      default='',
8875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help='server hostname to listen to')
8885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('-V', '--validation-host', '--validation_host',
8895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      dest='validation_host',
8905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      default=None,
8915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help='server hostname to validate in absolute path.')
8925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('-p', '--port', dest='port', type='int',
8935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      default=common.DEFAULT_WEB_SOCKET_PORT,
8945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help='port to listen to')
8955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('-P', '--validation-port', '--validation_port',
8965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      dest='validation_port', type='int',
8975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      default=None,
8985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help='server port to validate in absolute path.')
8995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('-w', '--websock-handlers', '--websock_handlers',
9005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      dest='websock_handlers',
9015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      default='.',
9025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help=('The root directory of WebSocket handler files. '
9035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'If the path is relative, --document-root is used '
9045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'as the base.'))
9055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('-m', '--websock-handlers-map-file',
9065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      '--websock_handlers_map_file',
9075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      dest='websock_handlers_map_file',
9085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      default=None,
9095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help=('WebSocket handlers map file. '
9105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'Each line consists of alias_resource_path and '
9115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'existing_resource_path, separated by spaces.'))
9125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('-s', '--scan-dir', '--scan_dir', dest='scan_dir',
9135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      default=None,
9145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help=('Must be a directory under --websock-handlers. '
9155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'Only handlers under this directory are scanned '
9165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'and registered to the server. '
9175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'Useful for saving scan time when the handler '
9185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'root directory contains lots of files that are '
9195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'not handler file or are handler files but you '
9205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'don\'t want them to be registered. '))
9215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('--allow-handlers-outside-root-dir',
9225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      '--allow_handlers_outside_root_dir',
9235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      dest='allow_handlers_outside_root_dir',
9245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      action='store_true',
9255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      default=False,
9265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help=('Scans WebSocket handlers even if their canonical '
9275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'path is not under --websock-handlers.'))
9285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('-d', '--document-root', '--document_root',
9295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      dest='document_root', default='.',
9305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help='Document root directory.')
9315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('-x', '--cgi-paths', '--cgi_paths', dest='cgi_paths',
9325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      default=None,
9335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help=('CGI paths relative to document_root.'
9345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'Comma-separated. (e.g -x /cgi,/htbin) '
9355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'Files under document_root/cgi_path are handled '
9365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'as CGI programs. Must be executable.'))
9375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('-t', '--tls', dest='use_tls', action='store_true',
9385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      default=False, help='use TLS (wss://)')
93953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    parser.add_option('--tls-module', '--tls_module', dest='tls_module',
94053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                      type='choice',
94153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                      choices = [_TLS_BY_STANDARD_MODULE, _TLS_BY_PYOPENSSL],
94253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                      help='Use ssl module if "%s" is specified. '
94353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                      'Use pyOpenSSL module if "%s" is specified' %
94453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                      (_TLS_BY_STANDARD_MODULE, _TLS_BY_PYOPENSSL))
9455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('-k', '--private-key', '--private_key',
9465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      dest='private_key',
9475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      default='', help='TLS private key file.')
9485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('-c', '--certificate', dest='certificate',
9495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      default='', help='TLS certificate file.')
9505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('--tls-client-auth', dest='tls_client_auth',
9515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      action='store_true', default=False,
95253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                      help='Requests TLS client auth on every connection.')
95353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    parser.add_option('--tls-client-cert-optional',
95453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                      dest='tls_client_cert_optional',
95553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                      action='store_true', default=False,
95653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                      help=('Makes client certificate optional even though '
95753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                            'TLS client auth is enabled.'))
9585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('--tls-client-ca', dest='tls_client_ca', default='',
9595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help=('Specifies a pem file which contains a set of '
9605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'concatenated CA certificates which are used to '
9615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'validate certificates passed from clients'))
9625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('--basic-auth', dest='use_basic_auth',
9635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      action='store_true', default=False,
9645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help='Requires Basic authentication.')
9655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('--basic-auth-credential',
9665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      dest='basic_auth_credential', default='test:test',
9675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help='Specifies the credential of basic authentication '
9685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      'by username:password pair (e.g. test:test).')
9695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('-l', '--log-file', '--log_file', dest='log_file',
9705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      default='', help='Log file.')
9715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # Custom log level:
9725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # - FINE: Prints status of each frame processing step
9735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('--log-level', '--log_level', type='choice',
9745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      dest='log_level', default='warn',
9755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      choices=['fine',
9765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                               'debug', 'info', 'warning', 'warn', 'error',
9775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                               'critical'],
9785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help='Log level.')
9795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('--deflate-log-level', '--deflate_log_level',
9805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      type='choice',
9815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      dest='deflate_log_level', default='warn',
9825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      choices=['debug', 'info', 'warning', 'warn', 'error',
9835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                               'critical'],
9845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help='Log level for _Deflater and _Inflater.')
9855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('--thread-monitor-interval-in-sec',
9865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      '--thread_monitor_interval_in_sec',
9875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      dest='thread_monitor_interval_in_sec',
9885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      type='int', default=-1,
9895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help=('If positive integer is specified, run a thread '
9905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'monitor to show the status of server threads '
9915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'periodically in the specified inteval in '
9925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'second. If non-positive integer is specified, '
9935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            'disable the thread monitor.'))
9945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('--log-max', '--log_max', dest='log_max', type='int',
9955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      default=_DEFAULT_LOG_MAX_BYTES,
9965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help='Log maximum bytes')
9975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('--log-count', '--log_count', dest='log_count',
9985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      type='int', default=_DEFAULT_LOG_BACKUP_COUNT,
9995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help='Log backup count')
10005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('--allow-draft75', dest='allow_draft75',
10015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      action='store_true', default=False,
10025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help='Obsolete option. Ignored.')
10035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('--strict', dest='strict', action='store_true',
10045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      default=False, help='Obsolete option. Ignored.')
10055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser.add_option('-q', '--queue', dest='request_queue_size', type='int',
10065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      default=_DEFAULT_REQUEST_QUEUE_SIZE,
10075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      help='request queue size')
10085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return parser
10105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class ThreadMonitor(threading.Thread):
10135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    daemon = True
10145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __init__(self, interval_in_sec):
10165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        threading.Thread.__init__(self, name='ThreadMonitor')
10175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._logger = util.get_class_logger(self)
10195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._interval_in_sec = interval_in_sec
10215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def run(self):
10235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        while True:
10245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            thread_name_list = []
10255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            for thread in threading.enumerate():
10265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                thread_name_list.append(thread.name)
10275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._logger.info(
10285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                "%d active threads: %s",
10295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                threading.active_count(),
10305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                ', '.join(thread_name_list))
10315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            time.sleep(self._interval_in_sec)
10325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def _parse_args_and_config(args):
10355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser = _build_option_parser()
10365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # First, parse options without configuration file.
10385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    temporary_options, temporary_args = parser.parse_args(args=args)
10395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if temporary_args:
10405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        logging.critical(
10415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            'Unrecognized positional arguments: %r', temporary_args)
10425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        sys.exit(1)
10435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if temporary_options.config_file:
10455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        try:
10465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            config_fp = open(temporary_options.config_file, 'r')
10475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        except IOError, e:
10485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            logging.critical(
10495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                'Failed to open configuration file %r: %r',
10505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                temporary_options.config_file,
10515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                e)
10525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            sys.exit(1)
10535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        config_parser = ConfigParser.SafeConfigParser()
10555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        config_parser.readfp(config_fp)
10565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        config_fp.close()
10575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        args_from_config = []
10595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for name, value in config_parser.items('pywebsocket'):
10605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            args_from_config.append('--' + name)
10615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            args_from_config.append(value)
10625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if args is None:
10635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            args = args_from_config
10645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else:
10655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            args = args_from_config + args
10665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return parser.parse_args(args=args)
10675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    else:
10685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return temporary_options, temporary_args
10695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def _main(args=None):
10725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """You can call this function from your own program, but please note that
10735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    this function has some side-effects that might affect your program. For
10745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    example, util.wrap_popen3_for_win use in this method replaces implementation
10755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    of os.popen3.
10765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """
10775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    options, args = _parse_args_and_config(args=args)
10795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    os.chdir(options.document_root)
10815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _configure_logging(options)
10835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
108453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    if options.allow_draft75:
108553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        logging.warning('--allow_draft75 option is obsolete.')
108653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
108753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    if options.strict:
108853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        logging.warning('--strict option is obsolete.')
108953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
10905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # TODO(tyoshino): Clean up initialization of CGI related values. Move some
10915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # of code here to WebSocketRequestHandler class if it's better.
10925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    options.cgi_directories = []
10935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    options.is_executable_method = None
10945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if options.cgi_paths:
10955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        options.cgi_directories = options.cgi_paths.split(',')
10965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if sys.platform in ('cygwin', 'win32'):
10975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            cygwin_path = None
10985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # For Win32 Python, it is expected that CYGWIN_PATH
10995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # is set to a directory of cygwin binaries.
11005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # For example, websocket_server.py in Chromium sets CYGWIN_PATH to
11015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # full path of third_party/cygwin/bin.
11025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if 'CYGWIN_PATH' in os.environ:
11035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                cygwin_path = os.environ['CYGWIN_PATH']
11045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            util.wrap_popen3_for_win(cygwin_path)
11055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            def __check_script(scriptpath):
11075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return util.get_script_interp(scriptpath, cygwin_path)
11085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            options.is_executable_method = __check_script
11105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if options.use_tls:
111253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        if options.tls_module is None:
111353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            if _import_ssl():
111453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                options.tls_module = _TLS_BY_STANDARD_MODULE
111553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                logging.debug('Using ssl module')
111653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            elif _import_pyopenssl():
111753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                options.tls_module = _TLS_BY_PYOPENSSL
111853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                logging.debug('Using pyOpenSSL module')
111953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            else:
112053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                logging.critical(
112153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                        'TLS support requires ssl or pyOpenSSL module.')
112253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                sys.exit(1)
112353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        elif options.tls_module == _TLS_BY_STANDARD_MODULE:
112453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            if not _import_ssl():
112553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                logging.critical('ssl module is not available')
112653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                sys.exit(1)
112753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        elif options.tls_module == _TLS_BY_PYOPENSSL:
112853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            if not _import_pyopenssl():
112953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                logging.critical('pyOpenSSL module is not available')
113053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                sys.exit(1)
113153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        else:
113253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            logging.critical('Invalid --tls-module option: %r',
113353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                             options.tls_module)
11345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            sys.exit(1)
113553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
11365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if not options.private_key or not options.certificate:
11375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            logging.critical(
11385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    'To use TLS, specify private_key and certificate.')
11395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            sys.exit(1)
11405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
114153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        if (options.tls_client_cert_optional and
114253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            not options.tls_client_auth):
114353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            logging.critical('Client authentication must be enabled to '
114453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                             'specify tls_client_cert_optional')
114553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            sys.exit(1)
114653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    else:
114753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        if options.tls_module is not None:
114853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            logging.critical('Use --tls-module option only together with '
114953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                             '--use-tls option.')
115053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            sys.exit(1)
115153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
115253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        if options.tls_client_auth:
115353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            logging.critical('TLS must be enabled for client authentication.')
115453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            sys.exit(1)
115553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
115653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        if options.tls_client_cert_optional:
11575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            logging.critical('TLS must be enabled for client authentication.')
11585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            sys.exit(1)
11595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if not options.scan_dir:
11615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        options.scan_dir = options.websock_handlers
11625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if options.use_basic_auth:
11645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        options.basic_auth_credential = 'Basic ' + base64.b64encode(
11655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            options.basic_auth_credential)
11665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    try:
11685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if options.thread_monitor_interval_in_sec > 0:
11695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # Run a thread monitor to show the status of server threads for
11705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # debugging.
11715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ThreadMonitor(options.thread_monitor_interval_in_sec).start()
11725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        server = WebSocketServer(options)
11745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        server.serve_forever()
11755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    except Exception, e:
11765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        logging.critical('mod_pywebsocket: %s' % e)
11775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        logging.critical('mod_pywebsocket: %s' % util.get_stack_trace())
11785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        sys.exit(1)
11795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)if __name__ == '__main__':
11825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _main(sys.argv[1:])
11835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# vi:sts=4 sw=4 et
1186