testserver_base.py revision a02191e04bc25c4935f804f2c080ae28663d096d
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import BaseHTTPServer 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import errno 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import json 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import optparse 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import re 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import socket 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import SocketServer 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import struct 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import warnings 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochimport tlslite.errors 18a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Ignore deprecation warnings, they make our output more cluttered. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)warnings.filterwarnings("ignore", category=DeprecationWarning) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if sys.platform == 'win32': 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) import msvcrt 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Using debug() seems to cause hangs on XP: see http://crbug.com/64515. 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)debug_output = sys.stderr 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def debug(string): 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) debug_output.write(string + "\n") 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) debug_output.flush() 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Error(Exception): 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Error class for this module.""" 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class OptionError(Error): 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Error for bad command line options.""" 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class FileMultiplexer(object): 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, fd1, fd2) : 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.__fd1 = fd1 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.__fd2 = fd2 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __del__(self) : 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.__fd1 != sys.stdout and self.__fd1 != sys.stderr: 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.__fd1.close() 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.__fd2 != sys.stdout and self.__fd2 != sys.stderr: 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.__fd2.close() 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def write(self, text) : 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.__fd1.write(text) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.__fd2.write(text) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def flush(self) : 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.__fd1.flush() 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.__fd2.flush() 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class ClientRestrictingServerMixIn: 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """Implements verify_request to limit connections to our configured IP 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) address.""" 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def verify_request(self, _request, client_address): 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return client_address[0] == self.server_address[0] 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class BrokenPipeHandlerMixIn: 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """Allows the server to deal with "broken pipe" errors (which happen if the 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) browser quits with outstanding requests, like for the favicon). This mix-in 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) requires the class to derive from SocketServer.BaseServer and not override its 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) handle_error() method. """ 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def handle_error(self, request, client_address): 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) value = sys.exc_info()[1] 76a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if isinstance(value, tlslite.errors.TLSClosedConnectionError): 77a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch print "testserver.py: Closed connection" 78a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if isinstance(value, socket.error): 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) err = value.args[0] 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if sys.platform in ('win32', 'cygwin'): 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # "An established connection was aborted by the software in your host." 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pipe_err = 10053 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) else: 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pipe_err = errno.EPIPE 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if err == pipe_err: 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) print "testserver.py: Broken pipe" 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 89a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if err == errno.ECONNRESET: 90a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch print "testserver.py: Connection reset by peer" 91a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SocketServer.BaseServer.handle_error(self, request, client_address) 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class StoppableHTTPServer(BaseHTTPServer.HTTPServer): 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """This is a specialization of BaseHTTPServer to allow it 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) to be exited cleanly (by setting its "stop" member to True).""" 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def serve_forever(self): 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.stop = False 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.nonce_time = None 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while not self.stop: 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.handle_request() 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.socket.close() 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def MultiplexerHack(std_fd, log_fd): 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """Creates a FileMultiplexer that will write to both specified files. 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) When running on Windows XP bots, stdout and stderr will be invalid file 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) handles, so log_fd will be returned directly. (This does not occur if you 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) run the test suite directly from a console, but only if the output of the 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) test executable is redirected.) 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """ 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if std_fd.fileno() <= 0: 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return log_fd 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return FileMultiplexer(std_fd, log_fd) 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class BasePageHandler(BaseHTTPServer.BaseHTTPRequestHandler): 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def __init__(self, request, client_address, socket_server, 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) connect_handlers, get_handlers, head_handlers, post_handlers, 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) put_handlers): 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._connect_handlers = connect_handlers 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._get_handlers = get_handlers 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._head_handlers = head_handlers 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._post_handlers = post_handlers 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._put_handlers = put_handlers 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BaseHTTPServer.BaseHTTPRequestHandler.__init__( 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self, request, client_address, socket_server) 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def log_request(self, *args, **kwargs): 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Disable request logging to declutter test log output. 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pass 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def _ShouldHandleRequest(self, handler_name): 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """Determines if the path can be handled by the handler. 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) We consider a handler valid if the path begins with the 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) handler name. It can optionally be followed by "?*", "/*". 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """ 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pattern = re.compile('%s($|\?|/).*' % handler_name) 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return pattern.match(self.path) 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def do_CONNECT(self): 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for handler in self._connect_handlers: 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if handler(): 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def do_GET(self): 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for handler in self._get_handlers: 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if handler(): 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def do_HEAD(self): 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for handler in self._head_handlers: 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if handler(): 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def do_POST(self): 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for handler in self._post_handlers: 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if handler(): 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def do_PUT(self): 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for handler in self._put_handlers: 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if handler(): 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TestServerRunner(object): 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Runs a test server and communicates with the controlling C++ test code. 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Subclasses should override the create_server method to create their server 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) object, and the add_options method to add their own options. 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self): 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser = optparse.OptionParser() 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.add_options() 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def main(self): 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.options, self.args = self.option_parser.parse_args() 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) logfile = open(self.options.log_file, 'w') 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sys.stderr = MultiplexerHack(sys.stderr, logfile) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.options.log_to_console: 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sys.stdout = MultiplexerHack(sys.stdout, logfile) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sys.stdout = logfile 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server_data = { 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'host': self.options.host, 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.server = self.create_server(server_data) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._notify_startup_complete(server_data) 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.run_server() 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def create_server(self, server_data): 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Creates a server object and returns it. 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Must populate server_data['port'], and can set additional server_data 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elements if desired.""" 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise NotImplementedError() 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def run_server(self): 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.server.serve_forever() 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except KeyboardInterrupt: 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'shutting down server' 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.server.stop = True 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def add_options(self): 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--startup-pipe', type='int', 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest='startup_pipe', 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='File handle of pipe to parent process') 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--log-to-console', action='store_const', 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const=True, default=False, 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest='log_to_console', 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='Enables or disables sys.stdout logging ' 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'to the console.') 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.option_parser.add_option('--log-file', default='testserver.log', 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dest='log_file', 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) help='The name of the server log file.') 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--port', default=0, type='int', 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='Port used by the server. If ' 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'unspecified, the server will listen on an ' 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'ephemeral port.') 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--host', default='127.0.0.1', 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest='host', 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='Hostname or IP upon which the server ' 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'will listen. Client connections will also ' 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'only be allowed from this address.') 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.option_parser.add_option('--data-dir', dest='data_dir', 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) help='Directory from which to read the ' 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 'files.') 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def _notify_startup_complete(self, server_data): 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Notify the parent that we've started. (BaseServer subclasses 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # bind their sockets on construction.) 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.options.startup_pipe is not None: 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server_data_json = json.dumps(server_data) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server_data_len = len(server_data_json) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'sending server_data: %s (%d bytes)' % ( 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server_data_json, server_data_len) 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if sys.platform == 'win32': 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fd = msvcrt.open_osfhandle(self.options.startup_pipe, 0) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fd = self.options.startup_pipe 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) startup_pipe = os.fdopen(fd, "w") 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # First write the data length as an unsigned 4-byte value. This 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # is _not_ using network byte ordering since the other end of the 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # pipe is on the same machine. 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) startup_pipe.write(struct.pack('=L', server_data_len)) 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) startup_pipe.write(server_data_json) 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) startup_pipe.close() 259