1*6777b538SAndroid Build Coastguard Worker# Copyright 2013 The Chromium Authors 2*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 3*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file. 4*6777b538SAndroid Build Coastguard Worker 5*6777b538SAndroid Build Coastguard Workerfrom six.moves import BaseHTTPServer 6*6777b538SAndroid Build Coastguard Workerimport errno 7*6777b538SAndroid Build Coastguard Workerimport json 8*6777b538SAndroid Build Coastguard Workerimport optparse 9*6777b538SAndroid Build Coastguard Workerimport os 10*6777b538SAndroid Build Coastguard Workerimport re 11*6777b538SAndroid Build Coastguard Workerimport socket 12*6777b538SAndroid Build Coastguard Workerfrom six.moves import socketserver as SocketServer 13*6777b538SAndroid Build Coastguard Workerimport struct 14*6777b538SAndroid Build Coastguard Workerimport sys 15*6777b538SAndroid Build Coastguard Workerimport warnings 16*6777b538SAndroid Build Coastguard Worker 17*6777b538SAndroid Build Coastguard Worker# Ignore deprecation warnings, they make our output more cluttered. 18*6777b538SAndroid Build Coastguard Workerwarnings.filterwarnings("ignore", category=DeprecationWarning) 19*6777b538SAndroid Build Coastguard Worker 20*6777b538SAndroid Build Coastguard Workerif sys.platform == 'win32': 21*6777b538SAndroid Build Coastguard Worker import msvcrt 22*6777b538SAndroid Build Coastguard Worker 23*6777b538SAndroid Build Coastguard Worker# Using debug() seems to cause hangs on XP: see http://crbug.com/64515. 24*6777b538SAndroid Build Coastguard Workerdebug_output = sys.stderr 25*6777b538SAndroid Build Coastguard Workerdef debug(string): 26*6777b538SAndroid Build Coastguard Worker debug_output.write(string + "\n") 27*6777b538SAndroid Build Coastguard Worker debug_output.flush() 28*6777b538SAndroid Build Coastguard Worker 29*6777b538SAndroid Build Coastguard Worker 30*6777b538SAndroid Build Coastguard Workerclass Error(Exception): 31*6777b538SAndroid Build Coastguard Worker """Error class for this module.""" 32*6777b538SAndroid Build Coastguard Worker 33*6777b538SAndroid Build Coastguard Worker 34*6777b538SAndroid Build Coastguard Workerclass OptionError(Error): 35*6777b538SAndroid Build Coastguard Worker """Error for bad command line options.""" 36*6777b538SAndroid Build Coastguard Worker 37*6777b538SAndroid Build Coastguard Worker 38*6777b538SAndroid Build Coastguard Workerclass FileMultiplexer(object): 39*6777b538SAndroid Build Coastguard Worker def __init__(self, fd1, fd2) : 40*6777b538SAndroid Build Coastguard Worker self.__fd1 = fd1 41*6777b538SAndroid Build Coastguard Worker self.__fd2 = fd2 42*6777b538SAndroid Build Coastguard Worker 43*6777b538SAndroid Build Coastguard Worker def __del__(self) : 44*6777b538SAndroid Build Coastguard Worker if self.__fd1 != sys.stdout and self.__fd1 != sys.stderr: 45*6777b538SAndroid Build Coastguard Worker self.__fd1.close() 46*6777b538SAndroid Build Coastguard Worker if self.__fd2 != sys.stdout and self.__fd2 != sys.stderr: 47*6777b538SAndroid Build Coastguard Worker self.__fd2.close() 48*6777b538SAndroid Build Coastguard Worker 49*6777b538SAndroid Build Coastguard Worker def write(self, text) : 50*6777b538SAndroid Build Coastguard Worker self.__fd1.write(text) 51*6777b538SAndroid Build Coastguard Worker self.__fd2.write(text) 52*6777b538SAndroid Build Coastguard Worker 53*6777b538SAndroid Build Coastguard Worker def flush(self) : 54*6777b538SAndroid Build Coastguard Worker self.__fd1.flush() 55*6777b538SAndroid Build Coastguard Worker self.__fd2.flush() 56*6777b538SAndroid Build Coastguard Worker 57*6777b538SAndroid Build Coastguard Worker 58*6777b538SAndroid Build Coastguard Workerclass ClientRestrictingServerMixIn: 59*6777b538SAndroid Build Coastguard Worker """Implements verify_request to limit connections to our configured IP 60*6777b538SAndroid Build Coastguard Worker address.""" 61*6777b538SAndroid Build Coastguard Worker 62*6777b538SAndroid Build Coastguard Worker def verify_request(self, _request, client_address): 63*6777b538SAndroid Build Coastguard Worker return client_address[0] == self.server_address[0] 64*6777b538SAndroid Build Coastguard Worker 65*6777b538SAndroid Build Coastguard Worker 66*6777b538SAndroid Build Coastguard Workerclass BrokenPipeHandlerMixIn: 67*6777b538SAndroid Build Coastguard Worker """Allows the server to deal with "broken pipe" errors (which happen if the 68*6777b538SAndroid Build Coastguard Worker browser quits with outstanding requests, like for the favicon). This mix-in 69*6777b538SAndroid Build Coastguard Worker requires the class to derive from SocketServer.BaseServer and not override its 70*6777b538SAndroid Build Coastguard Worker handle_error() method. """ 71*6777b538SAndroid Build Coastguard Worker 72*6777b538SAndroid Build Coastguard Worker def handle_error(self, request, client_address): 73*6777b538SAndroid Build Coastguard Worker value = sys.exc_info()[1] 74*6777b538SAndroid Build Coastguard Worker if isinstance(value, socket.error): 75*6777b538SAndroid Build Coastguard Worker err = value.args[0] 76*6777b538SAndroid Build Coastguard Worker if sys.platform in ('win32', 'cygwin'): 77*6777b538SAndroid Build Coastguard Worker # "An established connection was aborted by the software in your host." 78*6777b538SAndroid Build Coastguard Worker pipe_err = 10053 79*6777b538SAndroid Build Coastguard Worker else: 80*6777b538SAndroid Build Coastguard Worker pipe_err = errno.EPIPE 81*6777b538SAndroid Build Coastguard Worker if err == pipe_err: 82*6777b538SAndroid Build Coastguard Worker print("testserver.py: Broken pipe") 83*6777b538SAndroid Build Coastguard Worker return 84*6777b538SAndroid Build Coastguard Worker if err == errno.ECONNRESET: 85*6777b538SAndroid Build Coastguard Worker print("testserver.py: Connection reset by peer") 86*6777b538SAndroid Build Coastguard Worker return 87*6777b538SAndroid Build Coastguard Worker SocketServer.BaseServer.handle_error(self, request, client_address) 88*6777b538SAndroid Build Coastguard Worker 89*6777b538SAndroid Build Coastguard Worker 90*6777b538SAndroid Build Coastguard Workerclass StoppableHTTPServer(BaseHTTPServer.HTTPServer): 91*6777b538SAndroid Build Coastguard Worker """This is a specialization of BaseHTTPServer to allow it 92*6777b538SAndroid Build Coastguard Worker to be exited cleanly (by setting its "stop" member to True).""" 93*6777b538SAndroid Build Coastguard Worker 94*6777b538SAndroid Build Coastguard Worker def serve_forever(self): 95*6777b538SAndroid Build Coastguard Worker self.stop = False 96*6777b538SAndroid Build Coastguard Worker self.nonce_time = None 97*6777b538SAndroid Build Coastguard Worker while not self.stop: 98*6777b538SAndroid Build Coastguard Worker self.handle_request() 99*6777b538SAndroid Build Coastguard Worker self.socket.close() 100*6777b538SAndroid Build Coastguard Worker 101*6777b538SAndroid Build Coastguard Worker 102*6777b538SAndroid Build Coastguard Workerdef MultiplexerHack(std_fd, log_fd): 103*6777b538SAndroid Build Coastguard Worker """Creates a FileMultiplexer that will write to both specified files. 104*6777b538SAndroid Build Coastguard Worker 105*6777b538SAndroid Build Coastguard Worker When running on Windows XP bots, stdout and stderr will be invalid file 106*6777b538SAndroid Build Coastguard Worker handles, so log_fd will be returned directly. (This does not occur if you 107*6777b538SAndroid Build Coastguard Worker run the test suite directly from a console, but only if the output of the 108*6777b538SAndroid Build Coastguard Worker test executable is redirected.) 109*6777b538SAndroid Build Coastguard Worker """ 110*6777b538SAndroid Build Coastguard Worker if std_fd.fileno() <= 0: 111*6777b538SAndroid Build Coastguard Worker return log_fd 112*6777b538SAndroid Build Coastguard Worker return FileMultiplexer(std_fd, log_fd) 113*6777b538SAndroid Build Coastguard Worker 114*6777b538SAndroid Build Coastguard Worker 115*6777b538SAndroid Build Coastguard Workerclass BasePageHandler(BaseHTTPServer.BaseHTTPRequestHandler): 116*6777b538SAndroid Build Coastguard Worker 117*6777b538SAndroid Build Coastguard Worker def __init__(self, request, client_address, socket_server, 118*6777b538SAndroid Build Coastguard Worker connect_handlers, get_handlers, head_handlers, post_handlers, 119*6777b538SAndroid Build Coastguard Worker put_handlers): 120*6777b538SAndroid Build Coastguard Worker self._connect_handlers = connect_handlers 121*6777b538SAndroid Build Coastguard Worker self._get_handlers = get_handlers 122*6777b538SAndroid Build Coastguard Worker self._head_handlers = head_handlers 123*6777b538SAndroid Build Coastguard Worker self._post_handlers = post_handlers 124*6777b538SAndroid Build Coastguard Worker self._put_handlers = put_handlers 125*6777b538SAndroid Build Coastguard Worker BaseHTTPServer.BaseHTTPRequestHandler.__init__( 126*6777b538SAndroid Build Coastguard Worker self, request, client_address, socket_server) 127*6777b538SAndroid Build Coastguard Worker 128*6777b538SAndroid Build Coastguard Worker def log_request(self, *args, **kwargs): 129*6777b538SAndroid Build Coastguard Worker # Disable request logging to declutter test log output. 130*6777b538SAndroid Build Coastguard Worker pass 131*6777b538SAndroid Build Coastguard Worker 132*6777b538SAndroid Build Coastguard Worker def _ShouldHandleRequest(self, handler_name): 133*6777b538SAndroid Build Coastguard Worker """Determines if the path can be handled by the handler. 134*6777b538SAndroid Build Coastguard Worker 135*6777b538SAndroid Build Coastguard Worker We consider a handler valid if the path begins with the 136*6777b538SAndroid Build Coastguard Worker handler name. It can optionally be followed by "?*", "/*". 137*6777b538SAndroid Build Coastguard Worker """ 138*6777b538SAndroid Build Coastguard Worker 139*6777b538SAndroid Build Coastguard Worker pattern = re.compile('%s($|\?|/).*' % handler_name) 140*6777b538SAndroid Build Coastguard Worker return pattern.match(self.path) 141*6777b538SAndroid Build Coastguard Worker 142*6777b538SAndroid Build Coastguard Worker def do_CONNECT(self): 143*6777b538SAndroid Build Coastguard Worker for handler in self._connect_handlers: 144*6777b538SAndroid Build Coastguard Worker if handler(): 145*6777b538SAndroid Build Coastguard Worker return 146*6777b538SAndroid Build Coastguard Worker 147*6777b538SAndroid Build Coastguard Worker def do_GET(self): 148*6777b538SAndroid Build Coastguard Worker for handler in self._get_handlers: 149*6777b538SAndroid Build Coastguard Worker if handler(): 150*6777b538SAndroid Build Coastguard Worker return 151*6777b538SAndroid Build Coastguard Worker 152*6777b538SAndroid Build Coastguard Worker def do_HEAD(self): 153*6777b538SAndroid Build Coastguard Worker for handler in self._head_handlers: 154*6777b538SAndroid Build Coastguard Worker if handler(): 155*6777b538SAndroid Build Coastguard Worker return 156*6777b538SAndroid Build Coastguard Worker 157*6777b538SAndroid Build Coastguard Worker def do_POST(self): 158*6777b538SAndroid Build Coastguard Worker for handler in self._post_handlers: 159*6777b538SAndroid Build Coastguard Worker if handler(): 160*6777b538SAndroid Build Coastguard Worker return 161*6777b538SAndroid Build Coastguard Worker 162*6777b538SAndroid Build Coastguard Worker def do_PUT(self): 163*6777b538SAndroid Build Coastguard Worker for handler in self._put_handlers: 164*6777b538SAndroid Build Coastguard Worker if handler(): 165*6777b538SAndroid Build Coastguard Worker return 166*6777b538SAndroid Build Coastguard Worker 167*6777b538SAndroid Build Coastguard Worker 168*6777b538SAndroid Build Coastguard Workerclass TestServerRunner(object): 169*6777b538SAndroid Build Coastguard Worker """Runs a test server and communicates with the controlling C++ test code. 170*6777b538SAndroid Build Coastguard Worker 171*6777b538SAndroid Build Coastguard Worker Subclasses should override the create_server method to create their server 172*6777b538SAndroid Build Coastguard Worker object, and the add_options method to add their own options. 173*6777b538SAndroid Build Coastguard Worker """ 174*6777b538SAndroid Build Coastguard Worker 175*6777b538SAndroid Build Coastguard Worker def __init__(self): 176*6777b538SAndroid Build Coastguard Worker self.option_parser = optparse.OptionParser() 177*6777b538SAndroid Build Coastguard Worker self.add_options() 178*6777b538SAndroid Build Coastguard Worker 179*6777b538SAndroid Build Coastguard Worker def main(self): 180*6777b538SAndroid Build Coastguard Worker self.options, self.args = self.option_parser.parse_args() 181*6777b538SAndroid Build Coastguard Worker 182*6777b538SAndroid Build Coastguard Worker logfile = open(self.options.log_file, 'w') 183*6777b538SAndroid Build Coastguard Worker 184*6777b538SAndroid Build Coastguard Worker # http://crbug.com/248796 : Error logs streamed to normal sys.stderr will be 185*6777b538SAndroid Build Coastguard Worker # written to HTTP response payload when remote test server is used. 186*6777b538SAndroid Build Coastguard Worker # For this reason, some tests like ResourceFetcherTests.ResourceFetcher404 187*6777b538SAndroid Build Coastguard Worker # were failing on Android because remote test server is being used there. 188*6777b538SAndroid Build Coastguard Worker # To fix them, we need to use sys.stdout as sys.stderr if remote test server 189*6777b538SAndroid Build Coastguard Worker # is used. 190*6777b538SAndroid Build Coastguard Worker if self.options.on_remote_server: 191*6777b538SAndroid Build Coastguard Worker sys.stderr = sys.stdout 192*6777b538SAndroid Build Coastguard Worker 193*6777b538SAndroid Build Coastguard Worker sys.stderr = MultiplexerHack(sys.stderr, logfile) 194*6777b538SAndroid Build Coastguard Worker if self.options.log_to_console: 195*6777b538SAndroid Build Coastguard Worker sys.stdout = MultiplexerHack(sys.stdout, logfile) 196*6777b538SAndroid Build Coastguard Worker else: 197*6777b538SAndroid Build Coastguard Worker sys.stdout = logfile 198*6777b538SAndroid Build Coastguard Worker 199*6777b538SAndroid Build Coastguard Worker server_data = { 200*6777b538SAndroid Build Coastguard Worker 'host': self.options.host, 201*6777b538SAndroid Build Coastguard Worker } 202*6777b538SAndroid Build Coastguard Worker self.server = self.create_server(server_data) 203*6777b538SAndroid Build Coastguard Worker self._notify_startup_complete(server_data) 204*6777b538SAndroid Build Coastguard Worker self.run_server() 205*6777b538SAndroid Build Coastguard Worker 206*6777b538SAndroid Build Coastguard Worker def create_server(self, server_data): 207*6777b538SAndroid Build Coastguard Worker """Creates a server object and returns it. 208*6777b538SAndroid Build Coastguard Worker 209*6777b538SAndroid Build Coastguard Worker Must populate server_data['port'], and can set additional server_data 210*6777b538SAndroid Build Coastguard Worker elements if desired.""" 211*6777b538SAndroid Build Coastguard Worker raise NotImplementedError() 212*6777b538SAndroid Build Coastguard Worker 213*6777b538SAndroid Build Coastguard Worker def run_server(self): 214*6777b538SAndroid Build Coastguard Worker try: 215*6777b538SAndroid Build Coastguard Worker self.server.serve_forever() 216*6777b538SAndroid Build Coastguard Worker except KeyboardInterrupt: 217*6777b538SAndroid Build Coastguard Worker print('shutting down server') 218*6777b538SAndroid Build Coastguard Worker self.server.stop = True 219*6777b538SAndroid Build Coastguard Worker 220*6777b538SAndroid Build Coastguard Worker def add_options(self): 221*6777b538SAndroid Build Coastguard Worker self.option_parser.add_option('--startup-pipe', type='int', 222*6777b538SAndroid Build Coastguard Worker dest='startup_pipe', 223*6777b538SAndroid Build Coastguard Worker help='File handle of pipe to parent process') 224*6777b538SAndroid Build Coastguard Worker self.option_parser.add_option('--log-to-console', action='store_const', 225*6777b538SAndroid Build Coastguard Worker const=True, default=False, 226*6777b538SAndroid Build Coastguard Worker dest='log_to_console', 227*6777b538SAndroid Build Coastguard Worker help='Enables or disables sys.stdout logging ' 228*6777b538SAndroid Build Coastguard Worker 'to the console.') 229*6777b538SAndroid Build Coastguard Worker self.option_parser.add_option('--log-file', default='testserver.log', 230*6777b538SAndroid Build Coastguard Worker dest='log_file', 231*6777b538SAndroid Build Coastguard Worker help='The name of the server log file.') 232*6777b538SAndroid Build Coastguard Worker self.option_parser.add_option('--port', default=0, type='int', 233*6777b538SAndroid Build Coastguard Worker help='Port used by the server. If ' 234*6777b538SAndroid Build Coastguard Worker 'unspecified, the server will listen on an ' 235*6777b538SAndroid Build Coastguard Worker 'ephemeral port.') 236*6777b538SAndroid Build Coastguard Worker self.option_parser.add_option('--host', default='127.0.0.1', 237*6777b538SAndroid Build Coastguard Worker dest='host', 238*6777b538SAndroid Build Coastguard Worker help='Hostname or IP upon which the server ' 239*6777b538SAndroid Build Coastguard Worker 'will listen. Client connections will also ' 240*6777b538SAndroid Build Coastguard Worker 'only be allowed from this address.') 241*6777b538SAndroid Build Coastguard Worker self.option_parser.add_option('--data-dir', dest='data_dir', 242*6777b538SAndroid Build Coastguard Worker help='Directory from which to read the ' 243*6777b538SAndroid Build Coastguard Worker 'files.') 244*6777b538SAndroid Build Coastguard Worker self.option_parser.add_option('--on-remote-server', action='store_const', 245*6777b538SAndroid Build Coastguard Worker const=True, default=False, 246*6777b538SAndroid Build Coastguard Worker dest='on_remote_server', 247*6777b538SAndroid Build Coastguard Worker help='Whether remote server is being used or ' 248*6777b538SAndroid Build Coastguard Worker 'not.') 249*6777b538SAndroid Build Coastguard Worker 250*6777b538SAndroid Build Coastguard Worker def _notify_startup_complete(self, server_data): 251*6777b538SAndroid Build Coastguard Worker # Notify the parent that we've started. (BaseServer subclasses 252*6777b538SAndroid Build Coastguard Worker # bind their sockets on construction.) 253*6777b538SAndroid Build Coastguard Worker if self.options.startup_pipe is not None: 254*6777b538SAndroid Build Coastguard Worker server_data_json = json.dumps(server_data).encode() 255*6777b538SAndroid Build Coastguard Worker server_data_len = len(server_data_json) 256*6777b538SAndroid Build Coastguard Worker print('sending server_data: %s (%d bytes)' % 257*6777b538SAndroid Build Coastguard Worker (server_data_json, server_data_len)) 258*6777b538SAndroid Build Coastguard Worker if sys.platform == 'win32': 259*6777b538SAndroid Build Coastguard Worker fd = msvcrt.open_osfhandle(self.options.startup_pipe, 0) 260*6777b538SAndroid Build Coastguard Worker else: 261*6777b538SAndroid Build Coastguard Worker fd = self.options.startup_pipe 262*6777b538SAndroid Build Coastguard Worker startup_pipe = os.fdopen(fd, "wb") 263*6777b538SAndroid Build Coastguard Worker # First write the data length as an unsigned 4-byte value. This 264*6777b538SAndroid Build Coastguard Worker # is _not_ using network byte ordering since the other end of the 265*6777b538SAndroid Build Coastguard Worker # pipe is on the same machine. 266*6777b538SAndroid Build Coastguard Worker startup_pipe.write(struct.pack('=L', server_data_len)) 267*6777b538SAndroid Build Coastguard Worker startup_pipe.write(server_data_json) 268*6777b538SAndroid Build Coastguard Worker startup_pipe.close() 269