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