| # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import multiprocessing |
| import os |
| import SimpleHTTPServer |
| |
| |
| class LocalHTTPServer(object): |
| """Class to start a local HTTP server as a child process.""" |
| |
| def __init__(self, serve_dir): |
| parent_conn, child_conn = multiprocessing.Pipe() |
| self.process = multiprocessing.Process(target=_HTTPServerProcess, |
| args=(child_conn, serve_dir)) |
| self.process.start() |
| if parent_conn.poll(10): # wait 10 seconds |
| self.port = parent_conn.recv() |
| else: |
| raise Exception('Unable to launch HTTP server.') |
| |
| self.conn = parent_conn |
| |
| def Shutdown(self): |
| """Send a message to the child HTTP server process and wait for it to |
| finish.""" |
| self.conn.send(False) |
| self.process.join() |
| |
| def GetURL(self, rel_url): |
| """Get the full url for a file on the local HTTP server. |
| |
| Args: |
| rel_url: A URL fragment to convert to a full URL. For example, |
| GetURL('foobar.baz') -> 'http://localhost:1234/foobar.baz' |
| """ |
| return 'http://localhost:%d/%s' % (self.port, rel_url) |
| |
| |
| class QuietHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): |
| def log_message(self, msg_format, *args): |
| pass |
| |
| |
| def _HTTPServerProcess(conn, serve_dir): |
| """Run a local httpserver with a randomly-chosen port. |
| |
| This function assumes it is run as a child process using multiprocessing. |
| |
| Args: |
| conn: A connection to the parent process. The child process sends |
| the local port, and waits for a message from the parent to |
| stop serving. |
| serve_dir: The directory to serve. All files are accessible through |
| http://localhost:<port>/path/to/filename. |
| """ |
| import BaseHTTPServer |
| |
| os.chdir(serve_dir) |
| httpd = BaseHTTPServer.HTTPServer(('', 0), QuietHTTPRequestHandler) |
| conn.send(httpd.server_address[1]) # the chosen port number |
| httpd.timeout = 0.5 # seconds |
| running = True |
| while running: |
| httpd.handle_request() |
| if conn.poll(): |
| running = conn.recv() |
| conn.close() |