scgi-wsgi

Contents

Introduction

scgi-wsgi is a WSGI [1] server/gateway that implements SCGI [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, scgi-wsgi is significantly faster than any pure-Python (or hybrid) SCGI servers.

scgi-wsgi supports both threading and forking.

[1](1, 2) http://www.python.org/dev/peps/pep-0333/
[2]http://www.python.ca/scgi/protocol.txt
[3]Typically, you would use mod_scgi or mod_proxy_scgi (included with Apache HTTPD 2.2.14+) to connect your web server to scgi-wsgi.

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 scgi-wsgi may be found at http://www.saddi.com/software/scgi-wsgi/dist/

Building

First execute configure.py with the version of Python you wish to embed. So far scgi-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 scgi-wsgi executable that's ready to use.

At this time, scgi-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 scgi-wsgi, you most likely want to set two important environment variables: PYTHONHOME and PYTHONPATH.

PYTHONHOME determines where scgi-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 scgi-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:

scgi-wsgi myappmodule app

By default, scgi-wsgi will listen on port 4000.

Options

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

scgi-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 SCGI request, rather than a new thread.
-Q Do not attempt to decode REQUEST_URI/PATH_INFO.
-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 4000.
-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.
-m minConnections
 Minimum number of processes to maintain in the process pool. Only has meaning when forking. Default is 1.
-i maxIdle Maximum time a thread or process can remain idle in the pool in seconds. Default is 300 (5 minutes).
-E profile Set environment profile for SCGI. Default is pass-through. Other available profiles are request-uri and script-name. Only the shortest unique prefix needs to be given, which happens to be p, r, and s.
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, scgi-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 scgi-wsgi.

For example:

scgi-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.

Exit Codes

scgi-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.

Environment Profiles

Due to the inconsistency between the various SCGI connectors, you may need to specify an environment profile using the -E option. The default profile is pass-through. The profiles are described below:

  • pass-through passes SCRIPT_NAME and PATH_INFO unchanged from the connector. REQUEST_URI will be unquoted unless the -Q option is used. Any scriptName passed from the command-line (or via WSGI_SCRIPT_NAME) is ignored. This profile is meant for the original mod_scgi available at http://python.ca/scgi/
  • request-uri only trusts REQUEST_URI and derives SCRIPT_NAME and PATH_INFO from it. scriptName must be given from the command-line (or via WSGI_SCRIPT_NAME) if the application resides at a non-root location. This profile is meant for Apache HTTPD's mod_proxy_scgi.
  • script-name only trusts SCRIPT_NAME and PATH_INFO. It forms REQUEST_URI by their concatenation and then re-derives SCRIPT_NAME and PATH_INFO using scriptName given from the command-line (or WSGI_SCRIPT_NAME). This option is here for completeness.

Other SCGI modules (e.g. for lighttpd and nginx) have not yet been tested, but I imagine their handling of SCRIPT_NAME/PATH_INFO falls under one of the above.

License

scgi-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 scgi-wsgi related news under the Python category of my projects blog.