Home | History | Annotate | Download | only in tests
      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 
      5 import multiprocessing
      6 import os
      7 import SimpleHTTPServer
      8 
      9 
     10 class 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 
     41 class QuietHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
     42   def log_message(self, msg_format, *args):
     43     pass
     44 
     45 
     46 def _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