15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 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) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import multiprocessing 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import SimpleHTTPServer 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class LocalHTTPServer(object): 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Class to start a local HTTP server as a child process.""" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, serve_dir): 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parent_conn, child_conn = multiprocessing.Pipe() 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.process = multiprocessing.Process(target=_HTTPServerProcess, 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) args=(child_conn, serve_dir)) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.process.start() 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if parent_conn.poll(10): # wait 10 seconds 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.port = parent_conn.recv() 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise Exception('Unable to launch HTTP server.') 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.conn = parent_conn 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def Shutdown(self): 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Send a message to the child HTTP server process and wait for it to 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) finish.""" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.conn.send(False) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.process.join() 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def GetURL(self, rel_url): 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Get the full url for a file on the local HTTP server. 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rel_url: A URL fragment to convert to a full URL. For example, 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetURL('foobar.baz') -> 'http://localhost:1234/foobar.baz' 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 'http://localhost:%d/%s' % (self.port, rel_url) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class QuietHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def log_message(self, msg_format, *args): 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _HTTPServerProcess(conn, serve_dir): 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Run a local httpserver with a randomly-chosen port. 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This function assumes it is run as a child process using multiprocessing. 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn: A connection to the parent process. The child process sends 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) the local port, and waits for a message from the parent to 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stop serving. 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) serve_dir: The directory to serve. All files are accessible through 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) http://localhost:<port>/path/to/filename. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) import BaseHTTPServer 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.chdir(serve_dir) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) httpd = BaseHTTPServer.HTTPServer(('', 0), QuietHTTPRequestHandler) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn.send(httpd.server_address[1]) # the chosen port number 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) httpd.timeout = 0.5 # seconds 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) running = True 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while running: 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) httpd.handle_request() 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if conn.poll(): 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) running = conn.recv() 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn.close() 70