1d0825bca7fe65beaee391d30da42e937db621564Steve Block#!/usr/bin/env python 25e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block# Copyright (C) 2010 Google Inc. All rights reserved. 3d0825bca7fe65beaee391d30da42e937db621564Steve Block# 4d0825bca7fe65beaee391d30da42e937db621564Steve Block# Redistribution and use in source and binary forms, with or without 5d0825bca7fe65beaee391d30da42e937db621564Steve Block# modification, are permitted provided that the following conditions are 6d0825bca7fe65beaee391d30da42e937db621564Steve Block# met: 7d0825bca7fe65beaee391d30da42e937db621564Steve Block# 8d0825bca7fe65beaee391d30da42e937db621564Steve Block# * Redistributions of source code must retain the above copyright 9d0825bca7fe65beaee391d30da42e937db621564Steve Block# notice, this list of conditions and the following disclaimer. 10d0825bca7fe65beaee391d30da42e937db621564Steve Block# * Redistributions in binary form must reproduce the above 11d0825bca7fe65beaee391d30da42e937db621564Steve Block# copyright notice, this list of conditions and the following disclaimer 12d0825bca7fe65beaee391d30da42e937db621564Steve Block# in the documentation and/or other materials provided with the 13d0825bca7fe65beaee391d30da42e937db621564Steve Block# distribution. 145e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block# * Neither the name of Google Inc. nor the names of its 15d0825bca7fe65beaee391d30da42e937db621564Steve Block# contributors may be used to endorse or promote products derived from 16d0825bca7fe65beaee391d30da42e937db621564Steve Block# this software without specific prior written permission. 17d0825bca7fe65beaee391d30da42e937db621564Steve Block# 18d0825bca7fe65beaee391d30da42e937db621564Steve Block# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19d0825bca7fe65beaee391d30da42e937db621564Steve Block# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20d0825bca7fe65beaee391d30da42e937db621564Steve Block# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21d0825bca7fe65beaee391d30da42e937db621564Steve Block# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22d0825bca7fe65beaee391d30da42e937db621564Steve Block# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23d0825bca7fe65beaee391d30da42e937db621564Steve Block# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24d0825bca7fe65beaee391d30da42e937db621564Steve Block# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25d0825bca7fe65beaee391d30da42e937db621564Steve Block# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26d0825bca7fe65beaee391d30da42e937db621564Steve Block# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27d0825bca7fe65beaee391d30da42e937db621564Steve Block# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28d0825bca7fe65beaee391d30da42e937db621564Steve Block# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29d0825bca7fe65beaee391d30da42e937db621564Steve Block 30d0825bca7fe65beaee391d30da42e937db621564Steve Block"""A class to help start/stop the lighttpd server used by layout tests.""" 31d0825bca7fe65beaee391d30da42e937db621564Steve Block 3221939df44de1705786c545cd1bf519d47250322dBen Murdochfrom __future__ import with_statement 33d0825bca7fe65beaee391d30da42e937db621564Steve Block 3421939df44de1705786c545cd1bf519d47250322dBen Murdochimport codecs 35d0825bca7fe65beaee391d30da42e937db621564Steve Blockimport logging 36d0825bca7fe65beaee391d30da42e937db621564Steve Blockimport optparse 37d0825bca7fe65beaee391d30da42e937db621564Steve Blockimport os 38d0825bca7fe65beaee391d30da42e937db621564Steve Blockimport shutil 39d0825bca7fe65beaee391d30da42e937db621564Steve Blockimport subprocess 40d0825bca7fe65beaee391d30da42e937db621564Steve Blockimport sys 41d0825bca7fe65beaee391d30da42e937db621564Steve Blockimport tempfile 42d0825bca7fe65beaee391d30da42e937db621564Steve Blockimport time 43d0825bca7fe65beaee391d30da42e937db621564Steve Blockimport urllib 44d0825bca7fe65beaee391d30da42e937db621564Steve Block 45dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport factory 46d0825bca7fe65beaee391d30da42e937db621564Steve Blockimport http_server_base 47d0825bca7fe65beaee391d30da42e937db621564Steve Block 48dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block_log = logging.getLogger("webkitpy.layout_tests.port.http_server") 49dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 50d0825bca7fe65beaee391d30da42e937db621564Steve Block 518a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Blockclass HttpdNotStarted(Exception): 528a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block pass 53d0825bca7fe65beaee391d30da42e937db621564Steve Block 54d0825bca7fe65beaee391d30da42e937db621564Steve Block 55d0825bca7fe65beaee391d30da42e937db621564Steve Blockclass Lighttpd(http_server_base.HttpServerBase): 568a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block 578a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block def __init__(self, port_obj, output_dir, background=False, port=None, 582bde8e466a4451c7319e3a072d118917957d6554Steve Block root=None, run_background=None, layout_tests_dir=None): 59d0825bca7fe65beaee391d30da42e937db621564Steve Block """Args: 60d0825bca7fe65beaee391d30da42e937db621564Steve Block output_dir: the absolute path to the layout test result directory 61d0825bca7fe65beaee391d30da42e937db621564Steve Block """ 628a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block # Webkit tests 638a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block http_server_base.HttpServerBase.__init__(self, port_obj) 64d0825bca7fe65beaee391d30da42e937db621564Steve Block self._output_dir = output_dir 65d0825bca7fe65beaee391d30da42e937db621564Steve Block self._process = None 66d0825bca7fe65beaee391d30da42e937db621564Steve Block self._port = port 67d0825bca7fe65beaee391d30da42e937db621564Steve Block self._root = root 68d0825bca7fe65beaee391d30da42e937db621564Steve Block self._run_background = run_background 692bde8e466a4451c7319e3a072d118917957d6554Steve Block self._layout_tests_dir = layout_tests_dir 702bde8e466a4451c7319e3a072d118917957d6554Steve Block 71d0825bca7fe65beaee391d30da42e937db621564Steve Block if self._port: 72d0825bca7fe65beaee391d30da42e937db621564Steve Block self._port = int(self._port) 73d0825bca7fe65beaee391d30da42e937db621564Steve Block 742bde8e466a4451c7319e3a072d118917957d6554Steve Block if not self._layout_tests_dir: 752bde8e466a4451c7319e3a072d118917957d6554Steve Block self._layout_tests_dir = self._port_obj.layout_tests_dir() 762bde8e466a4451c7319e3a072d118917957d6554Steve Block 778a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block try: 788a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block self._webkit_tests = os.path.join( 792bde8e466a4451c7319e3a072d118917957d6554Steve Block self._layout_tests_dir, 'http', 'tests') 808a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block self._js_test_resource = os.path.join( 812bde8e466a4451c7319e3a072d118917957d6554Steve Block self._layout_tests_dir, 'fast', 'js', 'resources') 8281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch self._media_resource = os.path.join( 832bde8e466a4451c7319e3a072d118917957d6554Steve Block self._layout_tests_dir, 'media') 8481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch 858a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block except: 868a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block self._webkit_tests = None 878a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block self._js_test_resource = None 8881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch self._media_resource = None 898a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block 908a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block # Self generated certificate for SSL server (for client cert get 918a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block # <base-path>\chrome\test\data\ssl\certs\root_ca_cert.crt) 928a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block self._pem_file = os.path.join( 938a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block os.path.dirname(os.path.abspath(__file__)), 'httpd2.pem') 948a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block 958a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block # One mapping where we can get to everything 968a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block self.VIRTUALCONFIG = [] 978a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block 988a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block if self._webkit_tests: 998a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block self.VIRTUALCONFIG.extend( 1008a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block # Three mappings (one with SSL) for LayoutTests http tests 1018a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block [{'port': 8000, 'docroot': self._webkit_tests}, 1028a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block {'port': 8080, 'docroot': self._webkit_tests}, 1038a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block {'port': 8443, 'docroot': self._webkit_tests, 1048a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block 'sslcert': self._pem_file}]) 1058a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block 106d0825bca7fe65beaee391d30da42e937db621564Steve Block def is_running(self): 107d0825bca7fe65beaee391d30da42e937db621564Steve Block return self._process != None 108d0825bca7fe65beaee391d30da42e937db621564Steve Block 109d0825bca7fe65beaee391d30da42e937db621564Steve Block def start(self): 110d0825bca7fe65beaee391d30da42e937db621564Steve Block if self.is_running(): 111d0825bca7fe65beaee391d30da42e937db621564Steve Block raise 'Lighttpd already running' 112d0825bca7fe65beaee391d30da42e937db621564Steve Block 113f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch base_conf_file = self._port_obj.path_from_webkit_base('Tools', 1148a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block 'Scripts', 'webkitpy', 'layout_tests', 'port', 'lighttpd.conf') 115d0825bca7fe65beaee391d30da42e937db621564Steve Block out_conf_file = os.path.join(self._output_dir, 'lighttpd.conf') 116d0825bca7fe65beaee391d30da42e937db621564Steve Block time_str = time.strftime("%d%b%Y-%H%M%S") 117d0825bca7fe65beaee391d30da42e937db621564Steve Block access_file_name = "access.log-" + time_str + ".txt" 118d0825bca7fe65beaee391d30da42e937db621564Steve Block access_log = os.path.join(self._output_dir, access_file_name) 119d0825bca7fe65beaee391d30da42e937db621564Steve Block log_file_name = "error.log-" + time_str + ".txt" 120d0825bca7fe65beaee391d30da42e937db621564Steve Block error_log = os.path.join(self._output_dir, log_file_name) 121d0825bca7fe65beaee391d30da42e937db621564Steve Block 122d0825bca7fe65beaee391d30da42e937db621564Steve Block # Remove old log files. We only need to keep the last ones. 1238a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block self.remove_log_files(self._output_dir, "access.log-") 1248a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block self.remove_log_files(self._output_dir, "error.log-") 125d0825bca7fe65beaee391d30da42e937db621564Steve Block 126d0825bca7fe65beaee391d30da42e937db621564Steve Block # Write out the config 12721939df44de1705786c545cd1bf519d47250322dBen Murdoch with codecs.open(base_conf_file, "r", "utf-8") as file: 12821939df44de1705786c545cd1bf519d47250322dBen Murdoch base_conf = file.read() 12921939df44de1705786c545cd1bf519d47250322dBen Murdoch 13021939df44de1705786c545cd1bf519d47250322dBen Murdoch # FIXME: This should be re-worked so that this block can 13121939df44de1705786c545cd1bf519d47250322dBen Murdoch # use with open() instead of a manual file.close() call. 13221939df44de1705786c545cd1bf519d47250322dBen Murdoch # lighttpd.conf files seem to be UTF-8 without BOM: 13321939df44de1705786c545cd1bf519d47250322dBen Murdoch # http://redmine.lighttpd.net/issues/992 13421939df44de1705786c545cd1bf519d47250322dBen Murdoch f = codecs.open(out_conf_file, "w", "utf-8") 135d0825bca7fe65beaee391d30da42e937db621564Steve Block f.write(base_conf) 136d0825bca7fe65beaee391d30da42e937db621564Steve Block 137d0825bca7fe65beaee391d30da42e937db621564Steve Block # Write out our cgi handlers. Run perl through env so that it 138d0825bca7fe65beaee391d30da42e937db621564Steve Block # processes the #! line and runs perl with the proper command 139d0825bca7fe65beaee391d30da42e937db621564Steve Block # line arguments. Emulate apache's mod_asis with a cat cgi handler. 140d0825bca7fe65beaee391d30da42e937db621564Steve Block f.write(('cgi.assign = ( ".cgi" => "/usr/bin/env",\n' 141d0825bca7fe65beaee391d30da42e937db621564Steve Block ' ".pl" => "/usr/bin/env",\n' 142d0825bca7fe65beaee391d30da42e937db621564Steve Block ' ".asis" => "/bin/cat",\n' 143d0825bca7fe65beaee391d30da42e937db621564Steve Block ' ".php" => "%s" )\n\n') % 1448a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block self._port_obj._path_to_lighttpd_php()) 145d0825bca7fe65beaee391d30da42e937db621564Steve Block 146d0825bca7fe65beaee391d30da42e937db621564Steve Block # Setup log files 147d0825bca7fe65beaee391d30da42e937db621564Steve Block f.write(('server.errorlog = "%s"\n' 148d0825bca7fe65beaee391d30da42e937db621564Steve Block 'accesslog.filename = "%s"\n\n') % (error_log, access_log)) 149d0825bca7fe65beaee391d30da42e937db621564Steve Block 150d0825bca7fe65beaee391d30da42e937db621564Steve Block # Setup upload folders. Upload folder is to hold temporary upload files 151d0825bca7fe65beaee391d30da42e937db621564Steve Block # and also POST data. This is used to support XHR layout tests that 152d0825bca7fe65beaee391d30da42e937db621564Steve Block # does POST. 153d0825bca7fe65beaee391d30da42e937db621564Steve Block f.write(('server.upload-dirs = ( "%s" )\n\n') % (self._output_dir)) 154d0825bca7fe65beaee391d30da42e937db621564Steve Block 155d0825bca7fe65beaee391d30da42e937db621564Steve Block # Setup a link to where the js test templates are stored 156d0825bca7fe65beaee391d30da42e937db621564Steve Block f.write(('alias.url = ( "/js-test-resources" => "%s" )\n\n') % 157d0825bca7fe65beaee391d30da42e937db621564Steve Block (self._js_test_resource)) 158d0825bca7fe65beaee391d30da42e937db621564Steve Block 15981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch # Setup a link to where the media resources are stored. 16081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch f.write(('alias.url += ( "/media-resources" => "%s" )\n\n') % 16181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch (self._media_resource)) 16281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch 163d0825bca7fe65beaee391d30da42e937db621564Steve Block # dump out of virtual host config at the bottom. 164d0825bca7fe65beaee391d30da42e937db621564Steve Block if self._root: 165d0825bca7fe65beaee391d30da42e937db621564Steve Block if self._port: 166d0825bca7fe65beaee391d30da42e937db621564Steve Block # Have both port and root dir. 167d0825bca7fe65beaee391d30da42e937db621564Steve Block mappings = [{'port': self._port, 'docroot': self._root}] 168d0825bca7fe65beaee391d30da42e937db621564Steve Block else: 169d0825bca7fe65beaee391d30da42e937db621564Steve Block # Have only a root dir - set the ports as for LayoutTests. 170d0825bca7fe65beaee391d30da42e937db621564Steve Block # This is used in ui_tests to run http tests against a browser. 171d0825bca7fe65beaee391d30da42e937db621564Steve Block 172d0825bca7fe65beaee391d30da42e937db621564Steve Block # default set of ports as for LayoutTests but with a 173d0825bca7fe65beaee391d30da42e937db621564Steve Block # specified root. 174d0825bca7fe65beaee391d30da42e937db621564Steve Block mappings = [{'port': 8000, 'docroot': self._root}, 175d0825bca7fe65beaee391d30da42e937db621564Steve Block {'port': 8080, 'docroot': self._root}, 176d0825bca7fe65beaee391d30da42e937db621564Steve Block {'port': 8443, 'docroot': self._root, 1778a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block 'sslcert': self._pem_file}] 178d0825bca7fe65beaee391d30da42e937db621564Steve Block else: 179d0825bca7fe65beaee391d30da42e937db621564Steve Block mappings = self.VIRTUALCONFIG 180d0825bca7fe65beaee391d30da42e937db621564Steve Block for mapping in mappings: 181d0825bca7fe65beaee391d30da42e937db621564Steve Block ssl_setup = '' 182d0825bca7fe65beaee391d30da42e937db621564Steve Block if 'sslcert' in mapping: 183d0825bca7fe65beaee391d30da42e937db621564Steve Block ssl_setup = (' ssl.engine = "enable"\n' 184d0825bca7fe65beaee391d30da42e937db621564Steve Block ' ssl.pemfile = "%s"\n' % mapping['sslcert']) 185d0825bca7fe65beaee391d30da42e937db621564Steve Block 186d0825bca7fe65beaee391d30da42e937db621564Steve Block f.write(('$SERVER["socket"] == "127.0.0.1:%d" {\n' 187d0825bca7fe65beaee391d30da42e937db621564Steve Block ' server.document-root = "%s"\n' + 188d0825bca7fe65beaee391d30da42e937db621564Steve Block ssl_setup + 189d0825bca7fe65beaee391d30da42e937db621564Steve Block '}\n\n') % (mapping['port'], mapping['docroot'])) 190d0825bca7fe65beaee391d30da42e937db621564Steve Block f.close() 191d0825bca7fe65beaee391d30da42e937db621564Steve Block 1928a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block executable = self._port_obj._path_to_lighttpd() 1938a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block module_path = self._port_obj._path_to_lighttpd_modules() 194d0825bca7fe65beaee391d30da42e937db621564Steve Block start_cmd = [executable, 195d0825bca7fe65beaee391d30da42e937db621564Steve Block # Newly written config file 1968a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block '-f', os.path.join(self._output_dir, 'lighttpd.conf'), 197d0825bca7fe65beaee391d30da42e937db621564Steve Block # Where it can find its module dynamic libraries 198d0825bca7fe65beaee391d30da42e937db621564Steve Block '-m', module_path] 199d0825bca7fe65beaee391d30da42e937db621564Steve Block 200d0825bca7fe65beaee391d30da42e937db621564Steve Block if not self._run_background: 201d0825bca7fe65beaee391d30da42e937db621564Steve Block start_cmd.append(# Don't background 202d0825bca7fe65beaee391d30da42e937db621564Steve Block '-D') 203d0825bca7fe65beaee391d30da42e937db621564Steve Block 204d0825bca7fe65beaee391d30da42e937db621564Steve Block # Copy liblightcomp.dylib to /tmp/lighttpd/lib to work around the 205d0825bca7fe65beaee391d30da42e937db621564Steve Block # bug that mod_alias.so loads it from the hard coded path. 206d0825bca7fe65beaee391d30da42e937db621564Steve Block if sys.platform == 'darwin': 207d0825bca7fe65beaee391d30da42e937db621564Steve Block tmp_module_path = '/tmp/lighttpd/lib' 208d0825bca7fe65beaee391d30da42e937db621564Steve Block if not os.path.exists(tmp_module_path): 209d0825bca7fe65beaee391d30da42e937db621564Steve Block os.makedirs(tmp_module_path) 210d0825bca7fe65beaee391d30da42e937db621564Steve Block lib_file = 'liblightcomp.dylib' 211d0825bca7fe65beaee391d30da42e937db621564Steve Block shutil.copyfile(os.path.join(module_path, lib_file), 212d0825bca7fe65beaee391d30da42e937db621564Steve Block os.path.join(tmp_module_path, lib_file)) 213d0825bca7fe65beaee391d30da42e937db621564Steve Block 2146c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen env = self._port_obj.setup_environ_for_server() 21581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch _log.debug('Starting http server, cmd="%s"' % str(start_cmd)) 21621939df44de1705786c545cd1bf519d47250322dBen Murdoch # FIXME: Should use Executive.run_command 2172daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch self._process = subprocess.Popen(start_cmd, env=env, stdin=subprocess.PIPE) 218d0825bca7fe65beaee391d30da42e937db621564Steve Block 219d0825bca7fe65beaee391d30da42e937db621564Steve Block # Wait for server to start. 220d0825bca7fe65beaee391d30da42e937db621564Steve Block self.mappings = mappings 221d0825bca7fe65beaee391d30da42e937db621564Steve Block server_started = self.wait_for_action( 222d0825bca7fe65beaee391d30da42e937db621564Steve Block self.is_server_running_on_all_ports) 223d0825bca7fe65beaee391d30da42e937db621564Steve Block 224d0825bca7fe65beaee391d30da42e937db621564Steve Block # Our process terminated already 225d0825bca7fe65beaee391d30da42e937db621564Steve Block if not server_started or self._process.returncode != None: 226d0825bca7fe65beaee391d30da42e937db621564Steve Block raise google.httpd_utils.HttpdNotStarted('Failed to start httpd.') 227d0825bca7fe65beaee391d30da42e937db621564Steve Block 228dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block _log.debug("Server successfully started") 229d0825bca7fe65beaee391d30da42e937db621564Steve Block 230d0825bca7fe65beaee391d30da42e937db621564Steve Block # TODO(deanm): Find a nicer way to shutdown cleanly. Our log files are 231d0825bca7fe65beaee391d30da42e937db621564Steve Block # probably not being flushed, etc... why doesn't our python have os.kill ? 232d0825bca7fe65beaee391d30da42e937db621564Steve Block 233d0825bca7fe65beaee391d30da42e937db621564Steve Block def stop(self, force=False): 234d0825bca7fe65beaee391d30da42e937db621564Steve Block if not force and not self.is_running(): 235d0825bca7fe65beaee391d30da42e937db621564Steve Block return 236d0825bca7fe65beaee391d30da42e937db621564Steve Block 237d0825bca7fe65beaee391d30da42e937db621564Steve Block httpd_pid = None 238d0825bca7fe65beaee391d30da42e937db621564Steve Block if self._process: 239d0825bca7fe65beaee391d30da42e937db621564Steve Block httpd_pid = self._process.pid 2408a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block self._port_obj._shut_down_http_server(httpd_pid) 241d0825bca7fe65beaee391d30da42e937db621564Steve Block 242d0825bca7fe65beaee391d30da42e937db621564Steve Block if self._process: 24321939df44de1705786c545cd1bf519d47250322dBen Murdoch # wait() is not threadsafe and can throw OSError due to: 24421939df44de1705786c545cd1bf519d47250322dBen Murdoch # http://bugs.python.org/issue1731717 245d0825bca7fe65beaee391d30da42e937db621564Steve Block self._process.wait() 246d0825bca7fe65beaee391d30da42e937db621564Steve Block self._process = None 247