summaryrefslogtreecommitdiffstats
path: root/tools/python
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-27 00:12:16 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-27 00:12:16 +0000
commit920c091ac3ee15079194c82ae8a7a18215f3f23c (patch)
treed28515d1e7732e2b6d077df1b4855ace3f4ac84f /tools/python
parentae2c20f398933a9e86c387dcc465ec0f71065ffc (diff)
downloadchromium_src-920c091ac3ee15079194c82ae8a7a18215f3f23c.zip
chromium_src-920c091ac3ee15079194c82ae8a7a18215f3f23c.tar.gz
chromium_src-920c091ac3ee15079194c82ae8a7a18215f3f23c.tar.bz2
Add tools to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools/python')
-rw-r--r--tools/python/google/__init__.py1
-rw-r--r--tools/python/google/gethash_timer.py168
-rw-r--r--tools/python/google/httpd_config/httpd.conf734
-rw-r--r--tools/python/google/httpd_config/httpd2.conf280
-rw-r--r--tools/python/google/httpd_config/httpd2.pem36
-rw-r--r--tools/python/google/httpd_config/mime.types599
-rw-r--r--tools/python/google/httpd_utils.py219
-rw-r--r--tools/python/google/logging_utils.py110
-rw-r--r--tools/python/google/path_utils.py109
-rw-r--r--tools/python/google/platform_utils.py46
-rw-r--r--tools/python/google/platform_utils_win.py219
-rw-r--r--tools/python/google/process_utils.py156
12 files changed, 2677 insertions, 0 deletions
diff --git a/tools/python/google/__init__.py b/tools/python/google/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/tools/python/google/__init__.py
@@ -0,0 +1 @@
+
diff --git a/tools/python/google/gethash_timer.py b/tools/python/google/gethash_timer.py
new file mode 100644
index 0000000..b36a5df
--- /dev/null
+++ b/tools/python/google/gethash_timer.py
@@ -0,0 +1,168 @@
+#!/usr/bin/python
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Issue a series of GetHash requests to the SafeBrowsing servers and measure the
+# response times.
+#
+# Usage:
+#
+# $ ./gethash_timer.py --period=600 --samples=20 --output=resp.csv
+#
+# --period (or -p): The amount of time (in seconds) to wait between GetHash
+# requests. Using a value of more than 300 (5 minutes) to
+# include the effect of DNS.
+#
+# --samples (or -s): The number of requests to issue. If this parameter is not
+# specified, the test will run indefinitely.
+#
+# --output (or -o): The path to a file where the output will be written in
+# CSV format: sample_number,response_code,elapsed_time_ms
+
+import getopt
+import httplib
+import sys
+import time
+
+_GETHASH_HOST = 'safebrowsing.clients.google.com'
+_GETHASH_REQUEST = '/safebrowsing/gethash?client=googleclient&appver=1.0&pver=2.1'
+
+# Global logging file handle.
+g_file_handle = None
+
+
+def IssueGetHash(prefix):
+ '''Issue one GetHash request to the safebrowsing servers.
+ Args:
+ prefix: A 4 byte value to look up on the server.
+ Returns:
+ The HTTP response code for the GetHash request.
+ '''
+ body = '4:4\n' + prefix
+ h = httplib.HTTPConnection(_GETHASH_HOST)
+ h.putrequest('POST', _GETHASH_REQUEST)
+ h.putheader('content-length', str(len(body)))
+ h.endheaders()
+ h.send(body)
+ response_code = h.getresponse().status
+ h.close()
+ return response_code
+
+
+def TimedGetHash(prefix):
+ '''Measure the amount of time it takes to receive a GetHash response.
+ Args:
+ prefix: A 4 byte value to look up on the the server.
+ Returns:
+ A tuple of HTTP resonse code and the response time (in milliseconds).
+ '''
+ start = time.time()
+ response_code = IssueGetHash(prefix)
+ return response_code, (time.time() - start) * 1000
+
+
+def RunTimedGetHash(period, samples=None):
+ '''Runs an experiment to measure the amount of time it takes to receive
+ multiple responses from the GetHash servers.
+
+ Args:
+ period: A floating point value that indicates (in seconds) the delay
+ between requests.
+ samples: An integer value indicating the number of requests to make.
+ If 'None', the test continues indefinitely.
+ Returns:
+ None.
+ '''
+ global g_file_handle
+ prefix = '\x50\x61\x75\x6c'
+ sample_count = 1
+ while True:
+ response_code, elapsed_time = TimedGetHash(prefix)
+ LogResponse(sample_count, response_code, elapsed_time)
+ sample_count += 1
+ if samples is not None and sample_count == samples:
+ break
+ time.sleep(period)
+
+
+def LogResponse(sample_count, response_code, elapsed_time):
+ '''Output the response for one GetHash query.
+ Args:
+ sample_count: The current sample number.
+ response_code: The HTTP response code for the GetHash request.
+ elapsed_time: The round-trip time (in milliseconds) for the
+ GetHash request.
+ Returns:
+ None.
+ '''
+ global g_file_handle
+ output_list = (sample_count, response_code, elapsed_time)
+ print 'Request: %d, status: %d, elapsed time: %f ms' % output_list
+ if g_file_handle is not None:
+ g_file_handle.write(('%d,%d,%f' % output_list) + '\n')
+ g_file_handle.flush()
+
+
+def SetupOutputFile(file_name):
+ '''Open a file for logging results.
+ Args:
+ file_name: A path to a file to store the output.
+ Returns:
+ None.
+ '''
+ global g_file_handle
+ g_file_handle = open(file_name, 'w')
+
+
+if __name__ == '__main__':
+ period = 10
+ samples = None
+
+ options, args = getopt.getopt(sys.argv[1:],
+ 's:p:o:',
+ ['samples=', 'period=', 'output='])
+ for option, value in options:
+ if option == '-s' or option == '--samples':
+ samples = int(value)
+ elif option == '-p' or option == '--period':
+ period = float(value)
+ elif option == '-o' or option == '--output':
+ file_name = value
+ else:
+ print 'Bad option: %s' % option
+ sys.exit(1)
+ try:
+ print 'Starting Timed GetHash ----------'
+ SetupOutputFile(file_name)
+ RunTimedGetHash(period, samples)
+ except KeyboardInterrupt:
+ pass
+
+ print 'Timed GetHash complete ----------'
+ g_file_handle.close()
diff --git a/tools/python/google/httpd_config/httpd.conf b/tools/python/google/httpd_config/httpd.conf
new file mode 100644
index 0000000..fc7a498
--- /dev/null
+++ b/tools/python/google/httpd_config/httpd.conf
@@ -0,0 +1,734 @@
+##
+## httpd.conf -- Apache HTTP server configuration file
+##
+
+#
+# Based upon the NCSA server configuration files originally by Rob McCool.
+#
+# This is the main Apache server configuration file. It contains the
+# configuration directives that give the server its instructions.
+# See <URL:http://httpd.apache.org/docs/> for detailed information about
+# the directives.
+#
+# Do NOT simply read the instructions in here without understanding
+# what they do. They're here only as hints or reminders. If you are unsure
+# consult the online docs. You have been warned.
+#
+# After this file is processed, the server will look for and process
+# /private/etc/httpd/srm.conf and then /private/etc/httpd/access.conf
+# unless you have overridden these with ResourceConfig and/or
+# AccessConfig directives here.
+#
+# The configuration directives are grouped into three basic sections:
+# 1. Directives that control the operation of the Apache server process as a
+# whole (the 'global environment').
+# 2. Directives that define the parameters of the 'main' or 'default' server,
+# which responds to requests that aren't handled by a virtual host.
+# These directives also provide default values for the settings
+# of all virtual hosts.
+# 3. Settings for virtual hosts, which allow Web requests to be sent to
+# different IP addresses or hostnames and have them handled by the
+# same Apache server process.
+#
+# Configuration and logfile names: If the filenames you specify for many
+# of the server's control files begin with "/" (or "drive:/" for Win32), the
+# server will use that explicit path. If the filenames do *not* begin
+# with "/", the value of ServerRoot is prepended -- so "logs/foo.log"
+# with ServerRoot set to "/usr/local/apache" will be interpreted by the
+# server as "/usr/local/apache/logs/foo.log".
+#
+
+### Section 1: Global Environment
+#
+# The directives in this section affect the overall operation of Apache,
+# such as the number of concurrent requests it can handle or where it
+# can find its configuration files.
+#
+
+#
+# ServerType is either inetd, or standalone. Inetd mode is only supported on
+# Unix platforms.
+#
+ServerType standalone
+
+#
+# ServerRoot: The top of the directory tree under which the server's
+# configuration, error, and log files are kept.
+#
+# NOTE! If you intend to place this on an NFS (or otherwise network)
+# mounted filesystem then please read the LockFile documentation
+# (available at <URL:http://www.apache.org/docs/mod/core.html#lockfile>);
+# you will save yourself a lot of trouble.
+#
+#ServerRoot "/usr"
+
+#
+# The LockFile directive sets the path to the lockfile used when Apache
+# is compiled with either USE_FCNTL_SERIALIZED_ACCEPT or
+# USE_FLOCK_SERIALIZED_ACCEPT. This directive should normally be left at
+# its default value. The main reason for changing it is if the logs
+# directory is NFS mounted, since the lockfile MUST BE STORED ON A LOCAL
+# DISK. The PID of the main server process is automatically appended to
+# the filename.
+#
+#LockFile "/private/var/run/httpd.lock"
+
+#
+# PidFile: The file in which the server should record its process
+# identification number when it starts.
+#
+PidFile "/tmp/WebKit/httpd.pid"
+
+#
+# ScoreBoardFile: File used to store internal server process information.
+# Not all architectures require this. But if yours does (you'll know because
+# this file will be created when you run Apache) then you *must* ensure that
+# no two invocations of Apache share the same scoreboard file.
+#
+ScoreBoardFile "/tmp/WebKit/httpd.scoreboard"
+
+#
+# In the standard configuration, the server will process httpd.conf (this
+# file, specified by the -f command line option), srm.conf, and access.conf
+# in that order. The latter two files are now distributed empty, as it is
+# recommended that all directives be kept in a single file for simplicity.
+# The commented-out values below are the built-in defaults. You can have the
+# server ignore these files altogether by using "/dev/null" (for Unix) or
+# "nul" (for Win32) for the arguments to the directives.
+#
+ResourceConfig /dev/null
+AccessConfig /dev/null
+
+#
+# Timeout: The number of seconds before receives and sends time out.
+#
+Timeout 300
+
+#
+# KeepAlive: Whether or not to allow persistent connections (more than
+# one request per connection). Set to "Off" to deactivate.
+#
+KeepAlive On
+
+#
+# MaxKeepAliveRequests: The maximum number of requests to allow
+# during a persistent connection. Set to 0 to allow an unlimited amount.
+# We recommend you leave this number high, for maximum performance.
+#
+MaxKeepAliveRequests 100
+
+#
+# KeepAliveTimeout: Number of seconds to wait for the next request from the
+# same client on the same connection.
+#
+KeepAliveTimeout 15
+
+#
+# Server-pool size regulation. Rather than making you guess how many
+# server processes you need, Apache dynamically adapts to the load it
+# sees --- that is, it tries to maintain enough server processes to
+# handle the current load, plus a few spare servers to handle transient
+# load spikes (e.g., multiple simultaneous requests from a single
+# Netscape browser).
+#
+# It does this by periodically checking how many servers are waiting
+# for a request. If there are fewer than MinSpareServers, it creates
+# a new spare. If there are more than MaxSpareServers, some of the
+# spares die off. The default values are probably OK for most sites.
+#
+MinSpareServers 1
+MaxSpareServers 5
+
+#
+# Number of servers to start initially --- should be a reasonable ballpark
+# figure.
+#
+StartServers 1
+
+#
+# Limit on total number of servers running, i.e., limit on the number
+# of clients who can simultaneously connect --- if this limit is ever
+# reached, clients will be LOCKED OUT, so it should NOT BE SET TOO LOW.
+# It is intended mainly as a brake to keep a runaway server from taking
+# the system with it as it spirals down...
+#
+MaxClients 150
+
+#
+# MaxRequestsPerChild: the number of requests each child process is
+# allowed to process before the child dies. The child will exit so
+# as to avoid problems after prolonged use when Apache (and maybe the
+# libraries it uses) leak memory or other resources. On most systems, this
+# isn't really needed, but a few (such as Solaris) do have notable leaks
+# in the libraries. For these platforms, set to something like 10000
+# or so; a setting of 0 means unlimited.
+#
+# NOTE: This value does not include keepalive requests after the initial
+# request per connection. For example, if a child process handles
+# an initial request and 10 subsequent "keptalive" requests, it
+# would only count as 1 request towards this limit.
+#
+MaxRequestsPerChild 100000
+
+#
+# Listen: Allows you to bind Apache to specific IP addresses and/or
+# ports, instead of the default. See also the <VirtualHost>
+# directive.
+#
+# Configured from the httpd command line for WebKit layout tests.
+#
+Listen 127.0.0.1:8000
+Listen 127.0.0.1:8080
+Listen 127.0.0.1:8081
+Listen 127.0.0.1:9000
+Listen 127.0.0.1:9080
+
+#
+# Dynamic Shared Object (DSO) Support
+#
+# To be able to use the functionality of a module which was built as a DSO you
+# have to place corresponding `LoadModule' lines at this location so the
+# directives contained in it are actually available _before_ they are used.
+# Please read the file http://httpd.apache.org/docs/dso.html for more
+# details about the DSO mechanism and run `httpd -l' for the list of already
+# built-in (statically linked and thus always available) modules in your httpd
+# binary.
+#
+# Note: The order in which modules are loaded is important. Don't change
+# the order below without expert advice.
+#
+# Example:
+# LoadModule foo_module lib/apache/mod_foo.dll
+#LoadModule vhost_alias_module lib/apache/mod_vhost_alias.dll
+#LoadModule env_module lib/apache/mod_env.dll
+LoadModule config_log_module lib/apache/mod_log_config.dll
+#LoadModule mime_magic_module lib/apache/mod_mime_magic.dll
+LoadModule mime_module lib/apache/mod_mime.dll
+LoadModule negotiation_module lib/apache/mod_negotiation.dll
+#LoadModule status_module lib/apache/mod_status.dll
+#LoadModule info_module lib/apache/mod_info.dll
+LoadModule includes_module lib/apache/mod_include.dll
+LoadModule autoindex_module lib/apache/mod_autoindex.dll
+#LoadModule dir_module lib/apache/mod_dir.dll
+LoadModule cgi_module lib/apache/mod_cgi.dll
+LoadModule asis_module lib/apache/mod_asis.dll
+LoadModule imap_module lib/apache/mod_imap.dll
+LoadModule action_module lib/apache/mod_actions.dll
+#LoadModule speling_module lib/apache/mod_speling.dll
+#LoadModule userdir_module lib/apache/mod_userdir.dll
+LoadModule alias_module lib/apache/mod_alias.dll
+LoadModule rewrite_module lib/apache/mod_rewrite.dll
+LoadModule access_module lib/apache/mod_access.dll
+LoadModule auth_module lib/apache/mod_auth.dll
+#LoadModule anon_auth_module lib/apache/mod_auth_anon.dll
+#LoadModule dbm_auth_module lib/apache/mod_auth_dbm.dll
+#LoadModule digest_module lib/apache/mod_digest.dll
+#LoadModule proxy_module lib/apache/libproxy.dll
+#LoadModule cern_meta_module lib/apache/mod_cern_meta.dll
+#LoadModule expires_module lib/apache/mod_expires.dll
+LoadModule headers_module lib/apache/mod_headers.dll
+#LoadModule usertrack_module lib/apache/mod_usertrack.dll
+#LoadModule log_forensic_module lib/apache/mod_log_forensic.dll
+#LoadModule unique_id_module lib/apache/mod_unique_id.dll
+#LoadModule setenvif_module lib/apache/mod_setenvif.dll
+#LoadModule dav_module lib/apache/libdav.dll
+#LoadModule ssl_module lib/apache/libssl.dll
+#LoadModule perl_module lib/apache/libperl.dll
+LoadModule php4_module lib/apache/libphp4.dll
+#LoadModule hfs_apple_module lib/apache/mod_hfs_apple.dll
+#LoadModule bonjour_module lib/apache/mod_bonjour.dll
+
+# Reconstruction of the complete module list from all available modules
+# (static and shared ones) to achieve correct module execution order.
+# [WHENEVER YOU CHANGE THE LOADMODULE SECTION ABOVE UPDATE THIS, TOO]
+ClearModuleList
+#AddModule mod_vhost_alias.c
+#AddModule mod_env.c
+AddModule mod_log_config.c
+#AddModule mod_mime_magic.c
+AddModule mod_mime.c
+AddModule mod_negotiation.c
+#AddModule mod_status.c
+#AddModule mod_info.c
+AddModule mod_include.c
+AddModule mod_autoindex.c
+#AddModule mod_dir.c
+AddModule mod_cgi.c
+AddModule mod_asis.c
+AddModule mod_imap.c
+AddModule mod_actions.c
+#AddModule mod_speling.c
+#AddModule mod_userdir.c
+AddModule mod_alias.c
+AddModule mod_rewrite.c
+AddModule mod_access.c
+AddModule mod_auth.c
+#AddModule mod_auth_anon.c
+#AddModule mod_auth_dbm.c
+#AddModule mod_digest.c
+#AddModule mod_proxy.c
+#AddModule mod_cern_meta.c
+#AddModule mod_expires.c
+AddModule mod_headers.c
+#AddModule mod_usertrack.c
+#AddModule mod_log_forensic.c
+#AddModule mod_unique_id.c
+AddModule mod_so.c
+#AddModule mod_setenvif.c
+#AddModule mod_dav.c
+#AddModule mod_ssl.c
+#AddModule mod_perl.c
+AddModule mod_php4.c
+#AddModule mod_hfs_apple.c
+#AddModule mod_bonjour.c
+
+### Section 2: 'Main' server configuration
+#
+# The directives in this section set up the values used by the 'main'
+# server, which responds to any requests that aren't handled by a
+# <VirtualHost> definition. These values also provide defaults for
+# any <VirtualHost> containers you may define later in the file.
+#
+# All of these directives may appear inside <VirtualHost> containers,
+# in which case these default settings will be overridden for the
+# virtual host being defined.
+#
+
+#
+# ServerName allows you to set a host name which is sent back to clients for
+# your server if it's different than the one the program would get (i.e., use
+# "www" instead of the host's real name).
+#
+# Note: You cannot just invent host names and hope they work. The name you
+# define here must be a valid DNS name for your host. If you don't understand
+# this, ask your network administrator.
+# If your host doesn't have a registered DNS name, enter its IP address here.
+# You will have to access it by its address (e.g., http://123.45.67.89/)
+# anyway, and this will make redirections work in a sensible way.
+#
+# 127.0.0.1 is the TCP/IP local loop-back address, often named localhost. Your
+# machine always knows itself by this address. If you use Apache strictly for
+# local testing and development, you may use 127.0.0.1 as the server name.
+#
+ServerName 127.0.0.1
+
+#
+# DocumentRoot: The directory out of which you will serve your
+# documents. By default, all requests are taken from this directory, but
+# symbolic links and aliases may be used to point to other locations.
+#
+# Configured from the httpd command line for WebKit layout tests.
+#DocumentRoot "/Library/WebServer/Documents"
+
+#
+# Each directory to which Apache has access, can be configured with respect
+# to which services and features are allowed and/or disabled in that
+# directory (and its subdirectories).
+#
+<Directory />
+#
+# This may also be "None", "All", or any combination of "Indexes",
+# "Includes", "FollowSymLinks", "ExecCGI", or "MultiViews".
+#
+# Note that "MultiViews" must be named *explicitly* --- "Options All"
+# doesn't give it to you.
+#
+ Options Indexes FollowSymLinks MultiViews ExecCGI Includes
+
+#
+# This controls which options the .htaccess files in directories can
+# override. Can also be "All", or any combination of "Options", "FileInfo",
+# "AuthConfig", and "Limit"
+#
+ AllowOverride All
+
+#
+# Controls who can get stuff from this server.
+#
+ Order allow,deny
+ Allow from all
+</Directory>
+
+#
+# AccessFileName: The name of the file to look for in each directory
+# for access control information.
+#
+AccessFileName .htaccess
+
+#
+# The following lines prevent .htaccess files from being viewed by
+# Web clients. Since .htaccess files often contain authorization
+# information, access is disallowed for security reasons. Comment
+# these lines out if you want Web visitors to see the contents of
+# .htaccess files. If you change the AccessFileName directive above,
+# be sure to make the corresponding changes here.
+#
+# Also, folks tend to use names such as .htpasswd for password
+# files, so this will protect those as well.
+#
+<Files ~ "^\.([Hh][Tt]|[Dd][Ss]_[Ss])">
+ Order allow,deny
+ Deny from all
+ Satisfy All
+</Files>
+
+#
+# Apple specific filesystem protection.
+#
+
+<Files "rsrc">
+ Order allow,deny
+ Deny from all
+ Satisfy All
+</Files>
+
+<Directory ~ ".*\.\.namedfork">
+ Order allow,deny
+ Deny from all
+ Satisfy All
+</Directory>
+
+#
+# CacheNegotiatedDocs: By default, Apache sends "Pragma: no-cache" with each
+# document that was negotiated on the basis of content. This asks proxy
+# servers not to cache the document. Uncommenting the following line disables
+# this behavior, and proxies will be allowed to cache the documents.
+#
+#CacheNegotiatedDocs
+
+#
+# UseCanonicalName: (new for 1.3) With this setting turned on, whenever
+# Apache needs to construct a self-referencing URL (a URL that refers back
+# to the server the response is coming from) it will use ServerName and
+# Port to form a "canonical" name. With this setting off, Apache will
+# use the hostname:port that the client supplied, when possible. This
+# also affects SERVER_NAME and SERVER_PORT in CGI scripts.
+#
+UseCanonicalName On
+
+#
+# TypesConfig describes where the mime.types file (or equivalent) is
+# to be found.
+#
+# Configured from the httpd command line for WebKit layout tests.
+#
+#<IfModule mod_mime.c>
+# TypesConfig /private/etc/httpd/mime.types
+#</IfModule>
+
+#
+# DefaultType is the default MIME type the server will use for a document
+# if it cannot otherwise determine one, such as from filename extensions.
+# If your server contains mostly text or HTML documents, "text/plain" is
+# a good value. If most of your content is binary, such as applications
+# or images, you may want to use "application/octet-stream" instead to
+# keep browsers from trying to display binary files as though they are
+# text.
+#
+DefaultType text/plain
+
+#
+# HostnameLookups: Log the names of clients or just their IP addresses
+# e.g., www.apache.org (on) or 204.62.129.132 (off).
+# The default is off because it'd be overall better for the net if people
+# had to knowingly turn this feature on, since enabling it means that
+# each client request will result in AT LEAST one lookup request to the
+# nameserver.
+#
+HostnameLookups Off
+
+#
+# ErrorLog: The location of the error log file.
+# If you do not specify an ErrorLog directive within a <VirtualHost>
+# container, error messages relating to that virtual host will be
+# logged here. If you *do* define an error logfile for a <VirtualHost>
+# container, that host's errors will be logged there and not here.
+#
+# Configured from the httpd command line for WebKit layout tests.
+#ErrorLog "/tmp/layout-test-results/error_log"
+
+#
+# LogLevel: Control the number of messages logged to the error_log.
+# Possible values include: debug, info, notice, warn, error, crit,
+# alert, emerg.
+#
+LogLevel warn
+
+#
+# The following directives define some format nicknames for use with
+# a CustomLog directive (see below).
+#
+LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+LogFormat "%p %h %l %u %t \"%r\" %>s %b" common
+LogFormat "%{Referer}i -> %U" referer
+LogFormat "%{User-agent}i" agent
+
+#
+# The location and format of the access logfile (Common Logfile Format).
+# If you do not define any access logfiles within a <VirtualHost>
+# container, they will be logged here. Contrariwise, if you *do*
+# define per-<VirtualHost> access logfiles, transactions will be
+# logged therein and *not* in this file.
+#
+# Configured from the httpd command line for WebKit layout tests.
+#CustomLog "/tmp/layout-test-results/access_log" common
+
+#
+# If you prefer a single logfile with access, agent, and referer information
+# (Combined Logfile Format) you can use the following directive.
+#
+#CustomLog "/tmp/layout-test-results/access_log" combined
+
+#
+# Optionally add a line containing the server version and virtual host
+# name to server-generated pages (error documents, FTP directory listings,
+# mod_status and mod_info output etc., but not CGI generated documents).
+# Set to "EMail" to also include a mailto: link to the ServerAdmin.
+# Set to one of: On | Off | EMail
+#
+ServerSignature On
+
+#
+# Aliases: Add here as many aliases as you need (with no limit). The format is
+# Alias fakename realname
+#
+<IfModule mod_alias.c>
+</IfModule>
+# End of aliases.
+
+#
+# Redirect allows you to tell clients about documents which used to exist in
+# your server's namespace, but do not anymore. This allows you to tell the
+# clients where to look for the relocated document.
+# Format: Redirect old-URI new-URL
+#
+
+#
+# Document types.
+#
+<IfModule mod_mime.c>
+
+ #
+ # AddLanguage allows you to specify the language of a document. You can
+ # then use content negotiation to give a browser a file in a language
+ # it can understand.
+ #
+ # Note 1: The suffix does not have to be the same as the language
+ # keyword --- those with documents in Polish (whose net-standard
+ # language code is pl) may wish to use "AddLanguage pl .po" to
+ # avoid the ambiguity with the common suffix for perl scripts.
+ #
+ # Note 2: The example entries below illustrate that in quite
+ # some cases the two character 'Language' abbreviation is not
+ # identical to the two character 'Country' code for its country,
+ # E.g. 'Danmark/dk' versus 'Danish/da'.
+ #
+ # Note 3: In the case of 'ltz' we violate the RFC by using a three char
+ # specifier. But there is 'work in progress' to fix this and get
+ # the reference data for rfc1766 cleaned up.
+ #
+ # Danish (da) - Dutch (nl) - English (en) - Estonian (ee)
+ # French (fr) - German (de) - Greek-Modern (el)
+ # Italian (it) - Korean (kr) - Norwegian (no) - Norwegian Nynorsk (nn)
+ # Portugese (pt) - Luxembourgeois* (ltz)
+ # Spanish (es) - Swedish (sv) - Catalan (ca) - Czech(cs)
+ # Polish (pl) - Brazilian Portuguese (pt-br) - Japanese (ja)
+ # Russian (ru)
+ #
+ AddLanguage da .dk
+ AddLanguage nl .nl
+ AddLanguage en .en
+ AddLanguage et .ee
+ AddLanguage fr .fr
+ AddLanguage de .de
+ AddLanguage el .el
+ AddLanguage he .he
+ AddCharset ISO-8859-8 .iso8859-8
+ AddLanguage it .it
+ AddLanguage ja .ja
+ AddCharset ISO-2022-JP .jis
+ AddLanguage kr .kr
+ AddCharset ISO-2022-KR .iso-kr
+ AddLanguage nn .nn
+ AddLanguage no .no
+ AddLanguage pl .po
+ AddCharset ISO-8859-2 .iso-pl
+ AddLanguage pt .pt
+ AddLanguage pt-br .pt-br
+ AddLanguage ltz .lu
+ AddLanguage ca .ca
+ AddLanguage es .es
+ AddLanguage sv .sv
+ AddLanguage cs .cz .cs
+ AddLanguage ru .ru
+ AddLanguage zh-TW .zh-tw
+ AddCharset Big5 .Big5 .big5
+ AddCharset WINDOWS-1251 .cp-1251
+ AddCharset CP866 .cp866
+ AddCharset ISO-8859-5 .iso-ru
+ AddCharset KOI8-R .koi8-r
+ AddCharset UCS-2 .ucs2
+ AddCharset UCS-4 .ucs4
+ AddCharset UTF-8 .utf8
+
+ # LanguagePriority allows you to give precedence to some languages
+ # in case of a tie during content negotiation.
+ #
+ # Just list the languages in decreasing order of preference. We have
+ # more or less alphabetized them here. You probably want to change this.
+ #
+ <IfModule mod_negotiation.c>
+ LanguagePriority en da nl et fr de el it ja kr no pl pt pt-br ru ltz ca es sv tw
+ </IfModule>
+
+ #
+ # AddType allows you to tweak mime.types without actually editing it, or to
+ # make certain files to be certain types.
+ #
+ AddType application/x-tar .tgz
+
+ #
+ # AddEncoding allows you to have certain browsers uncompress
+ # information on the fly. Note: Not all browsers support this.
+ # Despite the name similarity, the following Add* directives have nothing
+ # to do with the FancyIndexing customization directives above.
+ #
+ AddEncoding x-compress .Z
+ AddEncoding x-gzip .gz .tgz
+ #
+ # If the AddEncoding directives above are commented-out, then you
+ # probably should define those extensions to indicate media types:
+ #
+ #AddType application/x-compress .Z
+ #AddType application/x-gzip .gz .tgz
+
+ #
+ # AddHandler allows you to map certain file extensions to "handlers",
+ # actions unrelated to filetype. These can be either built into the server
+ # or added with the Action command (see below)
+ #
+ # If you want to use server side includes, or CGI outside
+ # ScriptAliased directories, uncomment the following lines.
+ #
+ # To use CGI scripts:
+ #
+ AddHandler cgi-script .cgi .pl
+
+ #
+ # To use server-parsed HTML files
+ #
+ AddType text/html .shtml
+ AddHandler server-parsed .shtml
+
+ #
+ # Uncomment the following line to enable Apache's send-asis HTTP file
+ # feature
+ #
+ AddHandler send-as-is asis
+
+ #
+ # If you wish to use server-parsed imagemap files, use
+ #
+ #AddHandler imap-file map
+
+ #
+ # To enable type maps, you might want to use
+ #
+ #AddHandler type-map var
+
+</IfModule>
+# End of document types.
+
+#
+# Action lets you define media types that will execute a script whenever
+# a matching file is called. This eliminates the need for repeated URL
+# pathnames for oft-used CGI file processors.
+# Format: Action media/type /cgi-script/location
+# Format: Action handler-name /cgi-script/location
+#
+
+#
+# MetaDir: specifies the name of the directory in which Apache can find
+# meta information files. These files contain additional HTTP headers
+# to include when sending the document
+#
+#MetaDir .web
+
+#
+# MetaSuffix: specifies the file name suffix for the file containing the
+# meta information.
+#
+#MetaSuffix .meta
+
+#
+# Customizable error response (Apache style)
+# these come in three flavors
+#
+# 1) plain text
+#ErrorDocument 500 "The server made a boo boo.
+# n.b. the single leading (") marks it as text, it does not get output
+#
+# 2) local redirects
+#ErrorDocument 404 /missing.html
+# to redirect to local URL /missing.html
+#ErrorDocument 404 /cgi-bin/missing_handler.pl
+# N.B.: You can redirect to a script or a document using server-side-includes.
+#
+# 3) external redirects
+#ErrorDocument 402 http://some.other-server.com/subscription_info.html
+# N.B.: Many of the environment variables associated with the original
+# request will *not* be available to such a script.
+
+#
+# Proxy Server directives. Uncomment the following lines to
+# enable the proxy server:
+#
+#<IfModule mod_proxy.c>
+# ProxyRequests On
+
+# <Directory proxy:*>
+# Order deny,allow
+# Deny from all
+# Allow from .your-domain.com
+# </Directory>
+
+ #
+ # Enable/disable the handling of HTTP/1.1 "Via:" headers.
+ # ("Full" adds the server version; "Block" removes all outgoing Via: headers)
+ # Set to one of: Off | On | Full | Block
+ #
+# ProxyVia On
+
+ #
+ # To enable the cache as well, edit and uncomment the following lines:
+ # (no cacheing without CacheRoot)
+ #
+# CacheRoot "/private/var/run/proxy"
+# CacheSize 5
+# CacheGcInterval 4
+# CacheMaxExpire 24
+# CacheLastModifiedFactor 0.1
+# CacheDefaultExpire 1
+# NoCache a-domain.com another-domain.edu joes.garage-sale.com
+
+#</IfModule>
+# End of proxy directives.
+
+
+<IfModule mod_php4.c>
+ # If php is turned on, we repsect .php and .phps files.
+ AddType application/x-httpd-php .php
+ AddType application/x-httpd-php-source .phps
+
+ # Since most users will want index.php to work we
+ # also automatically enable index.php
+ <IfModule mod_dir.c>
+ DirectoryIndex index.html index.php
+ </IfModule>
+</IfModule>
+
+<IfModule mod_rewrite.c>
+ RewriteEngine On
+ RewriteCond %{REQUEST_METHOD} ^TRACE
+ RewriteRule .* - [F]
+</IfModule>
diff --git a/tools/python/google/httpd_config/httpd2.conf b/tools/python/google/httpd_config/httpd2.conf
new file mode 100644
index 0000000..8c96f75
--- /dev/null
+++ b/tools/python/google/httpd_config/httpd2.conf
@@ -0,0 +1,280 @@
+## httpd2.conf -- Apache 2.x HTTP server configuration file
+
+#
+# Listen: Allows you to bind Apache to specific IP addresses and/or
+# ports, instead of the default. See also the <VirtualHost>
+# directive.
+#
+Listen 127.0.0.1:8000
+Listen 127.0.0.1:8080
+Listen 127.0.0.1:8081
+Listen 127.0.0.1:8443
+Listen 127.0.0.1:9000
+Listen 127.0.0.1:9080
+Listen 127.0.0.1:9443
+
+#
+# Dynamic Shared Object (DSO) Support
+#
+# To be able to use the functionality of a module which was built as a DSO you
+# have to place corresponding `LoadModule' lines at this location so the
+# directives contained in it are actually available _before_ they are used.
+# Please read the file http://httpd.apache.org/docs/dso.html for more
+# details about the DSO mechanism and run `httpd -l' for the list of already
+# built-in (statically linked and thus always available) modules in your httpd
+# binary.
+#
+# Note: The order in which modules are loaded is important. Don't change
+# the order below without expert advice.
+#
+#LoadModule authn_file_module lib/apache2/mod_authn_file.so
+#LoadModule authn_dbm_module lib/apache2/mod_authn_dbm.so
+#LoadModule authn_anon_module lib/apache2/mod_authn_anon.so
+#LoadModule authn_dbd_module lib/apache2/mod_authn_dbd.so
+#LoadModule authn_default_module lib/apache2/mod_authn_default.so
+LoadModule authz_host_module lib/apache2/mod_authz_host.so
+#LoadModule authz_groupfile_module lib/apache2/mod_authz_groupfile.so
+#LoadModule authz_user_module lib/apache2/mod_authz_user.so
+#LoadModule authz_dbm_module lib/apache2/mod_authz_dbm.so
+#LoadModule authz_owner_module lib/apache2/mod_authz_owner.so
+#LoadModule authz_default_module lib/apache2/mod_authz_default.so
+#LoadModule auth_basic_module lib/apache2/mod_auth_basic.so
+#LoadModule auth_digest_module lib/apache2/mod_auth_digest.so
+#LoadModule dbd_module lib/apache2/mod_dbd.so
+#LoadModule dumpio_module lib/apache2/mod_dumpio.so
+#LoadModule ext_filter_module lib/apache2/mod_ext_filter.so
+LoadModule include_module lib/apache2/mod_include.so
+#LoadModule filter_module lib/apache2/mod_filter.so
+#LoadModule deflate_module lib/apache2/mod_deflate.so
+LoadModule log_config_module lib/apache2/mod_log_config.so
+#LoadModule log_forensic_module lib/apache2/mod_log_forensic.so
+#LoadModule logio_module lib/apache2/mod_logio.so
+#LoadModule env_module lib/apache2/mod_env.so
+#LoadModule mime_magic_module lib/apache2/mod_mime_magic.so
+#LoadModule cern_meta_module lib/apache2/mod_cern_meta.so
+#LoadModule expires_module lib/apache2/mod_expires.so
+LoadModule headers_module lib/apache2/mod_headers.so
+#LoadModule ident_module lib/apache2/mod_ident.so
+#LoadModule usertrack_module lib/apache2/mod_usertrack.so
+#LoadModule unique_id_module lib/apache2/mod_unique_id.so
+#LoadModule setenvif_module lib/apache2/mod_setenvif.so
+#LoadModule version_module lib/apache2/mod_version.so
+#LoadModule proxy_module lib/apache2/mod_proxy.so
+#LoadModule proxy_connect_module lib/apache2/mod_proxy_connect.so
+#LoadModule proxy_ftp_module lib/apache2/mod_proxy_ftp.so
+#LoadModule proxy_http_module lib/apache2/mod_proxy_http.so
+#LoadModule proxy_ajp_module lib/apache2/mod_proxy_ajp.so
+#LoadModule proxy_balancer_module lib/apache2/mod_proxy_balancer.so
+LoadModule ssl_module lib/apache2/mod_ssl.so
+LoadModule mime_module lib/apache2/mod_mime.so
+#LoadModule dav_module lib/apache2/mod_dav.so
+#LoadModule status_module lib/apache2/mod_status.so
+LoadModule autoindex_module lib/apache2/mod_autoindex.so
+LoadModule asis_module lib/apache2/mod_asis.so
+#LoadModule info_module lib/apache2/mod_info.so
+LoadModule cgi_module lib/apache2/mod_cgi.so
+#LoadModule dav_fs_module lib/apache2/mod_dav_fs.so
+#LoadModule vhost_alias_module lib/apache2/mod_vhost_alias.so
+LoadModule negotiation_module lib/apache2/mod_negotiation.so
+#LoadModule dir_module lib/apache2/mod_dir.so
+LoadModule imagemap_module lib/apache2/mod_imagemap.so
+LoadModule actions_module lib/apache2/mod_actions.so
+#LoadModule speling_module lib/apache2/mod_speling.so
+#LoadModule userdir_module lib/apache2/mod_userdir.so
+LoadModule alias_module lib/apache2/mod_alias.so
+LoadModule rewrite_module lib/apache2/mod_rewrite.so
+LoadModule php5_module lib/apache2/cygphp5.so
+
+#LoadModule imap_module lib/apache/mod_imap.dll
+#LoadModule access_module lib/apache/mod_access.dll
+#LoadModule auth_module lib/apache/mod_auth.dll
+
+
+#
+# Each directory to which Apache has access, can be configured with respect
+# to which services and features are allowed and/or disabled in that
+# directory (and its subdirectories).
+#
+<Directory />
+ Options Indexes FollowSymLinks MultiViews ExecCGI Includes
+ AllowOverride All
+ Order allow,deny
+ Allow from all
+</Directory>
+
+
+#
+# Apple specific filesystem protection.
+#
+<Files "rsrc">
+ Order allow,deny
+ Deny from all
+ Satisfy All
+</Files>
+<Directory ~ ".*\.\.namedfork">
+ Order allow,deny
+ Deny from all
+ Satisfy All
+</Directory>
+
+
+#
+# UseCanonicalName: (new for 1.3) With this setting turned on, whenever
+# Apache needs to construct a self-referencing URL (a URL that refers back
+# to the server the response is coming from) it will use ServerName and
+# Port to form a "canonical" name. With this setting off, Apache will
+# use the hostname:port that the client supplied, when possible. This
+# also affects SERVER_NAME and SERVER_PORT in CGI scripts.
+#
+UseCanonicalName On
+
+
+#
+# The following directives define some format nicknames for use with
+# a CustomLog directive (see below).
+#
+LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+LogFormat "%h %l %u %t \"%r\" %>s %b" common
+LogFormat "%{Referer}i -> %U" referer
+LogFormat "%{User-agent}i" agent
+
+
+#
+# Optionally add a line containing the server version and virtual host
+# name to server-generated pages (error documents, FTP directory listings,
+# mod_status and mod_info output etc., but not CGI generated documents).
+# Set to "EMail" to also include a mailto: link to the ServerAdmin.
+# Set to one of: On | Off | EMail
+#
+ServerSignature On
+
+
+#
+# Document types.
+#
+<IfModule mime_module>
+
+ #
+ # AddLanguage allows you to specify the language of a document. You can
+ # then use content negotiation to give a browser a file in a language
+ # it can understand.
+ #
+ # Note 1: The suffix does not have to be the same as the language
+ # keyword --- those with documents in Polish (whose net-standard
+ # language code is pl) may wish to use "AddLanguage pl .po" to
+ # avoid the ambiguity with the common suffix for perl scripts.
+ #
+ # Note 2: The example entries below illustrate that in quite
+ # some cases the two character 'Language' abbreviation is not
+ # identical to the two character 'Country' code for its country,
+ # E.g. 'Danmark/dk' versus 'Danish/da'.
+ #
+ # Note 3: In the case of 'ltz' we violate the RFC by using a three char
+ # specifier. But there is 'work in progress' to fix this and get
+ # the reference data for rfc1766 cleaned up.
+ #
+ # Danish (da) - Dutch (nl) - English (en) - Estonian (ee)
+ # French (fr) - German (de) - Greek-Modern (el)
+ # Italian (it) - Korean (kr) - Norwegian (no) - Norwegian Nynorsk (nn)
+ # Portugese (pt) - Luxembourgeois* (ltz)
+ # Spanish (es) - Swedish (sv) - Catalan (ca) - Czech(cs)
+ # Polish (pl) - Brazilian Portuguese (pt-br) - Japanese (ja)
+ # Russian (ru)
+ #
+ AddLanguage da .dk
+ AddLanguage nl .nl
+ AddLanguage en .en
+ AddLanguage et .ee
+ AddLanguage fr .fr
+ AddLanguage de .de
+ AddLanguage el .el
+ AddLanguage he .he
+ AddCharset ISO-8859-8 .iso8859-8
+ AddLanguage it .it
+ AddLanguage ja .ja
+ AddCharset ISO-2022-JP .jis
+ AddLanguage kr .kr
+ AddCharset ISO-2022-KR .iso-kr
+ AddLanguage nn .nn
+ AddLanguage no .no
+ AddLanguage pl .po
+ AddCharset ISO-8859-2 .iso-pl
+ AddLanguage pt .pt
+ AddLanguage pt-br .pt-br
+ AddLanguage ltz .lu
+ AddLanguage ca .ca
+ AddLanguage es .es
+ AddLanguage sv .sv
+ AddLanguage cs .cz .cs
+ AddLanguage ru .ru
+ AddLanguage zh-TW .zh-tw
+ AddCharset Big5 .Big5 .big5
+ AddCharset WINDOWS-1251 .cp-1251
+ AddCharset CP866 .cp866
+ AddCharset ISO-8859-5 .iso-ru
+ AddCharset KOI8-R .koi8-r
+ AddCharset UCS-2 .ucs2
+ AddCharset UCS-4 .ucs4
+ AddCharset UTF-8 .utf8
+
+ # LanguagePriority allows you to give precedence to some languages
+ # in case of a tie during content negotiation.
+ #
+ # Just list the languages in decreasing order of preference. We have
+ # more or less alphabetized them here. You probably want to change this.
+ #
+ <IfModule negotiation_module>
+ LanguagePriority en da nl et fr de el it ja kr no pl pt pt-br ru ltz ca es sv tw
+ </IfModule>
+
+ #
+ # AddType allows you to tweak mime.types without actually editing it, or to
+ # make certain files to be certain types.
+ #
+ AddType application/x-tar .tgz
+
+ #
+ # AddEncoding allows you to have certain browsers uncompress
+ # information on the fly. Note: Not all browsers support this.
+ # Despite the name similarity, the following Add* directives have nothing
+ # to do with the FancyIndexing customization directives above.
+ #
+ AddEncoding x-compress .Z
+ AddEncoding x-gzip .gz .tgz
+
+ #
+ # AddHandler allows you to map certain file extensions to "handlers",
+ # actions unrelated to filetype. These can be either built into the server
+ # or added with the Action command (see below)
+ #
+ # If you want to use server side includes, or CGI outside
+ # ScriptAliased directories, uncomment the following lines.
+ #
+ # To use CGI scripts:
+ #
+ AddHandler cgi-script .cgi .pl
+
+ #
+ # To use server-parsed HTML files
+ #
+ AddType text/html .shtml
+ AddHandler server-parsed .shtml
+
+ #
+ # Uncomment the following line to enable Apache's send-asis HTTP file
+ # feature
+ #
+ AddHandler send-as-is asis
+</IfModule>
+
+
+<IfModule php5_module>
+ AddType application/x-httpd-php .php
+ AddType application/x-httpd-php-source .phps
+</IfModule>
+
+<IfModule rewrite_module>
+ RewriteEngine On
+ RewriteCond %{REQUEST_METHOD} ^TRACE
+ RewriteRule .* - [F]
+</IfModule>
diff --git a/tools/python/google/httpd_config/httpd2.pem b/tools/python/google/httpd_config/httpd2.pem
new file mode 100644
index 0000000..1ad5794
--- /dev/null
+++ b/tools/python/google/httpd_config/httpd2.pem
@@ -0,0 +1,36 @@
+-----BEGIN CERTIFICATE-----
+MIIDazCCAtSgAwIBAgIBEDANBgkqhkiG9w0BAQUFADByMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIG
+A1UEChMLR29vZ2xlIEluYy4xIDAeBgNVBAMTF2F0dGljdXMuY29ycC5nb29nbGUu
+Y29tMB4XDTA2MDEwMTAwMDAwMFoXDTIwMDEwMTAwMDAwMFowTDELMAkGA1UEBhMC
+VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFDASBgNVBAoTC0dvb2dsZSBJbmMuMRIw
+EAYDVQQDEwkxMjcuMC4wLjEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAK0I
+45wdTT2/fui9FfNOR17idQF0L/kpn88D1OzF0w0h3TMBN8szpOxAQYT2MTuB17Dt
+ttMiwzLuoByP7KipmeKy63GFlV7dHS2XEirzP23c/RxZ/7W9UQ/VmgSvXjNzIXyu
+t+Ylfeg6VfFANsPQmov3SIO1Zh3NQRS/d+M5ig7lAgMBAAGjggE1MIIBMTAJBgNV
+HRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZp
+Y2F0ZTAdBgNVHQ4EFgQU6n4XBAZRnkrXMlko23vCClLlztEwgY4GA1UdIwSBhjCB
+g6F2pHQwcjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNV
+BAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC0dvb2dsZSBJbmMuMSAwHgYDVQQD
+ExdhdHRpY3VzLmNvcnAuZ29vZ2xlLmNvbYIJAKGvvYc2FdhzMEYGA1UdHwQ/MD0w
+O6A5oDeGNWh0dHA6Ly9jaHJvbWV0d3MuY29ycC5nb29nbGUuY29tOjgwODAvY3Js
+L2F0dGljdXMuY3JsMA0GCSqGSIb3DQEBBQUAA4GBAHt8Zxf4D86QBuWkP2STN4Pg
+aLzut1eaY0u5DOxr3fqrwbaDlPJrJJqQJmMPwUItVMjw+zWO/CmoBY7vsJMcX/57
++kIHoQ+XCQJdOnM7qa3Hslt4bLRx+d0zQqt6/+gBNrz5F36njgansvxjnnacbApv
+uNQFNT5wCAqRadGn4d63
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQCtCOOcHU09v37ovRXzTkde4nUBdC/5KZ/PA9TsxdMNId0zATfL
+M6TsQEGE9jE7gdew7bbTIsMy7qAcj+yoqZnisutxhZVe3R0tlxIq8z9t3P0cWf+1
+vVEP1ZoEr14zcyF8rrfmJX3oOlXxQDbD0JqL90iDtWYdzUEUv3fjOYoO5QIDAQAB
+AoGALSNMfMUICTuTF5N7zmR1KcNZUm/Es/KvxYjyWnGghKR4131R2Kg4NYjtjonK
+fgN5CKZ6Msm2seqdydWhnr3fbl3KhPF7nTdFUR6OM4eUuUH3nV1DS1w9AW0Z/4nB
+3OipLkxvTtRomfEUoZdE3I4+2T9iBdfPGduZ3CNR1H9EL2ECQQDfyT3dOVg5Zr7Q
+gZ8rQhyxtA+OhWvqU9F5Ahii002fIMj//rMIowvGesW2rfMwYs/oFF36l2vXOhvh
+whL+hmJ/AkEAxfFnlp8hT3WeRqJ74b3QSkyItWz7XbSQRPFWurPEfNI8wz57Svvy
+8tv396X8yImPwxXhihjSn9bwSHoon0WUmwJBAMt2S1HUblsaCEjIYS/SVwZWIILC
+2Z/d/yiW+FEp7nvMMhNVve8PVohpXVM/CkkmvcJSqjNI8ppnUaxLaDuTcP8CQQCn
+40L7K+ky3g3q1zG/nCEog5WIW/Ev31BmSVRIcuT7Ac5rw3kLdnrvpcbCE9U9uf9n
+dg2f9cHftIyEzKfbv0Z1AkAlX4x7De9edylrZ14IA9BbEe0ztsCik3UGXYriYfwY
+Z9h+uyhqNJT+SaWjb1QcBQ8jbYC0d2zxQSMuf8NxYrd2
+-----END RSA PRIVATE KEY-----
diff --git a/tools/python/google/httpd_config/mime.types b/tools/python/google/httpd_config/mime.types
new file mode 100644
index 0000000..6735f1b
--- /dev/null
+++ b/tools/python/google/httpd_config/mime.types
@@ -0,0 +1,599 @@
+# This is a comment. I love comments.
+
+# This file controls what Internet media types are sent to the client for
+# given file extension(s). Sending the correct media type to the client
+# is important so they know how to handle the content of the file.
+# Extra types can either be added here or by using an AddType directive
+# in your config files. For more information about Internet media types,
+# please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type
+# registry is at <http://www.iana.org/assignments/media-types/>.
+
+# MIME type Extensions
+application/activemessage
+application/andrew-inset ez
+application/applefile
+application/atom+xml atom
+application/atomicmail
+application/batch-smtp
+application/beep+xml
+application/cals-1840
+application/cnrp+xml
+application/commonground
+application/cpl+xml
+application/cybercash
+application/dca-rft
+application/dec-dx
+application/dvcs
+application/edi-consent
+application/edifact
+application/edi-x12
+application/eshop
+application/font-tdpfr
+application/http
+application/hyperstudio
+application/iges
+application/index
+application/index.cmd
+application/index.obj
+application/index.response
+application/index.vnd
+application/iotp
+application/ipp
+application/isup
+application/mac-binhex40 hqx
+application/mac-compactpro cpt
+application/macwriteii
+application/marc
+application/mathematica
+application/mathml+xml mathml
+application/msword doc
+application/news-message-id
+application/news-transmission
+application/ocsp-request
+application/ocsp-response
+application/octet-stream bin dms lha lzh exe class so dll dmg
+application/oda oda
+application/ogg ogg
+application/parityfec
+application/pdf pdf
+application/pgp-encrypted
+application/pgp-keys
+application/pgp-signature
+application/pkcs10
+application/pkcs7-mime
+application/pkcs7-signature
+application/pkix-cert
+application/pkix-crl
+application/pkixcmp
+application/postscript ai eps ps
+application/prs.alvestrand.titrax-sheet
+application/prs.cww
+application/prs.nprend
+application/prs.plucker
+application/qsig
+application/rdf+xml rdf
+application/reginfo+xml
+application/remote-printing
+application/riscos
+application/rtf
+application/sdp
+application/set-payment
+application/set-payment-initiation
+application/set-registration
+application/set-registration-initiation
+application/sgml
+application/sgml-open-catalog
+application/sieve
+application/slate
+application/smil smi smil
+application/srgs gram
+application/srgs+xml grxml
+application/timestamp-query
+application/timestamp-reply
+application/tve-trigger
+application/vemmi
+application/vnd.3gpp.pic-bw-large
+application/vnd.3gpp.pic-bw-small
+application/vnd.3gpp.pic-bw-var
+application/vnd.3gpp.sms
+application/vnd.3m.post-it-notes
+application/vnd.accpac.simply.aso
+application/vnd.accpac.simply.imp
+application/vnd.acucobol
+application/vnd.acucorp
+application/vnd.adobe.xfdf
+application/vnd.aether.imp
+application/vnd.amiga.ami
+application/vnd.anser-web-certificate-issue-initiation
+application/vnd.anser-web-funds-transfer-initiation
+application/vnd.audiograph
+application/vnd.blueice.multipass
+application/vnd.bmi
+application/vnd.businessobjects
+application/vnd.canon-cpdl
+application/vnd.canon-lips
+application/vnd.cinderella
+application/vnd.claymore
+application/vnd.commerce-battelle
+application/vnd.commonspace
+application/vnd.contact.cmsg
+application/vnd.cosmocaller
+application/vnd.criticaltools.wbs+xml
+application/vnd.ctc-posml
+application/vnd.cups-postscript
+application/vnd.cups-raster
+application/vnd.cups-raw
+application/vnd.curl
+application/vnd.cybank
+application/vnd.data-vision.rdz
+application/vnd.dna
+application/vnd.dpgraph
+application/vnd.dreamfactory
+application/vnd.dxr
+application/vnd.ecdis-update
+application/vnd.ecowin.chart
+application/vnd.ecowin.filerequest
+application/vnd.ecowin.fileupdate
+application/vnd.ecowin.series
+application/vnd.ecowin.seriesrequest
+application/vnd.ecowin.seriesupdate
+application/vnd.enliven
+application/vnd.epson.esf
+application/vnd.epson.msf
+application/vnd.epson.quickanime
+application/vnd.epson.salt
+application/vnd.epson.ssf
+application/vnd.ericsson.quickcall
+application/vnd.eudora.data
+application/vnd.fdf
+application/vnd.ffsns
+application/vnd.fints
+application/vnd.flographit
+application/vnd.framemaker
+application/vnd.fsc.weblaunch
+application/vnd.fujitsu.oasys
+application/vnd.fujitsu.oasys2
+application/vnd.fujitsu.oasys3
+application/vnd.fujitsu.oasysgp
+application/vnd.fujitsu.oasysprs
+application/vnd.fujixerox.ddd
+application/vnd.fujixerox.docuworks
+application/vnd.fujixerox.docuworks.binder
+application/vnd.fut-misnet
+application/vnd.grafeq
+application/vnd.groove-account
+application/vnd.groove-help
+application/vnd.groove-identity-message
+application/vnd.groove-injector
+application/vnd.groove-tool-message
+application/vnd.groove-tool-template
+application/vnd.groove-vcard
+application/vnd.hbci
+application/vnd.hhe.lesson-player
+application/vnd.hp-hpgl
+application/vnd.hp-hpid
+application/vnd.hp-hps
+application/vnd.hp-pcl
+application/vnd.hp-pclxl
+application/vnd.httphone
+application/vnd.hzn-3d-crossword
+application/vnd.ibm.afplinedata
+application/vnd.ibm.electronic-media
+application/vnd.ibm.minipay
+application/vnd.ibm.modcap
+application/vnd.ibm.rights-management
+application/vnd.ibm.secure-container
+application/vnd.informix-visionary
+application/vnd.intercon.formnet
+application/vnd.intertrust.digibox
+application/vnd.intertrust.nncp
+application/vnd.intu.qbo
+application/vnd.intu.qfx
+application/vnd.irepository.package+xml
+application/vnd.is-xpr
+application/vnd.japannet-directory-service
+application/vnd.japannet-jpnstore-wakeup
+application/vnd.japannet-payment-wakeup
+application/vnd.japannet-registration
+application/vnd.japannet-registration-wakeup
+application/vnd.japannet-setstore-wakeup
+application/vnd.japannet-verification
+application/vnd.japannet-verification-wakeup
+application/vnd.jisp
+application/vnd.kde.karbon
+application/vnd.kde.kchart
+application/vnd.kde.kformula
+application/vnd.kde.kivio
+application/vnd.kde.kontour
+application/vnd.kde.kpresenter
+application/vnd.kde.kspread
+application/vnd.kde.kword
+application/vnd.kenameaapp
+application/vnd.koan
+application/vnd.liberty-request+xml
+application/vnd.llamagraphics.life-balance.desktop
+application/vnd.llamagraphics.life-balance.exchange+xml
+application/vnd.lotus-1-2-3
+application/vnd.lotus-approach
+application/vnd.lotus-freelance
+application/vnd.lotus-notes
+application/vnd.lotus-organizer
+application/vnd.lotus-screencam
+application/vnd.lotus-wordpro
+application/vnd.mcd
+application/vnd.mediastation.cdkey
+application/vnd.meridian-slingshot
+application/vnd.micrografx.flo
+application/vnd.micrografx.igx
+application/vnd.mif mif
+application/vnd.minisoft-hp3000-save
+application/vnd.mitsubishi.misty-guard.trustweb
+application/vnd.mobius.daf
+application/vnd.mobius.dis
+application/vnd.mobius.mbk
+application/vnd.mobius.mqy
+application/vnd.mobius.msl
+application/vnd.mobius.plc
+application/vnd.mobius.txf
+application/vnd.mophun.application
+application/vnd.mophun.certificate
+application/vnd.motorola.flexsuite
+application/vnd.motorola.flexsuite.adsi
+application/vnd.motorola.flexsuite.fis
+application/vnd.motorola.flexsuite.gotap
+application/vnd.motorola.flexsuite.kmr
+application/vnd.motorola.flexsuite.ttc
+application/vnd.motorola.flexsuite.wem
+application/vnd.mozilla.xul+xml xul
+application/vnd.ms-artgalry
+application/vnd.ms-asf
+application/vnd.ms-excel xls
+application/vnd.ms-lrm
+application/vnd.ms-powerpoint ppt
+application/vnd.ms-project
+application/vnd.ms-tnef
+application/vnd.ms-works
+application/vnd.ms-wpl
+application/vnd.mseq
+application/vnd.msign
+application/vnd.music-niff
+application/vnd.musician
+application/vnd.netfpx
+application/vnd.noblenet-directory
+application/vnd.noblenet-sealer
+application/vnd.noblenet-web
+application/vnd.novadigm.edm
+application/vnd.novadigm.edx
+application/vnd.novadigm.ext
+application/vnd.obn
+application/vnd.osa.netdeploy
+application/vnd.palm
+application/vnd.pg.format
+application/vnd.pg.osasli
+application/vnd.powerbuilder6
+application/vnd.powerbuilder6-s
+application/vnd.powerbuilder7
+application/vnd.powerbuilder7-s
+application/vnd.powerbuilder75
+application/vnd.powerbuilder75-s
+application/vnd.previewsystems.box
+application/vnd.publishare-delta-tree
+application/vnd.pvi.ptid1
+application/vnd.pwg-multiplexed
+application/vnd.pwg-xhtml-print+xml
+application/vnd.quark.quarkxpress
+application/vnd.rapid
+application/vnd.rn-realmedia rm
+application/vnd.s3sms
+application/vnd.sealed.net
+application/vnd.seemail
+application/vnd.shana.informed.formdata
+application/vnd.shana.informed.formtemplate
+application/vnd.shana.informed.interchange
+application/vnd.shana.informed.package
+application/vnd.smaf
+application/vnd.sss-cod
+application/vnd.sss-dtf
+application/vnd.sss-ntf
+application/vnd.street-stream
+application/vnd.svd
+application/vnd.swiftview-ics
+application/vnd.triscape.mxs
+application/vnd.trueapp
+application/vnd.truedoc
+application/vnd.ufdl
+application/vnd.uplanet.alert
+application/vnd.uplanet.alert-wbxml
+application/vnd.uplanet.bearer-choice
+application/vnd.uplanet.bearer-choice-wbxml
+application/vnd.uplanet.cacheop
+application/vnd.uplanet.cacheop-wbxml
+application/vnd.uplanet.channel
+application/vnd.uplanet.channel-wbxml
+application/vnd.uplanet.list
+application/vnd.uplanet.list-wbxml
+application/vnd.uplanet.listcmd
+application/vnd.uplanet.listcmd-wbxml
+application/vnd.uplanet.signal
+application/vnd.vcx
+application/vnd.vectorworks
+application/vnd.vidsoft.vidconference
+application/vnd.visio
+application/vnd.visionary
+application/vnd.vividence.scriptfile
+application/vnd.vsf
+application/vnd.wap.sic
+application/vnd.wap.slc
+application/vnd.wap.wbxml wbxml
+application/vnd.wap.wmlc wmlc
+application/vnd.wap.wmlscriptc wmlsc
+application/vnd.webturbo
+application/vnd.wrq-hp3000-labelled
+application/vnd.wt.stf
+application/vnd.wv.csp+wbxml
+application/vnd.xara
+application/vnd.xfdl
+application/vnd.yamaha.hv-dic
+application/vnd.yamaha.hv-script
+application/vnd.yamaha.hv-voice
+application/vnd.yellowriver-custom-menu
+application/voicexml+xml vxml
+application/watcherinfo+xml
+application/whoispp-query
+application/whoispp-response
+application/wita
+application/wordperfect5.1
+application/x-bcpio bcpio
+application/x-cdlink vcd
+application/x-chess-pgn pgn
+application/x-compress
+application/x-cpio cpio
+application/x-csh csh
+application/x-director dcr dir dxr
+application/x-dvi dvi
+application/x-futuresplash spl
+application/x-gtar gtar
+application/x-gzip
+application/x-hdf hdf
+application/x-javascript js
+application/x-java-jnlp-file jnlp
+application/x-koan skp skd skt skm
+application/x-latex latex
+application/x-netcdf nc cdf
+application/x-sh sh
+application/x-shar shar
+application/x-shockwave-flash swf
+application/x-stuffit sit
+application/x-sv4cpio sv4cpio
+application/x-sv4crc sv4crc
+application/x-tar tar
+application/x-tcl tcl
+application/x-tex tex
+application/x-texinfo texinfo texi
+application/x-troff t tr roff
+application/x-troff-man man
+application/x-troff-me me
+application/x-troff-ms ms
+application/x-ustar ustar
+application/x-wais-source src
+application/x400-bp
+application/xhtml+xml xhtml xht
+application/xslt+xml xslt
+application/xml xml xsl
+application/xml-dtd dtd
+application/xml-external-parsed-entity
+application/zip zip
+audio/32kadpcm
+audio/amr
+audio/amr-wb
+audio/basic au snd
+audio/cn
+audio/dat12
+audio/dsr-es201108
+audio/dvi4
+audio/evrc
+audio/evrc0
+audio/g722
+audio/g.722.1
+audio/g723
+audio/g726-16
+audio/g726-24
+audio/g726-32
+audio/g726-40
+audio/g728
+audio/g729
+audio/g729D
+audio/g729E
+audio/gsm
+audio/gsm-efr
+audio/l8
+audio/l16
+audio/l20
+audio/l24
+audio/lpc
+audio/midi mid midi kar
+audio/mpa
+audio/mpa-robust
+audio/mp4a-latm m4a m4p
+audio/mpeg mpga mp2 mp3
+audio/parityfec
+audio/pcma
+audio/pcmu
+audio/prs.sid
+audio/qcelp
+audio/red
+audio/smv
+audio/smv0
+audio/telephone-event
+audio/tone
+audio/vdvi
+audio/vnd.3gpp.iufp
+audio/vnd.cisco.nse
+audio/vnd.cns.anp1
+audio/vnd.cns.inf1
+audio/vnd.digital-winds
+audio/vnd.everad.plj
+audio/vnd.lucent.voice
+audio/vnd.nortel.vbk
+audio/vnd.nuera.ecelp4800
+audio/vnd.nuera.ecelp7470
+audio/vnd.nuera.ecelp9600
+audio/vnd.octel.sbc
+audio/vnd.qcelp
+audio/vnd.rhetorex.32kadpcm
+audio/vnd.vmx.cvsd
+audio/x-aiff aif aiff aifc
+audio/x-alaw-basic
+audio/x-mpegurl m3u
+audio/x-pn-realaudio ram ra
+audio/x-pn-realaudio-plugin
+audio/x-wav wav
+chemical/x-pdb pdb
+chemical/x-xyz xyz
+image/bmp bmp
+image/cgm cgm
+image/g3fax
+image/gif gif
+image/ief ief
+image/jpeg jpeg jpg jpe
+image/jp2 jp2
+image/naplps
+image/pict pict pic pct
+image/png png
+image/prs.btif
+image/prs.pti
+image/svg+xml svg
+image/t38
+image/tiff tiff tif
+image/tiff-fx
+image/vnd.cns.inf2
+image/vnd.djvu djvu djv
+image/vnd.dwg
+image/vnd.dxf
+image/vnd.fastbidsheet
+image/vnd.fpx
+image/vnd.fst
+image/vnd.fujixerox.edmics-mmr
+image/vnd.fujixerox.edmics-rlc
+image/vnd.globalgraphics.pgb
+image/vnd.mix
+image/vnd.ms-modi
+image/vnd.net-fpx
+image/vnd.svf
+image/vnd.wap.wbmp wbmp
+image/vnd.xiff
+image/x-cmu-raster ras
+image/x-macpaint pntg pnt mac
+image/x-icon ico
+image/x-portable-anymap pnm
+image/x-portable-bitmap pbm
+image/x-portable-graymap pgm
+image/x-portable-pixmap ppm
+image/x-quicktime qtif qti
+image/x-rgb rgb
+image/x-xbitmap xbm
+image/x-xpixmap xpm
+image/x-xwindowdump xwd
+message/delivery-status
+message/disposition-notification
+message/external-body
+message/http
+message/news
+message/partial
+message/rfc822
+message/s-http
+message/sip
+message/sipfrag
+model/iges igs iges
+model/mesh msh mesh silo
+model/vnd.dwf
+model/vnd.flatland.3dml
+model/vnd.gdl
+model/vnd.gs-gdl
+model/vnd.gtw
+model/vnd.mts
+model/vnd.parasolid.transmit.binary
+model/vnd.parasolid.transmit.text
+model/vnd.vtu
+model/vrml wrl vrml
+multipart/alternative
+multipart/appledouble
+multipart/byteranges
+multipart/digest
+multipart/encrypted
+multipart/form-data
+multipart/header-set
+multipart/mixed
+multipart/parallel
+multipart/related
+multipart/report
+multipart/signed
+multipart/voice-message
+text/calendar ics ifb
+text/css css
+text/directory
+text/enriched
+text/html html htm
+text/parityfec
+text/plain asc txt
+text/prs.lines.tag
+text/rfc822-headers
+text/richtext rtx
+text/rtf rtf
+text/sgml sgml sgm
+text/t140
+text/tab-separated-values tsv
+text/uri-list
+text/vnd.abc
+text/vnd.curl
+text/vnd.dmclientscript
+text/vnd.fly
+text/vnd.fmi.flexstor
+text/vnd.in3d.3dml
+text/vnd.in3d.spot
+text/vnd.iptc.nitf
+text/vnd.iptc.newsml
+text/vnd.latex-z
+text/vnd.motorola.reflex
+text/vnd.ms-mediapackage
+text/vnd.net2phone.commcenter.command
+text/vnd.sun.j2me.app-descriptor
+text/vnd.wap.si
+text/vnd.wap.sl
+text/vnd.wap.wml wml
+text/vnd.wap.wmlscript wmls
+text/x-setext etx
+text/xml
+text/xml-external-parsed-entity
+video/bmpeg
+video/bt656
+video/celb
+video/dv
+video/h261
+video/h263
+video/h263-1998
+video/h263-2000
+video/jpeg
+video/mp1s
+video/mp2p
+video/mp2t
+video/mp4 mp4
+video/mp4v-es
+video/mpv
+video/mpeg mpeg mpg mpe
+video/nv
+video/parityfec
+video/pointer
+video/quicktime qt mov
+video/smpte292m
+video/vnd.fvt
+video/vnd.motorola.video
+video/vnd.motorola.videop
+video/vnd.mpegurl mxu m4u
+video/vnd.nokia.interleaved-multimedia
+video/vnd.objectvideo
+video/vnd.vivo
+video/x-dv dv dif
+video/x-msvideo avi
+video/x-sgi-movie movie
+x-conference/x-cooltalk ice
diff --git a/tools/python/google/httpd_utils.py b/tools/python/google/httpd_utils.py
new file mode 100644
index 0000000..7f76ca6
--- /dev/null
+++ b/tools/python/google/httpd_utils.py
@@ -0,0 +1,219 @@
+#!/bin/env python
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""A class to help start/stop a local apache http server."""
+
+import logging
+import optparse
+import os
+import subprocess
+import sys
+import time
+import urllib
+
+import google.path_utils
+import google.platform_utils
+
+class HttpdNotStarted(Exception): pass
+
+def ApacheConfigDir(start_dir):
+ """Returns a path to the directory holding the Apache config files."""
+ return google.path_utils.FindUpward(start_dir, 'tools', 'python',
+ 'google', 'httpd_config')
+
+
+def GetCygserverPath(start_dir, apache2=False):
+ """Returns the path to the directory holding cygserver.exe file."""
+ cygserver_path = None
+ if apache2:
+ cygserver_path = google.path_utils.FindUpward(start_dir, 'third_party',
+ 'cygwin', 'usr', 'sbin')
+ return cygserver_path
+
+
+def StartServer(document_root=None, output_dir=None, apache2=False):
+ """Starts a local server on port 8000 using the basic configuration files.
+
+ Args:
+ document_root: If present, specifies the document root for the server;
+ otherwise, the filesystem's root (e.g., C:/ or /) will be used.
+ output_dir: If present, specifies where to put server logs; otherwise,
+ they'll be placed in the system's temp dir (e.g., $TEMP or /tmp).
+ apache2: boolean if true will cause this function to configure
+ for Apache 2.x as opposed to Apache 1.3.x
+
+ Returns: the ApacheHttpd object that was created
+ """
+ script_dir = google.path_utils.ScriptDir()
+ platform_util = google.platform_utils.PlatformUtility(script_dir)
+ if not output_dir:
+ output_dir = platform_util.GetTempDirectory()
+ if not document_root:
+ document_root = platform_util.GetFilesystemRoot()
+ apache_config_dir = ApacheConfigDir(script_dir)
+ if apache2:
+ httpd_conf_path = os.path.join(apache_config_dir, 'httpd2.conf')
+ else:
+ httpd_conf_path = os.path.join(apache_config_dir, 'httpd.conf')
+ mime_types_path = os.path.join(apache_config_dir, 'mime.types')
+ start_cmd = platform_util.GetStartHttpdCommand(output_dir,
+ httpd_conf_path,
+ mime_types_path,
+ document_root,
+ apache2=apache2)
+ stop_cmd = platform_util.GetStopHttpdCommand()
+ httpd = ApacheHttpd(start_cmd, stop_cmd, [8000],
+ cygserver_path=GetCygserverPath(script_dir, apache2))
+ httpd.StartServer()
+ return httpd
+
+
+def StopServers(apache2=False):
+ """Calls the platform's stop command on a newly created server, forcing it
+ to stop.
+
+ The details depend on the behavior of the platform stop command. For example,
+ it's often implemented to kill all running httpd processes, as implied by
+ the name of this function.
+
+ Args:
+ apache2: boolean if true will cause this function to configure
+ for Apache 2.x as opposed to Apache 1.3.x
+ """
+ script_dir = google.path_utils.ScriptDir()
+ platform_util = google.platform_utils.PlatformUtility(script_dir)
+ httpd = ApacheHttpd('', platform_util.GetStopHttpdCommand(), [],
+ cygserver_path=GetCygserverPath(script_dir, apache2))
+ httpd.StopServer(force=True)
+
+
+class ApacheHttpd(object):
+ def __init__(self, start_command, stop_command, port_list,
+ cygserver_path=None):
+ """Args:
+ start_command: command list to call to start the httpd
+ stop_command: command list to call to stop the httpd if one has been
+ started. May kill all httpd processes running on the machine.
+ port_list: list of ports expected to respond on the local machine when
+ the server has been successfully started.
+ cygserver_path: Path to cygserver.exe. If specified, exe will be started
+ with server as well as stopped when server is stopped.
+ """
+ self._http_server_proc = None
+ self._start_command = start_command
+ self._stop_command = stop_command
+ self._port_list = port_list
+ self._cygserver_path = cygserver_path
+
+ def StartServer(self):
+ if self._http_server_proc:
+ return
+ if self._cygserver_path:
+ cygserver_exe = os.path.join(self._cygserver_path, "cygserver.exe")
+ cygbin = google.path_utils.FindUpward(cygserver_exe, 'third_party',
+ 'cygwin', 'bin')
+ env = os.environ
+ env['PATH'] += ";" + cygbin
+ subprocess.Popen(cygserver_exe, env=env)
+ logging.info('Starting http server')
+ self._http_server_proc = subprocess.Popen(self._start_command)
+
+ # Ensure that the server is running on all the desired ports.
+ for port in self._port_list:
+ if not self._UrlIsAlive('http://127.0.0.1:%s/' % str(port)):
+ raise HttpdNotStarted('Failed to start httpd on port %s' % str(port))
+
+ def _UrlIsAlive(self, url):
+ """Checks to see if we get an http response from |url|.
+ We poll the url 5 times with a 1 second delay. If we don't
+ get a reply in that time, we give up and assume the httpd
+ didn't start properly.
+
+ Args:
+ url: The URL to check.
+ Return:
+ True if the url is alive.
+ """
+ wait_time = 5
+ while wait_time > 0:
+ try:
+ response = urllib.urlopen(url)
+ # Server is up and responding.
+ return True
+ except IOError:
+ pass
+ wait_time -= 1
+ # Wait a second and try again.
+ time.sleep(1)
+
+ return False
+
+ def StopServer(self, force=False):
+ """If we started an httpd.exe process, or if force is True, call
+ self._stop_command (passed in on init so it can be platform-dependent).
+ This will presumably kill it, and may also kill any other httpd.exe
+ processes that are running.
+ """
+ if force or self._http_server_proc:
+ logging.info('Stopping http server')
+ kill_proc = subprocess.Popen(self._stop_command,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ logging.info('%s\n%s' % (kill_proc.stdout.read(),
+ kill_proc.stderr.read()))
+ self._http_server_proc = None
+ if self._cygserver_path:
+ subprocess.Popen(["taskkill.exe", "/f", "/im", "cygserver.exe"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+
+if '__main__' == __name__:
+ # Provide some command line params for starting/stopping the http server
+ # manually.
+ option_parser = optparse.OptionParser()
+ option_parser.add_option('-k', '--server', help='Server action (start|stop)')
+ option_parser.add_option('-r', '--root', help='Document root (optional)')
+ option_parser.add_option('-a', '--apache2', action='store_true',
+ default=False, help='Starts Apache 2 instead of Apache 1.3 (default).')
+ options, args = option_parser.parse_args()
+
+ if not options.server:
+ print ("Usage: %s -k {start|stop} [-r document_root] [--apache2]" %
+ sys.argv[0])
+ sys.exit(0)
+
+ document_root = None
+ if options.root:
+ document_root = options.root
+
+ if 'start' == options.server:
+ StartServer(document_root, apache2=options.apache2)
+ else:
+ StopServers(apache2=options.apache2)
diff --git a/tools/python/google/logging_utils.py b/tools/python/google/logging_utils.py
new file mode 100644
index 0000000..cf9f3fa
--- /dev/null
+++ b/tools/python/google/logging_utils.py
@@ -0,0 +1,110 @@
+#!/bin/env python
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# logging_utils.py
+
+''' Utility functions and objects for logging.
+'''
+
+import logging
+import sys
+
+class StdoutStderrHandler(logging.Handler):
+ ''' Subclass of logging.Handler which outputs to either stdout or stderr
+ based on a threshold level.
+ '''
+
+ def __init__(self, threshold=logging.WARNING, err=sys.stderr, out=sys.stdout):
+ ''' Args:
+ threshold: below this logging level messages are sent to stdout,
+ otherwise they are sent to stderr
+ err: a stream object that error messages are sent to, defaults to
+ sys.stderr
+ out: a stream object that non-error messages are sent to, defaults to
+ sys.stdout
+ '''
+ logging.Handler.__init__(self)
+ self._err = logging.StreamHandler(err)
+ self._out = logging.StreamHandler(out)
+ self._threshold = threshold
+ self._last_was_err = False
+
+ def setLevel(self, lvl):
+ logging.Handler.setLevel(self, lvl)
+ self._err.setLevel(lvl)
+ self._out.setLevel(lvl)
+
+ def setFormatter(self, formatter):
+ logging.Handler.setFormatter(self, formatter)
+ self._err.setFormatter(formatter)
+ self._out.setFormatter(formatter)
+
+ def emit(self, record):
+ if record.levelno < self._threshold:
+ self._out.emit(record)
+ self._last_was_err = False
+ else:
+ self._err.emit(record)
+ self._last_was_err = False
+
+ def flush(self):
+ # preserve order on the flushing, the stalest stream gets flushed first
+ if self._last_was_err:
+ self._out.flush()
+ self._err.flush()
+ else:
+ self._err.flush()
+ self._out.flush()
+
+
+FORMAT = "%(asctime)s %(filename)s [%(levelname)s] %(message)s"
+DATEFMT = "%H:%M:%S"
+
+def config_root(level=logging.INFO, threshold=logging.WARNING, format=FORMAT,
+ datefmt=DATEFMT):
+ ''' Configure the root logger to use a StdoutStderrHandler and some default
+ formatting.
+ Args:
+ level: messages below this level are ignored
+ threshold: below this logging level messages are sent to stdout,
+ otherwise they are sent to stderr
+ format: format for log messages, see logger.Format
+ datefmt: format for date in log messages
+
+ '''
+ # to set the handler of the root logging object, we need to do setup
+ # manually rather than using basicConfig
+ root = logging.getLogger()
+ root.setLevel(level)
+ formatter = logging.Formatter(format, datefmt)
+ handler = StdoutStderrHandler(threshold=threshold)
+ handler.setLevel(level)
+ handler.setFormatter(formatter)
+ root.addHandler(handler)
diff --git a/tools/python/google/path_utils.py b/tools/python/google/path_utils.py
new file mode 100644
index 0000000..0585614
--- /dev/null
+++ b/tools/python/google/path_utils.py
@@ -0,0 +1,109 @@
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Some utility methods for getting and manipulating paths."""
+
+# TODO(pamg): Have the buildbot use these, too.
+
+
+import errno
+import os
+import sys
+
+class PathNotFound(Exception): pass
+
+def ScriptDir():
+ """Get the full path to the directory containing the current script."""
+ script_filename = os.path.abspath(sys.argv[0])
+ return os.path.dirname(script_filename)
+
+def FindAncestor(start_dir, ancestor):
+ """Finds an ancestor dir in a path.
+
+ For example, FindAncestor('c:\foo\bar\baz', 'bar') would return
+ 'c:\foo\bar'. Unlike FindUpward*, this only looks at direct path ancestors.
+ """
+ start_dir = os.path.abspath(start_dir)
+ path = start_dir
+ while True:
+ (parent, tail) = os.path.split(path)
+ if tail == ancestor:
+ return path
+ if not tail:
+ break
+ path = parent
+ raise PathNotFound("Unable to find ancestor %s in %s" % (ancestor, start_dir))
+
+def FindUpwardParent(start_dir, *desired_list):
+ """Finds the desired object's parent, searching upward from the start_dir.
+
+ Searches start_dir and all its parents looking for the desired directory
+ or file, which may be given in one or more path components. Returns the
+ first directory in which the top desired path component was found, or raises
+ PathNotFound if it wasn't.
+ """
+ desired_path = os.path.join(*desired_list)
+ last_dir = ''
+ cur_dir = start_dir
+ found_path = os.path.join(cur_dir, desired_path)
+ while not os.path.exists(found_path):
+ last_dir = cur_dir
+ cur_dir = os.path.dirname(cur_dir)
+ if last_dir == cur_dir:
+ raise PathNotFound('Unable to find %s above %s' %
+ (desired_path, start_dir))
+ found_path = os.path.join(cur_dir, desired_path)
+ # Strip the entire original desired path from the end of the one found
+ # and remove a trailing path separator, if present.
+ found_path = found_path[:len(found_path) - len(desired_path)]
+ if found_path.endswith(os.sep):
+ found_path = found_path[:len(found_path) - 1]
+ return found_path
+
+
+def FindUpward(start_dir, *desired_list):
+ """Returns a path to the desired directory or file, searching upward.
+
+ Searches start_dir and all its parents looking for the desired directory
+ or file, which may be given in one or more path components. Returns the full
+ path to the desired object, or raises PathNotFound if it wasn't found.
+ """
+ parent = FindUpwardParent(start_dir, *desired_list)
+ return os.path.join(parent, *desired_list)
+
+
+def MaybeMakeDirectory(*path):
+ """Creates an entire path, if it doesn't already exist."""
+ file_path = os.path.join(*path)
+ try:
+ os.makedirs(file_path)
+ except OSError, e:
+ # errno.EEXIST is "File exists". If we see another error, re-raise.
+ if e.errno != errno.EEXIST:
+ raise
diff --git a/tools/python/google/platform_utils.py b/tools/python/google/platform_utils.py
new file mode 100644
index 0000000..1fcb182
--- /dev/null
+++ b/tools/python/google/platform_utils.py
@@ -0,0 +1,46 @@
+#!/bin/env python
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Platform-specific utilities and pseudo-constants
+
+Any functions whose implementations or values differ from one platform to
+another should be defined in their respective platform_utils_<platform>.py
+modules. The appropriate one of those will be imported into this module to
+provide callers with a common, platform-independent interface.
+"""
+
+import sys
+
+# We may not support the version of Python that a user has installed (Cygwin
+# especially has had problems), but we'll allow the platform utils to be
+# included in any case so we don't get an import error.
+if sys.platform in ('cygwin', 'win32'):
+ from platform_utils_win import *
+
diff --git a/tools/python/google/platform_utils_win.py b/tools/python/google/platform_utils_win.py
new file mode 100644
index 0000000..df72e3d
--- /dev/null
+++ b/tools/python/google/platform_utils_win.py
@@ -0,0 +1,219 @@
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""Platform-specific utility methods shared by several scripts."""
+
+import os
+import re
+import subprocess
+import sys
+
+import google.path_utils
+
+# Cache a single cygpath process for use throughout, even across instances of
+# the PlatformUtility class.
+_cygpath_proc = None
+
+class PlatformUtility(object):
+ def __init__(self, base_dir):
+ """Args:
+ base_dir: a directory above which third_party/cygwin can be found,
+ used to locate the cygpath executable for path conversions.
+ """
+ self._cygwin_root = None
+ self._base_dir = base_dir
+
+ def _CygwinRoot(self):
+ """Returns the full path to third_party/cygwin/."""
+ if not self._cygwin_root:
+ self._cygwin_root = google.path_utils.FindUpward(self._base_dir,
+ 'third_party', 'cygwin')
+ return self._cygwin_root
+
+ def _PathToExecutable(self, executable):
+ """Returns the full path to an executable in Cygwin's bin dir."""
+ return os.path.join(self._CygwinRoot(), 'bin', executable)
+
+ def GetAbsolutePath(self, path, force=False):
+ """Returns an absolute windows path. If platform is cygwin, converts it to
+ windows style using cygpath.
+
+ For performance reasons, we use a single cygpath process, shared among all
+ instances of this class. Otherwise Python can run out of file handles.
+ """
+ if not force and sys.platform != "cygwin":
+ return os.path.abspath(path)
+ global _cygpath_proc
+ if not _cygpath_proc:
+ cygpath_command = [self._PathToExecutable("cygpath.exe"),
+ "-a", "-m", "-f", "-"]
+ _cygpath_proc = subprocess.Popen(cygpath_command,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+ _cygpath_proc.stdin.write(path + "\n")
+ return _cygpath_proc.stdout.readline().rstrip()
+
+ def GetFilesystemRoot(self):
+ """Returns the root directory of the file system."""
+ return os.environ['SYSTEMDRIVE'] + '\\'
+
+ def GetTempDirectory(self):
+ """Returns the file system's base temp directory, or the filesystem root
+ if the standard temp directory can't be determined.
+
+ Note that this does not use a random subdirectory, so it's not
+ intrinsically secure. If you need a secure subdir, use the tempfile
+ package.
+ """
+ return os.environ.get('TEMP', self.GetFilesystemRoot())
+
+ def FilenameToUri(self, path, use_http=False, use_ssl=False, port=8000):
+ """Convert a Windows style path to a URI.
+
+ Args:
+ path: For an http URI, the path relative to the httpd server's
+ DocumentRoot; for a file URI, the full path to the file.
+ use_http: if True, returns a URI of the form http://127.0.0.1:8000/.
+ If False, returns a file:/// URI.
+ use_ssl: if True, returns HTTPS URL (https://127.0.0.1:8000/).
+ This parameter is ignored if use_http=False.
+ port: The port number to append when returning an HTTP URI
+ """
+ if use_http:
+ protocol = 'http'
+ if use_ssl:
+ protocol = 'https'
+ path = path.replace("\\", "/")
+ return "%s://127.0.0.1:%s/%s" % (protocol, str(port), path)
+ return "file:///" + self.GetAbsolutePath(path)
+
+ def GetStartHttpdCommand(self, output_dir,
+ httpd_conf_path, mime_types_path,
+ document_root=None, apache2=False):
+ """Prepares the config file and output directory to start an httpd server.
+ Returns a list of strings containing the server's command line+args.
+
+ Args:
+ output_dir: the path to the server's output directory, for log files.
+ It will be created if necessary.
+ httpd_conf_path: full path to the httpd.conf file to be used.
+ mime_types_path: full path to the mime.types file to be used.
+ document_root: full path to the DocumentRoot. If None, the DocumentRoot
+ from the httpd.conf file will be used. Note that the httpd.conf
+ file alongside this script does not specify any DocumentRoot, so if
+ you're using that one, be sure to specify a document_root here.
+ apache2: boolean if true will cause this function to return start
+ command for Apache 2.x as opposed to Apache 1.3.x
+ """
+
+ if document_root:
+ document_root = GetCygwinPath(document_root)
+ exe_name = "httpd"
+ cert_file = ""
+ if apache2:
+ exe_name = "httpd2"
+ cert_file = google.path_utils.FindUpward(self._base_dir, 'tools',
+ 'python', 'google',
+ 'httpd_config', 'httpd2.pem')
+ httpd_vars = {
+ "httpd_executable_path": GetCygwinPath(
+ os.path.join(self._CygwinRoot(), "usr", "sbin", exe_name)),
+ "httpd_conf_path": GetCygwinPath(httpd_conf_path),
+ "ssl_certificate_file": GetCygwinPath(cert_file),
+ "document_root" : document_root,
+ "server_root": GetCygwinPath(os.path.join(self._CygwinRoot(), "usr")),
+ "mime_types_path": GetCygwinPath(mime_types_path),
+ "output_dir": GetCygwinPath(output_dir),
+ "bindir": GetCygwinPath(os.path.join(self._CygwinRoot(), "bin")),
+ "user": os.environ.get("USERNAME", os.environ.get("USER", "")),
+ }
+ if not httpd_vars["user"]:
+ # Failed to get the username from the environment; use whoami.exe
+ # instead.
+ proc = subprocess.Popen(self._PathToExecutable("whoami.exe"),
+ stdout=subprocess.PIPE)
+ httpd_vars["user"] = proc.stdout.read().strip()
+
+ if not httpd_vars["user"]:
+ raise Exception("Failed to get username.")
+
+ google.path_utils.MaybeMakeDirectory(output_dir)
+
+ # We have to wrap the command in bash because the cygwin environment
+ # is required for httpd to run.
+ # -C: process directive before reading config files
+ # -c: process directive after reading config files
+ # Apache wouldn't run CGIs with permissions==700 unless we add
+ # -c User "<username>"
+ bash = self._PathToExecutable("bash.exe")
+ httpd_cmd_string = (
+ ' PATH=%(bindir)s %(httpd_executable_path)s'
+ ' -f %(httpd_conf_path)s'
+ ' -c \'TypesConfig "%(mime_types_path)s"\''
+ ' -c \'CustomLog "%(output_dir)s/access_log.txt" common\''
+ ' -c \'ErrorLog "%(output_dir)s/error_log.txt"\''
+ ' -c \'PidFile "%(output_dir)s/httpd.pid"\''
+ ' -C \'User "%(user)s"\''
+ ' -C \'ServerRoot "%(server_root)s"\''
+ )
+ if apache2:
+ httpd_cmd_string = ('export CYGWIN=server;' + httpd_cmd_string +
+ ' -c \'SSLCertificateFile "%(ssl_certificate_file)s"\'')
+ if document_root:
+ httpd_cmd_string += ' -C \'DocumentRoot "%(document_root)s"\''
+
+ httpd_cmd = [bash, "-c", httpd_cmd_string % httpd_vars]
+ return httpd_cmd
+
+ def GetStopHttpdCommand(self):
+ """Returns a list of strings that contains the command line+args needed to
+ stop the http server used in the http tests.
+ """
+ # Force kill (/f) *all* httpd processes. This has the side effect of
+ # killing httpd processes that we didn't start.
+ return ["taskkill.exe", "/f", "/im", "httpd*"]
+
+###########################################################################
+# This method is specific to windows, expected to be used only by *_win.py
+# files.
+
+def GetCygwinPath(path):
+ """Convert a Windows path to a cygwin path.
+
+ The cygpath utility insists on converting paths that it thinks are Cygwin
+ root paths to what it thinks the correct roots are. So paths such as
+ "C:\b\slave\webkit-release-kjs\build\third_party\cygwin\bin" are converted to
+ plain "/usr/bin". To avoid this, we do the conversion manually.
+
+ The path is expected to be an absolute path, on any drive.
+ """
+ drive_regexp = re.compile(r'([a-z]):[/\\]', re.IGNORECASE)
+ def LowerDrive(matchobj):
+ return '/cygdrive/%s/' % matchobj.group(1).lower()
+ path = drive_regexp.sub(LowerDrive, path)
+ return path.replace('\\', '/')
diff --git a/tools/python/google/process_utils.py b/tools/python/google/process_utils.py
new file mode 100644
index 0000000..966fdf6
--- /dev/null
+++ b/tools/python/google/process_utils.py
@@ -0,0 +1,156 @@
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""Shared process-related utility functions."""
+
+import errno
+import os
+import subprocess
+import sys
+
+class CommandNotFound(Exception): pass
+
+
+TASKKILL = os.path.join(os.environ['WINDIR'], 'system32', 'taskkill.exe')
+TASKKILL_PROCESS_NOT_FOUND_ERR = 128
+# On windows 2000 there is no taskkill.exe, we need to have pskill somewhere
+# in the path.
+PSKILL = 'pskill.exe'
+PSKILL_PROCESS_NOT_FOUND_ERR = -1
+
+def KillAll(executables):
+ """Tries to kill all copies of each process in the processes list. Returns
+ an error if any running processes couldn't be killed.
+ """
+ result = 0
+ if os.path.exists(TASKKILL):
+ command = [TASKKILL, '/f', '/im']
+ process_not_found_err = TASKKILL_PROCESS_NOT_FOUND_ERR
+ else:
+ command = [PSKILL, '/t']
+ process_not_found_err = PSKILL_PROCESS_NOT_FOUND_ERR
+
+ for name in executables:
+ new_error = RunCommand(command + [name])
+ # Ignore "process not found" error.
+ if new_error != 0 and new_error != process_not_found_err:
+ result = new_error
+ return result
+
+def RunCommandFull(command, verbose=True, collect_output=False,
+ print_output=True):
+ """Runs the command list.
+
+ Prints the given command (which should be a list of one or more strings).
+ If specified, prints its stderr (and optionally stdout) to stdout,
+ line-buffered, converting line endings to CRLF (see note below). If
+ specified, collects the output as a list of lines and returns it. Waits
+ for the command to terminate and returns its status.
+
+ Args:
+ command: the full command to run, as a list of one or more strings
+ verbose: if True, combines all output (stdout and stderr) into stdout.
+ Otherwise, prints only the command's stderr to stdout.
+ collect_output: if True, collects the output of the command as a list of
+ lines and returns it
+ print_output: if True, prints the output of the command
+
+ Returns:
+ A tuple consisting of the process's exit status and output. If
+ collect_output is False, the output will be [].
+
+ Raises:
+ CommandNotFound if the command executable could not be found.
+ """
+ print '\n' + subprocess.list2cmdline(command).replace('\\', '/') + '\n', ###
+
+ if verbose:
+ out = subprocess.PIPE
+ err = subprocess.STDOUT
+ else:
+ out = file(os.devnull, 'w')
+ err = subprocess.PIPE
+ try:
+ proc = subprocess.Popen(command, stdout=out, stderr=err, bufsize=1)
+ except OSError, e:
+ if e.errno == errno.ENOENT:
+ raise CommandNotFound('Unable to find "%s"' % command[0])
+ raise
+
+ output = []
+
+ if verbose:
+ read_from = proc.stdout
+ else:
+ read_from = proc.stderr
+ line = read_from.readline()
+ while line:
+ line = line.rstrip()
+
+ if collect_output:
+ output.append(line)
+
+ if print_output:
+ # Windows Python converts \n to \r\n automatically whenever it
+ # encounters it written to a text file (including stdout). The only
+ # way around it is to write to a binary file, which isn't feasible for
+ # stdout. So we end up with \r\n here even though we explicitly write
+ # \n. (We could write \r instead, which doesn't get converted to \r\n,
+ # but that's probably more troublesome for people trying to read the
+ # files.)
+ print line + '\n',
+
+ # Python on windows writes the buffer only when it reaches 4k. This is
+ # not fast enough for all purposes.
+ sys.stdout.flush()
+ line = read_from.readline()
+
+ if not verbose:
+ out.close()
+ return (proc.returncode, output)
+
+def RunCommand(command, verbose=True):
+ """Runs the command list, printing its output and returning its exit status.
+
+ Prints the given command (which should be a list of one or more strings),
+ then runs it and prints its stderr (and optionally stdout) to stdout,
+ line-buffered, converting line endings to CRLF. Waits for the command to
+ terminate and returns its status.
+
+ Args:
+ command: the full command to run, as a list of one or more strings
+ verbose: if True, combines all output (stdout and stderr) into stdout.
+ Otherwise, prints only the command's stderr to stdout.
+
+ Returns:
+ The process's exit status.
+
+ Raises:
+ CommandNotFound if the command executable could not be found.
+ """
+ return RunCommandFull(command, verbose)[0]