<NME> apache.py
<BEF>  # vim: set sw=4 expandtab :
 #
 # 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.
 #
 # Originally developed by Gregory Trubetskoy.
 #

import sys
import traceback
import time
import os
import pdb
import stat
import inspect
import importlib
import types
import _apache
try:
    from html import escape
except:
    from cgi import escape

try:
    import threading
except:
    import dummy_threading as threading

# Cache for values of PythonPath that have been seen already.
_path_cache = {}
_path_cache_lock = threading.Lock()

_result_warning = """Handler has returned result or raised SERVER_RETURN
exception with argument having non integer type. Type of value returned
was %s, whereas expected """ + str(int) + "."

class CallBack:
    """
    A generic callback object.
    """

 #
 # Originally developed by Gregory Trubetskoy.
 #
 # $Id: apache.py,v 1.79 2003/10/08 21:04:11 grisha Exp $

import sys
import traceback
            self.req = req

        def pop(self):

            handlers = self.req.hstack.split()

            if not handlers:
                return None
            else:
                self.req.hstack = " ".join(handlers[1:])
                return handlers[0]

    def ConnectionDispatch(self, conn):

        # config
        config, debug  = conn.base_server.get_config(), False
        if "PythonDebug" in config:
            debug = config["PythonDebug"] == "1"

        try:

            handler = conn.hlist.handler

            # split module::handler
            l = handler.split('::', 1)
            module_name = l[0]
            if len(l) == 1:
                # no oject, provide default
                obj_str = "connectionhandler"
            else:
                obj_str = l[1]

            # evaluate pythonpath and set sys.path to
            # resulting value if not already done

            if "PythonPath" in config:
                _path_cache_lock.acquire()
                try:
                    pathstring = config["PythonPath"]
                    if pathstring not in _path_cache:
                        newpath = eval(pathstring)
                        _path_cache[pathstring] = None
                        sys.path[:] = newpath
                finally:
                    _path_cache_lock.release()

            # import module
            autoreload = True
            if "PythonAutoReload" in config:
                autoreload = config["PythonAutoReload"] == "1"
            module = import_module(module_name,
                                   autoreload=autoreload,
                                   log=debug)
            # find the object
            obj = resolve_object(module, obj_str,
                                    arg=conn, silent=0)

            # Only permit debugging using pdb if Apache has
            # actually been started in single process mode.

            pdb_debug = False
            if "PythonEnablePdb" in config:
                pdb_debug = config["PythonEnablePdb"] == "1"

            if pdb_debug and exists_config_define("ONE_PROCESS"):

                # Don't use pdb.runcall() as it results in
                # a bogus 'None' response when pdb session
                # is quit. With this code the exception
                # marking that the session has been quit is
                # propogated back up and it is obvious in
                # the error message what actually occurred.

                debugger = pdb.Pdb()
                debugger.reset()
                sys.settrace(debugger.trace_dispatch)

                try:
                    result = obj(conn)

                finally:
                    debugger.quitting = 1
                    sys.settrace(None)

            else:
                result = obj(conn)

            assert (result.__class__ is int), \
                   "ConnectionHandler '%s' returned invalid return code." % handler

        except:
            # Error (usually parsing)
            try:
                exc_type, exc_value, exc_traceback = sys.exc_info()
                result = self.ReportError(exc_type, exc_value, exc_traceback, srv=conn.base_server,
                                          phase="ConnectionHandler",
                                          hname=handler, debug=debug)
            finally:
                exc_traceback = None

        return result

    def FilterDispatch(self, fltr):
        req = fltr.req

        # config
        config, debug  = req.get_config(), False
        if "PythonDebug" in config:
            debug = config["PythonDebug"] == "1"

        try:

            # split module::handler
            l = fltr.handler.split('::', 1)
            module_name = l[0]
            if len(l) == 1:
                # no oject, provide default
                if fltr.is_input:
                    obj_str = "inputfilter"
                else:
                    obj_str = "outputfilter"
            else:
                obj_str = l[1]

            # add the directory to pythonpath if
            # not there yet, or evaluate pythonpath
            # and set sys.path to resulting value
            # if not already done

            if "PythonPath" in config:
                _path_cache_lock.acquire()
                try:
                    pathstring = config["PythonPath"]
                    if pathstring not in _path_cache:
                        newpath = eval(pathstring)
                        _path_cache[pathstring] = None
                        sys.path[:] = newpath
                finally:
                    _path_cache_lock.release()
            else:
                if fltr.dir:
                    _path_cache_lock.acquire()
                    try:
                        if fltr.dir not in sys.path:
                            sys.path[:0] = [fltr.dir]
                    finally:
                        _path_cache_lock.release()

            # import module
            autoreload = True
            if "PythonAutoReload" in config:
                autoreload = config["PythonAutoReload"] == "1"
            module = import_module(module_name,
                                   autoreload=autoreload,
                                   log=debug)

            # find the object
            obj = resolve_object(module, obj_str,
                                    arg=fltr, silent=0)

            # Only permit debugging using pdb if Apache has
            # actually been started in single process mode.

            pdb_debug = False
            if "PythonEnablePdb" in config:
                pdb_debug = config["PythonEnablePdb"] == "1"

            if pdb_debug and exists_config_define("ONE_PROCESS"):

                # Don't use pdb.runcall() as it results in
                # a bogus 'None' response when pdb session
                # is quit. With this code the exception
                # marking that the session has been quit is
                # propogated back up and it is obvious in
                # the error message what actually occurred.

                debugger = pdb.Pdb()
                debugger.reset()
                sys.settrace(debugger.trace_dispatch)

                try:
                    result = obj(fltr)

                finally:
                    debugger.quitting = 1
                    sys.settrace(None)

            else:
                result = obj(fltr)

            # always flush the filter. without a FLUSH or EOS bucket,
            # the content is never written to the network.
            # XXX an alternative is to tell the user to flush() always
            if not fltr.closed:
                fltr.flush()

        except SERVER_RETURN as value:
            # SERVER_RETURN indicates a non-local abort from below
            # with value as (result, status) or (result, None) or result
            try:
                if len(value.args) == 2:
                    (result, status) = value.args
                    if status:
                        req.status = status
                else:
                    result = value.args[0]

                if result.__class__ is not int:
                    s = "Value raised with SERVER_RETURN is invalid. It is a "
                    s = s + "%s, but it must be a tuple or an int." % result.__class__
                    _apache.log_error(s, APLOG_ERR, req.server)

                    return

            except:
                pass

        except:
            # Error (usually parsing)
            try:
                exc_type, exc_value, exc_traceback = sys.exc_info()
                fltr.disable()
                result = self.ReportError(exc_type, exc_value, exc_traceback, req=req, filter=fltr,
                                          phase=fltr.name, hname=fltr.handler,
                                          debug=debug)
            finally:
                exc_traceback = None

        return OK

    def HandlerDispatch(self, req):
        """
        This is the handler dispatcher.
        """

        # be cautious
        result = HTTP_INTERNAL_SERVER_ERROR

        # config
        config, debug = req.get_config(), False
        if "PythonDebug" in config:
            debug = config["PythonDebug"] == "1"

        default_obj_str = _phase_handler_names[req.phase]

        # Lookup expected status values that allow us to
        # continue when multiple handlers exist.
        expected = _status_values[default_obj_str]

        try:
            hlist = req.hlist

            while hlist.handler is not None:

                # split module::handler
                l = hlist.handler.split('::', 1)

                module_name = l[0]
                if len(l) == 1:
                    # no object, provide default
                    obj_str = default_obj_str
                else:
                    obj_str = l[1]

                # add the directory to pythonpath if
                # not there yet, or evaluate pythonpath
                # and set sys.path to resulting value
                # if not already done

                if "PythonPath" in config:
                    _path_cache_lock.acquire()
                    try:
                        pathstring = config["PythonPath"]
                        if pathstring not in _path_cache:
                            newpath = eval(pathstring)
                            _path_cache[pathstring] = None
                            sys.path[:] = newpath
                    finally:
                        _path_cache_lock.release()
                else:
                    if not hlist.is_location:
                        directory = hlist.directory
                        if directory:
                            _path_cache_lock.acquire()
                            try:
                                if directory not in sys.path:
                                    sys.path[:0] = [directory]
                            finally:
                                _path_cache_lock.release()

                # import module
                autoreload = True
                if "PythonAutoReload" in config:
                    autoreload = config["PythonAutoReload"] == "1"
                module = import_module(module_name,
                                       autoreload=autoreload,
                                       log=debug)

                # find the object
                if '.' not in obj_str: # this is an optimization
                    try:
                        obj = module.__dict__[obj_str]
                    except:
                        if not hlist.silent:
                            s = "module '%s' contains no '%s'" % (module.__file__, obj_str)
                            raise AttributeError(s)
                else:
                    obj = resolve_object(module, obj_str,
                                         arg=req, silent=hlist.silent)

                if not hlist.silent or obj is not None:

                    try:
                        # Only permit debugging using pdb if Apache has
                        # actually been started in single process mode.

                        pdb_debug = False
                        if "PythonEnablePdb" in config:
                            pdb_debug = config["PythonEnablePdb"] == "1"

                        if pdb_debug and exists_config_define("ONE_PROCESS"):

                            # Don't use pdb.runcall() as it results in
                            # a bogus 'None' response when pdb session
                            # is quit. With this code the exception
                            # marking that the session has been quit is
                            # propogated back up and it is obvious in
                            # the error message what actually occurred.

                            debugger = pdb.Pdb()
                            debugger.reset()
                            sys.settrace(debugger.trace_dispatch)

                            try:
                                result = obj(req)

                            finally:
                                debugger.quitting = 1
                                sys.settrace(None)

                        else:
                            result = obj(req)

                    except SERVER_RETURN as value:

                        # The SERVER_RETURN exception type when raised
                        # otherwise indicates an abort from below with
                        # value as (result, status) or (result, None) or
                        # result.

                        if len(value.args) == 2:
                            (result, status) = value.args
                            if status:
                                req.status = status
                        else:
                            result = value.args[0]

                    assert (result.__class__ is int), \
                            _result_warning % result.__class__

                    # stop cycling through handlers
                    if result not in expected:
                        break

                elif hlist.silent:
                    # A missing handler when in silent mode will
                    # only propagate DECLINED if it is the first
                    # and only handler.

                    if result == HTTP_INTERNAL_SERVER_ERROR:
                        result = DECLINED

                hlist.next()

        except:
            # Error (usually parsing)
            try:
                exc_type, exc_value, exc_traceback = sys.exc_info()
                result = self.ReportError(exc_type, exc_value, exc_traceback, req=req,
                                          phase=req.phase, hname=hlist.handler, debug=debug)
            finally:
                exc_traceback = None

        return result

    def IncludeDispatch(self, fltr, tag, code):

        try:
            # config
            config, debug = fltr.req.get_config(), False
            if "PythonDebug" in config:
                debug = config["PythonDebug"] == "1"

            if not hasattr(fltr.req,"ssi_globals"):
                fltr.req.ssi_globals = {}

            fltr.req.ssi_globals["filter"] = fltr
            fltr.req.ssi_globals["__file__"] = fltr.req.filename

            code = code.replace('\r\n', '\n').rstrip()

            if tag == 'eval':
                result = eval(code, fltr.req.ssi_globals)
                if result is not None:
                    fltr.write(str(result))
            elif tag == 'exec':
                exec(code, fltr.req.ssi_globals)
        if not file or (path and not filter(file.startswith, path)):
            # there is a script by this name already imported, but it's in
            # a different directory, therefore it's a different script
            mtime, oldtime = 0, -1
        elif autoreload: 
            oldmtime = module.__dict__.get("__mtime__", 0)
            mtime = module_mtime(module)
                result = self.ReportError(exc_type, exc_value, exc_traceback,
                                          req=fltr.req, filter=fltr,
                                          phase=fltr.name,
                                          hname=fltr.req.filename,
                                          debug=debug)
            finally:
                exc_traceback = None

            raise

        fltr.req.ssi_globals["filter"] = None

        return OK

    def ImportDispatch(self, name):

        # config
        config, debug = main_server.get_config(), False
        if "PythonDebug" in config:
            debug = config["PythonDebug"] == "1"

        # evaluate pythonpath and set sys.path to
        # resulting value if not already done

        if "PythonPath" in config:
            _path_cache_lock.acquire()
            try:
                pathstring = config["PythonPath"]
                if pathstring not in _path_cache:
                    newpath = eval(pathstring)
                    _path_cache[pathstring] = None
                    sys.path[:] = newpath
            finally:
                _path_cache_lock.release()

        # split module::function
        l = name.split('::', 1)
        module_name = l[0]
        func_name = None
        if len(l) != 1:
            func_name = l[1]

        module = import_module(module_name, log=debug)

        if func_name:
            getattr(module, func_name)()

    def ReportError(self, etype, evalue, etb, req=None, filter=None, srv=None,
                    phase="N/A", hname="N/A", debug=0):
        """
        This function is only used when debugging is on.
        It sends the output similar to what you'd see
        when using Python interactively to the browser
        """
        try:       # try/finally
            try:        # try/except

                if str(etype) == "exceptions.IOError" \
                   and str(evalue)[:5] == "Write":
                    # if this is an IOError while writing to client,
                    # it is probably better not to try to write to the cleint
                    # even if debug is on.
                    debug = 0

                # write to log
                for e in traceback.format_exception(etype, evalue, etb):
                    s = "%s %s: %s" % (phase, hname, e[:-1])
                    if req:
                        req.log_error(s, APLOG_ERR)
                    else:
                        _apache.log_error(s, APLOG_ERR, srv)

                if not debug or not req:
                    return HTTP_INTERNAL_SERVER_ERROR
                else:
                    # write to client
                    req.status = HTTP_INTERNAL_SERVER_ERROR
                    req.content_type = 'text/html'

                    s = '\n<pre>\nMod_python error: "%s %s"\n\n' % (phase, hname)
                    for e in traceback.format_exception(etype, evalue, etb):
                        s = s + escape(e) + '\n'
                    s = s + "</pre>\n"

                    if filter:
                        filter.write(s)
                        filter.flush()
                    else:
                        req.write(s)

                    return DONE
            except:
                # last try
                traceback.print_exc()
                sys.stderr.flush()

        finally:
            # erase the traceback
            etb = None
            # we do not return anything

def import_module(module_name, autoreload=1, log=0, path=None):
    """
    Get the module to handle the request. If
    autoreload is on, then the module will be reloaded
    if it has changed since the last import.
    """

    # nlehuen: this is a big lock, we'll have to refine it later to get better performance.
    # For now, we'll concentrate on thread-safety.
    # (Re)import
    if module_name in sys.modules:

        # The module has been imported already
        module = sys.modules[module_name]
        oldmtime, mtime  = 0, 0

        if autoreload:

            # but is it in the path?
            try:
                file = module.__dict__["__file__"]
            except KeyError:
                file = None

            # the "and not" part of this condition is to prevent execution
            # of arbitrary already imported modules, such as os. The
            # reason we use startswith as opposed to exact match is that
            # modules inside packages are actually in subdirectories.

            if not file or (path and not list(filter(file.startswith, path))):
                # there is a script by this name already imported, but it's in
                # a different directory, therefore it's a different script
                mtime, oldmtime = 0, -1 # trigger import
            else:
                try:
                    last_check = module.__dict__["__mtime_check__"]
                except KeyError:
                    last_check = 0

                if (time.time() - last_check) > 1:
                    oldmtime = module.__dict__.get("__mtime__", 0)
                    mtime = module_mtime(module)
        else:
            pass
    else:
        mtime, oldmtime = 0, -1

    if mtime != oldmtime:

        # Import the module
        if log:
            if path:
                s = "mod_python: (Re)importing module '%s' with path set to '%s'" % (module_name, path)
            else:
                s = "mod_python: (Re)importing module '%s'" % module_name
            _apache.log_error(s, APLOG_NOTICE)

        parent = None
        module = importlib.import_module(module_name)

        if mtime == 0:
            mtime = module_mtime(module)

        module.__mtime__ = mtime

    return module

def module_mtime(module):
    """Get modification time of module"""
    mtime = 0
    if "__file__" in module.__dict__:

        filepath = module.__file__

        try:
            # this try/except block is a workaround for a Python bug in
            # 2.0, 2.1 and 2.1.1. See
            # http://sourceforge.net/tracker/?group_id=5470&atid=105470&func=detail&aid=422004

            if os.path.exists(filepath):
                mtime = os.path.getmtime(filepath)

            if os.path.exists(filepath[:-1]) :
                mtime = max(mtime, os.path.getmtime(filepath[:-1]))

            module.__dict__["__mtime_check__"] = time.time()
        except OSError: pass

    return mtime

def resolve_object(module, obj_str, arg=None, silent=0):
    """
    This function traverses the objects separated by .
    (period) to find the last one we're looking for:

       From left to right, find objects, if it is
       an unbound method of a class, instantiate the
       class passing the request as single argument

    'arg' is sometimes req, sometimes filter,
    sometimes connection
    """

    obj = module

    for obj_str in obj_str.split('.'):

        parent = obj

        # don't throw attribute errors when silent
        if silent and not hasattr(obj, obj_str):
            return None

        # this adds a little clarity if we have an attriute error
        if obj == module and not hasattr(module, obj_str):
            if hasattr(module, "__file__"):
                s = "module '%s' contains no '%s'" % (module.__file__, obj_str)
                raise AttributeError(s)

        obj = getattr(obj, obj_str)

        if inspect.isclass(parent):
            # The parent of this object is a class,
            # it needs to be instantiated
            instance = parent(arg)
            obj = getattr(instance, obj_str)

    return obj

def build_cgi_env(req):
    """
    Utility function that returns a dictionary of
    CGI environment variables as described in
    http://hoohoo.ncsa.uiuc.edu/cgi/env.html
    """

    req.add_cgi_vars()
    env = req.subprocess_env.copy()

    if req.path_info and len(req.path_info) > 0:
        env["SCRIPT_NAME"] = req.uri[:-len(req.path_info)]
    else:
        env["SCRIPT_NAME"] = req.uri

    env["GATEWAY_INTERFACE"] = "Python-CGI/1.1"

    # you may want to comment this out for better security
    if "authorization" in req.headers_in:
        env["HTTP_AUTHORIZATION"] = req.headers_in["authorization"]

    return env

class NullIO(object):
    """ Abstract IO
    """
    def tell(self): return 0
    def read(self, n = -1): return ""
    def readline(self, length = None): return ""
    def readlines(self): return []
    def write(self, s): pass
    def writelines(self, list):
        self.write("".join(list))
    def isatty(self): return 0
    def flush(self): pass
    def close(self): pass
    def detach(self): pass
    def seek(self, pos, mode = 0): pass

class CGIStdin(NullIO):

    def __init__(self, req):
        self.pos = 0
        self.req = req
        self.BLOCK = 65536 # 64K
        # note that self.buf sometimes contains leftovers
        # that were read, but not used when readline was used
        self.buf = ""

    def read(self, n = -1):
        if n == 0:
            return ""
        if n == -1:
            s = self.req.read(self.BLOCK)
            while s:
                self.buf = self.buf + s
                self.pos = self.pos + len(s)
                s = self.req.read(self.BLOCK)
            result = self.buf
            self.buf = ""
            return result
        else:
            if self.buf:
                s = self.buf[:n]
                n = n - len(s)
            else:
                s = ""
            s = s + self.req.read(n)
            self.pos = self.pos + len(s)
            return s

    def readlines(self):
        s = (self.buf + self.read()).split('\n')
        return [s + '\n' for s in s]

    def readline(self, n = -1):

        if n == 0:
            return ""

        # fill up the buffer
        self.buf = self.buf + self.req.read(self.BLOCK)

        # look for \n in the buffer
        i = self.buf.find('\n')
        while i == -1: # if \n not found - read more
            if (n != -1) and (len(self.buf) >= n): # we're past n
                i = n - 1
                break
            x = len(self.buf)
            self.buf = self.buf + self.req.read(self.BLOCK)
            if len(self.buf) == x: # nothing read, eof
                i = x - 1
                break
            i = self.buf.find('\n', x)

        # carve out the piece, then shorten the buffer
        result = self.buf[:i+1]
        self.buf = self.buf[i+1:]
        self.pos = self.pos + len(result)
        return result


class CGIStdout(NullIO):

    """
    Class that allows writing to the socket directly for CGI.
    """

    def __init__(self, req):
        self.pos = 0
        self.req = req
        self.headers_sent = 0
        self.headers = ""

    def write(self, s):

        if not s: return

        if not self.headers_sent:
            self.headers = self.headers + s

            # are headers over yet?
            headers_over = 0

            # first try RFC-compliant CRLF
            ss = self.headers.split('\r\n\r\n', 1)
            if len(ss) < 2:
                # second try with \n\n
                ss = self.headers.split('\n\n', 1)
                if len(ss) >= 2:
                    headers_over = 1
            else:
                headers_over = 1

            if headers_over:
                # headers done, process them
                ss[0] = ss[0].replace('\r\n', '\n')
                lines = ss[0].split('\n')
                for line in lines:
                    h, v = line.split(":", 1)
                    v = v.strip()
                    if h.lower() == "status":
                        status = int(v.split()[0])
                        self.req.status = status
                    elif h.lower() == "content-type":
                        self.req.content_type = v
                        self.req.headers_out[h] = v
                    else:
                        self.req.headers_out.add(h, v)

                self.headers_sent = 1

                # write the body if any at this point
                self.req.write(ss[1])
        else:
            self.req.write(str(s))

        self.pos = self.pos + len(s)

    def tell(self): return self.pos

def setup_cgi(req):
    """
    Replace sys.stdin and stdout with an objects that read/write to
    the socket, as well as substitute the os.environ.
    Returns (environ, stdin, stdout) which you must save and then use
    with restore_nocgi().
    """

    # save env
    save_env = os.environ.copy()

    si = sys.stdin
    so = sys.stdout

    os.environ.update(build_cgi_env(req))

    sys.stdout = CGIStdout(req)
    sys.stdin = CGIStdin(req)

    sys.argv = [] # keeps cgi.py happy

    return save_env, si, so

def restore_nocgi(sav_env, si, so):
    """ see setup_cgi() """

    osenv = os.environ

    # restore env
    for k in list(osenv.keys()):
        del osenv[k]
    for k in sav_env:
        osenv[k] = sav_env[k]

    sys.stdout = si
    sys.stdin = so

interpreter = None
main_server = None
_callback = None

def register_cleanup(callback, data=None):
    _apache.register_cleanup(interpreter, main_server, callback, data)

def init(name, server):
    """
        This function is called by the server at startup time
    """

    global interpreter
    global main_server
    interpreter = name
    main_server = server

    sys.argv = ["mod_python"]

    global _callback
    _callback = CallBack()
    return _callback

## Some functions made public
make_table = _apache.table
log_error = _apache.log_error
table = _apache.table
config_tree = _apache.config_tree
server_root = _apache.server_root
mpm_query = _apache.mpm_query
exists_config_define = _apache.exists_config_define
stat = _apache.stat

## Some constants

HTTP_CONTINUE                     = 100
HTTP_SWITCHING_PROTOCOLS          = 101
HTTP_PROCESSING                   = 102
HTTP_OK                           = 200
HTTP_CREATED                      = 201
HTTP_ACCEPTED                     = 202
HTTP_NON_AUTHORITATIVE            = 203
HTTP_NO_CONTENT                   = 204
HTTP_RESET_CONTENT                = 205
HTTP_PARTIAL_CONTENT              = 206
HTTP_MULTI_STATUS                 = 207
HTTP_MULTIPLE_CHOICES             = 300
HTTP_MOVED_PERMANENTLY            = 301
HTTP_MOVED_TEMPORARILY            = 302
HTTP_SEE_OTHER                    = 303
HTTP_NOT_MODIFIED                 = 304
HTTP_USE_PROXY                    = 305
HTTP_TEMPORARY_REDIRECT           = 307
HTTP_BAD_REQUEST                  = 400
HTTP_UNAUTHORIZED                 = 401
HTTP_PAYMENT_REQUIRED             = 402
HTTP_FORBIDDEN                    = 403
HTTP_NOT_FOUND                    = 404
HTTP_METHOD_NOT_ALLOWED           = 405
HTTP_NOT_ACCEPTABLE               = 406
HTTP_PROXY_AUTHENTICATION_REQUIRED= 407
HTTP_REQUEST_TIME_OUT             = 408
HTTP_CONFLICT                     = 409
HTTP_GONE                         = 410
HTTP_LENGTH_REQUIRED              = 411
HTTP_PRECONDITION_FAILED          = 412
HTTP_REQUEST_ENTITY_TOO_LARGE     = 413
HTTP_REQUEST_URI_TOO_LARGE        = 414
HTTP_UNSUPPORTED_MEDIA_TYPE       = 415
HTTP_RANGE_NOT_SATISFIABLE        = 416
HTTP_EXPECTATION_FAILED           = 417
HTTP_IM_A_TEAPOT                  = 418
HTTP_UNPROCESSABLE_ENTITY         = 422
HTTP_LOCKED                       = 423
HTTP_FAILED_DEPENDENCY            = 424
HTTP_UPGRADE_REQUIRED             = 426
HTTP_INTERNAL_SERVER_ERROR        = 500
HTTP_NOT_IMPLEMENTED              = 501
HTTP_BAD_GATEWAY                  = 502
HTTP_SERVICE_UNAVAILABLE          = 503
HTTP_GATEWAY_TIME_OUT             = 504
HTTP_VERSION_NOT_SUPPORTED        = 505
HTTP_VARIANT_ALSO_VARIES          = 506
HTTP_INSUFFICIENT_STORAGE         = 507
HTTP_NOT_EXTENDED                 = 510

# The APLOG constants in Apache are derived from syslog.h
# constants, so we do same here.

try:
    import syslog
    APLOG_EMERG = syslog.LOG_EMERG     # system is unusable
    APLOG_ALERT = syslog.LOG_ALERT     # action must be taken immediately
    APLOG_CRIT = syslog.LOG_CRIT       # critical conditions
    APLOG_ERR = syslog.LOG_ERR         # error conditions
    APLOG_WARNING = syslog.LOG_WARNING # warning conditions
    APLOG_NOTICE = syslog.LOG_NOTICE   # normal but significant condition
    APLOG_INFO = syslog.LOG_INFO       # informational
    APLOG_DEBUG = syslog.LOG_DEBUG     # debug-level messages
except ImportError:
    APLOG_EMERG = 0
    APLOG_ALERT = 1
    APLOG_CRIT = 2
    APLOG_ERR = 3
    APLOG_WARNING = 4
    APLOG_NOTICE = 5
    APLOG_INFO = 6
    APLOG_DEBUG = 7

APLOG_NOERRNO = 0 # DEPRECATED
OK = REQ_PROCEED = 0
DONE = -2
DECLINED = REQ_NOACTION = -1

_phase_handler_names = {}
for _phase in ["PythonPostReadRequestHandler",
              "PythonTransHandler",
              "PythonHeaderParserHandler",
              "PythonInitHandler",
              "PythonAccessHandler",
              "PythonAuthenHandler",
              "PythonAuthzHandler",
              "PythonTypeHandler",
              "PythonFixupHandler",
              "PythonHandler",
              "PythonLogHandler",
              "PythonCleanupHandler"]:
    _phase_handler_names[_phase] = _phase[len("python"):].lower()

_status_values = {
    "postreadrequesthandler":   [ DECLINED, OK ],
    "transhandler":             [ DECLINED ],
    "headerparserhandler":      [ DECLINED, OK ],
    "inithandler":              [ DECLINED, OK ],
    "accesshandler":            [ DECLINED, OK ],
    "authenhandler":            [ DECLINED ],
    "authzhandler":             [ DECLINED ],
    "typehandler":              [ DECLINED ],
    "fixuphandler":             [ DECLINED, OK ],
    "handler":                  [ OK ],
    "loghandler":               [ DECLINED, OK ],
    "cleanuphandler":           [ OK ],
}

# constants for get_remote_host
REMOTE_HOST = 0
REMOTE_NAME = 1
REMOTE_NOLOOKUP = 2
REMOTE_DOUBLE_REV = 3

# legacy/mod_python things
REQ_ABORTED = HTTP_INTERNAL_SERVER_ERROR
REQ_EXIT = "REQ_EXIT"
SERVER_RETURN = _apache.SERVER_RETURN

# the req.finfo tuple
FINFO_MODE = 0
FINFO_INO = 1
FINFO_DEV = 2
FINFO_NLINK = 3
FINFO_UID = 4
FINFO_GID = 5
FINFO_SIZE = 6
FINFO_ATIME = 7
FINFO_MTIME = 8
FINFO_CTIME = 9
FINFO_FNAME = 10
FINFO_NAME = 11
FINFO_FILETYPE = 12

# the req.parsed_uri
URI_SCHEME = 0
URI_HOSTINFO = 1
URI_USER = 2
URI_PASSWORD = 3
URI_HOSTNAME = 4
URI_PORT = 5
URI_PATH = 6
URI_QUERY = 7
URI_FRAGMENT = 8

# for req.proxyreq
PROXYREQ_NONE = 0       # No proxy
PROXYREQ_PROXY = 1      # Standard proxy
PROXYREQ_REVERSE = 2    # Reverse proxy
PROXYREQ_RESPONSE = 3   # Origin response

# methods for req.allow_method()
M_GET = 0               # RFC 2616: HTTP
M_PUT = 1
M_POST = 2
M_DELETE = 3
M_CONNECT = 4
M_OPTIONS = 5
M_TRACE = 6             # RFC 2616: HTTP
M_PATCH = 7
M_PROPFIND = 8          # RFC 2518: WebDAV
M_PROPPATCH = 9
M_MKCOL = 10
M_COPY = 11
M_MOVE = 12
M_LOCK = 13
M_UNLOCK = 14           # RFC2518: WebDAV
M_VERSION_CONTROL = 15  # RFC3253: WebDAV Versioning
M_CHECKOUT = 16
M_UNCHECKOUT = 17
M_CHECKIN = 18
M_UPDATE = 19
M_LABEL = 20
M_REPORT = 21
M_MKWORKSPACE = 22
M_MKACTIVITY = 23
M_BASELINE_CONTROL = 24
M_MERGE = 25
M_INVALID = 26           # RFC3253: WebDAV Versioning

# for req.used_path_info
AP_REQ_ACCEPT_PATH_INFO = 0  # Accept request given path_info
AP_REQ_REJECT_PATH_INFO = 1  # Send 404 error if path_info was given
AP_REQ_DEFAULT_PATH_INFO = 2 # Module's choice for handling path_info


# for mpm_query
AP_MPMQ_NOT_SUPPORTED      = 0  # This value specifies whether
                                # an MPM is capable of
                                # threading or forking.
AP_MPMQ_STATIC             = 1  # This value specifies whether
                                # an MPM is using a static # of
                                # threads or daemons.
AP_MPMQ_DYNAMIC            = 2  # This value specifies whether
                                # an MPM is using a dynamic # of
                                # threads or daemons.

AP_MPMQ_MAX_DAEMON_USED    = 1  # Max # of daemons used so far
AP_MPMQ_IS_THREADED        = 2  # MPM can do threading
AP_MPMQ_IS_FORKED          = 3  # MPM can do forking
AP_MPMQ_HARD_LIMIT_DAEMONS = 4  # The compiled max # daemons
AP_MPMQ_HARD_LIMIT_THREADS = 5  # The compiled max # threads
AP_MPMQ_MAX_THREADS        = 6  # # of threads/child by config
AP_MPMQ_MIN_SPARE_DAEMONS  = 7  # Min # of spare daemons
AP_MPMQ_MIN_SPARE_THREADS  = 8  # Min # of spare threads
AP_MPMQ_MAX_SPARE_DAEMONS  = 9  # Max # of spare daemons
AP_MPMQ_MAX_SPARE_THREADS  = 10 # Max # of spare threads
AP_MPMQ_MAX_REQUESTS_DAEMON= 11 # Max # of requests per daemon
AP_MPMQ_MAX_DAEMONS        = 12 # Max # of daemons by config

# magic mime types
CGI_MAGIC_TYPE = "application/x-httpd-cgi"
INCLUDES_MAGIC_TYPE = "text/x-server-parsed-html"
INCLUDES_MAGIC_TYPE3 = "text/x-server-parsed-html3"
DIR_MAGIC_TYPE = "httpd/unix-directory"

# for req.read_body
REQUEST_NO_BODY = 0
REQUEST_CHUNKED_ERROR = 1
REQUEST_CHUNKED_DECHUNK = 2

# for req.connection.keepalive
AP_CONN_UNKNOWN = _apache.AP_CONN_UNKNOWN
AP_CONN_CLOSE = _apache.AP_CONN_CLOSE
AP_CONN_KEEPALIVE = _apache.AP_CONN_KEEPALIVE

# for req.finfo[apache.FINFO_FILETYPE]
APR_NOFILE = _apache.APR_NOFILE
APR_REG = _apache.APR_REG
APR_DIR = _apache.APR_DIR
APR_CHR = _apache.APR_CHR
APR_BLK = _apache.APR_BLK
APR_PIPE = _apache.APR_PIPE
APR_LNK = _apache.APR_LNK
APR_SOCK = _apache.APR_SOCK
APR_UNKFILE = _apache.APR_UNKFILE

# module magic
MODULE_MAGIC_NUMBER_MAJOR = _apache.MODULE_MAGIC_NUMBER_MAJOR
MODULE_MAGIC_NUMBER_MINOR = _apache.MODULE_MAGIC_NUMBER_MINOR

# for apache.stat()
APR_FINFO_LINK = 0x00000001 # Stat the link not the file itself if it is a link
APR_FINFO_MTIME = 0x00000010 # Modification Time
APR_FINFO_CTIME = 0x00000020 # Creation or inode-changed time
APR_FINFO_ATIME = 0x00000040 # Access Time
APR_FINFO_SIZE = 0x00000100 # Size of the file
APR_FINFO_CSIZE = 0x00000200 # Storage size consumed by the file
APR_FINFO_DEV = 0x00001000 # Device
APR_FINFO_INODE = 0x00002000 # Inode
APR_FINFO_NLINK = 0x00004000 # Number of links
APR_FINFO_TYPE = 0x00008000 # Type
APR_FINFO_USER = 0x00010000 # User
APR_FINFO_GROUP = 0x00020000 # Group
APR_FINFO_UPROT = 0x00100000 # User protection bits
APR_FINFO_GPROT = 0x00200000 # Group protection bits
APR_FINFO_WPROT = 0x00400000 # World protection bits
APR_FINFO_ICASE = 0x01000000 # if dev is case insensitive
APR_FINFO_NAME = 0x02000000 # ->name in proper case
APR_FINFO_MIN = 0x00008170 # type, mtime, ctime, atime, size
APR_FINFO_IDENT = 0x00003000 # dev and inode
APR_FINFO_OWNER = 0x00030000 # user and group
APR_FINFO_PROT = 0x00700000 # all protections
APR_FINFO_NORM = 0x0073b170 # an atomic unix apr_stat()
APR_FINFO_DIRENT = 0x02000000 # an atomic unix apr_dir_read()

<MSG> small but significant typo


<DFF> @@ -54,7 +54,7 @@
  #
  # Originally developed by Gregory Trubetskoy.
  #
- # $Id: apache.py,v 1.79 2003/10/08 21:04:11 grisha Exp $
+ # $Id: apache.py,v 1.80 2004/01/16 04:50:15 grisha Exp $
 
 import sys
 import traceback
@@ -468,7 +468,7 @@ def import_module(module_name, autoreload=1, log=0, path=None):
         if not file or (path and not filter(file.startswith, path)):
             # there is a script by this name already imported, but it's in
             # a different directory, therefore it's a different script
-            mtime, oldtime = 0, -1
+            mtime, oldmtime = 0, -1
         elif autoreload: 
             oldmtime = module.__dict__.get("__mtime__", 0)
             mtime = module_mtime(module)

{'commit': 'diff --git a/lib/python/mod_python/apache.py b/lib/python/mod_python/apache.py\nindex 72c8717..044eb97 100755\n--- a/lib/python/mod_python/apache.py\n+++ b/lib/python/mod_python/apache.py\n@@ -54,7 +54,7 @@\n  #\n  # Originally developed by Gregory Trubetskoy.\n  #\n- # $Id: apache.py,v 1.79 2003/10/08 21:04:11 grisha Exp $\n+ # $Id: apache.py,v 1.80 2004/01/16 04:50:15 grisha Exp $\n \n import sys\n import traceback\n@@ -468,7 +468,7 @@ def import_module(module_name, autoreload=1, log=0, path=None):\n         if not file or (path and not filter(file.startswith, path)):\n             # there is a script by this name already imported, but it\'s in\n             # a different directory, therefore it\'s a different script\n-            mtime, oldtime = 0, -1\n+            mtime, oldmtime = 0, -1\n         elif autoreload: \n             oldmtime = module.__dict__.get("__mtime__", 0)\n             mtime = module_mtime(module)\n', 'commit_subject': 'small but significant typo', 'repo_name': 'grisha/mod_python', 'committer': {'name': 'grisha', 'email': 'grisha', 'time_sec': '1074228615', 'tz_offset': '0', 'date': {'seconds': '1074228615'}}, 'commit_tree': 'd785f3e51dbb2b69091b493df8f2f9d5aabd9d34', 'commit_message': 'small but significant typo\n\n', 'language_name': 'Shell', 'license': 'apache-2.0', 'hunks': '@@ -54,7 +54,7 @@\n  #\n  # Originally developed by Gregory Trubetskoy.\n  #\n- # $Id: apache.py,v 1.79 2003/10/08 21:04:11 grisha Exp $\n+ # $Id: apache.py,v 1.80 2004/01/16 04:50:15 grisha Exp $\n \n import sys\n import traceback\n@@ -468,7 +468,7 @@ def import_module(module_name, autoreload=1, log=0, path=None):\n         if not file or (path and not filter(file.startswith, path)):\n             # there is a script by this name already imported, but it\'s in\n             # a different directory, therefore it\'s a different script\n-            mtime, oldtime = 0, -1\n+            mtime, oldmtime = 0, -1\n         elif autoreload: \n             oldmtime = module.__dict__.get("__mtime__", 0)\n             mtime = module_mtime(module)\n', 'addition_count': 2, 'deletion_count': 2, 'src_file': 'a/lib/python/mod_python/apache.py', 'tgt_file': 'b/lib/python/mod_python/apache.py', 'file_extension': '.py', 'before_file': ' # vim: set sw=4 expandtab :\n #\n # Copyright (C) 2000, 2001, 2013 Gregory Trubetskoy\n # Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Apache Software Foundation\n #\n # Licensed under the Apache License, Version 2.0 (the "License"); you\n # may not use this file except in compliance with the License.  You\n # may obtain a copy of the License at\n #\n #      http://www.apache.org/licenses/LICENSE-2.0\n #\n # Unless required by applicable law or agreed to in writing, software\n # distributed under the License is distributed on an "AS IS" BASIS,\n # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n # implied.  See the License for the specific language governing\n # permissions and limitations under the License.\n #\n # Originally developed by Gregory Trubetskoy.\n #\n\nimport sys\nimport traceback\nimport time\nimport os\nimport pdb\nimport stat\nimport inspect\nimport importlib\nimport types\nimport _apache\ntry:\n    from html import escape\nexcept:\n    from cgi import escape\n\ntry:\n    import threading\nexcept:\n    import dummy_threading as threading\n\n# Cache for values of PythonPath that have been seen already.\n_path_cache = {}\n_path_cache_lock = threading.Lock()\n\n_result_warning = """Handler has returned result or raised SERVER_RETURN\nexception with argument having non integer type. Type of value returned\nwas %s, whereas expected """ + str(int) + "."\n\nclass CallBack:\n    """\n    A generic callback object.\n    """\n\n #\n # Originally developed by Gregory Trubetskoy.\n #\n # $Id: apache.py,v 1.79 2003/10/08 21:04:11 grisha Exp $\n\nimport sys\nimport traceback\n            self.req = req\n\n        def pop(self):\n\n            handlers = self.req.hstack.split()\n\n            if not handlers:\n                return None\n            else:\n                self.req.hstack = " ".join(handlers[1:])\n                return handlers[0]\n\n    def ConnectionDispatch(self, conn):\n\n        # config\n        config, debug  = conn.base_server.get_config(), False\n        if "PythonDebug" in config:\n            debug = config["PythonDebug"] == "1"\n\n        try:\n\n            handler = conn.hlist.handler\n\n            # split module::handler\n            l = handler.split(\'::\', 1)\n            module_name = l[0]\n            if len(l) == 1:\n                # no oject, provide default\n                obj_str = "connectionhandler"\n            else:\n                obj_str = l[1]\n\n            # evaluate pythonpath and set sys.path to\n            # resulting value if not already done\n\n            if "PythonPath" in config:\n                _path_cache_lock.acquire()\n                try:\n                    pathstring = config["PythonPath"]\n                    if pathstring not in _path_cache:\n                        newpath = eval(pathstring)\n                        _path_cache[pathstring] = None\n                        sys.path[:] = newpath\n                finally:\n                    _path_cache_lock.release()\n\n            # import module\n            autoreload = True\n            if "PythonAutoReload" in config:\n                autoreload = config["PythonAutoReload"] == "1"\n            module = import_module(module_name,\n                                   autoreload=autoreload,\n                                   log=debug)\n            # find the object\n            obj = resolve_object(module, obj_str,\n                                    arg=conn, silent=0)\n\n            # Only permit debugging using pdb if Apache has\n            # actually been started in single process mode.\n\n            pdb_debug = False\n            if "PythonEnablePdb" in config:\n                pdb_debug = config["PythonEnablePdb"] == "1"\n\n            if pdb_debug and exists_config_define("ONE_PROCESS"):\n\n                # Don\'t use pdb.runcall() as it results in\n                # a bogus \'None\' response when pdb session\n                # is quit. With this code the exception\n                # marking that the session has been quit is\n                # propogated back up and it is obvious in\n                # the error message what actually occurred.\n\n                debugger = pdb.Pdb()\n                debugger.reset()\n                sys.settrace(debugger.trace_dispatch)\n\n                try:\n                    result = obj(conn)\n\n                finally:\n                    debugger.quitting = 1\n                    sys.settrace(None)\n\n            else:\n                result = obj(conn)\n\n            assert (result.__class__ is int), \\\n                   "ConnectionHandler \'%s\' returned invalid return code." % handler\n\n        except:\n            # Error (usually parsing)\n            try:\n                exc_type, exc_value, exc_traceback = sys.exc_info()\n                result = self.ReportError(exc_type, exc_value, exc_traceback, srv=conn.base_server,\n                                          phase="ConnectionHandler",\n                                          hname=handler, debug=debug)\n            finally:\n                exc_traceback = None\n\n        return result\n\n    def FilterDispatch(self, fltr):\n        req = fltr.req\n\n        # config\n        config, debug  = req.get_config(), False\n        if "PythonDebug" in config:\n            debug = config["PythonDebug"] == "1"\n\n        try:\n\n            # split module::handler\n            l = fltr.handler.split(\'::\', 1)\n            module_name = l[0]\n            if len(l) == 1:\n                # no oject, provide default\n                if fltr.is_input:\n                    obj_str = "inputfilter"\n                else:\n                    obj_str = "outputfilter"\n            else:\n                obj_str = l[1]\n\n            # add the directory to pythonpath if\n            # not there yet, or evaluate pythonpath\n            # and set sys.path to resulting value\n            # if not already done\n\n            if "PythonPath" in config:\n                _path_cache_lock.acquire()\n                try:\n                    pathstring = config["PythonPath"]\n                    if pathstring not in _path_cache:\n                        newpath = eval(pathstring)\n                        _path_cache[pathstring] = None\n                        sys.path[:] = newpath\n                finally:\n                    _path_cache_lock.release()\n            else:\n                if fltr.dir:\n                    _path_cache_lock.acquire()\n                    try:\n                        if fltr.dir not in sys.path:\n                            sys.path[:0] = [fltr.dir]\n                    finally:\n                        _path_cache_lock.release()\n\n            # import module\n            autoreload = True\n            if "PythonAutoReload" in config:\n                autoreload = config["PythonAutoReload"] == "1"\n            module = import_module(module_name,\n                                   autoreload=autoreload,\n                                   log=debug)\n\n            # find the object\n            obj = resolve_object(module, obj_str,\n                                    arg=fltr, silent=0)\n\n            # Only permit debugging using pdb if Apache has\n            # actually been started in single process mode.\n\n            pdb_debug = False\n            if "PythonEnablePdb" in config:\n                pdb_debug = config["PythonEnablePdb"] == "1"\n\n            if pdb_debug and exists_config_define("ONE_PROCESS"):\n\n                # Don\'t use pdb.runcall() as it results in\n                # a bogus \'None\' response when pdb session\n                # is quit. With this code the exception\n                # marking that the session has been quit is\n                # propogated back up and it is obvious in\n                # the error message what actually occurred.\n\n                debugger = pdb.Pdb()\n                debugger.reset()\n                sys.settrace(debugger.trace_dispatch)\n\n                try:\n                    result = obj(fltr)\n\n                finally:\n                    debugger.quitting = 1\n                    sys.settrace(None)\n\n            else:\n                result = obj(fltr)\n\n            # always flush the filter. without a FLUSH or EOS bucket,\n            # the content is never written to the network.\n            # XXX an alternative is to tell the user to flush() always\n            if not fltr.closed:\n                fltr.flush()\n\n        except SERVER_RETURN as value:\n            # SERVER_RETURN indicates a non-local abort from below\n            # with value as (result, status) or (result, None) or result\n            try:\n                if len(value.args) == 2:\n                    (result, status) = value.args\n                    if status:\n                        req.status = status\n                else:\n                    result = value.args[0]\n\n                if result.__class__ is not int:\n                    s = "Value raised with SERVER_RETURN is invalid. It is a "\n                    s = s + "%s, but it must be a tuple or an int." % result.__class__\n                    _apache.log_error(s, APLOG_ERR, req.server)\n\n                    return\n\n            except:\n                pass\n\n        except:\n            # Error (usually parsing)\n            try:\n                exc_type, exc_value, exc_traceback = sys.exc_info()\n                fltr.disable()\n                result = self.ReportError(exc_type, exc_value, exc_traceback, req=req, filter=fltr,\n                                          phase=fltr.name, hname=fltr.handler,\n                                          debug=debug)\n            finally:\n                exc_traceback = None\n\n        return OK\n\n    def HandlerDispatch(self, req):\n        """\n        This is the handler dispatcher.\n        """\n\n        # be cautious\n        result = HTTP_INTERNAL_SERVER_ERROR\n\n        # config\n        config, debug = req.get_config(), False\n        if "PythonDebug" in config:\n            debug = config["PythonDebug"] == "1"\n\n        default_obj_str = _phase_handler_names[req.phase]\n\n        # Lookup expected status values that allow us to\n        # continue when multiple handlers exist.\n        expected = _status_values[default_obj_str]\n\n        try:\n            hlist = req.hlist\n\n            while hlist.handler is not None:\n\n                # split module::handler\n                l = hlist.handler.split(\'::\', 1)\n\n                module_name = l[0]\n                if len(l) == 1:\n                    # no object, provide default\n                    obj_str = default_obj_str\n                else:\n                    obj_str = l[1]\n\n                # add the directory to pythonpath if\n                # not there yet, or evaluate pythonpath\n                # and set sys.path to resulting value\n                # if not already done\n\n                if "PythonPath" in config:\n                    _path_cache_lock.acquire()\n                    try:\n                        pathstring = config["PythonPath"]\n                        if pathstring not in _path_cache:\n                            newpath = eval(pathstring)\n                            _path_cache[pathstring] = None\n                            sys.path[:] = newpath\n                    finally:\n                        _path_cache_lock.release()\n                else:\n                    if not hlist.is_location:\n                        directory = hlist.directory\n                        if directory:\n                            _path_cache_lock.acquire()\n                            try:\n                                if directory not in sys.path:\n                                    sys.path[:0] = [directory]\n                            finally:\n                                _path_cache_lock.release()\n\n                # import module\n                autoreload = True\n                if "PythonAutoReload" in config:\n                    autoreload = config["PythonAutoReload"] == "1"\n                module = import_module(module_name,\n                                       autoreload=autoreload,\n                                       log=debug)\n\n                # find the object\n                if \'.\' not in obj_str: # this is an optimization\n                    try:\n                        obj = module.__dict__[obj_str]\n                    except:\n                        if not hlist.silent:\n                            s = "module \'%s\' contains no \'%s\'" % (module.__file__, obj_str)\n                            raise AttributeError(s)\n                else:\n                    obj = resolve_object(module, obj_str,\n                                         arg=req, silent=hlist.silent)\n\n                if not hlist.silent or obj is not None:\n\n                    try:\n                        # Only permit debugging using pdb if Apache has\n                        # actually been started in single process mode.\n\n                        pdb_debug = False\n                        if "PythonEnablePdb" in config:\n                            pdb_debug = config["PythonEnablePdb"] == "1"\n\n                        if pdb_debug and exists_config_define("ONE_PROCESS"):\n\n                            # Don\'t use pdb.runcall() as it results in\n                            # a bogus \'None\' response when pdb session\n                            # is quit. With this code the exception\n                            # marking that the session has been quit is\n                            # propogated back up and it is obvious in\n                            # the error message what actually occurred.\n\n                            debugger = pdb.Pdb()\n                            debugger.reset()\n                            sys.settrace(debugger.trace_dispatch)\n\n                            try:\n                                result = obj(req)\n\n                            finally:\n                                debugger.quitting = 1\n                                sys.settrace(None)\n\n                        else:\n                            result = obj(req)\n\n                    except SERVER_RETURN as value:\n\n                        # The SERVER_RETURN exception type when raised\n                        # otherwise indicates an abort from below with\n                        # value as (result, status) or (result, None) or\n                        # result.\n\n                        if len(value.args) == 2:\n                            (result, status) = value.args\n                            if status:\n                                req.status = status\n                        else:\n                            result = value.args[0]\n\n                    assert (result.__class__ is int), \\\n                            _result_warning % result.__class__\n\n                    # stop cycling through handlers\n                    if result not in expected:\n                        break\n\n                elif hlist.silent:\n                    # A missing handler when in silent mode will\n                    # only propagate DECLINED if it is the first\n                    # and only handler.\n\n                    if result == HTTP_INTERNAL_SERVER_ERROR:\n                        result = DECLINED\n\n                hlist.next()\n\n        except:\n            # Error (usually parsing)\n            try:\n                exc_type, exc_value, exc_traceback = sys.exc_info()\n                result = self.ReportError(exc_type, exc_value, exc_traceback, req=req,\n                                          phase=req.phase, hname=hlist.handler, debug=debug)\n            finally:\n                exc_traceback = None\n\n        return result\n\n    def IncludeDispatch(self, fltr, tag, code):\n\n        try:\n            # config\n            config, debug = fltr.req.get_config(), False\n            if "PythonDebug" in config:\n                debug = config["PythonDebug"] == "1"\n\n            if not hasattr(fltr.req,"ssi_globals"):\n                fltr.req.ssi_globals = {}\n\n            fltr.req.ssi_globals["filter"] = fltr\n            fltr.req.ssi_globals["__file__"] = fltr.req.filename\n\n            code = code.replace(\'\\r\\n\', \'\\n\').rstrip()\n\n            if tag == \'eval\':\n                result = eval(code, fltr.req.ssi_globals)\n                if result is not None:\n                    fltr.write(str(result))\n            elif tag == \'exec\':\n                exec(code, fltr.req.ssi_globals)\n        if not file or (path and not filter(file.startswith, path)):\n            # there is a script by this name already imported, but it\'s in\n            # a different directory, therefore it\'s a different script\n            mtime, oldtime = 0, -1\n        elif autoreload: \n            oldmtime = module.__dict__.get("__mtime__", 0)\n            mtime = module_mtime(module)\n                result = self.ReportError(exc_type, exc_value, exc_traceback,\n                                          req=fltr.req, filter=fltr,\n                                          phase=fltr.name,\n                                          hname=fltr.req.filename,\n                                          debug=debug)\n            finally:\n                exc_traceback = None\n\n            raise\n\n        fltr.req.ssi_globals["filter"] = None\n\n        return OK\n\n    def ImportDispatch(self, name):\n\n        # config\n        config, debug = main_server.get_config(), False\n        if "PythonDebug" in config:\n            debug = config["PythonDebug"] == "1"\n\n        # evaluate pythonpath and set sys.path to\n        # resulting value if not already done\n\n        if "PythonPath" in config:\n            _path_cache_lock.acquire()\n            try:\n                pathstring = config["PythonPath"]\n                if pathstring not in _path_cache:\n                    newpath = eval(pathstring)\n                    _path_cache[pathstring] = None\n                    sys.path[:] = newpath\n            finally:\n                _path_cache_lock.release()\n\n        # split module::function\n        l = name.split(\'::\', 1)\n        module_name = l[0]\n        func_name = None\n        if len(l) != 1:\n            func_name = l[1]\n\n        module = import_module(module_name, log=debug)\n\n        if func_name:\n            getattr(module, func_name)()\n\n    def ReportError(self, etype, evalue, etb, req=None, filter=None, srv=None,\n                    phase="N/A", hname="N/A", debug=0):\n        """\n        This function is only used when debugging is on.\n        It sends the output similar to what you\'d see\n        when using Python interactively to the browser\n        """\n        try:       # try/finally\n            try:        # try/except\n\n                if str(etype) == "exceptions.IOError" \\\n                   and str(evalue)[:5] == "Write":\n                    # if this is an IOError while writing to client,\n                    # it is probably better not to try to write to the cleint\n                    # even if debug is on.\n                    debug = 0\n\n                # write to log\n                for e in traceback.format_exception(etype, evalue, etb):\n                    s = "%s %s: %s" % (phase, hname, e[:-1])\n                    if req:\n                        req.log_error(s, APLOG_ERR)\n                    else:\n                        _apache.log_error(s, APLOG_ERR, srv)\n\n                if not debug or not req:\n                    return HTTP_INTERNAL_SERVER_ERROR\n                else:\n                    # write to client\n                    req.status = HTTP_INTERNAL_SERVER_ERROR\n                    req.content_type = \'text/html\'\n\n                    s = \'\\n<pre>\\nMod_python error: "%s %s"\\n\\n\' % (phase, hname)\n                    for e in traceback.format_exception(etype, evalue, etb):\n                        s = s + escape(e) + \'\\n\'\n                    s = s + "</pre>\\n"\n\n                    if filter:\n                        filter.write(s)\n                        filter.flush()\n                    else:\n                        req.write(s)\n\n                    return DONE\n            except:\n                # last try\n                traceback.print_exc()\n                sys.stderr.flush()\n\n        finally:\n            # erase the traceback\n            etb = None\n            # we do not return anything\n\ndef import_module(module_name, autoreload=1, log=0, path=None):\n    """\n    Get the module to handle the request. If\n    autoreload is on, then the module will be reloaded\n    if it has changed since the last import.\n    """\n\n    # nlehuen: this is a big lock, we\'ll have to refine it later to get better performance.\n    # For now, we\'ll concentrate on thread-safety.\n    # (Re)import\n    if module_name in sys.modules:\n\n        # The module has been imported already\n        module = sys.modules[module_name]\n        oldmtime, mtime  = 0, 0\n\n        if autoreload:\n\n            # but is it in the path?\n            try:\n                file = module.__dict__["__file__"]\n            except KeyError:\n                file = None\n\n            # the "and not" part of this condition is to prevent execution\n            # of arbitrary already imported modules, such as os. The\n            # reason we use startswith as opposed to exact match is that\n            # modules inside packages are actually in subdirectories.\n\n            if not file or (path and not list(filter(file.startswith, path))):\n                # there is a script by this name already imported, but it\'s in\n                # a different directory, therefore it\'s a different script\n                mtime, oldmtime = 0, -1 # trigger import\n            else:\n                try:\n                    last_check = module.__dict__["__mtime_check__"]\n                except KeyError:\n                    last_check = 0\n\n                if (time.time() - last_check) > 1:\n                    oldmtime = module.__dict__.get("__mtime__", 0)\n                    mtime = module_mtime(module)\n        else:\n            pass\n    else:\n        mtime, oldmtime = 0, -1\n\n    if mtime != oldmtime:\n\n        # Import the module\n        if log:\n            if path:\n                s = "mod_python: (Re)importing module \'%s\' with path set to \'%s\'" % (module_name, path)\n            else:\n                s = "mod_python: (Re)importing module \'%s\'" % module_name\n            _apache.log_error(s, APLOG_NOTICE)\n\n        parent = None\n        module = importlib.import_module(module_name)\n\n        if mtime == 0:\n            mtime = module_mtime(module)\n\n        module.__mtime__ = mtime\n\n    return module\n\ndef module_mtime(module):\n    """Get modification time of module"""\n    mtime = 0\n    if "__file__" in module.__dict__:\n\n        filepath = module.__file__\n\n        try:\n            # this try/except block is a workaround for a Python bug in\n            # 2.0, 2.1 and 2.1.1. See\n            # http://sourceforge.net/tracker/?group_id=5470&atid=105470&func=detail&aid=422004\n\n            if os.path.exists(filepath):\n                mtime = os.path.getmtime(filepath)\n\n            if os.path.exists(filepath[:-1]) :\n                mtime = max(mtime, os.path.getmtime(filepath[:-1]))\n\n            module.__dict__["__mtime_check__"] = time.time()\n        except OSError: pass\n\n    return mtime\n\ndef resolve_object(module, obj_str, arg=None, silent=0):\n    """\n    This function traverses the objects separated by .\n    (period) to find the last one we\'re looking for:\n\n       From left to right, find objects, if it is\n       an unbound method of a class, instantiate the\n       class passing the request as single argument\n\n    \'arg\' is sometimes req, sometimes filter,\n    sometimes connection\n    """\n\n    obj = module\n\n    for obj_str in obj_str.split(\'.\'):\n\n        parent = obj\n\n        # don\'t throw attribute errors when silent\n        if silent and not hasattr(obj, obj_str):\n            return None\n\n        # this adds a little clarity if we have an attriute error\n        if obj == module and not hasattr(module, obj_str):\n            if hasattr(module, "__file__"):\n                s = "module \'%s\' contains no \'%s\'" % (module.__file__, obj_str)\n                raise AttributeError(s)\n\n        obj = getattr(obj, obj_str)\n\n        if inspect.isclass(parent):\n            # The parent of this object is a class,\n            # it needs to be instantiated\n            instance = parent(arg)\n            obj = getattr(instance, obj_str)\n\n    return obj\n\ndef build_cgi_env(req):\n    """\n    Utility function that returns a dictionary of\n    CGI environment variables as described in\n    http://hoohoo.ncsa.uiuc.edu/cgi/env.html\n    """\n\n    req.add_cgi_vars()\n    env = req.subprocess_env.copy()\n\n    if req.path_info and len(req.path_info) > 0:\n        env["SCRIPT_NAME"] = req.uri[:-len(req.path_info)]\n    else:\n        env["SCRIPT_NAME"] = req.uri\n\n    env["GATEWAY_INTERFACE"] = "Python-CGI/1.1"\n\n    # you may want to comment this out for better security\n    if "authorization" in req.headers_in:\n        env["HTTP_AUTHORIZATION"] = req.headers_in["authorization"]\n\n    return env\n\nclass NullIO(object):\n    """ Abstract IO\n    """\n    def tell(self): return 0\n    def read(self, n = -1): return ""\n    def readline(self, length = None): return ""\n    def readlines(self): return []\n    def write(self, s): pass\n    def writelines(self, list):\n        self.write("".join(list))\n    def isatty(self): return 0\n    def flush(self): pass\n    def close(self): pass\n    def detach(self): pass\n    def seek(self, pos, mode = 0): pass\n\nclass CGIStdin(NullIO):\n\n    def __init__(self, req):\n        self.pos = 0\n        self.req = req\n        self.BLOCK = 65536 # 64K\n        # note that self.buf sometimes contains leftovers\n        # that were read, but not used when readline was used\n        self.buf = ""\n\n    def read(self, n = -1):\n        if n == 0:\n            return ""\n        if n == -1:\n            s = self.req.read(self.BLOCK)\n            while s:\n                self.buf = self.buf + s\n                self.pos = self.pos + len(s)\n                s = self.req.read(self.BLOCK)\n            result = self.buf\n            self.buf = ""\n            return result\n        else:\n            if self.buf:\n                s = self.buf[:n]\n                n = n - len(s)\n            else:\n                s = ""\n            s = s + self.req.read(n)\n            self.pos = self.pos + len(s)\n            return s\n\n    def readlines(self):\n        s = (self.buf + self.read()).split(\'\\n\')\n        return [s + \'\\n\' for s in s]\n\n    def readline(self, n = -1):\n\n        if n == 0:\n            return ""\n\n        # fill up the buffer\n        self.buf = self.buf + self.req.read(self.BLOCK)\n\n        # look for \\n in the buffer\n        i = self.buf.find(\'\\n\')\n        while i == -1: # if \\n not found - read more\n            if (n != -1) and (len(self.buf) >= n): # we\'re past n\n                i = n - 1\n                break\n            x = len(self.buf)\n            self.buf = self.buf + self.req.read(self.BLOCK)\n            if len(self.buf) == x: # nothing read, eof\n                i = x - 1\n                break\n            i = self.buf.find(\'\\n\', x)\n\n        # carve out the piece, then shorten the buffer\n        result = self.buf[:i+1]\n        self.buf = self.buf[i+1:]\n        self.pos = self.pos + len(result)\n        return result\n\n\nclass CGIStdout(NullIO):\n\n    """\n    Class that allows writing to the socket directly for CGI.\n    """\n\n    def __init__(self, req):\n        self.pos = 0\n        self.req = req\n        self.headers_sent = 0\n        self.headers = ""\n\n    def write(self, s):\n\n        if not s: return\n\n        if not self.headers_sent:\n            self.headers = self.headers + s\n\n            # are headers over yet?\n            headers_over = 0\n\n            # first try RFC-compliant CRLF\n            ss = self.headers.split(\'\\r\\n\\r\\n\', 1)\n            if len(ss) < 2:\n                # second try with \\n\\n\n                ss = self.headers.split(\'\\n\\n\', 1)\n                if len(ss) >= 2:\n                    headers_over = 1\n            else:\n                headers_over = 1\n\n            if headers_over:\n                # headers done, process them\n                ss[0] = ss[0].replace(\'\\r\\n\', \'\\n\')\n                lines = ss[0].split(\'\\n\')\n                for line in lines:\n                    h, v = line.split(":", 1)\n                    v = v.strip()\n                    if h.lower() == "status":\n                        status = int(v.split()[0])\n                        self.req.status = status\n                    elif h.lower() == "content-type":\n                        self.req.content_type = v\n                        self.req.headers_out[h] = v\n                    else:\n                        self.req.headers_out.add(h, v)\n\n                self.headers_sent = 1\n\n                # write the body if any at this point\n                self.req.write(ss[1])\n        else:\n            self.req.write(str(s))\n\n        self.pos = self.pos + len(s)\n\n    def tell(self): return self.pos\n\ndef setup_cgi(req):\n    """\n    Replace sys.stdin and stdout with an objects that read/write to\n    the socket, as well as substitute the os.environ.\n    Returns (environ, stdin, stdout) which you must save and then use\n    with restore_nocgi().\n    """\n\n    # save env\n    save_env = os.environ.copy()\n\n    si = sys.stdin\n    so = sys.stdout\n\n    os.environ.update(build_cgi_env(req))\n\n    sys.stdout = CGIStdout(req)\n    sys.stdin = CGIStdin(req)\n\n    sys.argv = [] # keeps cgi.py happy\n\n    return save_env, si, so\n\ndef restore_nocgi(sav_env, si, so):\n    """ see setup_cgi() """\n\n    osenv = os.environ\n\n    # restore env\n    for k in list(osenv.keys()):\n        del osenv[k]\n    for k in sav_env:\n        osenv[k] = sav_env[k]\n\n    sys.stdout = si\n    sys.stdin = so\n\ninterpreter = None\nmain_server = None\n_callback = None\n\ndef register_cleanup(callback, data=None):\n    _apache.register_cleanup(interpreter, main_server, callback, data)\n\ndef init(name, server):\n    """\n        This function is called by the server at startup time\n    """\n\n    global interpreter\n    global main_server\n    interpreter = name\n    main_server = server\n\n    sys.argv = ["mod_python"]\n\n    global _callback\n    _callback = CallBack()\n    return _callback\n\n## Some functions made public\nmake_table = _apache.table\nlog_error = _apache.log_error\ntable = _apache.table\nconfig_tree = _apache.config_tree\nserver_root = _apache.server_root\nmpm_query = _apache.mpm_query\nexists_config_define = _apache.exists_config_define\nstat = _apache.stat\n\n## Some constants\n\nHTTP_CONTINUE                     = 100\nHTTP_SWITCHING_PROTOCOLS          = 101\nHTTP_PROCESSING                   = 102\nHTTP_OK                           = 200\nHTTP_CREATED                      = 201\nHTTP_ACCEPTED                     = 202\nHTTP_NON_AUTHORITATIVE            = 203\nHTTP_NO_CONTENT                   = 204\nHTTP_RESET_CONTENT                = 205\nHTTP_PARTIAL_CONTENT              = 206\nHTTP_MULTI_STATUS                 = 207\nHTTP_MULTIPLE_CHOICES             = 300\nHTTP_MOVED_PERMANENTLY            = 301\nHTTP_MOVED_TEMPORARILY            = 302\nHTTP_SEE_OTHER                    = 303\nHTTP_NOT_MODIFIED                 = 304\nHTTP_USE_PROXY                    = 305\nHTTP_TEMPORARY_REDIRECT           = 307\nHTTP_BAD_REQUEST                  = 400\nHTTP_UNAUTHORIZED                 = 401\nHTTP_PAYMENT_REQUIRED             = 402\nHTTP_FORBIDDEN                    = 403\nHTTP_NOT_FOUND                    = 404\nHTTP_METHOD_NOT_ALLOWED           = 405\nHTTP_NOT_ACCEPTABLE               = 406\nHTTP_PROXY_AUTHENTICATION_REQUIRED= 407\nHTTP_REQUEST_TIME_OUT             = 408\nHTTP_CONFLICT                     = 409\nHTTP_GONE                         = 410\nHTTP_LENGTH_REQUIRED              = 411\nHTTP_PRECONDITION_FAILED          = 412\nHTTP_REQUEST_ENTITY_TOO_LARGE     = 413\nHTTP_REQUEST_URI_TOO_LARGE        = 414\nHTTP_UNSUPPORTED_MEDIA_TYPE       = 415\nHTTP_RANGE_NOT_SATISFIABLE        = 416\nHTTP_EXPECTATION_FAILED           = 417\nHTTP_IM_A_TEAPOT                  = 418\nHTTP_UNPROCESSABLE_ENTITY         = 422\nHTTP_LOCKED                       = 423\nHTTP_FAILED_DEPENDENCY            = 424\nHTTP_UPGRADE_REQUIRED             = 426\nHTTP_INTERNAL_SERVER_ERROR        = 500\nHTTP_NOT_IMPLEMENTED              = 501\nHTTP_BAD_GATEWAY                  = 502\nHTTP_SERVICE_UNAVAILABLE          = 503\nHTTP_GATEWAY_TIME_OUT             = 504\nHTTP_VERSION_NOT_SUPPORTED        = 505\nHTTP_VARIANT_ALSO_VARIES          = 506\nHTTP_INSUFFICIENT_STORAGE         = 507\nHTTP_NOT_EXTENDED                 = 510\n\n# The APLOG constants in Apache are derived from syslog.h\n# constants, so we do same here.\n\ntry:\n    import syslog\n    APLOG_EMERG = syslog.LOG_EMERG     # system is unusable\n    APLOG_ALERT = syslog.LOG_ALERT     # action must be taken immediately\n    APLOG_CRIT = syslog.LOG_CRIT       # critical conditions\n    APLOG_ERR = syslog.LOG_ERR         # error conditions\n    APLOG_WARNING = syslog.LOG_WARNING # warning conditions\n    APLOG_NOTICE = syslog.LOG_NOTICE   # normal but significant condition\n    APLOG_INFO = syslog.LOG_INFO       # informational\n    APLOG_DEBUG = syslog.LOG_DEBUG     # debug-level messages\nexcept ImportError:\n    APLOG_EMERG = 0\n    APLOG_ALERT = 1\n    APLOG_CRIT = 2\n    APLOG_ERR = 3\n    APLOG_WARNING = 4\n    APLOG_NOTICE = 5\n    APLOG_INFO = 6\n    APLOG_DEBUG = 7\n\nAPLOG_NOERRNO = 0 # DEPRECATED\nOK = REQ_PROCEED = 0\nDONE = -2\nDECLINED = REQ_NOACTION = -1\n\n_phase_handler_names = {}\nfor _phase in ["PythonPostReadRequestHandler",\n              "PythonTransHandler",\n              "PythonHeaderParserHandler",\n              "PythonInitHandler",\n              "PythonAccessHandler",\n              "PythonAuthenHandler",\n              "PythonAuthzHandler",\n              "PythonTypeHandler",\n              "PythonFixupHandler",\n              "PythonHandler",\n              "PythonLogHandler",\n              "PythonCleanupHandler"]:\n    _phase_handler_names[_phase] = _phase[len("python"):].lower()\n\n_status_values = {\n    "postreadrequesthandler":   [ DECLINED, OK ],\n    "transhandler":             [ DECLINED ],\n    "headerparserhandler":      [ DECLINED, OK ],\n    "inithandler":              [ DECLINED, OK ],\n    "accesshandler":            [ DECLINED, OK ],\n    "authenhandler":            [ DECLINED ],\n    "authzhandler":             [ DECLINED ],\n    "typehandler":              [ DECLINED ],\n    "fixuphandler":             [ DECLINED, OK ],\n    "handler":                  [ OK ],\n    "loghandler":               [ DECLINED, OK ],\n    "cleanuphandler":           [ OK ],\n}\n\n# constants for get_remote_host\nREMOTE_HOST = 0\nREMOTE_NAME = 1\nREMOTE_NOLOOKUP = 2\nREMOTE_DOUBLE_REV = 3\n\n# legacy/mod_python things\nREQ_ABORTED = HTTP_INTERNAL_SERVER_ERROR\nREQ_EXIT = "REQ_EXIT"\nSERVER_RETURN = _apache.SERVER_RETURN\n\n# the req.finfo tuple\nFINFO_MODE = 0\nFINFO_INO = 1\nFINFO_DEV = 2\nFINFO_NLINK = 3\nFINFO_UID = 4\nFINFO_GID = 5\nFINFO_SIZE = 6\nFINFO_ATIME = 7\nFINFO_MTIME = 8\nFINFO_CTIME = 9\nFINFO_FNAME = 10\nFINFO_NAME = 11\nFINFO_FILETYPE = 12\n\n# the req.parsed_uri\nURI_SCHEME = 0\nURI_HOSTINFO = 1\nURI_USER = 2\nURI_PASSWORD = 3\nURI_HOSTNAME = 4\nURI_PORT = 5\nURI_PATH = 6\nURI_QUERY = 7\nURI_FRAGMENT = 8\n\n# for req.proxyreq\nPROXYREQ_NONE = 0       # No proxy\nPROXYREQ_PROXY = 1      # Standard proxy\nPROXYREQ_REVERSE = 2    # Reverse proxy\nPROXYREQ_RESPONSE = 3   # Origin response\n\n# methods for req.allow_method()\nM_GET = 0               # RFC 2616: HTTP\nM_PUT = 1\nM_POST = 2\nM_DELETE = 3\nM_CONNECT = 4\nM_OPTIONS = 5\nM_TRACE = 6             # RFC 2616: HTTP\nM_PATCH = 7\nM_PROPFIND = 8          # RFC 2518: WebDAV\nM_PROPPATCH = 9\nM_MKCOL = 10\nM_COPY = 11\nM_MOVE = 12\nM_LOCK = 13\nM_UNLOCK = 14           # RFC2518: WebDAV\nM_VERSION_CONTROL = 15  # RFC3253: WebDAV Versioning\nM_CHECKOUT = 16\nM_UNCHECKOUT = 17\nM_CHECKIN = 18\nM_UPDATE = 19\nM_LABEL = 20\nM_REPORT = 21\nM_MKWORKSPACE = 22\nM_MKACTIVITY = 23\nM_BASELINE_CONTROL = 24\nM_MERGE = 25\nM_INVALID = 26           # RFC3253: WebDAV Versioning\n\n# for req.used_path_info\nAP_REQ_ACCEPT_PATH_INFO = 0  # Accept request given path_info\nAP_REQ_REJECT_PATH_INFO = 1  # Send 404 error if path_info was given\nAP_REQ_DEFAULT_PATH_INFO = 2 # Module\'s choice for handling path_info\n\n\n# for mpm_query\nAP_MPMQ_NOT_SUPPORTED      = 0  # This value specifies whether\n                                # an MPM is capable of\n                                # threading or forking.\nAP_MPMQ_STATIC             = 1  # This value specifies whether\n                                # an MPM is using a static # of\n                                # threads or daemons.\nAP_MPMQ_DYNAMIC            = 2  # This value specifies whether\n                                # an MPM is using a dynamic # of\n                                # threads or daemons.\n\nAP_MPMQ_MAX_DAEMON_USED    = 1  # Max # of daemons used so far\nAP_MPMQ_IS_THREADED        = 2  # MPM can do threading\nAP_MPMQ_IS_FORKED          = 3  # MPM can do forking\nAP_MPMQ_HARD_LIMIT_DAEMONS = 4  # The compiled max # daemons\nAP_MPMQ_HARD_LIMIT_THREADS = 5  # The compiled max # threads\nAP_MPMQ_MAX_THREADS        = 6  # # of threads/child by config\nAP_MPMQ_MIN_SPARE_DAEMONS  = 7  # Min # of spare daemons\nAP_MPMQ_MIN_SPARE_THREADS  = 8  # Min # of spare threads\nAP_MPMQ_MAX_SPARE_DAEMONS  = 9  # Max # of spare daemons\nAP_MPMQ_MAX_SPARE_THREADS  = 10 # Max # of spare threads\nAP_MPMQ_MAX_REQUESTS_DAEMON= 11 # Max # of requests per daemon\nAP_MPMQ_MAX_DAEMONS        = 12 # Max # of daemons by config\n\n# magic mime types\nCGI_MAGIC_TYPE = "application/x-httpd-cgi"\nINCLUDES_MAGIC_TYPE = "text/x-server-parsed-html"\nINCLUDES_MAGIC_TYPE3 = "text/x-server-parsed-html3"\nDIR_MAGIC_TYPE = "httpd/unix-directory"\n\n# for req.read_body\nREQUEST_NO_BODY = 0\nREQUEST_CHUNKED_ERROR = 1\nREQUEST_CHUNKED_DECHUNK = 2\n\n# for req.connection.keepalive\nAP_CONN_UNKNOWN = _apache.AP_CONN_UNKNOWN\nAP_CONN_CLOSE = _apache.AP_CONN_CLOSE\nAP_CONN_KEEPALIVE = _apache.AP_CONN_KEEPALIVE\n\n# for req.finfo[apache.FINFO_FILETYPE]\nAPR_NOFILE = _apache.APR_NOFILE\nAPR_REG = _apache.APR_REG\nAPR_DIR = _apache.APR_DIR\nAPR_CHR = _apache.APR_CHR\nAPR_BLK = _apache.APR_BLK\nAPR_PIPE = _apache.APR_PIPE\nAPR_LNK = _apache.APR_LNK\nAPR_SOCK = _apache.APR_SOCK\nAPR_UNKFILE = _apache.APR_UNKFILE\n\n# module magic\nMODULE_MAGIC_NUMBER_MAJOR = _apache.MODULE_MAGIC_NUMBER_MAJOR\nMODULE_MAGIC_NUMBER_MINOR = _apache.MODULE_MAGIC_NUMBER_MINOR\n\n# for apache.stat()\nAPR_FINFO_LINK = 0x00000001 # Stat the link not the file itself if it is a link\nAPR_FINFO_MTIME = 0x00000010 # Modification Time\nAPR_FINFO_CTIME = 0x00000020 # Creation or inode-changed time\nAPR_FINFO_ATIME = 0x00000040 # Access Time\nAPR_FINFO_SIZE = 0x00000100 # Size of the file\nAPR_FINFO_CSIZE = 0x00000200 # Storage size consumed by the file\nAPR_FINFO_DEV = 0x00001000 # Device\nAPR_FINFO_INODE = 0x00002000 # Inode\nAPR_FINFO_NLINK = 0x00004000 # Number of links\nAPR_FINFO_TYPE = 0x00008000 # Type\nAPR_FINFO_USER = 0x00010000 # User\nAPR_FINFO_GROUP = 0x00020000 # Group\nAPR_FINFO_UPROT = 0x00100000 # User protection bits\nAPR_FINFO_GPROT = 0x00200000 # Group protection bits\nAPR_FINFO_WPROT = 0x00400000 # World protection bits\nAPR_FINFO_ICASE = 0x01000000 # if dev is case insensitive\nAPR_FINFO_NAME = 0x02000000 # ->name in proper case\nAPR_FINFO_MIN = 0x00008170 # type, mtime, ctime, atime, size\nAPR_FINFO_IDENT = 0x00003000 # dev and inode\nAPR_FINFO_OWNER = 0x00030000 # user and group\nAPR_FINFO_PROT = 0x00700000 # all protections\nAPR_FINFO_NORM = 0x0073b170 # an atomic unix apr_stat()\nAPR_FINFO_DIRENT = 0x02000000 # an atomic unix apr_dir_read()\n', 'message': 'small but significant typo\n\n', 'author_name': 'grisha', 'lang': 'py'}