ajp-wsgi

Contents

Introduction

ajp-wsgi is a WSGI [1] server/gateway that implements AJP 1.3 [2] to communicate with a web server [3]. It is written in C and embeds a Python interpreter to run the actual application. Since all of the low-level transport code is in C, ajp-wsgi is significantly faster than flup's [4] pure-Python ajp server.

ajp-wsgi supports both threading and forking.

[1](1, 2) http://www.python.org/dev/peps/pep-0333/
[2]http://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html
[3]Typically, you would use tomcat-connectors (for Apache HTTPD 1.3.x, 2.0.x, or even IIS) or mod_proxy_ajp (included with Apache HTTPD 2.2.x) to connect your web server to ajp-wsgi.
[4]http://www.saddi.com/software/flup/

Features

  • Wholly written in C - the Python Global Interpreter Lock only enters the picture when calling the WSGI application, allowing greater concurrency.
  • If the iterable returned by the WSGI application has a length and that length is 1, the Content-Length header is automatically deduced.
  • Supports the wsgi.file_wrapper feature. On some platforms (i.e. FreeBSD), it is implemented using the OS-level sendfile(2) syscall.

Downloading

The latest version of ajp-wsgi may be found at http://www.saddi.com/software/ajp-wsgi/dist/

Building

First execute configure.py with the version of Python you wish to embed. So far ajp-wsgi has been tested with Python 2.3, 2.4, 2.5, 2.6, and 2.7.

python configure.py

Next, execute make. If everything goes well, you should have an ajp-wsgi executable that's ready to use.

At this time, ajp-wsgi is only confirmed to compile/work on FreeBSD 6.x, Mac OS X 10.6, and (Gentoo) Linux. Other Linux distros probably work as well. Patches and/or suggestions to improve portability are highly welcome!

Using

Before using ajp-wsgi, you most likely want to set two important environment variables: PYTHONHOME and PYTHONPATH.

PYTHONHOME determines where ajp-wsgi will import its standard Python modules. If you are using a "virtual" Python installation, set this to the base directory of your installation. Otherwise, leave it unset to use your default Python's modules (the Python found in your PATH).

For example:

export PYTHONHOME=/home/myusername

PYTHONPATH is any additional directories to search for Python modules. Note that the current directory is always searched first. For example, to search the directories named mymodules and othermodules in your home directory:

export PYTHONPATH=$HOME/mymodules:$HOME/othermodules

Note that other standard Python environment variables are also accepted by the embedded interpreter, e.g. PYTHONOPTIMIZE.

Finally, to actually use ajp-wsgi, simply execute it with the name of the module for your WSGI application, and the name of your application's object within that module:

ajp-wsgi myappmodule app

By default, ajp-wsgi will listen on port 8009.

Options

The ajp-wsgi command-line options take the following form:

ajp-wsgi [-BFQVv] [-l <logFile>]
         [-h <ifname>] [-p <port>]
         [-n <maxConnections>]
         <moduleName> <appName> [<scriptName>]

Where:

-V Report version and exit.
-v Run verbosely.
-B Run in the background. It is strongly recommended that you use the -l logFile option as well.
-F Use a new process (fork) for each AJP connection, rather than a new thread.
-Q Do not attempt to decode REQUEST_URI/PATH_INFO. [6]
-l logFile Redirect stderr to logFile. stderr is where most of the useful diagnostic messages (tracebacks, etc.) go.
-h ifname Bind to interface ifname rather than localhost. May be a resolvable name or an IPv4/IPv6 address.
-p port Listen on port port rather than 8009.
-n maxConnections
 Maximum number of threads or processes. When threading, default is MAX_INT, i.e. effectively unlimited. When forking, the default is 16. Note that the -t option served the same purpose in previous versions. As of 1.1, it is deprecated, but it will still set maxConnections correctly.
moduleName
Name of the Python module to import. sys.path (which includes the current directory) will be searched for the module. Use the PYTHONPATH environment variable to add more search paths.
appName
Name of the application object within the module. This must be a Python callable object that takes 2 arguments. See [1] for more information.
scriptName

By default, ajp-wsgi assumes your application is mounted at the virtual host root. If it isn't, you will need to specify its mount point (aka context) as the third argument to ajp-wsgi.

For example:

ajp-wsgi myappmodule app /foo

If the application is mounted at http://example.com/foo

Not setting this correctly will result in an erroneous PATH_INFO being passed to your application... which will probably break it.

[6]If using mod_jk with the ForwardURICompat option (the default), this option is needed to ensure that the REQUEST_URI is not decoded twice. If using mod_proxy_ajp or mod_jk with the ForwardURIEscaped option, there is no need to use this option.

Exit Codes

ajp-wsgi exits 0 if it received a SIGINT or SIGTERM; 1 if there is a problem with the command-line arguments; 2 if there is a general problem (e.g. socket errors, thread errors, out of memory); and 3 if it received a SIGHUP.

License

ajp-wsgi is licensed under a standard 2-clause BSD license, reproduced below:

Copyright (c) 2006 Allan Saddi <allan@saddi.com>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

Support

Please direct any questions to me at <allan@saddi.com>.

Please submit bug reports or patches at my general Trac site.

Now and then, there may be ajp-wsgi related news under the Python category of my projects blog.