Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(368)

Side by Side Diff: Tools/Scripts/webkitpy/layout_tests/servers/apache_http_server.py

Issue 135583003: checkpoint Blink-side work to use Apache on Windows (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: first complete patch Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright (C) 2011 Google Inc. All rights reserved. 1 # Copyright (C) 2011 Google Inc. All rights reserved.
2 # 2 #
3 # Redistribution and use in source and binary forms, with or without 3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are 4 # modification, are permitted provided that the following conditions are
5 # met: 5 # met:
6 # 6 #
7 # * Redistributions of source code must retain the above copyright 7 # * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer. 8 # notice, this list of conditions and the following disclaimer.
9 # * Redistributions in binary form must reproduce the above 9 # * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer 10 # copyright notice, this list of conditions and the following disclaimer
(...skipping 12 matching lines...) Expand all
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 28
29 """A class to start/stop the apache http server used by layout tests.""" 29 """A class to start/stop the apache http server used by layout tests."""
30 30
31 31
32 import logging 32 import logging
33 import os
34 import re
35 import socket 33 import socket
36 import sys
37 34
38 from webkitpy.layout_tests.servers import http_server_base 35 from webkitpy.layout_tests.servers import http_server_base
39 36
40 37
41 _log = logging.getLogger(__name__) 38 _log = logging.getLogger(__name__)
42 39
43 40
44 class LayoutTestApacheHttpd(http_server_base.HttpServerBase): 41 class LayoutTestApacheHttpd(http_server_base.HttpServerBase):
45 def __init__(self, port_obj, output_dir, additional_dirs=None, number_of_ser vers=None): 42 def __init__(self, port_obj, output_dir, additional_dirs=None, number_of_ser vers=None):
46 """Args: 43 """Args:
(...skipping 14 matching lines...) Expand all
61 58
62 test_dir = self._port_obj.layout_tests_dir() 59 test_dir = self._port_obj.layout_tests_dir()
63 js_test_resources_dir = self._filesystem.join(test_dir, "resources") 60 js_test_resources_dir = self._filesystem.join(test_dir, "resources")
64 media_resources_dir = self._filesystem.join(test_dir, "media") 61 media_resources_dir = self._filesystem.join(test_dir, "media")
65 mime_types_path = self._filesystem.join(test_dir, "http", "conf", "mime. types") 62 mime_types_path = self._filesystem.join(test_dir, "http", "conf", "mime. types")
66 cert_file = self._filesystem.join(test_dir, "http", "conf", "webkit-http d.pem") 63 cert_file = self._filesystem.join(test_dir, "http", "conf", "webkit-http d.pem")
67 access_log = self._filesystem.join(output_dir, "access_log.txt") 64 access_log = self._filesystem.join(output_dir, "access_log.txt")
68 error_log = self._filesystem.join(output_dir, "error_log.txt") 65 error_log = self._filesystem.join(output_dir, "error_log.txt")
69 document_root = self._filesystem.join(test_dir, "http", "tests") 66 document_root = self._filesystem.join(test_dir, "http", "tests")
70 67
71 # FIXME: We shouldn't be calling a protected method of _port_obj! 68 self._is_win = self._port_obj.host.platform.is_win()
72 executable = self._port_obj._path_to_apache() 69
70 executable = self._port_obj.path_to_apache()
71
72 server_root = self._filesystem.dirname(self._filesystem.dirname(executab le))
73 73
74 start_cmd = [executable, 74 start_cmd = [executable,
75 '-f', "\"%s\"" % self._get_apache_config_file_path(test_dir, output_ dir), 75 '-f', "%s" % self._port_obj.path_to_apache_config_file(),
76 '-C', "\'DocumentRoot \"%s\"\'" % document_root, 76 '-C', "ServerRoot %s" % server_root,
77 '-c', "\'Alias /js-test-resources \"%s\"'" % js_test_resources_dir, 77 '-C', "DocumentRoot %s" % document_root,
78 '-c', "\'Alias /media-resources \"%s\"'" % media_resources_dir, 78 '-c', "Alias /js-test-resources %s" % js_test_resources_dir,
79 '-c', "\'TypesConfig \"%s\"\'" % mime_types_path, 79 '-c', "Alias /media-resources %s" % media_resources_dir,
80 '-c', "\'CustomLog \"%s\" common\'" % access_log, 80 '-c', "TypesConfig %s" % mime_types_path,
81 '-c', "\'ErrorLog \"%s\"\'" % error_log, 81 '-c', "CustomLog %s common" % access_log,
82 '-C', "\'User \"%s\"\'" % os.environ.get("USERNAME", os.environ.get( "USER", "")), 82 '-c', "ErrorLog %s" % error_log,
83 '-c', "\'PidFile %s'" % self._pid_file, 83 '-c', "PidFile %s" % self._pid_file,
84 '-k', "start"] 84 ]
85
85 86
86 enable_ipv6 = self._port_obj.http_server_supports_ipv6() 87 enable_ipv6 = self._port_obj.http_server_supports_ipv6()
87 # Perform part of the checks Apache's APR does when trying to listen to 88 # Perform part of the checks Apache's APR does when trying to listen to
88 # a specific host/port. This allows us to avoid trying to listen to 89 # a specific host/port. This allows us to avoid trying to listen to
89 # IPV6 addresses when it fails on Apache. APR itself tries to call 90 # IPV6 addresses when it fails on Apache. APR itself tries to call
90 # getaddrinfo() again without AI_ADDRCONFIG if the first call fails 91 # getaddrinfo() again without AI_ADDRCONFIG if the first call fails
91 # with EBADFLAGS, but that is not how it normally fails in our use 92 # with EBADFLAGS, but that is not how it normally fails in our use
92 # cases, so ignore that for now. 93 # cases, so ignore that for now.
93 # See https://bugs.webkit.org/show_bug.cgi?id=98602#c7 94 # See https://bugs.webkit.org/show_bug.cgi?id=98602#c7
94 try: 95 try:
95 socket.getaddrinfo('::1', 0, 0, 0, 0, socket.AI_ADDRCONFIG) 96 socket.getaddrinfo('::1', 0, 0, 0, 0, socket.AI_ADDRCONFIG)
96 except: 97 except:
97 enable_ipv6 = False 98 enable_ipv6 = False
98 99
99 for mapping in self._mappings: 100 for mapping in self._mappings:
100 port = mapping['port'] 101 port = mapping['port']
101 102
102 start_cmd += ['-C', "\'Listen 127.0.0.1:%d\'" % port] 103 start_cmd += ['-C', "Listen 127.0.0.1:%d" % port]
103 104
104 # We listen to both IPv4 and IPv6 loop-back addresses, but ignore 105 # We listen to both IPv4 and IPv6 loop-back addresses, but ignore
105 # requests to 8000 from random users on network. 106 # requests to 8000 from random users on network.
106 # See https://bugs.webkit.org/show_bug.cgi?id=37104 107 # See https://bugs.webkit.org/show_bug.cgi?id=37104
107 if enable_ipv6: 108 if enable_ipv6:
108 start_cmd += ['-C', "\'Listen [::1]:%d\'" % port] 109 start_cmd += ['-C', "\'Listen [::1]:%d\'" % port]
109 110
110 if additional_dirs: 111 if additional_dirs:
111 for alias, path in additional_dirs.iteritems(): 112 for alias, path in additional_dirs.iteritems():
112 start_cmd += ['-c', "\'Alias %s \"%s\"\'" % (alias, path), 113 start_cmd += ['-c', "'Alias %s \"%s\"\'" % (alias, path),
113 # Disable CGI handler for additional dirs. 114 # Disable CGI handler for additional dirs.
114 '-c', "\'<Location %s>\'" % alias, 115 '-c', "<Location %s>" % alias,
115 '-c', "\'RemoveHandler .cgi .pl\'", 116 '-c', "RemoveHandler .cgi .pl",
116 '-c', "\'</Location>\'"] 117 '-c', "</Location>"]
117 118
118 if self._number_of_servers: 119 if self._number_of_servers:
119 start_cmd += ['-c', "\'StartServers %d\'" % self._number_of_servers, 120 if self._is_win:
120 '-c', "\'MinSpareServers %d\'" % self._number_of_serve rs, 121 start_cmd += ['-c', "ThreadsPerChild %d" % self._number_of_serve rs]
121 '-c', "\'MaxSpareServers %d\'" % self._number_of_serve rs] 122 else:
123 start_cmd += ['-c', "StartServers %d" % self._number_of_servers,
124 '-c', "MinSpareServers %d" % self._number_of_serve rs,
125 '-c', "MaxSpareServers %d" % self._number_of_serve rs]
122 126
123 stop_cmd = [executable, 127 start_cmd.extend(['-c', "SSLCertificateFile %s" % cert_file])
124 '-f', "\"%s\"" % self._get_apache_config_file_path(test_dir, output_ dir), 128 self._start_cmd = start_cmd
scottmg 2014/02/04 04:58:01 so much better!
125 '-c', "\'PidFile %s'" % self._pid_file,
126 '-k', "stop"]
127
128 start_cmd.extend(['-c', "\'SSLCertificateFile %s\'" % cert_file])
129 # Join the string here so that Cygwin/Windows and Mac/Linux
130 # can use the same code. Otherwise, we could remove the single
131 # quotes above and keep cmd as a sequence.
132 # FIXME: It's unclear if this is still needed.
133 self._start_cmd = " ".join(start_cmd)
134 self._stop_cmd = " ".join(stop_cmd)
135
136 def _get_apache_config_file_path(self, test_dir, output_dir):
137 """Returns the path to the apache config file to use.
138 Args:
139 test_dir: absolute path to the LayoutTests directory.
140 output_dir: absolute path to the layout test results directory.
141 """
142 httpd_config = self._port_obj._path_to_apache_config_file()
143 httpd_config_copy = os.path.join(output_dir, "httpd.conf")
144 httpd_conf = self._filesystem.read_text_file(httpd_config)
145
146 # FIXME: Why do we need to copy the config file since we're not modifyin g it?
147 self._filesystem.write_text_file(httpd_config_copy, httpd_conf)
148
149 return httpd_config_copy
150 129
151 def _spawn_process(self): 130 def _spawn_process(self):
152 _log.debug('Starting %s server, cmd="%s"' % (self._name, str(self._start _cmd))) 131 _log.debug('Starting %s server, cmd="%s"' % (self._name, str(self._start _cmd)))
153 retval, err = self._run(self._start_cmd) 132 retval, err = self._run(self._start_cmd)
154 if retval or len(err): 133 if retval or len(err):
155 raise http_server_base.ServerError('Failed to start %s: %s' % (self. _name, err)) 134 raise http_server_base.ServerError('Failed to start %s: %s' % (self. _name, err))
156 135
157 # For some reason apache isn't guaranteed to have created the pid file b efore 136 # For some reason apache isn't guaranteed to have created the pid file b efore
158 # the process exits, so we wait a little while longer. 137 # the process exits, so we wait a little while longer.
159 if not self._wait_for_action(lambda: self._filesystem.exists(self._pid_f ile)): 138 if not self._wait_for_action(lambda: self._filesystem.exists(self._pid_f ile)):
160 raise http_server_base.ServerError('Failed to start %s: no pid file found' % self._name) 139 raise http_server_base.ServerError('Failed to start %s: no pid file found' % self._name)
161 140
162 return int(self._filesystem.read_text_file(self._pid_file)) 141 return int(self._filesystem.read_text_file(self._pid_file))
163 142
143 def stop(self):
144 self._stop_running_server()
145
164 def _stop_running_server(self): 146 def _stop_running_server(self):
165 # If apache was forcefully killed, the pid file will not have been delet ed, so check 147 # If apache was forcefully killed, the pid file will not have been delet ed, so check
166 # that the process specified by the pid_file no longer exists before del eting the file. 148 # that the process specified by the pid_file no longer exists before del eting the file.
167 if self._pid and not self._executive.check_running_pid(self._pid): 149 if self._pid and not self._executive.check_running_pid(self._pid):
168 self._filesystem.remove(self._pid_file) 150 self._filesystem.remove(self._pid_file)
169 return 151 return
170 152
171 retval, err = self._run(self._stop_cmd) 153 self._executive.kill_process(self._pid)
172 if retval or len(err):
173 raise http_server_base.ServerError('Failed to stop %s: %s' % (self._ name, err))
174
175 # For some reason apache isn't guaranteed to have actually stopped after
176 # the stop command returns, so we wait a little while longer for the
177 # pid file to be removed.
178 if not self._wait_for_action(lambda: not self._filesystem.exists(self._p id_file)):
179 raise http_server_base.ServerError('Failed to stop %s: pid file stil l exists' % self._name)
180 154
181 def _run(self, cmd): 155 def _run(self, cmd):
182 # Use shell=True because we join the arguments into a string for 156 self._process = self._executive.popen(cmd, stdout=self._executive.PIPE, stderr=self._executive.PIPE)
183 # the sake of Window/Cygwin and it needs quoting that breaks 157 if self._process.returncode is not None:
184 # shell=False. 158 return (self._process.returncode, self._process.stderr.read())
185 # FIXME: We should not need to be joining shell arguments into strings. 159 return (0, '')
186 # shell=True is a trail of tears.
187 # Note: Not thread safe: http://bugs.python.org/issue2320
188 process = self._executive.popen(cmd, shell=True, stderr=self._executive. PIPE)
189 process.wait()
190 retval = process.returncode
191 err = process.stderr.read()
192 return (retval, err)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698