[[FastCGI]]

FastCGI Developer's Kit

Mark R. Brown
Open Market, Inc.

Document Version: 1.08
11 June 1996

Copyright © 1996 Open Market, Inc. 245 First Street, Cambridge, MA 02142 U.S.A.
Tel: 617-621-9500 Fax: 617-621-1703 URL: http://www.openmarket.com/
$Id: fcgi-devel-kit.htm,v 1.6 2002/02/25 00:42:59 robs Exp $


1. Introduction

FastCGI is an open extension to CGI that provides high performance for all Internet applications without the penalties of Web server APIs.

FastCGI is designed to be layered on top of existing Web server APIs. For instance, the mod_fastcgi Apache module adds FastCGI support to the Apache server. FastCGI can also be used, with reduced functionality and reduced performance, on any Web server that supports CGI.

This FastCGI Developer's Kit is designed to make developing FastCGI applications easy. The kit currently supports FastCGI applications written in C/C++, Perl, Tcl, and Java.

This document:

The kit includes a technical white paper, doc/fastcgi-whitepaper/fastcgi.htm. You should read at least the first three sections of the technical white paper before starting to write FastCGI applications. The performance paper will help you understand how application design affects performance with FastCGI.

The FastCGI Specification, doc/fcgi-spec.html, defines the interface between a FastCGI application and a Web server that supports FastCGI. The software in the kit implements the specification. You don't need to read the specification in order to write applications.

Additional information is provided in the FAQ document, which contains frequently asked questions about application development using FastCGI, as well as some general information.

Experience with CGI programming will be extremely valuable in writing FastCGI applications. If you don't have enough experience with CGI programming, you should read one information on the W3C CGI page.

2. Getting started

The kit is a compressed tar (tar.Z) file, distributed via the fastcgi-archives.github.io Web page. Unpacking the tar file creates a new directory fcgi-devel-kit.

Open the kit's index page, fcgi-devel-kit/index.html, using the "Open File" command in your Web browser. The index page gives you an overview of the kit structure and helps you navigate the kit. The index page also contains links that run some example applications, but the applications won't work when index.html is opened using the "Open File" command because they aren't aren't being accessed through a Web server.

In order to use the kit in earnest you'll need a Web server that you control, a Web server running with your user ID. The Web server will be starting FastCGI applications that you will need to debug; this will be a lot more convenient for you if these processes run with your user ID. It is best to have a Web server that supports FastCGI. Section 4 discusses Web server issues.

If you can, keep the kit on a file system accessible from your personal workstation, do your builds on your workstation, and run your Web server on your workstation. If that's not possible, arrange a configuration such that the kit is accessible from the machine that's going to run your Web server, and build the kit and your applications on a machine that's configured exactly the same way (same processor architecture, operating system, etc.) as the machine that's going to run your Web server.

To build the kit you execute this sequence of commands in the fcgi-devel-kit directory:

    % ./configure
    % make

We've built and exercised the kit on these platforms (listed in alphabetical order):

Once you've built the kit, follow the directions in Section 4 to bring up your Web server and run the example applications.

3. Writing applications

3.1 Using the fcgi_stdio library

The fcgi_stdio library provides the easiest transition for C CGI programs and C CGI programmers to FastCGI. Using this library your application can run using either CGI or FastCGI, with the same binary for both situations.

To introduce the fcgi_stdio library we give a pair of examples: a tiny CGI program and the translation of this program to FastCGI. These two example programs are included in the kit.

The CGI program is examples/tiny-cgi.c:

    #include <stdio.h>
    #include <stdlib.h>

    void main(void)
    {
        int count = 0;
        printf("Content-type: text/html\r\n"
               "\r\n"
               "<title>CGI Hello!</title>"
               "<h1>CGI Hello!</h1>"
               "Request number %d running on host <i>%s</i>\n",
               ++count, getenv("SERVER_NAME"));
    }

The key features of this tiny CGI program are:

The count variable is degenerate in this example; the CGI program runs a single request, so the request number is always one. This variable will be more interesting in the FastCGI example.

The corresponding FastCGI program is examples/tiny-fcgi.c:

    #include "fcgi_stdio.h"
    #include <stdlib.h>

    void main(void)
    {
        int count = 0;
        while(FCGI_Accept() >= 0)
            printf("Content-type: text/html\r\n"
                   "\r\n"
                   "<title>FastCGI Hello!</title>"
                   "<h1>FastCGI Hello!</h1>"
                   "Request number %d running on host <i>%s</i>\n",
                    ++count, getenv("SERVER_NAME"));
    }

The key features of this tiny FastCGI program are:

The count variable increments each time through the loop, so the program displays a new request number each time. You can use the reload button in your browser to demonstrate this, once you've got the program built and running.

Building the program

If you can build examples/tiny-cgi.c, it will be straightforward for you to build examples/tiny-fcgi.c. You need to:

See examples/Makefile (created by configure) for a Makefile that builds both programs. Autoconf handles the platform-dependent linking issues; to see how, examine configure.in and examples/Makefile.in.

Running the program

Section 4 is all about how to run FastCGI applications.

You can use CGI to run application binaries built with the fcgi_stdio library. The FCGI_Accept function tests its environment to determine how the application was invoked. If it was invoked as a CGI program, the first call to FCGI_Accept is essentially a no-op and the second call returns -1. In effect, the request loop disappears.

Of course, when a FastCGI application is run using CGI it does not get the benefits of FastCGI. For instance, the application exits after servicing a single request, so it cannot maintain cached information.

Implementation details

fcgi_stdio.h works by first including stdio.h, then defining macros to replace essentially all of the types and procedures defined in stdio.h. (stdio.h defines a few procedures that have nothing to do with FILE *, such as sprintf and sscanf; fcgi_stdio.h doesn't replace these.) For instance, FILE becomes FCGI_FILE and printf becomes FCGI_printf. You'll only see these new names if you read fcgi_stdio.h or examine your C source code after preprocessing.

Here are some consequences of this implementation technique:

Converting CGI programs

The main task in converting a CGI program into a FastCGI program is separating the code that needs to execute once, initializing the program, from the code that needs to run for each request. In our tiny example, initializing the count variable is outside the loop, while incrementing the count variable goes inside.

Retained application state may be an issue. You must ensure that any application state created in processing one request has no unintended effects on later requests. FastCGI offers the possibility of significant application performance improvements, through caching; it is up to you to make the caches work correctly.

Storage leaks may be an issue. Many CGI programs don't worry about storage leaks because the programs don't run for long enough for bloating to be a problem. When converting to FastCGI, you can either use a tool such as Valgrind to discover and fix storage leaks, or you can run a C garbage collector such as Boehm-Demers-Weiser conservative garbage collector

Limitations

Currently there are some limits to the compatibility provided by the fcgi_stdio library:

Reference documentation

The FCGI_Accept manpage, doc/FCGI_Accept.3, describes the function in the traditional format.

The FCGI_Finish (doc/FCGI_Finish.3), FCGI_SetExitStatus (doc/FCGI_SetExitStatus.3), and FCGI_StartFilterData (doc/FCGI_StartFilterData.3) manpages document capabilities of the fcgi-stdio library that are not illustrated above.

3.2 Using the fcgiapp library

The fcgiapp library is a second C library for FastCGI. It does not provide the high degree of source code compatibility provided by fcgi_stdio; in return, it does not make such heavy use of #define. fcgi_stdio is implemented as a thin layer on top of fcgiapp.

Applications built using the fcgiapp library cannot run as CGI programs; that feature is provided at the fcgi_stdio level.

Functions defined in fcgiapp are named using the prefix FCGX_ rather than FCGI_. For instance, FCGX_Accept is the fcgiapp version of FCGI_Accept.

Documentation of the fcgiapp library takes the form of extensive comments in the header file include/fcgiapp.h. The sample programs examples/tiny-fcgi2.c and examples/echo2.c illustrate how to use fcgiapp.

3.3 Using Perl and Tcl

A major advantage of the FastCGI approach to high-performance Web applications is its language-neutrality. CGI scripts written in popular languages such as Perl and Tcl can be evolved into high-performance FastCGI applications.

We have produced FastCGI-integrated Perl and Tcl interpreters. Doing so was easy, since Perl and Tcl are conventional C applications and fcgi_stdio was designed for converting conventional C applications. Essentially no source code changes were required in these programs; a small amount of code was added in order to make FCGI_Accept and other FastCGI primitives available in these languages. And because these interpreters were developed using fcgi_stdio, they run standard Perl and Tcl applications (e.g. CGI scripts) as well as FastCGI applications.

See the fastcgi-archives.github.io Web page for more information about the Perl and Tcl libraries.

Here are the Perl and Tcl versions of tiny-fcgi:

#!./perl
use FCGI;
$count = 0;
while(FCGI::accept() >= 0) {
    print("Content-type: text/html\r\n\r\n",
          "<title>FastCGI Hello! (Perl)</title>\n",
          "<h1>FastCGI Hello! (Perl)</h1>\n";
          "Request number ",  ++$count,
          " running on host <i>";$env(SERVER_NAME)</i>");
}
#!./tclsh
set count 0 
while {[FCGI_Accept] >= 0 } {
    incr count
    puts -nonewline "Content-type: text/html\r\n\r\n"
    puts "<title>FastCGI Hello! (Tcl)</title>"
    puts "<h1>FastCGI Hello! (Tcl)</h1>"
    puts "Request number $count running on host <i>$env(SERVER_NAME)</i>"
}

Converting a Perl or Tcl CGI application to FastCGI is not fundamentally different from converting a C CGI application to FastCGI. You separate the portion of the application that performs one-time initialization from the portion that performs per-request processing. You put the per-request processing into a loop controlled by FCGI::accept (Perl) or FCGI_Accept (Tcl).

3.4 Using Java

Java is not just for browser-based applets. It is already suitable for writing some Web server applications, and its range of applicability will only grow as Java compilers and other Java tools improve. Java's modules, garbage collection, and threads are especially valuable for writing long-lived application servers.

The FCGIInterface class provides facilities for Java applications analogous to what fcgi_stdio provides for C applications. Using this library your Java application can run using either CGI or FastCGI.

The kit includes separate companion document on using FastCGI with Java. The source code for FastCGI classes is contained in directory java/src and the compiled code in java/classes.

Here is the Java version of tiny-fcgi:

import FCGIInterface;

class TinyFCGI { 
    public static void main (String args[]) {  
        int count = 0;
        while(new FCGIInterface().FCGIaccept()>= 0) {
            count ++;
            System.out.println("Content-type: text/html\r\n\r\n");
            System.out.println(
                    "<title>FastCGI Hello! (Java)</title>");
            System.out.println("<h1>FastCGI Hello! (Java)</h1>");
            System.out.println(
                    "request number " + count + " running on host <i>" +
                    System.getProperty("SERVER_NAME") + "</i>");
        }
    }
}

4. Running applications

4.1 Using a Web server that supports FastCGI

For a current listing of Web servers that support FastCGI, see the fastcgi-archives.github.io Web page.

Some of the Web servers that support FastCGI perform management of FastCGI applications. You don't need to start and stop FastCGI applications; the Web server takes care of this. If an application process should crash, the Web server restarts it.

Web servers support FastCGI via new configuration directives. Since these directives are server-specific, get more information from the documentation that accompanies each server.

4.2 Using cgi-fcgi with any Web server

The program cgi-fcgi allows you to run FastCGI applications using any Web server that supports CGI.

Here is how cgi-fcgi works. cgi-fcgi is a standard CGI program that uses Unix domain or TCP/IP sockets to communicate with a FastCGI application. cgi-fcgi takes the path name or host/port name of a listening socket as a parameter and connects to the FastCGI application listening on that socket. cgi-fcgi then forwards the CGI environment variables and stdin data to the FastCGI application, and forwards the stdout and stderr data from the FastCGI application to the Web server. When the FastCGI application signals the end of its response, cgi-fcgi flushes its buffers and exits.

Obviously, having cgi-fcgi is not as good as having a server with integrated FastCGI support:

But cgi-fcgi does allow you to develop applications that retain state in memory between connections, which often provides a major performance boost over normal CGI. And all the applications you develop using cgi-fcgi will work with Web servers that have integrated support for FastCGI.

The file examples/tiny-fcgi.cgi demonstrates a way to use cgi-fcgi to run a typical application, in this case the examples/tiny-fcgi application:

    #!../cgi-fcgi/cgi-fcgi -f
    -connect sockets/tiny-fcgi tiny-fcgi

On most Unix platforms, executing this command-interpreter file runs cgi-fcgi with arguments -f and examples/tiny-fcgi.cgi. (Beware: On some Unix platforms, including HP-UX, the first line of a command-interpreter file cannot contain more than 32 characters, including the newline; you may need to install the cgi-fcgi application in a standard place like /usr/local/bin or create a symbolic link to the cgi-fcgi application in the directory containing your application.) The cgi-fcgi program reads the command-interpreter file and connects to the FastCGI application whose listening socket is examples/sockets/tiny-fcgi.

Continuing the example, if cgi-fcgi's connection attempt fails, it creates a new process running the program examples/tiny-fcgi and listening on socket examples/sockets/tiny-fcgi. Then cgi-fcgi retries the connection attempt, which now should succeed.

The cgi-fcgi program has two other modes of operation. In one mode it connects to applications but does not start them; in the other it starts applications but does not connect to them. These modes are required when using TCP/IP. The cgi-fcgi manpage, doc/cgi-fcgi.1, tells the full story.

To run the example applications using cgi-fcgi, start your Web server and give it the directory fcgi-devel-kit as the root of its URL space. If the machine running your server is called bowser and your server is running on port 8888, you'd then open the URL http://bowser:8888/index.html to reach the kit's index page. Now the links on the index page that run example applications via cgi-fcgi should be active.

5. Known problems

On Digital UNIX 3.0 there's a problem with Unix domain listening sockets on NFS file systems. The symptom when using cgi-fcgi is an exit status of 38 (ENOTSOCK: socket operation on non-socket), but cgi-fcgi may dump core in this case when compiled optimized. Work-around: Store your Unix domain listening sockets on a non NFS file system, upgrade to Digital UNIX 3.2, or use TCP sockets.

On AIX there's a problem with shared listening sockets. The symptoms can include application core dumps and kernel panic. Work-around: Run a single FastCGI application server per listening socket.

6. Getting support

The FastCGI Archives Issues are used for discussions of issues in developing FastCGI applications, see https://github.com/FastCGI-Archives/fcgi2/issues.


© 1996, Open Market, Inc. / mbrown@openmarket.com