1 # Copyright (C) 2011 Google Inc. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
7 # * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 # * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer
11 # in the documentation and/or other materials provided with the
13 # * Neither the name of Google Inc. nor the names of its
14 # contributors may be used to endorse or promote products derived from
15 # this software without specific prior written permission.
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
29 """A class to help start/stop the lighttpd server used by layout tests."""
35 from webkitpy.layout_tests.servers import server_base
38 _log = logging.getLogger(__name__)
41 class Lighttpd(server_base.ServerBase):
43 def __init__(self, port_obj, output_dir, background=False, port=None,
44 root=None, run_background=None, additional_dirs=None,
45 layout_tests_dir=None, number_of_servers=None):
47 output_dir: the absolute path to the layout test result directory
50 super(Lighttpd, self).__init__(port_obj, number_of_servers)
51 self._name = 'lighttpd'
52 self._log_prefixes = ('access.log-', 'error.log-')
53 self._output_dir = output_dir
56 self._run_background = run_background
57 self._additional_dirs = additional_dirs
58 self._layout_tests_dir = layout_tests_dir
60 self._pid_file = self._filesystem.join(self._runtime_path, '%s.pid' % self._name)
63 self._port = int(self._port)
65 if not self._layout_tests_dir:
66 self._layout_tests_dir = self._port_obj.layout_tests_dir()
68 self._webkit_tests = os.path.join(self._layout_tests_dir, 'http', 'tests')
69 self._js_test_resource = os.path.join(self._layout_tests_dir, 'resources')
70 self._media_resource = os.path.join(self._layout_tests_dir, 'media')
72 # Self generated certificate for SSL server (for client cert get
73 # <base-path>\chrome\test\data\ssl\certs\root_ca_cert.crt)
74 self._pem_file = os.path.join(
75 os.path.dirname(os.path.abspath(__file__)), 'httpd2.pem')
77 # One mapping where we can get to everything
78 self.VIRTUALCONFIG = []
80 if self._webkit_tests:
81 self.VIRTUALCONFIG.extend(
82 # Three mappings (one with SSL) for LayoutTests http tests
83 [{'port': 8000, 'docroot': self._webkit_tests},
84 {'port': 8080, 'docroot': self._webkit_tests},
85 {'port': 8443, 'docroot': self._webkit_tests,
86 'sslcert': self._pem_file}])
88 def _prepare_config(self):
89 base_conf_file = self._port_obj.path_from_webkit_base('Tools',
90 'Scripts', 'webkitpy', 'layout_tests', 'servers', 'lighttpd.conf')
91 out_conf_file = os.path.join(self._output_dir, 'lighttpd.conf')
92 time_str = time.strftime("%d%b%Y-%H%M%S")
93 access_file_name = "access.log-" + time_str + ".txt"
94 access_log = os.path.join(self._output_dir, access_file_name)
95 log_file_name = "error.log-" + time_str + ".txt"
96 error_log = os.path.join(self._output_dir, log_file_name)
98 # Write out the config
99 base_conf = self._filesystem.read_text_file(base_conf_file)
101 # FIXME: This should be re-worked so that this block can
102 # use with open() instead of a manual file.close() call.
103 f = self._filesystem.open_text_file_for_writing(out_conf_file)
106 # Write out our cgi handlers. Run perl through env so that it
107 # processes the #! line and runs perl with the proper command
108 # line arguments. Emulate apache's mod_asis with a cat cgi handler.
109 f.write(('cgi.assign = ( ".cgi" => "/usr/bin/env",\n'
110 ' ".pl" => "/usr/bin/env",\n'
111 ' ".asis" => "/bin/cat",\n'
112 ' ".php" => "%s" )\n\n') %
113 self._port_obj.path_to_lighttpd_php())
116 f.write(('server.errorlog = "%s"\n'
117 'accesslog.filename = "%s"\n\n') % (error_log, access_log))
119 # Setup upload folders. Upload folder is to hold temporary upload files
120 # and also POST data. This is used to support XHR layout tests that
122 f.write(('server.upload-dirs = ( "%s" )\n\n') % (self._output_dir))
124 # Setup a link to where the js test templates are stored
125 f.write(('alias.url = ( "/js-test-resources" => "%s" )\n\n') %
126 (self._js_test_resource))
128 if self._additional_dirs:
129 for alias, path in self._additional_dirs.iteritems():
130 f.write(('alias.url += ( "%s" => "%s" )\n\n') % (alias, path))
132 # Setup a link to where the media resources are stored.
133 f.write(('alias.url += ( "/media-resources" => "%s" )\n\n') %
134 (self._media_resource))
136 # dump out of virtual host config at the bottom.
139 # Have both port and root dir.
140 mappings = [{'port': self._port, 'docroot': self._root}]
142 # Have only a root dir - set the ports as for LayoutTests.
143 # This is used in ui_tests to run http tests against a browser.
145 # default set of ports as for LayoutTests but with a
147 mappings = [{'port': 8000, 'docroot': self._root},
148 {'port': 8080, 'docroot': self._root},
149 {'port': 8443, 'docroot': self._root,
150 'sslcert': self._pem_file}]
152 mappings = self.VIRTUALCONFIG
153 for mapping in mappings:
155 if 'sslcert' in mapping:
156 ssl_setup = (' ssl.engine = "enable"\n'
157 ' ssl.pemfile = "%s"\n' % mapping['sslcert'])
159 f.write(('$SERVER["socket"] == "127.0.0.1:%d" {\n'
160 ' server.document-root = "%s"\n' +
162 '}\n\n') % (mapping['port'], mapping['docroot']))
165 executable = self._port_obj.path_to_lighttpd()
166 module_path = self._port_obj.path_to_lighttpd_modules()
167 start_cmd = [executable,
168 # Newly written config file
169 '-f', os.path.join(self._output_dir, 'lighttpd.conf'),
170 # Where it can find its module dynamic libraries
173 if not self._run_background:
174 start_cmd.append(# Don't background
177 # Copy liblightcomp.dylib to /tmp/lighttpd/lib to work around the
178 # bug that mod_alias.so loads it from the hard coded path.
179 if self._port_obj.host.platform.is_mac():
180 tmp_module_path = '/tmp/lighttpd/lib'
181 if not self._filesystem.exists(tmp_module_path):
182 self._filesystem.maybe_make_directory(tmp_module_path)
183 lib_file = 'liblightcomp.dylib'
184 self._filesystem.copyfile(self._filesystem.join(module_path, lib_file),
185 self._filesystem.join(tmp_module_path, lib_file))
187 self._start_cmd = start_cmd
188 self._env = self._port_obj.setup_environ_for_server('lighttpd')
189 self._mappings = mappings