blob: 9d40ab6945e27aeec61fb98be747747e2f007b79 [file] [log] [blame]
yuzo9d0f0302009-10-02 01:55:18 +00001# Copyright 2009, Google Inc.
2# All rights reserved.
yuzoe6371be2009-09-17 10:54:10 +00003#
yuzo9d0f0302009-10-02 01:55:18 +00004# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are
6# met:
yuzoe6371be2009-09-17 10:54:10 +00007#
yuzo9d0f0302009-10-02 01:55:18 +00008# * Redistributions of source code must retain the above copyright
9# notice, this list of conditions and the following disclaimer.
10# * Redistributions in binary form must reproduce the above
11# copyright notice, this list of conditions and the following disclaimer
12# in the documentation and/or other materials provided with the
13# distribution.
14# * Neither the name of Google Inc. nor the names of its
15# contributors may be used to endorse or promote products derived from
16# this software without specific prior written permission.
yuzoe6371be2009-09-17 10:54:10 +000017#
yuzo9d0f0302009-10-02 01:55:18 +000018# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
yuzoe6371be2009-09-17 10:54:10 +000029
30
31"""PythonHeaderParserHandler for mod_pywebsocket.
32
33Apache HTTP Server and mod_python must be configured such that this
34function is called to handle Web Socket request.
35"""
36
37
38from mod_python import apache
39
40import dispatch
41import handshake
ukaia0595812010-03-17 06:56:50 +000042import logging
yuzoe6371be2009-09-17 10:54:10 +000043import util
44
45
46# PythonOption to specify the handler root directory.
47_PYOPT_HANDLER_ROOT = 'mod_pywebsocket.handler_root'
48
yuzo73979182009-10-26 02:27:34 +000049# PythonOption to specify the handler scan directory.
50# This must be a directory under the root directory.
51# The default is the root directory.
52_PYOPT_HANDLER_SCAN = 'mod_pywebsocket.handler_scan'
53
ukaia0595812010-03-17 06:56:50 +000054# PythonOption to specify to allow draft75 handshake.
55# The default is None (Off)
56_PYOPT_ALLOW_DRAFT75 = 'mod_pywebsocket.allow_draft75'
57
58
59class ApacheLogHandler(logging.Handler):
60 """Wrapper logging.Handler to emit log message to apache's error.log"""
61 _LEVELS = {
62 logging.DEBUG: apache.APLOG_DEBUG,
63 logging.INFO: apache.APLOG_INFO,
64 logging.WARNING: apache.APLOG_WARNING,
65 logging.ERROR: apache.APLOG_ERR,
66 logging.CRITICAL: apache.APLOG_CRIT,
67 }
68 def __init__(self, request=None):
69 logging.Handler.__init__(self)
70 self.log_error = apache.log_error
71 if request is not None:
72 self.log_error = request.log_error
73
74 def emit(self, record):
75 apache_level = apache.APLOG_DEBUG
76 if record.levelno in ApacheLogHandler._LEVELS:
77 apache_level = ApacheLogHandler._LEVELS[record.levelno]
78 self.log_error(record.getMessage(), apache_level)
79
80
81logging.getLogger("mod_pywebsocket").addHandler(ApacheLogHandler())
82
yuzoe6371be2009-09-17 10:54:10 +000083
84def _create_dispatcher():
85 _HANDLER_ROOT = apache.main_server.get_options().get(
86 _PYOPT_HANDLER_ROOT, None)
87 if not _HANDLER_ROOT:
88 raise Exception('PythonOption %s is not defined' % _PYOPT_HANDLER_ROOT,
89 apache.APLOG_ERR)
yuzo73979182009-10-26 02:27:34 +000090 _HANDLER_SCAN = apache.main_server.get_options().get(
91 _PYOPT_HANDLER_SCAN, _HANDLER_ROOT)
92 dispatcher = dispatch.Dispatcher(_HANDLER_ROOT, _HANDLER_SCAN)
yuzoe6371be2009-09-17 10:54:10 +000093 for warning in dispatcher.source_warnings():
94 apache.log_error('mod_pywebsocket: %s' % warning, apache.APLOG_WARNING)
95 return dispatcher
96
97
98# Initialize
99_dispatcher = _create_dispatcher()
100
101
102def headerparserhandler(request):
103 """Handle request.
104
105 Args:
106 request: mod_python request.
107
108 This function is named headerparserhandler because it is the default name
109 for a PythonHeaderParserHandler.
110 """
111
112 try:
ukaia0595812010-03-17 06:56:50 +0000113 allowDraft75 = apache.main_server.get_options().get(
114 _PYOPT_ALLOW_DRAFT75, None)
115 handshaker = handshake.Handshaker(request, _dispatcher,
116 allowDraft75=allowDraft75)
yuzo4d122642009-10-15 09:41:56 +0000117 handshaker.do_handshake()
yuzo2fba4642009-10-15 10:02:46 +0000118 request.log_error('mod_pywebsocket: resource: %r' % request.ws_resource,
yuzoe6371be2009-09-17 10:54:10 +0000119 apache.APLOG_DEBUG)
ukaia0595812010-03-17 06:56:50 +0000120 try:
121 _dispatcher.transfer_data(request)
122 except Exception, e:
123 # Catch exception in transfer_data.
124 # In this case, handshake has been successful, so just log the
125 # exception and return apache.DONE
126 request.log_error('mod_pywebsocket: %s' % e, apache.APLOG_WARNING)
yuzoe6371be2009-09-17 10:54:10 +0000127 except handshake.HandshakeError, e:
128 # Handshake for ws/wss failed.
129 # But the request can be valid http/https request.
130 request.log_error('mod_pywebsocket: %s' % e, apache.APLOG_INFO)
131 return apache.DECLINED
132 except dispatch.DispatchError, e:
133 request.log_error('mod_pywebsocket: %s' % e, apache.APLOG_WARNING)
134 return apache.DECLINED
135 return apache.DONE # Return DONE such that no other handlers are invoked.
136
137
138# vi:sts=4 sw=4 et