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.
To increase efficency, this module embeds directly in the server the Python Interpreter, thus allowing the server itself to execute this kind of scripts.
AddHandler python/x-httpd-cgi .pyto mean that whenever the server is asked for a resource whose name ends with .py it should treat it through this module.
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>adds the given path in front of the standard one when executing Python Scripts in a particular directory.
PythonPath /users/lele/Library/testing-python
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
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.
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.
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.
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.
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.
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']