# # Copyright (C) 2000, 2001, 2013 Gregory Trubetskoy # Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Apache Software Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); you # may not use this file except in compliance with the License. You # may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. See the License for the specific language governing # permissions and limitations under the License. # # # Config maker, a la HTMLGen. This could grow into something useful. # from __future__ import print_function import sys import os import shutil # this is so that it could be referred to in a Container only_if import mod_python class Directive: def __init__(self, name, val, flipslash=1): self.name = name self.val = val self.indent = 0 self.flipslash = flipslash def __repr__(self): i = " " * self.indent s = i + '%s(%s)' % (self.name, repr(self.val)) if self.flipslash: s = s.replace("\\", "/") return s def __str__(self): i = " " * self.indent s = i + '%s %s\n' % (self.name, self.val) if self.flipslash: s = s.replace("\\", "/") return s class Container: def __init__(self, *args, **kwargs): self.args = list(args) self.indent = 0 self.only_if = kwargs.get('only_if') def append(self, value): if not (isinstance(value, Directive) or isinstance(value, Container) or isinstance(value, ContainerTag) or isinstance(value, Comment)): raise TypeError("appended value must be an instance of Directive, Container, ContainerTag or Comment") self.args.append(value) def __repr__(self): i = " " * self.indent s = i + 'Container(' for arg in self.args: arg.indent = self.indent + 4 s += "\n%s," % repr(arg) s += "\n" + i + (self.only_if and (' only_if=%s)' % repr(self.only_if)) or ')') return s def __str__(self): if self.only_if and not eval(self.only_if): return "" s = "" for arg in self.args: arg.indent = self.indent s += "%s" % str(arg) return s class ContainerTag: def __init__(self, tag, attr, args, flipslash=1): self.tag = tag self.attr = attr self.args = args self.indent = 0 self.flipslash = flipslash def __repr__(self): i = " " * self.indent s = i + "%s(%s," % (self.tag, repr(self.attr)) if self.flipslash: s = s.replace("\\", "/") for arg in self.args: arg.indent = self.indent + 4 s += "\n%s," % repr(arg) s += "\n" + i + ")" return s def __str__(self): i = " " * self.indent s = i + "<%s %s>\n" % (self.tag, self.attr) if self.flipslash: s = s.replace("\\", "/") for arg in self.args: arg.indent = self.indent + 2 s += "%s" % str(arg) s += i + "\n" % self.tag return s class Comment: def __init__(self, comment): self.comment = comment self.indent = 0 def __repr__(self): i = " " * self.indent lines = self.comment.splitlines() s = i + "Comment(%s" % repr(lines[0]+"\n") for line in lines[1:]: s += "\n " + i + repr(line+"\n") s += ")" return s def __str__(self): i = " " * self.indent s = "" for line in self.comment.splitlines(): s += i + '# %s\n' % line return s ## directives class AddHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class AddOutputFilter(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class AddType(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class AuthBasicAuthoritative(Directive): # New in Apache 2.2 def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class AuthBasicProvider(Directive): # New in Apache 2.2 def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class AuthType(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class AuthName(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class CustomLog(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class Directory(ContainerTag): def __init__(self, dir, *args): ContainerTag.__init__(self, self.__class__.__name__, dir, args) class DirectoryIndex(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class DocumentRoot(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class ErrorLog(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class Files(ContainerTag): def __init__(self, dir, *args): ContainerTag.__init__(self, self.__class__.__name__, dir, args) class IfModule(ContainerTag): def __init__(self, dir, *args): ContainerTag.__init__(self, self.__class__.__name__, dir, args) class KeepAliveTimeout(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class Listen(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class LoadModule(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class Location(ContainerTag): def __init__(self, dir, *args): ContainerTag.__init__(self, self.__class__.__name__, dir, args) class LogLevel(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class LogFormat(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val, flipslash=0) class LockFile(Directive): def __init__(self, val): import sys if sys.platform!='win32': Directive.__init__(self, self.__class__.__name__, val) else: Directive.__init__(self, '#'+self.__class__.__name__, val) class MaxConnectionsPerChild(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class MaxClients(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class MaxRequestsPerChild(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class MaxSpareServers(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class MaxSpareThreads(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class MaxThreadsPerChild(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class MinSpareThreads(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class Mutex(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class NameVirtualHost(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class NumServers(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class Options(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PidFile(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonAuthenHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonAuthzHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonCleanupHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonConnectionHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonDebug(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonAccessHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonPostReadRequestHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonTransHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonFixupHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonImport(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonPath(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val, flipslash=0) class PythonOutputFilter(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonOption(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class Require(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class SetHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class ServerAdmin(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class ServerName(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class ServerPath(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class ServerRoot(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class StartServers(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class StartThreads(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class ThreadsPerChild(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class Timeout(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class TypesConfig(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonInterpPerDirectory(Directive): def __init__(self, val='Off'): Directive.__init__(self, self.__class__.__name__, val) class PythonInterpPerDirective(Directive): def __init__(self, val='Off'): Directive.__init__(self, self.__class__.__name__, val) class VirtualHost(ContainerTag): def __init__(self, addr, *args): ContainerTag.__init__(self, self.__class__.__name__, addr, args) ## utility functions def quote_if_space(s): # Windows doesn't like quotes when there are # no spaces, but needs them otherwise, # TODO: Is this still true? if s.find(" ") != -1: s = '"%s"' % s return s def write_basic_config(server_root, listen='0.0.0.0:8888', conf="conf", logs="logs", htdocs="public", pythonhandler="mod_python.publisher", pythonpath=[], pythonoptions=[], mp_comments=[], conf_name='httpd_conf.py', createdirs=True, replace_config=False): """This generates a sensible Apache configuration""" conf_path = os.path.join(server_root, conf, conf_name) if os.path.exists(conf_path) and not replace_config: print('Error: %s already exists, aborting.' % repr(conf_path), file=sys.stderr) return if createdirs: for dirname in [server_root, os.path.join(server_root, htdocs), os.path.join(server_root, conf), os.path.join(server_root, logs)]: if os.path.isdir(dirname): print("Warning: directory %s already exists, continuing." % repr(dirname), file=sys.stderr) else: print("Creating directory %s." % repr(dirname), file=sys.stderr) os.mkdir(dirname) # try to find mime.types mime_types_dest = os.path.join(server_root, conf, 'mime.types') if os.path.isfile(mime_types_dest): print("Warning: file %s already exists, continuing." % repr(mime_types_dest), file=sys.stderr) else: for mime_types_dir in [mod_python.version.SYSCONFDIR, '/etc']: mime_types_src = os.path.join(mime_types_dir, 'mime.types') if os.path.isfile(mime_types_src): print("Copying %s to %s" % (repr(mime_types_src), repr(mime_types_dest)), file=sys.stderr) shutil.copy(mime_types_src, mime_types_dest) break mime_types = os.path.join(conf, "mime.types") if not os.path.exists(os.path.join(server_root, mime_types)): print("Warning: file %s does not exist." % repr(os.path.join(server_root, mime_types)), file=sys.stderr) if not os.path.isdir(os.path.join(server_root, htdocs)): print("Warning: %s does not exist or not a directory." % repr(os.path.join(server_root, htdocs)), file=sys.stderr) modpath = mod_python.version.LIBEXECDIR modules = Container(Comment("\nLoad the necessary modules (this is the default httpd set):\n\n")) for module in [ ['authn_file_module', 'mod_authn_file.so'], ['authn_core_module', 'mod_authn_core.so'], ['authz_host_module', 'mod_authz_host.so'], ['authz_groupfile_module', 'mod_authz_groupfile.so'], ['authz_user_module', 'mod_authz_user.so'], ['authz_core_module', 'mod_authz_core.so'], ['access_compat_module', 'mod_access_compat.so'], ['auth_basic_module', 'mod_auth_basic.so'], ['reqtimeout_module', 'mod_reqtimeout.so'], ['include_module', 'mod_include.so'], ['filter_module', 'mod_filter.so'], ['mime_module', 'mod_mime.so'], ['log_config_module', 'mod_log_config.so'], ['env_module', 'mod_env.so'], ['headers_module', 'mod_headers.so'], ['setenvif_module', 'mod_setenvif.so'], ['version_module', 'mod_version.so'], ['unixd_module', 'mod_unixd.so'], ['status_module', 'mod_status.so'], ['autoindex_module', 'mod_autoindex.so'], ['dir_module', 'mod_dir.so'], ['alias_module', 'mod_alias.so'], ]: modules.append( LoadModule("%s %s" % (module[0], quote_if_space(os.path.join(modpath, module[1])))) ) main = Container(Comment("\nMain configuration options:\n\n"), ServerRoot(server_root), Container(MaxConnectionsPerChild('65536'), only_if="mod_python.version.HTTPD_VERSION[0:3] == '2.4'"), Container(MaxRequestsPerChild('65536'), only_if="mod_python.version.HTTPD_VERSION[0:3] < '2.4'"), LogFormat(r'"%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined'), CustomLog("%s combined" % quote_if_space(os.path.join(logs, "access_log"))), ErrorLog(quote_if_space(os.path.join(logs, "error_log"))), LogLevel("warn"), PidFile(quote_if_space(os.path.join(logs, "httpd.pid"))), TypesConfig(quote_if_space(mime_types)), # The only reason we need a ServerName is so that Apache does not # generate a warning about being unable to determine its name. ServerName("127.0.0.1"), Listen(listen), DocumentRoot(quote_if_space(os.path.join(server_root, htdocs))), Container(LockFile(quote_if_space(os.path.join(logs, "accept.lock"))), only_if="mod_python.version.HTTPD_VERSION[0:3] == '2.2'"), ) mp = Container(Comment("\nmod_python-specific options:\n\n"), LoadModule("python_module %s" % quote_if_space(quote_if_space(os.path.join(modpath, 'mod_python.so')))), SetHandler("mod_python"), Comment("PythonDebug On"), PythonHandler(pythonhandler), ) if pythonpath: pp = "sys.path+[" for p in pythonpath: pp += repr(p)+"," pp += "]" mp.append(PythonPath('"%s"' % pp)) for po in pythonoptions: mp.append(PythonOption(po)) for c in mp_comments: mp.append(Comment(c)) config = Container() config.append(Comment( "\n" "This config was auto-generated, do not edit!\n" "\n" )) config.append(modules) config.append(main) config.append(mp) s = """#!%s # # This config was auto-generated, but you can edit it! # It can be used to generate an Apache config by simply # running it. We recommend you run it like this: # $ mod_python genconfig > #\n """ % mod_python.version.PYTHON_BIN s += "from mod_python.httpdconf import *\n\n" s += "config = " + repr(config) s += "\n\nprint(config)\n" print("Writing %s." % repr(conf_path), file=sys.stderr) open(conf_path, 'w').write(s) return conf_path