Sun Java System Web Server 7.0 Update 7 Administrator's Guide

Sample FastCGI Applications

This section contains sample FastCGI applications written using PHP, Perl and C.

Responder application in PHP (ListDir.php)

<?php
 		$dir = "/tmp/";

		// Open a known directory, and proceed to read its contents
		if (is_dir($dir)) {
			if ($dh = opendir($dir)) {
 				while (($file = readdir($dh)) !== false) {
 					echo "filename: $file : filetype: " . filetype($dir . $file) . "\n";
 				}
				closedir($dh);
			}

		}
?>

obj.conf snippet for the above example:

<Object name="default">
		NameTrans fn="assign-name" from="/fcgi/*" name="responder.fcgi"
</Object>
<Object name="responder.fcgi">
		Service fn="responder-fastcgi" app-path="/foo/fastcgi-enabled-php-installation/bin/php" 
			bind-path="localhost:3431"  min-procs=3
</Object>

Authorizer application in Perl (SimpleAuth.pl)

#!/usr/bin/perl

use FCGI;

while (FCGI::accept >= 0) {
		if( $ENV{'HTTP_AUTHORIZATION'} ) { 
        # This value can be further decoded to get the actual 
			# username and password and then
        # perform some kind of user validation. This program only 
        # checks for the presence of
        # of this environment param and is not really bothered about its value

        print( "Status: 200\r\n" );
        print( "\r\n" );

    } else {
       
        print( "Status: 401\r\n" );
        print( "WWW-Authenticate: basic realm=\"foo\"\r\n" );
        print( "\r\n" );  

   }

}

obj.conf settings for the above example:

<Object name="responder.fcgi">
		AuthTrans fn="auth-fastcgi" app-path="/fastcgi/apps/auth/SimpleAuth.pl" 
		bind-path="localhost:3432"
		Service fn="responder-fastcgi" app-path="/foo/fastcgi-enabled-php-installation/bin/php" 
		bind-path="localhost:3433" app-env="PHP_FCGI_CHILDREN=8" min-procs=1
</Object>

On first request to http://localhost/fcgi/php/ListDir.php, the authentication dialogue box is displayed by the browser. After the user enters the username and password, the contents of "/tmp" directory are listed.

Filter application in C (SimpleFilter.c)

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

		void main(void) {
			size_t PageSize = 1024 * 3;
    		char *page;
    		FCGX_Stream *in, *out, *err;
    		FCGX_ParamArray envp;

		 	int count=0;
    		page = (char *)malloc(PageSize);

		 	if (page == NULL) {

				printf("Content-type: text/x-server-parsed-html\r\n");
				printf("<title>malloc failure</title>");
				printf("<h1>Cannot allocate memory to run filter. exiting</h1>");
				printf("\r\n\r\n");
				exit(2);
			}

			while(FCGI_Accept() >= 0) {

         	char *tmp;
         	char *execcgi;      
         	char *dataLenStr = NULL;
         	int numchars = 0;
         	int stdinDataSize = 0;
         	int filterDataLen = 0;
         	int dataToBeRead = 0;
         	int x = 0;
         	int loopCount = 0;   
				

			  	count++;
         	dataLenStr = getenv("FCGI_DATA_LENGTH");
        
         	if(dataLenStr)
             	filterDataLen = atoi(dataLenStr);
   
				/* clear out stdin */
         	while (EOF != getc(stdin)) {
             	stdinDataSize++;
         	}

				dataToBeRead = filterDataLen;
        	FCGI_StartFilterData();
        	tmp = page; /** just in case fread or fwrite moves our pointer **/


				//start responding
				printf("Content-type: text/plain\r\n");
				printf("\r\n"); /** send a new line at the beginning **/
				printf("<title>SIMPLE FILTER</title>");
				printf(<h1>This page was Filtered by SimpleFilter FastCGI filter</h1>");
				printf("file size=%d<br>", filterDatalen);
				printf("stdin size=%d<br>, stdinDataSize);


				while(dataToBeRead > 0 ) {
           		x = 0;
           		page = tmp;
            
           		if(dataToBeRead > PageSize)
             		 x = PageSize;
           		else
              		 x = dataToBeRead;
					numchars = fread((void *)(page), 1, x, stdin);
				
					if( numchars == 0 )
						continue; 
					/** at this point your data is in page pointer, so do 
					whatever you want 
               with it before sending it back to the server.
					In this example, no data is manipulated. Only the count of number of 
               times the filter data is read and the total bytes read 
					at the end of every 
               loop is printed. **/	

					dataToBeRead -= numchars;
					loopCount++;
					printf("loop count = %d ... so far read %d bytes <br>", loopCount, 
					(filterDatalen - dataToBeRead));
				}
				printf("\r\n\r\n"); /** send a new line at the end of transfer **/

				fflush(stdout);

				page = tmp; /** restore page pointer **/
				memset(page,NULL,numchars);
		}

		free(page);
}

Example obj.conf settings for the above example.

If this FastCGI application is available on the same machine where the Web Server is running, then

<Object name=<"filter.fcgi">
						Service fn="filter-fastcgi" app-path="/fastcgi/apps/filter/SimpleFilter.exe" 
             bind-path="localhost:3434" app-env="LD_LIBRARY_PATH=/fastcgi/fcgi-2.4/libfcgi/.libs"
</Object>

If the application is running on a remote machine, then the following lines of code must be included in the obj.conf file:

<Object name="filter.fcgi">
			Service fn="filter-fastcgi" bind-path="<remote-host>:<remote-port>"
</Object>

If "FilterThisFile" of size "26868" bytes located under the fcgi directory under the Web Server instance's docroot directory is the file to be filtered a request to "http://localhost/fcgi/filter/FilterThisFile" produces the following output:

This page was Filtered by SimpleFilter FastCGI filter

file size = 26868

stdin size = 0

loop count = 1... so far read 3072 bytes

loop count = 2... so far read 6144 bytes

loop count = 3... so far read 9216 bytes

loop count = 4... so far read 12288 bytes

loop count = 5... so far read 15360 bytes

loop count = 6... so far read 18432 bytes

loop count = 7... so far read 21504 bytes

loop count = 8... so far read 24576 bytes

loop count = 9... so far read 26868 bytes