yuzo | 9d0f030 | 2009-10-02 01:55:18 +0000 | [diff] [blame] | 1 | # Copyright 2009, Google Inc. |
| 2 | # All rights reserved. |
yuzo | e6371be | 2009-09-17 10:54:10 +0000 | [diff] [blame] | 3 | # |
yuzo | 9d0f030 | 2009-10-02 01:55:18 +0000 | [diff] [blame] | 4 | # Redistribution and use in source and binary forms, with or without |
| 5 | # modification, are permitted provided that the following conditions are |
| 6 | # met: |
yuzo | e6371be | 2009-09-17 10:54:10 +0000 | [diff] [blame] | 7 | # |
yuzo | 9d0f030 | 2009-10-02 01:55:18 +0000 | [diff] [blame] | 8 | # * 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. |
yuzo | e6371be | 2009-09-17 10:54:10 +0000 | [diff] [blame] | 17 | # |
yuzo | 9d0f030 | 2009-10-02 01:55:18 +0000 | [diff] [blame] | 18 | # 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. |
yuzo | e6371be | 2009-09-17 10:54:10 +0000 | [diff] [blame] | 29 | |
| 30 | |
| 31 | """PythonHeaderParserHandler for mod_pywebsocket. |
| 32 | |
| 33 | Apache HTTP Server and mod_python must be configured such that this |
| 34 | function is called to handle Web Socket request. |
| 35 | """ |
| 36 | |
| 37 | |
| 38 | from mod_python import apache |
| 39 | |
| 40 | import dispatch |
| 41 | import handshake |
ukai | a059581 | 2010-03-17 06:56:50 +0000 | [diff] [blame^] | 42 | import logging |
yuzo | e6371be | 2009-09-17 10:54:10 +0000 | [diff] [blame] | 43 | import util |
| 44 | |
| 45 | |
| 46 | # PythonOption to specify the handler root directory. |
| 47 | _PYOPT_HANDLER_ROOT = 'mod_pywebsocket.handler_root' |
| 48 | |
yuzo | 7397918 | 2009-10-26 02:27:34 +0000 | [diff] [blame] | 49 | # 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 | |
ukai | a059581 | 2010-03-17 06:56:50 +0000 | [diff] [blame^] | 54 | # PythonOption to specify to allow draft75 handshake. |
| 55 | # The default is None (Off) |
| 56 | _PYOPT_ALLOW_DRAFT75 = 'mod_pywebsocket.allow_draft75' |
| 57 | |
| 58 | |
| 59 | class 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 | |
| 81 | logging.getLogger("mod_pywebsocket").addHandler(ApacheLogHandler()) |
| 82 | |
yuzo | e6371be | 2009-09-17 10:54:10 +0000 | [diff] [blame] | 83 | |
| 84 | def _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) |
yuzo | 7397918 | 2009-10-26 02:27:34 +0000 | [diff] [blame] | 90 | _HANDLER_SCAN = apache.main_server.get_options().get( |
| 91 | _PYOPT_HANDLER_SCAN, _HANDLER_ROOT) |
| 92 | dispatcher = dispatch.Dispatcher(_HANDLER_ROOT, _HANDLER_SCAN) |
yuzo | e6371be | 2009-09-17 10:54:10 +0000 | [diff] [blame] | 93 | 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 | |
| 102 | def 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: |
ukai | a059581 | 2010-03-17 06:56:50 +0000 | [diff] [blame^] | 113 | allowDraft75 = apache.main_server.get_options().get( |
| 114 | _PYOPT_ALLOW_DRAFT75, None) |
| 115 | handshaker = handshake.Handshaker(request, _dispatcher, |
| 116 | allowDraft75=allowDraft75) |
yuzo | 4d12264 | 2009-10-15 09:41:56 +0000 | [diff] [blame] | 117 | handshaker.do_handshake() |
yuzo | 2fba464 | 2009-10-15 10:02:46 +0000 | [diff] [blame] | 118 | request.log_error('mod_pywebsocket: resource: %r' % request.ws_resource, |
yuzo | e6371be | 2009-09-17 10:54:10 +0000 | [diff] [blame] | 119 | apache.APLOG_DEBUG) |
ukai | a059581 | 2010-03-17 06:56:50 +0000 | [diff] [blame^] | 120 | 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) |
yuzo | e6371be | 2009-09-17 10:54:10 +0000 | [diff] [blame] | 127 | 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 |