Roll src/third_party/WebKit f007c95:0171005 (svn 185074:185088)
[chromium-blink-merge.git] / tools / python / google / httpd_utils.py
blob4a03ffc7fb0c4f7167238b77a6f49a16c7ebbf4f
1 #!/usr/bin/env python
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """A class to help start/stop a local apache http server."""
8 import logging
9 import optparse
10 import os
11 import subprocess
12 import sys
13 import time
14 import urllib
16 import google.path_utils
17 import google.platform_utils
19 class HttpdNotStarted(Exception): pass
21 def UrlIsAlive(url):
22 """Checks to see if we get an http response from |url|.
23 We poll the url 5 times with a 1 second delay. If we don't
24 get a reply in that time, we give up and assume the httpd
25 didn't start properly.
27 Args:
28 url: The URL to check.
29 Return:
30 True if the url is alive.
31 """
32 wait_time = 5
33 while wait_time > 0:
34 try:
35 response = urllib.urlopen(url)
36 # Server is up and responding.
37 return True
38 except IOError:
39 pass
40 wait_time -= 1
41 # Wait a second and try again.
42 time.sleep(1)
44 return False
46 def ApacheConfigDir(start_dir):
47 """Returns a path to the directory holding the Apache config files."""
48 return google.path_utils.FindUpward(start_dir, 'tools', 'python',
49 'google', 'httpd_config')
52 def GetCygserverPath(start_dir, apache2=False):
53 """Returns the path to the directory holding cygserver.exe file."""
54 cygserver_path = None
55 if apache2:
56 cygserver_path = google.path_utils.FindUpward(start_dir, 'third_party',
57 'cygwin', 'usr', 'sbin')
58 return cygserver_path
61 def StartServer(document_root=None, output_dir=None, apache2=False):
62 """Starts a local server on port 8000 using the basic configuration files.
64 Args:
65 document_root: If present, specifies the document root for the server;
66 otherwise, the filesystem's root (e.g., C:/ or /) will be used.
67 output_dir: If present, specifies where to put server logs; otherwise,
68 they'll be placed in the system's temp dir (e.g., $TEMP or /tmp).
69 apache2: boolean if true will cause this function to configure
70 for Apache 2.x as opposed to Apache 1.3.x
72 Returns: the ApacheHttpd object that was created
73 """
74 script_dir = google.path_utils.ScriptDir()
75 platform_util = google.platform_utils.PlatformUtility(script_dir)
76 if not output_dir:
77 output_dir = platform_util.GetTempDirectory()
78 if not document_root:
79 document_root = platform_util.GetFilesystemRoot()
80 apache_config_dir = ApacheConfigDir(script_dir)
81 if apache2:
82 httpd_conf_path = os.path.join(apache_config_dir, 'httpd2.conf')
83 else:
84 httpd_conf_path = os.path.join(apache_config_dir, 'httpd.conf')
85 mime_types_path = os.path.join(apache_config_dir, 'mime.types')
86 start_cmd = platform_util.GetStartHttpdCommand(output_dir,
87 httpd_conf_path,
88 mime_types_path,
89 document_root,
90 apache2=apache2)
91 stop_cmd = platform_util.GetStopHttpdCommand()
92 httpd = ApacheHttpd(start_cmd, stop_cmd, [8000],
93 cygserver_path=GetCygserverPath(script_dir, apache2))
94 httpd.StartServer()
95 return httpd
98 def StopServers(apache2=False):
99 """Calls the platform's stop command on a newly created server, forcing it
100 to stop.
102 The details depend on the behavior of the platform stop command. For example,
103 it's often implemented to kill all running httpd processes, as implied by
104 the name of this function.
106 Args:
107 apache2: boolean if true will cause this function to configure
108 for Apache 2.x as opposed to Apache 1.3.x
110 script_dir = google.path_utils.ScriptDir()
111 platform_util = google.platform_utils.PlatformUtility(script_dir)
112 httpd = ApacheHttpd('', platform_util.GetStopHttpdCommand(), [],
113 cygserver_path=GetCygserverPath(script_dir, apache2))
114 httpd.StopServer(force=True)
117 class ApacheHttpd(object):
118 def __init__(self, start_command, stop_command, port_list,
119 cygserver_path=None):
120 """Args:
121 start_command: command list to call to start the httpd
122 stop_command: command list to call to stop the httpd if one has been
123 started. May kill all httpd processes running on the machine.
124 port_list: list of ports expected to respond on the local machine when
125 the server has been successfully started.
126 cygserver_path: Path to cygserver.exe. If specified, exe will be started
127 with server as well as stopped when server is stopped.
129 self._http_server_proc = None
130 self._start_command = start_command
131 self._stop_command = stop_command
132 self._port_list = port_list
133 self._cygserver_path = cygserver_path
135 def StartServer(self):
136 if self._http_server_proc:
137 return
138 if self._cygserver_path:
139 cygserver_exe = os.path.join(self._cygserver_path, "cygserver.exe")
140 cygbin = google.path_utils.FindUpward(cygserver_exe, 'third_party',
141 'cygwin', 'bin')
142 env = os.environ
143 env['PATH'] += ";" + cygbin
144 subprocess.Popen(cygserver_exe, env=env)
145 logging.info('Starting http server')
146 self._http_server_proc = subprocess.Popen(self._start_command)
148 # Ensure that the server is running on all the desired ports.
149 for port in self._port_list:
150 if not UrlIsAlive('http://127.0.0.1:%s/' % str(port)):
151 raise HttpdNotStarted('Failed to start httpd on port %s' % str(port))
153 def StopServer(self, force=False):
154 """If we started an httpd.exe process, or if force is True, call
155 self._stop_command (passed in on init so it can be platform-dependent).
156 This will presumably kill it, and may also kill any other httpd.exe
157 processes that are running.
159 if force or self._http_server_proc:
160 logging.info('Stopping http server')
161 kill_proc = subprocess.Popen(self._stop_command,
162 stdout=subprocess.PIPE,
163 stderr=subprocess.PIPE)
164 logging.info('%s\n%s' % (kill_proc.stdout.read(),
165 kill_proc.stderr.read()))
166 self._http_server_proc = None
167 if self._cygserver_path:
168 subprocess.Popen(["taskkill.exe", "/f", "/im", "cygserver.exe"],
169 stdout=subprocess.PIPE,
170 stderr=subprocess.PIPE)
173 def main():
174 # Provide some command line params for starting/stopping the http server
175 # manually.
176 option_parser = optparse.OptionParser()
177 option_parser.add_option('-k', '--server', help='Server action (start|stop)')
178 option_parser.add_option('-r', '--root', help='Document root (optional)')
179 option_parser.add_option('-a', '--apache2', action='store_true',
180 default=False, help='Starts Apache 2 instead of Apache 1.3 (default). '
181 'Ignored on Mac (apache2 is used always)')
182 options, args = option_parser.parse_args()
184 if not options.server:
185 print ("Usage: %s -k {start|stop} [-r document_root] [--apache2]" %
186 sys.argv[0])
187 return 1
189 document_root = None
190 if options.root:
191 document_root = options.root
193 if 'start' == options.server:
194 StartServer(document_root, apache2=options.apache2)
195 else:
196 StopServers(apache2=options.apache2)
199 if '__main__' == __name__:
200 sys.exit(main())