[APACHE DOCUMENTATION]

Module mod_pyapache

This module is contained in the mod_pyapache.c file, and is not compiled in by default. It allows the server to execute Python Scripts natively, without the need of an external Python Interpreter. Moreover, it provides access to the server API, so that your scripts may access the runtime internals of Apache.

Summary

The server normally treats Python Scripts in the same way as any other CGI Scripts: each of them is feeded to the underlying Operating System, requesting it to run them in some way, that is usually to launch an external interpreter (some kind of shell for Shell Scripts, Perl for Perl Scripts, and so on) and telling it to execute the script.

To increase efficency, this module embeds directly in the server the Python Interpreter, thus allowing the server itself to execute this kind of scripts.


Activation

The module is enabled by putting somewhere in the srm.conf file
AddHandler python/x-httpd-cgi .py
to mean that whenever the server is asked for a resource whose name ends with .py it should treat it through this module.

Directives

This module adds five directives that alter in some way the execution of the scripts. They may be used indifferently in any Apache's config file, either from a <Directory> section in the access.conf, or from defaults in srm.conf.

PythonPath

Syntax: PythonPath pathnames:to:prepend:to:the:standard:loadpath
Context: directory, .htaccess
Status: Extension
Module: mod_pyapache

The PythonPath directive lets you add the location of the modules you will import in the scripts. The standard load path is computed at compile time, usually to /usr/local/lib/python1.4:/usr/local/lib/python1.4/mach-dep:/usr/local/lib/python1.4/sharedmodules; with this directive you may add the location of your modules to the standard path. Example:

<Directory /usr/local/etc/apache/cgi-bin/lele>
PythonPath /users/lele/Library/testing-python
adds the given path in front of the standard one when executing Python Scripts in a particular directory.

PythonVerbose

Syntax: PythonVerbose boolean
Default: PythonVerbose off
Context: directory, .htaccess
Status: Extension
Module: mod_pyapache

This directive enables the verbosity flag of the embedded Python Interpreter; its use is mainly for debugging purposes, and it is the equivalent of the Python -v command line option. Boolean is either on or off. I found it particularly handy to find out that I was importing an old version of a module instead of the `current' one: by turning on verbosity you will get a trace of the imports in the error log file (usually `logs/error_log'):

# /usr/local/lib/python1.4/os.pyc matches /usr/local/lib/python1.4/os.py
import os # precompiled from /usr/local/lib/python1.4/os.pyc
import posix # builtin
# /usr/local/lib/python1.4/posixpath.pyc matches /usr/local/lib/python1.4/posixpath.py
import posixpath # precompiled from /usr/local/lib/python1.4/posixpath.pyc
# /usr/local/lib/python1.4/stat.pyc matches /usr/local/lib/python1.4/stat.py
import stat # precompiled from /usr/local/lib/python1.4/stat.pyc

PythonDebug

Syntax: PythonDebug boolean
Default: PythonDebug off
Context: directory, .htaccess
Status: Extension
Module: mod_pyapache

This directive enables the debug flag of the embedded Python Interpreter; its use is mainly for debugging purposes, and it is the equivalent of the Python -d command line option. Boolean is either on or off.

PythonPersistent

Syntax: PythonPersistent boolean
Default: PythonPersistent off
Context: directory, .htaccess
Status: Extension
Module: mod_pyapache

First of all be warned: this functionality needs more test.

  Guido van Rossum, the author of Python, on Wed, 12 Jun 1996 said:

    """Alas, there really is no way to reset the interpreter to
       virginal state without the possibility of leaking memory. You
       either have to trust your CGI scripts not to mess with other
       modules and not to create circular links, or you have to fork
       it as a subprocess."""
Normally the execution of a Python script (as well as any other CGI script) needs a new process to be created (forked in Unix terminology) by the Apache server. This step may be eliminated by enabling this feature: in this way the script gets executed in the same process space of the server, speeding up a little bit the operation.

PythonTrustedScripts

Syntax: PythonTrustedScripts boolean
Default: PythonPersistent on
Context: directory, .htaccess
Status: Extension
Module: mod_pyapache

This directive can be used in persistent mode only, and when On the Python Interpreter gets initialized once, and never destroyed; imported module are never released; sys.stderr remains hooked to the server's error_log lifetime. On the other hand, a module gets imported almost once, so you cannot count on import side effects.

When turned Off, each script execution is bracketed between a Py_Initialize() and PyImport_Cleanup(): since the latter does not completely release Python Interpreter, there will be memory leaks for EACH HANDLED REQUEST. For this reason, this option is activated by default when in PythonPersistent mode.


Apache Module

This section of the manual is not complete: it's here mostly to encourage someone to fill it. Its content assumes you already know both the Python language and the internals of the Apache server.

From within a Python Script you may want to access the details of the current request. This can be done by importing the module Apache.

The Apache module has just one member, .request, which is an instance of the ApacheRequest class.

ApacheRequest object

An instance of this class encapsulates the request currently served by the Apache server.

ApacheConnection object

An instance of this class wraps...

ApacheServer object

An instance of this class wraps...

ApacheBuffer object

This is probably the smarter (?) object in this module: it is an approximation of a Python fileobject, in the sense that it implements just the very basic methods of such an object: read, write and a do-nothing flush; they are enough to hook an instance of it in place of the standard fileobject sys.stdin and sys.stdout.

The read method will return a string composed of bytes coming from the client, thus giving the script access to the arguments of a M_POST or a M_PUT request.

The write method needs additional machinery: until it does not find the end-of-headers condition it will collect them, updating the internal tables of the server, like scan_script_headers() does. To complicate things, we have to parse headers `incrementally', since we aren't getting them from a stream, but directly as the script writes them on its output. Once the headers come at end, the remaining stuff is sent to the client, as usual. This step does not happen for NPH scripts: the output of the script is sent directly to the client.

The flush method is there for compatibility: it lets you use your `old' scripts, where you used to add a "sys.stdout.flush()" to sync the script output.

ApacheTable object

An instance of this class approximates a Python dictionary, and it's a wrapper around the Apache's table objects.

Example

import Apache

print "Content-type: text/html"
print

r = Apache.request
print "Request's doc: ", r.__doc__
print "Request's text: ", r.the_request
print "Request's members: ", r.__members__
print "Remote host: ", r.get_remote_host()
try:
    print r.get_remote_logname()
except Apache.error, m:
    print "Cannot get remote logname: ", m

c = r.connection
print "Connection's doc: ", c.__doc__
print "Connection's remote IP: ", c.remote_ip
print "Connection's members: ", c.__members__

print "Headers in: ", r.headers_in.items()
print "Headers out: ", r.headers_out.items()
print "Err Headers out: ", r.err_headers_out.items()
print "Subprocess env: ", r.subprocess_env.items()
print "Notes: ", r.notes.items()

s = c.server
print "Server's doc: ", s.__doc__
print "Server's admin: ", s.server_admin
print "Server's members: ", s.__members__

This gives:

Request's doc:  ApacheRequest is a Python wrapper around the Apache's `request_rec' object.
Request's text:  GET /~lele/pyapache.py
Request's members:  ['args', 'assbackwards', 'content_encoding', 'content_language', 'content_type', 'filename', 'handler', 'header_only', 'hostname', 'method', 'path_info', 'protocol', 'proxyreq', 'status_line', 'the_request', 'uri', 'server', 'connection', 'headers_in', 'headers_out', 'err_headers_out', 'subprocess_env', 'notes']
Remote host:  localhost
Cannot get remote logname:  Cannot access `remote_logname'
Connection's doc:  ApacheConnection is a Python wrapper around the Apache's `connection' object.
Connection's remote IP:  127.0.0.1
Connection's members:  ['auth_type', 'keepalive', 'keepalives', 'keptalive', 'remote_ip', 'user', 'server']
Headers in:  []
Headers out:  []
Err Headers out:  []
Subprocess env:  [('PATH', '/etc:/usr/etc:/usr/ucb:/bin:/usr/bin:/usr/local/bin:/usr/sybase/bin:/LocalApps:/NextApps:/NextAdmin:/NextDeveloper/Demos'), ('SERVER_SOFTWARE', 'Apache/1.2b4'), ('SERVER_NAME', 'nautilus'), ('SERVER_PORT', '80'), ('REMOTE_HOST', 'localhost'), ('REMOTE_ADDR', '127.0.0.1'), ('DOCUMENT_ROOT', '/usr/local/etc/apache/htdocs'), ('SERVER_ADMIN', 'lele@nautilus.eclipse.it'), ('SCRIPT_FILENAME', '/users/lele/public_html/pyapache.py'), ('REMOTE_PORT', '2623'), ('GATEWAY_INTERFACE', 'CGI/1.1'), ('SERVER_PROTOCOL', 'HTTP/0.9'), ('REQUEST_METHOD', 'GET'), ('QUERY_STRING', ''), ('SCRIPT_NAME', '/~lele/pyapache.py')]
Notes:  []
Server's doc:  ApacheServer is a Python wrapper around Apache's `server' object.
Server's admin:  lele@nautilus.eclipse.it
Server's members:  ['access_confname', 'port', 'server_admin', 'server_hostname', 'srm_confname']

Index Home