546 lines
18 KiB
Python
546 lines
18 KiB
Python
#
|
|
# 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 + "</%s>\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 <this filename> > <new apache confg>
|
|
#\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
|