1# Copyright (c) 2012 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import multiprocessing 6import os 7import SimpleHTTPServer 8 9 10class LocalHTTPServer(object): 11 """Class to start a local HTTP server as a child process.""" 12 13 def __init__(self, serve_dir): 14 parent_conn, child_conn = multiprocessing.Pipe() 15 self.process = multiprocessing.Process(target=_HTTPServerProcess, 16 args=(child_conn, serve_dir)) 17 self.process.start() 18 if parent_conn.poll(10): # wait 10 seconds 19 self.port = parent_conn.recv() 20 else: 21 raise Exception('Unable to launch HTTP server.') 22 23 self.conn = parent_conn 24 25 def Shutdown(self): 26 """Send a message to the child HTTP server process and wait for it to 27 finish.""" 28 self.conn.send(False) 29 self.process.join() 30 31 def GetURL(self, rel_url): 32 """Get the full url for a file on the local HTTP server. 33 34 Args: 35 rel_url: A URL fragment to convert to a full URL. For example, 36 GetURL('foobar.baz') -> 'http://localhost:1234/foobar.baz' 37 """ 38 return 'http://localhost:%d/%s' % (self.port, rel_url) 39 40 41class QuietHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): 42 def log_message(self, msg_format, *args): 43 pass 44 45 46def _HTTPServerProcess(conn, serve_dir): 47 """Run a local httpserver with a randomly-chosen port. 48 49 This function assumes it is run as a child process using multiprocessing. 50 51 Args: 52 conn: A connection to the parent process. The child process sends 53 the local port, and waits for a message from the parent to 54 stop serving. 55 serve_dir: The directory to serve. All files are accessible through 56 http://localhost:<port>/path/to/filename. 57 """ 58 import BaseHTTPServer 59 60 os.chdir(serve_dir) 61 httpd = BaseHTTPServer.HTTPServer(('', 0), QuietHTTPRequestHandler) 62 conn.send(httpd.server_address[1]) # the chosen port number 63 httpd.timeout = 0.5 # seconds 64 running = True 65 while running: 66 httpd.handle_request() 67 if conn.poll(): 68 running = conn.recv() 69 conn.close() 70