Chromium Code Reviews| Index: net/tools/testserver/testserver.py |
| diff --git a/net/tools/testserver/testserver.py b/net/tools/testserver/testserver.py |
| index 162609bbf5c995880371de906f5158198b1aba45..d9fe6834e200ad1b8827a92af9f5ecc7aae01f88 100755 |
| --- a/net/tools/testserver/testserver.py |
| +++ b/net/tools/testserver/testserver.py |
| @@ -13,14 +13,17 @@ It can use https if you specify the flag --https=CERT where CERT is the path |
| to a pem file containing the certificate and private key that should be used. |
| """ |
| +import asyncore |
| import base64 |
| import BaseHTTPServer |
| import cgi |
| +import errno |
| import optparse |
| import os |
| import re |
| -import shutil |
| +import select |
| import SocketServer |
| +import socket |
| import sys |
| import struct |
| import time |
| @@ -58,6 +61,14 @@ def debug(str): |
| debug_output.write(str + "\n") |
| debug_output.flush() |
| +class Error(Exception): |
| + """Error class for this module.""" |
| + pass |
| + |
| +class UnexpectedSocketType(Error): |
| + """Raised when a value of a socket map is of unknown type.""" |
| + pass |
| + |
| class StoppableHTTPServer(BaseHTTPServer.HTTPServer): |
| """This is a specialization of of BaseHTTPServer to allow it |
| to be exited cleanly (by setting its "stop" member to True).""" |
| @@ -120,12 +131,109 @@ class SyncHTTPServer(StoppableHTTPServer): |
| # We import here to avoid pulling in chromiumsync's dependencies |
| # unless strictly necessary. |
| import chromiumsync |
| - self._sync_handler = chromiumsync.TestServer() |
| + import xmppserver |
| StoppableHTTPServer.__init__(self, server_address, request_handler_class) |
| + self._sync_handler = chromiumsync.TestServer() |
| + self._socket_map = { self.fileno(): self } |
| + self._xmpp_server = xmppserver.XmppServer( |
|
cbentzel
2010/11/18 11:59:09
Should xmpp_server be run a separate thread so you
akalin
2010/11/18 23:32:58
I think the complexity of this select loop (especi
|
| + self._socket_map, ('localhost', 0)) |
| + self.xmpp_port = self._xmpp_server.getsockname()[1] |
| def HandleCommand(self, query, raw_request): |
| return self._sync_handler.HandleCommand(query, raw_request) |
| + def serve_forever(self): |
| + """This is a merge of asyncore.loop() and SocketServer.serve_forever(). |
| + """ |
| + |
| + def HandleSocketServerRequestNoBlock(socket_server): |
| + """Handles a single request for a SocketServer.BaseServer. |
| + |
| + Copied from SocketServer._handle_request_noblock(). |
| + """ |
| + try: |
| + request, client_address = socket_server.get_request() |
| + except socket.error: |
| + return |
| + if socket_server.verify_request(request, client_address): |
| + try: |
| + socket_server.process_request(request, client_address) |
| + except: |
| + socket_server.handle_error(request, client_address) |
| + socket_server.close_request(request) |
| + |
| + def RunDispatcherHandler(dispatcher, handler): |
| + """Handles a single event for an asyncore.dispatcher. |
| + |
| + Adapted from asyncore.read() et al. |
| + """ |
| + try: |
| + handler(dispatcher) |
| + except (asyncore.ExitNow, KeyboardInterrupt, SystemExit): |
| + raise |
| + except: |
| + dispatcher.handle_error() |
| + |
| + poll_interval = 0.5 |
| + |
| + while map: |
| + r = []; w = []; e = [] |
| + for fd, obj in self._socket_map.items(): |
| + if isinstance(obj, SocketServer.BaseServer): |
| + r.append(fd) |
| + elif isinstance(obj, asyncore.dispatcher): |
| + is_r = obj.readable() |
| + is_w = obj.writable() |
| + if is_r: |
| + r.append(fd) |
| + if is_w: |
| + w.append(fd) |
| + if is_r or is_w: |
| + e.append(fd) |
| + else: |
| + raise UnexpectedSocketType() |
| + |
| + if [] == r == w == e: |
| + time.sleep(poll_interval) |
|
Paweł Hajdan Jr.
2010/11/18 11:58:45
hmmm, why? Can we wait for an event that would mak
akalin
2010/11/18 23:32:58
Actually, this case should never happen. Removed
|
| + continue |
| + |
| + try: |
| + r, w, e = select.select(r, w, e, poll_interval) |
| + except select.error, err: |
| + if err.args[0] != errno.EINTR: |
| + raise |
| + else: |
| + continue |
| + |
| + for fd in r: |
| + obj = self._socket_map.get(fd) |
| + if obj is None: |
| + continue |
| + if isinstance(obj, SocketServer.BaseServer): |
| + HandleSocketServerRequestNoBlock(obj) |
| + elif isinstance(obj, asyncore.dispatcher): |
| + RunDispatcherHandler(obj, asyncore.dispatcher.handle_read_event) |
| + else: |
| + raise UnexpectedSocketType() |
| + |
| + for fd in w: |
| + obj = self._socket_map.get(fd) |
| + if obj is None: |
| + continue |
| + if isinstance(obj, asyncore.dispatcher): |
| + RunDispatcherHandler(obj, asyncore.dispatcher.handle_write_event) |
| + else: |
| + raise UnexpectedSocketType() |
| + |
| + for fd in e: |
| + obj = self._socket_map.get(fd) |
| + if obj is None: |
| + continue |
| + if isinstance(obj, asyncore.dispatcher): |
| + RunDispatcherHandler(obj, asyncore.dispatcher.handle_expt_event) |
| + else: |
| + raise UnexpectedSocketType() |
| + |
| class BasePageHandler(BaseHTTPServer.BaseHTTPRequestHandler): |
| @@ -1249,6 +1357,8 @@ def main(options, args): |
| port = options.port |
| + server_data = {} |
| + |
| if options.server_type == SERVER_HTTP: |
| if options.cert: |
| # let's make sure the cert file exists. |
| @@ -1271,12 +1381,14 @@ def main(options, args): |
| server.data_dir = MakeDataDir() |
| server.file_root_url = options.file_root_url |
| - listen_port = server.server_port |
| + server_data['port'] = server.server_port |
|
cbentzel
2010/11/18 11:59:09
Should this move to unique key per server type?
akalin
2010/11/18 23:32:58
Hmm I don't think so. Then run_testserver would h
|
| server._device_management_handler = None |
| elif options.server_type == SERVER_SYNC: |
| server = SyncHTTPServer(('127.0.0.1', port), SyncPageHandler) |
| print 'Sync HTTP server started on port %d...' % server.server_port |
| - listen_port = server.server_port |
| + print 'Sync XMPP server started on port %d...' % server.xmpp_port |
| + server_data['port'] = server.server_port |
| + server_data['xmpp_port'] = server.xmpp_port |
| # means FTP Server |
| else: |
| my_data_dir = MakeDataDir() |
| @@ -1301,15 +1413,12 @@ def main(options, args): |
| # Instantiate FTP server class and listen to 127.0.0.1:port |
| address = ('127.0.0.1', port) |
| server = pyftpdlib.ftpserver.FTPServer(address, ftp_handler) |
| - listen_port = server.socket.getsockname()[1] |
| - print 'FTP server started on port %d...' % listen_port |
| + server_data['port'] = server.socket.getsockname()[1] |
| + print 'FTP server started on port %d...' % server_data['port'] |
| # Notify the parent that we've started. (BaseServer subclasses |
| # bind their sockets on construction.) |
| if options.startup_pipe is not None: |
| - server_data = { |
| - 'port': listen_port |
| - } |
| server_data_json = json.dumps(server_data) |
| print 'sending server_data: %s' % server_data_json |
| server_data_len = len(server_data_json) |