Changeset 51406 in webkit


Ignore:
Timestamp:
Nov 25, 2009 10:16:09 PM (14 years ago)
Author:
eric@webkit.org
Message:

2009-11-25 Yuzo Fujishima <yuzo@google.com>

Reviewed by Eric Seidel.

Update pywebsocket to 0.4.2

Update pywebsocket to 0.4.2
https://bugs.webkit.org/show_bug.cgi?id=31861

  • pywebsocket/example/echo_client.py:
  • pywebsocket/example/echo_wsh.py:
  • pywebsocket/mod_pywebsocket/init.py:
  • pywebsocket/mod_pywebsocket/dispatch.py:
  • pywebsocket/mod_pywebsocket/msgutil.py:
  • pywebsocket/mod_pywebsocket/standalone.py:
  • pywebsocket/setup.py:
  • pywebsocket/test/test_dispatch.py:
  • pywebsocket/test/test_msgutil.py:
Location:
trunk/WebKitTools
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebKitTools/ChangeLog

    r51405 r51406  
     12009-11-25  Yuzo Fujishima  <yuzo@google.com>
     2
     3        Reviewed by Eric Seidel.
     4
     5        Update pywebsocket to 0.4.2
     6
     7        Update pywebsocket to 0.4.2
     8        https://bugs.webkit.org/show_bug.cgi?id=31861
     9
     10        * pywebsocket/example/echo_client.py:
     11        * pywebsocket/example/echo_wsh.py:
     12        * pywebsocket/mod_pywebsocket/__init__.py:
     13        * pywebsocket/mod_pywebsocket/dispatch.py:
     14        * pywebsocket/mod_pywebsocket/msgutil.py:
     15        * pywebsocket/mod_pywebsocket/standalone.py:
     16        * pywebsocket/setup.py:
     17        * pywebsocket/test/test_dispatch.py:
     18        * pywebsocket/test/test_msgutil.py:
     19
    1202009-11-25  Adam Barth  <abarth@webkit.org>
    221
  • trunk/WebKitTools/pywebsocket/example/echo_client.py

    r49672 r51406  
    4747
    4848
     49_TIMEOUT_SEC = 10
     50
    4951_DEFAULT_PORT = 80
    5052_DEFAULT_SECURE_PORT = 443
     
    5860        _CONNECTION_HEADER)
    5961
     62_GOODBYE_MESSAGE = 'Goodbye'
     63
    6064
    6165def _method_line(resource):
     
    97101        """
    98102        self._socket = socket.socket()
     103        self._socket.settimeout(self._options.socket_timeout)
    99104        try:
    100105            self._socket.connect((self._options.server_host,
     
    103108                self._socket = _TLSSocket(self._socket)
    104109            self._handshake()
    105             for line in self._options.message.split(','):
     110            for line in self._options.message.split(',') + [_GOODBYE_MESSAGE]:
    106111                frame = '\x00' + line.encode('utf-8') + '\xff'
    107112                self._socket.send(frame)
     
    112117                    raise Exception('Incorrect echo: %r' % received)
    113118                if self._options.verbose:
    114                     print 'Recv: %s' % received[1:-1].decode('utf-8')
     119                    print 'Recv: %s' % received[1:-1].decode('utf-8',
     120                                                             'replace')
    115121        finally:
    116122            self._socket.close()
     
    167173                      default='/echo', help='resource path')
    168174    parser.add_option('-m', '--message', dest='message', type='string',
    169                       help='comma-separated messages to send')
     175                      help=('comma-separated messages to send excluding "%s" '
     176                            'that is always sent at the end' %
     177                            _GOODBYE_MESSAGE))
    170178    parser.add_option('-q', '--quiet', dest='verbose', action='store_false',
    171179                      default=True, help='suppress messages')
    172180    parser.add_option('-t', '--tls', dest='use_tls', action='store_true',
    173181                      default=False, help='use TLS (wss://)')
     182    parser.add_option('-k', '--socket_timeout', dest='socket_timeout',
     183                      type='int', default=_TIMEOUT_SEC,
     184                      help='Timeout(sec) for sockets')
     185
    174186    (options, unused_args) = parser.parse_args()
    175187
  • trunk/WebKitTools/pywebsocket/example/echo_wsh.py

    r49672 r51406  
    3232
    3333
     34_GOODBYE_MESSAGE = 'Goodbye'
     35
     36
    3437def web_socket_do_extra_handshake(request):
    3538    pass  # Always accept.
     
    4043        line = msgutil.receive_message(request)
    4144        msgutil.send_message(request, line)
     45        if line == _GOODBYE_MESSAGE:
     46            return
    4247
    4348
  • trunk/WebKitTools/pywebsocket/mod_pywebsocket/__init__.py

    r50102 r51406  
    9797using request. mod_pywebsocket.msgutil module provides utilities
    9898for data transfer.
     99
     100A Web Socket handler must be thread-safe if the server (Apache or
     101standalone.py) is configured to use threads.
    99102"""
    100103
  • trunk/WebKitTools/pywebsocket/mod_pywebsocket/dispatch.py

    r51099 r51406  
    6363
    6464    path = path.replace('\\', os.path.sep)
    65     path = os.path.abspath(path)
     65    path = os.path.realpath(path)
    6666    path = path.replace('\\', '/')
    6767    return path
     
    137137        if scan_dir is None:
    138138            scan_dir = root_dir
    139         if not os.path.realpath(scan_dir).startswith(os.path.realpath(root_dir)):
     139        if not os.path.realpath(scan_dir).startswith(
     140                os.path.realpath(root_dir)):
    140141            raise DispatchError('scan_dir:%s must be a directory under '
    141142                                'root_dir:%s.' % (scan_dir, root_dir))
     
    183184    def _handler(self, request):
    184185        try:
    185             return self._handlers[request.ws_resource]
     186            ws_resource_path = request.ws_resource.split('?', 1)[0]
     187            return self._handlers[ws_resource_path]
    186188        except KeyError:
    187189            raise DispatchError('No handler for: %r' % request.ws_resource)
     
    189191    def _source_files_in_dir(self, root_dir, scan_dir):
    190192        """Source all the handler source files in the scan_dir directory.
    191        
     193
    192194        The resource path is determined relative to root_dir.
    193195        """
  • trunk/WebKitTools/pywebsocket/mod_pywebsocket/msgutil.py

    r49672 r51406  
    7474            # The payload is delimited with \xff.
    7575            bytes = _read_until(request, '\xff')
    76             message = bytes.decode('utf-8')
     76            # The Web Socket protocol section 4.4 specifies that invalid
     77            # characters must be replaced with U+fffd REPLACEMENT CHARACTER.
     78            message = bytes.decode('utf-8', 'replace')
    7779            if frame_type == 0x00:
    7880                return message
  • trunk/WebKitTools/pywebsocket/mod_pywebsocket/standalone.py

    r50102 r51406  
    3939                         [-s <scan_dir>]
    4040                         [-d <document_root>]
     41                         ... for other options, see _main below ...
    4142
    4243<ws_port> is the port number to use for ws:// connection.
     
    6061import SocketServer
    6162import logging
     63import logging.handlers
    6264import optparse
    6365import os
     
    7476import dispatch
    7577import handshake
     78
     79
     80_LOG_LEVELS = {
     81    'debug': logging.DEBUG,
     82    'info': logging.INFO,
     83    'warn': logging.WARN,
     84    'error': logging.ERROR,
     85    'critical': logging.CRITICAL};
     86
     87_DEFAULT_LOG_MAX_BYTES = 1024 * 256
     88_DEFAULT_LOG_BACKUP_COUNT = 5
     89
     90
     91def _print_warnings_if_any(dispatcher):
     92    warnings = dispatcher.source_warnings()
     93    if warnings:
     94        for warning in warnings:
     95            logging.warning('mod_pywebsocket: %s' % warning)
    7696
    7797
     
    153173        return socket_
    154174
     175
    155176class WebSocketRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
    156177    """SimpleHTTPRequestHandler specialized for Web Socket."""
     
    160181
    161182        self.connection = self.request
    162         self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
    163         self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
     183        self.rfile = socket._fileobject(self.request, 'rb', self.rbufsize)
     184        self.wfile = socket._fileobject(self.request, 'wb', self.wbufsize)
    164185
    165186    def __init__(self, *args, **keywords):
    166187        self._request = _StandaloneRequest(
    167188                self, WebSocketRequestHandler.options.use_tls)
    168         self._dispatcher = dispatch.Dispatcher(
    169                 WebSocketRequestHandler.options.websock_handlers,
    170                 WebSocketRequestHandler.options.scan_dir)
     189        self._dispatcher = WebSocketRequestHandler.options.dispatcher
    171190        self._print_warnings_if_any()
    172191        self._handshaker = handshake.Handshaker(self._request,
     
    201220        return result
    202221
     222    def log_request(self, code='-', size='-'):
     223        """Override BaseHTTPServer.log_request."""
     224
     225        logging.info('"%s" %s %s',
     226                     self.requestline, str(code), str(size))
     227
     228    def log_error(self, *args):
     229        """Override BaseHTTPServer.log_error."""
     230
     231        # Despite the name, this method is for warnings than for errors.
     232        # For example, HTTP status code is logged by this method.
     233        logging.warn('%s - %s' % (self.address_string(), (args[0] % args[1:])))
     234
     235
     236def _configure_logging(options):
     237    logger = logging.getLogger()
     238    logger.setLevel(_LOG_LEVELS[options.log_level])
     239    if options.log_file:
     240        handler = logging.handlers.RotatingFileHandler(
     241                options.log_file, 'a', options.log_max, options.log_count)
     242    else:
     243        handler = logging.StreamHandler()
     244    formatter = logging.Formatter(
     245            "[%(asctime)s] [%(levelname)s] %(name)s: %(message)s")
     246    handler.setFormatter(formatter)
     247    logger.addHandler(handler)
     248
    203249
    204250def _main():
    205     logging.basicConfig()
    206 
    207251    parser = optparse.OptionParser()
    208252    parser.add_option('-p', '--port', dest='port', type='int',
     
    225269    parser.add_option('-c', '--certificate', dest='certificate',
    226270                      default='', help='TLS certificate file.')
     271    parser.add_option('-l', '--log_file', dest='log_file',
     272                      default='', help='Log file.')
     273    parser.add_option('--log_level', type='choice', dest='log_level',
     274                      default='warn',
     275                      choices=['debug', 'info', 'warn', 'error', 'critical'],
     276                      help='Log level.')
     277    parser.add_option('--log_max', dest='log_max', type='int',
     278                      default=_DEFAULT_LOG_MAX_BYTES,
     279                      help='Log maximum bytes')
     280    parser.add_option('--log_count', dest='log_count', type='int',
     281                      default=_DEFAULT_LOG_BACKUP_COUNT,
     282                      help='Log backup count')
    227283    options = parser.parse_args()[0]
     284
     285    os.chdir(options.document_root)
     286
     287    _configure_logging(options)
    228288
    229289    if options.use_tls:
    230290        if not _HAS_OPEN_SSL:
    231             print >>sys.stderr, 'To use TLS, install pyOpenSSL.'
     291            logging.critical('To use TLS, install pyOpenSSL.')
    232292            sys.exit(1)
    233293        if not options.private_key or not options.certificate:
    234             print >>sys.stderr, ('To use TLS, specify private_key and '
    235                                  'certificate.')
     294            logging.critical(
     295                    'To use TLS, specify private_key and certificate.')
    236296            sys.exit(1)
    237297
     
    239299        options.scan_dir = options.websock_handlers
    240300
    241     WebSocketRequestHandler.options = options
    242     WebSocketServer.options = options
    243 
    244     os.chdir(options.document_root)
    245 
    246     server = WebSocketServer(('', options.port), WebSocketRequestHandler)
    247     server.serve_forever()
     301    try:
     302        # Share a Dispatcher among request handlers to save time for
     303        # instantiation.  Dispatcher can be shared because it is thread-safe.
     304        options.dispatcher = dispatch.Dispatcher(options.websock_handlers,
     305                                                 options.scan_dir)
     306        _print_warnings_if_any(options.dispatcher)
     307
     308        WebSocketRequestHandler.options = options
     309        WebSocketServer.options = options
     310
     311        server = WebSocketServer(('', options.port), WebSocketRequestHandler)
     312        server.serve_forever()
     313    except Exception, e:
     314        logging.critical(str(e))
     315        sys.exit(1)
    248316
    249317
  • trunk/WebKitTools/pywebsocket/setup.py

    r50102 r51406  
    5757      packages=[_PACKAGE_NAME],
    5858      url='http://code.google.com/p/pywebsocket/',
    59       version='0.4.1',
     59      version='0.4.2',
    6060      )
    6161
  • trunk/WebKitTools/pywebsocket/test/test_dispatch.py

    r50102 r51406  
    157157                         request.connection.written_data())
    158158
     159        request = mock.MockRequest(connection=mock.MockConn(''))
     160        request.ws_resource = '/sub/plain?'
     161        request.ws_protocol = None
     162        dispatcher.transfer_data(request)
     163        self.assertEqual('sub/plain_wsh.py is called for /sub/plain?, None',
     164                         request.connection.written_data())
     165
     166        request = mock.MockRequest(connection=mock.MockConn(''))
     167        request.ws_resource = '/sub/plain?q=v'
     168        request.ws_protocol = None
     169        dispatcher.transfer_data(request)
     170        self.assertEqual('sub/plain_wsh.py is called for /sub/plain?q=v, None',
     171                         request.connection.written_data())
     172
    159173    def test_transfer_data_no_handler(self):
    160174        dispatcher = dispatch.Dispatcher(_TEST_HANDLERS_DIR, None)
  • trunk/WebKitTools/pywebsocket/test/test_msgutil.py

    r49672 r51406  
    7171        # U+672c is encoded as e6,9c,ac in UTF-8
    7272        self.assertEqual(u'\u672c', msgutil.receive_message(request))
     73
     74    def test_receive_message_erroneous_unicode(self):
     75        # \x80 and \x81 are invalid as UTF-8.
     76        request = _create_request('\x00\x80\x81\xff')
     77        # Invalid characters should be replaced with
     78        # U+fffd REPLACEMENT CHARACTER
     79        self.assertEqual(u'\ufffd\ufffd', msgutil.receive_message(request))
    7380
    7481    def test_receive_message_discard(self):
Note: See TracChangeset for help on using the changeset viewer.