FastCGI


  • code structure
  • fcgi_stdio library
  • fcgiapp library
  • read GET parameters
  • read POST parameters
  • read from sqlite3 database
  • write to sqlite3 database

  • FastCGI applications are long-lived, and can persist between client calls. the server spawns the FastCGI process once and it continues to run and satisfy client requests until it is explicitly terminated. you can also ask the Web server to start multiple copies of a FastCGI application. a long-lived application can cache information in memory between requests, allowing it to respond more quickly to later requests

    FastCGI applications can run on any node that can be reached from your Web server using TCP/IP protocols. for example, you might want to run the FastCGI application on a high-speed computer server or database engine, and run the Web server on a different node

    the main task of FastCGI program is separating the initialization code from the code that needs to run for each request. the structure should look something like this:

      Initialization code
    
      Start of response loop
            body of response loop
      End of response loop
    

    the initialization code is run exactly once, when the application is initialized. initialization code usually performs time-consuming operations such as opening databases or calculating values for tables or bitmaps

    the response loop runs continuously, waiting for client requests to arrive. the loop starts with a call to FCGI_Accept, a routine in the FastCGI library. the FCGI_Accept routine blocks program execution until a client requests the FastCGI application. when a client request comes in, FCGI_Accept unblocks, runs one iteration of the response loop body, and then blocks again waiting for another client request. the loop terminates only when the system administrator or the Web server kills the FastCGI application

    there are two libraries, fcgi_stdio and fcgiapp, for building FastCGI applications in C

    the FastCGI implementation basically creates a bidirectional connection between two processes that have no relationship. FastCGI uses a single connection for all the data associated with an application

    the data on the connection is encapsulated using a FastCGI protocol that allows stdin and the environment variables to share the same half connection (on the way in) and stdout and stderr to share the half connection (on the way out)

    on the input side, the FastCGI application receives data on the connection, unpacks it to separate stdin from the environment variables and then invokes the application

    on the output side, FastCGI wraps stdout and stderr with appropriate protocol headers, and sends the encapsulated data out to the server

    since a FastCGI application does not always run on the same node as the HTTP server, two implementations of the connection are supported:


    code structure

    to structure code for FastCGI, you separate your code into two sections:

    a response loop typically has the following format:

      while ( FCGI_Accept() >= 0 ) 
      {
           # body of response loop
      } 

    the FCGI_Accept blocks until a client request comes in, and then returns 0. if there is a system failure FCGI_Accept will return -1. if the application was invoked as a CGI program, the first call to FCGI_Accept returns 0 and the second always returns -1, producing CGI behavior

    note that the CGI world encourages small scripts, whereas FastCGI encourages combining scripts


    there are two libraries in the kit: fcgi_stdio and fcgiapp. you must include one of these header files in your program:

    the fcgi_stdio library is a layer on top of the fcgiapp library

    the fcgiapp library is more specific to FastCGI, without trying to provide the veneer of familiarity with CGI

    fcgi_stdio library

    the library fcgi_stdio.h contains macros to translate the types and procedures defined in stdio.h into the appropriate FastCGI calls

    for example, consider a FastCGI program written in C containing the following line of code:

        fprintf (stdout, "<H2> hello world! </H2>/n") ; 

    fcgi_stdio.h header file contains the macro

      #define fprintf FCGI_fprintf 
    so the preprocessor translates the fprintf call into the following call:
        FCGI_fprintf (stdout, "<H2> hello world! </H2>/n"); 

    FCGI_fprintf takes the same arguments as fprintf. the implementation of FCGI_fprintf tests the file to see if it is a normal C stream or a FastCGI stream, and calls the appropriate implementation

    the fcgi_stdio.h header file contains macros to translate calls to all ISO stdio.h routines (and all conventional Posix additions, such as fileno, fdopen, popen, and pclose) into their FastCGI equivalents

     /* 
     * fcgi_stdio.h --
     *
     *      FastCGI-stdio compatibility package
     *
     *
     * Copyright (c) 1996 Open Market, Inc.
     *
     * See the file "LICENSE.TERMS" for information on usage and redistribution
     * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
     *
     * $Id: fcgi_stdio.h,v 1.5 2001/06/22 13:21:15 robs Exp $
     */
    
    #ifndef _FCGI_STDIO
    #define _FCGI_STDIO 1
    
    #include <stdio.h>
    #include <sys/types.h>
    #include "fcgiapp.h"
    
    #if defined (c_plusplus) || defined (__cplusplus)
    extern "C" {
    #endif
    
    #ifndef DLLAPI
    #ifdef _WIN32
    #define DLLAPI __declspec(dllimport)
    #else
    #define DLLAPI
    #endif
    #endif
    
    /*
     * Wrapper type for FILE
     */
    
    typedef struct {
        FILE *stdio_stream;
        FCGX_Stream *fcgx_stream;
    } FCGI_FILE;
    
    /*
     * The four new functions and two new macros
     */
    
    DLLAPI int FCGI_Accept(void);
    DLLAPI void FCGI_Finish(void);
    DLLAPI int FCGI_StartFilterData(void);
    DLLAPI void FCGI_SetExitStatus(int status);
    
    #define FCGI_ToFILE(fcgi_file) (fcgi_file->stdio_stream)
    #define FCGI_ToFcgiStream(fcgi_file) (fcgi_file->fcgx_stream)
    
    /*
     * Wrapper stdin, stdout, and stderr variables, set up by FCGI_Accept()
     */
    
    DLLAPI extern	FCGI_FILE	_fcgi_sF[];
    #define FCGI_stdin	(&_fcgi_sF[0])
    #define FCGI_stdout	(&_fcgi_sF[1])
    #define FCGI_stderr	(&_fcgi_sF[2])
    
    /*
     * Wrapper function prototypes, grouped according to sections
     * of Harbison & Steele, "C: A Reference Manual," fourth edition,
     * Prentice-Hall, 1995.
     */
    
    DLLAPI void FCGI_perror(const char *str);
    
    DLLAPI FCGI_FILE *FCGI_fopen(const char *path, const char *mode);
    DLLAPI int        FCGI_fclose(FCGI_FILE *fp);
    DLLAPI int        FCGI_fflush(FCGI_FILE *fp);
    DLLAPI FCGI_FILE *FCGI_freopen(const char *path, const char *mode, FCGI_FILE *fp);
    
    DLLAPI int        FCGI_setvbuf(FCGI_FILE *fp, char *buf, int bufmode, size_t size);
    DLLAPI void       FCGI_setbuf(FCGI_FILE *fp, char *buf);
    
    DLLAPI int        FCGI_fseek(FCGI_FILE *fp, long offset, int whence);
    DLLAPI int        FCGI_ftell(FCGI_FILE *fp);
    DLLAPI void       FCGI_rewind(FCGI_FILE *fp);
    #ifdef HAVE_FPOS
    DLLAPI int        FCGI_fgetpos(FCGI_FILE *fp, fpos_t *pos);
    DLLAPI int        FCGI_fsetpos(FCGI_FILE *fp, const fpos_t *pos);
    #endif
    DLLAPI int        FCGI_fgetc(FCGI_FILE *fp);
    DLLAPI int        FCGI_getchar(void);
    DLLAPI int        FCGI_ungetc(int c, FCGI_FILE *fp);
    
    DLLAPI char      *FCGI_fgets(char *str, int size, FCGI_FILE *fp);
    DLLAPI char      *FCGI_gets(char *str);
    
    /*
     * Not yet implemented
     *
     * int        FCGI_fscanf(FCGI_FILE *fp, const char *format, ...);
     * int        FCGI_scanf(const char *format, ...);
     *
     */
    
    DLLAPI int        FCGI_fputc(int c, FCGI_FILE *fp);
    DLLAPI int        FCGI_putchar(int c);
    
    DLLAPI int        FCGI_fputs(const char *str, FCGI_FILE *fp);
    DLLAPI int        FCGI_puts(const char *str);
    
    DLLAPI int        FCGI_fprintf(FCGI_FILE *fp, const char *format, ...);
    DLLAPI int        FCGI_printf(const char *format, ...);
    
    DLLAPI int        FCGI_vfprintf(FCGI_FILE *fp, const char *format, va_list ap);
    DLLAPI int        FCGI_vprintf(const char *format, va_list ap);
    
    DLLAPI size_t     FCGI_fread(void *ptr, size_t size, size_t nmemb, FCGI_FILE *fp);
    DLLAPI size_t     FCGI_fwrite(void *ptr, size_t size, size_t nmemb, FCGI_FILE *fp);
    
    DLLAPI int        FCGI_feof(FCGI_FILE *fp);
    DLLAPI int        FCGI_ferror(FCGI_FILE *fp);
    DLLAPI void       FCGI_clearerr(FCGI_FILE *fp);
    
    DLLAPI FCGI_FILE *FCGI_tmpfile(void);
    
    DLLAPI int        FCGI_fileno(FCGI_FILE *fp);
    DLLAPI FCGI_FILE *FCGI_fdopen(int fd, const char *mode);
    DLLAPI FCGI_FILE *FCGI_popen(const char *cmd, const char *type);
    DLLAPI int        FCGI_pclose(FCGI_FILE *);
    
    /*
     * The remaining definitions are for application programs,
     * not for fcgi_stdio.c
     */
    
    #ifndef NO_FCGI_DEFINES
    
    /*
     * Replace standard types, variables, and functions with FastCGI wrappers.
     * Use undef in case a macro is already defined.
     */
    
    #undef  FILE
    #define	FILE     FCGI_FILE
    
    #undef  stdin
    #define	stdin    FCGI_stdin
    #undef  stdout
    #define	stdout   FCGI_stdout
    #undef  stderr
    #define	stderr   FCGI_stderr
    
    #undef  perror
    #define	perror   FCGI_perror
    
    #undef  fopen
    #define	fopen    FCGI_fopen
    #undef  fclose
    #define	fclose   FCGI_fclose
    #undef  fflush
    #define	fflush   FCGI_fflush
    #undef  freopen
    #define	freopen  FCGI_freopen
    
    #undef  setvbuf
    #define	setvbuf  FCGI_setvbuf
    #undef  setbuf
    #define	setbuf   FCGI_setbuf
    
    #undef  fseek
    #define fseek    FCGI_fseek
    #undef  ftell
    #define ftell    FCGI_ftell
    #undef  rewind
    #define rewind   FCGI_rewind
    #undef  fgetpos
    #define fgetpos  FCGI_fgetpos
    #undef  fsetpos
    #define fsetpos  FCGI_fsetpos
    
    #undef  fgetc
    #define	fgetc    FCGI_fgetc
    #undef  getc
    #define getc     FCGI_fgetc
    #undef  getchar
    #define	getchar  FCGI_getchar
    #undef  ungetc
    #define ungetc   FCGI_ungetc
    
    #undef  fgets
    #define fgets    FCGI_fgets
    #undef  gets
    #define	gets     FCGI_gets
    
    #undef  fputc
    #define fputc    FCGI_fputc
    #undef  putc
    #define putc     FCGI_fputc
    #undef  putchar
    #define	putchar  FCGI_putchar
    
    #undef  fputs
    #define	fputs    FCGI_fputs
    #undef  puts
    #define	puts     FCGI_puts
    
    #undef  fprintf
    #define	fprintf  FCGI_fprintf
    #undef  printf
    #define	printf   FCGI_printf
    
    #undef  vfprintf
    #define vfprintf FCGI_vfprintf
    #undef  vprintf
    #define vprintf  FCGI_vprintf
    
    #undef  fread
    #define	fread    FCGI_fread
    #undef  fwrite
    #define fwrite   FCGI_fwrite
    
    #undef  feof
    #define	feof     FCGI_feof
    #undef  ferror
    #define ferror   FCGI_ferror
    #undef  clearerr
    #define	clearerr FCGI_clearerr
    
    #undef  tmpfile
    #define tmpfile  FCGI_tmpfile
    
    #undef  fileno
    #define fileno   FCGI_fileno
    #undef  fdopen
    #define fdopen   FCGI_fdopen
    #undef  popen
    #define popen    FCGI_popen
    #undef  pclose
    #define	pclose   FCGI_pclose
    
    #endif /* NO_FCGI_DEFINES */
    
    #if defined (__cplusplus) || defined (c_plusplus)
    } /* terminate extern "C" { */
    #endif
    
    #endif /* _FCGI_STDIO */
    

    fcgiapp library

     /*
     * fcgiapp.h --
     *
     *      Definitions for FastCGI application server programs
     *
     *
     * Copyright (c) 1996 Open Market, Inc.
     *
     * See the file "LICENSE.TERMS" for information on usage and redistribution
     * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
     *
     * $Id: fcgiapp.h,v 1.14 2003/06/22 00:16:44 robs Exp $
     */
    
    #ifndef _FCGIAPP_H
    #define _FCGIAPP_H
    
    /* Hack to see if we are building TCL - TCL needs varargs not stdarg */
    #ifndef TCL_LIBRARY
    #include <stdarg.h>
    #else
    #include <varargs.h>
    #endif
    
    #ifndef DLLAPI
    #ifdef _WIN32
    #define DLLAPI __declspec(dllimport)
    #else
    #define DLLAPI
    #endif
    #endif
    
    #if defined (c_plusplus) || defined (__cplusplus)
    extern "C" {
    #endif
    
    /*
     * Error codes.  Assigned to avoid conflict with EOF and errno(2).
     */
    #define FCGX_UNSUPPORTED_VERSION -2
    #define FCGX_PROTOCOL_ERROR -3
    #define FCGX_PARAMS_ERROR -4
    #define FCGX_CALL_SEQ_ERROR -5
    
    /*
     * This structure defines the state of a FastCGI stream.
     * Streams are modeled after the FILE type defined in stdio.h.
     * (We wouldn't need our own if platform vendors provided a
     * standard way to subclass theirs.)
     * The state of a stream is private and should only be accessed
     * by the procedures defined below.
     */
    typedef struct FCGX_Stream {
        unsigned char *rdNext;    /* reader: first valid byte
                                   * writer: equals stop */
        unsigned char *wrNext;    /* writer: first free byte
                                   * reader: equals stop */
        unsigned char *stop;      /* reader: last valid byte + 1
                                   * writer: last free byte + 1 */
        unsigned char *stopUnget; /* reader: first byte of current buffer
                                   * fragment, for ungetc
                                   * writer: undefined */
        int isReader;
        int isClosed;
        int wasFCloseCalled;
        int FCGI_errno;                /* error status */
        void (*fillBuffProc) (struct FCGX_Stream *stream);
        void (*emptyBuffProc) (struct FCGX_Stream *stream, int doClose);
        void *data;
    } FCGX_Stream;
    
    /*
     * An environment (as defined by environ(7)): A NULL-terminated array
     * of strings, each string having the form name=value.
     */
    typedef char **FCGX_ParamArray;
    
    /*
     * FCGX_Request Flags
     *
     * Setting FCGI_FAIL_ACCEPT_ON_INTR prevents FCGX_Accept() from
     * restarting upon being interrupted.
     */
    #define FCGI_FAIL_ACCEPT_ON_INTR	1
    
    /*
     * FCGX_Request -- State associated with a request.
     *
     * Its exposed for API simplicity, I expect parts of it to change!
     */
    typedef struct FCGX_Request {
        int requestId;            /* valid if isBeginProcessed */
        int role;
        FCGX_Stream *in;
        FCGX_Stream *out;
        FCGX_Stream *err;
        char **envp;
    
        /* Don't use anything below here */
    
        struct Params *paramsPtr;
        int ipcFd;                /* < 0 means no connection */
        int isBeginProcessed;     /* FCGI_BEGIN_REQUEST seen */
        int keepConnection;       /* don't close ipcFd at end of request */
        int appStatus;
        int nWriters;             /* number of open writers (0..2) */
        int flags;
        int listen_sock;
        int detached;
    } FCGX_Request;
    
    
    /*
     *======================================================================
     * Control
     *======================================================================
     */
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_IsCGI --
     *
     *      Returns TRUE iff this process appears to be a CGI process
     *      rather than a FastCGI process.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI int FCGX_IsCGI(void);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_Init --
     *
     *      Initialize the FCGX library.  Call in multi-threaded apps
     *      before calling FCGX_Accept_r().
     *
     *      Returns 0 upon success.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI int FCGX_Init(void);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_OpenSocket --
     *
     *	Create a FastCGI listen socket.
     *
     *	path is the Unix domain socket (named pipe for WinNT), or a colon
     *	followed by a port number.  e.g. "/tmp/fastcgi/mysocket", ":5000"
     *
     *	backlog is the listen queue depth used in the listen() call.
     *
     *  Returns the socket's file descriptor or -1 on error.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI int FCGX_OpenSocket(const char *path, int backlog);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_InitRequest --
     *
     *	Initialize a FCGX_Request for use with FCGX_Accept_r().
     *
     * 	sock is a file descriptor returned by FCGX_OpenSocket() or 0 (default).
     * 	The only supported flag at this time is FCGI_FAIL_ON_INTR.
     *
     * 	Returns 0 upon success.
     *----------------------------------------------------------------------
     */
    DLLAPI int FCGX_InitRequest(FCGX_Request *request, int sock, int flags);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_Accept_r --
     *
     *      Accept a new request (multi-thread safe).  Be sure to call
     * 	FCGX_Init() first.
     *
     * Results:
     *	0 for successful call, -1 for error.
     *
     * Side effects:
     *
     *      Finishes the request accepted by (and frees any
     *      storage allocated by) the previous call to FCGX_Accept.
     *      Creates input, output, and error streams and
     *      assigns them to *in, *out, and *err respectively.
     *      Creates a parameters data structure to be accessed
     *      via getenv(3) (if assigned to environ) or by FCGX_GetParam
     *      and assigns it to *envp.
     *
     *      DO NOT retain pointers to the envp array or any strings
     *      contained in it (e.g. to the result of calling FCGX_GetParam),
     *      since these will be freed by the next call to FCGX_Finish
     *      or FCGX_Accept.
     *
     *	DON'T use the FCGX_Request, its structure WILL change.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI int FCGX_Accept_r(FCGX_Request *request);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_Finish_r --
     *
     *      Finish the request (multi-thread safe).
     *
     * Side effects:
     *
     *      Finishes the request accepted by (and frees any
     *      storage allocated by) the previous call to FCGX_Accept.
     *
     *      DO NOT retain pointers to the envp array or any strings
     *      contained in it (e.g. to the result of calling FCGX_GetParam),
     *      since these will be freed by the next call to FCGX_Finish
     *      or FCGX_Accept.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI void FCGX_Finish_r(FCGX_Request *request);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_Free --
     *
     *      Free the memory and, if close is true, 
     *	    IPC FD associated with the request (multi-thread safe).
     *
     *----------------------------------------------------------------------
     */
    DLLAPI void FCGX_Free(FCGX_Request * request, int close);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_Accept --
     *
     *      Accept a new request (NOT multi-thread safe).
     *
     * Results:
     *	0 for successful call, -1 for error.
     *
     * Side effects:
     *
     *      Finishes the request accepted by (and frees any
     *      storage allocated by) the previous call to FCGX_Accept.
     *      Creates input, output, and error streams and
     *      assigns them to *in, *out, and *err respectively.
     *      Creates a parameters data structure to be accessed
     *      via getenv(3) (if assigned to environ) or by FCGX_GetParam
     *      and assigns it to *envp.
     *
     *      DO NOT retain pointers to the envp array or any strings
     *      contained in it (e.g. to the result of calling FCGX_GetParam),
     *      since these will be freed by the next call to FCGX_Finish
     *      or FCGX_Accept.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI int FCGX_Accept(
            FCGX_Stream **in,
            FCGX_Stream **out,
            FCGX_Stream **err,
            FCGX_ParamArray *envp);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_Finish --
     *
     *      Finish the current request (NOT multi-thread safe).
     *
     * Side effects:
     *
     *      Finishes the request accepted by (and frees any
     *      storage allocated by) the previous call to FCGX_Accept.
     *
     *      DO NOT retain pointers to the envp array or any strings
     *      contained in it (e.g. to the result of calling FCGX_GetParam),
     *      since these will be freed by the next call to FCGX_Finish
     *      or FCGX_Accept.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI void FCGX_Finish(void);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_StartFilterData --
     *
     *      stream is an input stream for a FCGI_FILTER request.
     *      stream is positioned at EOF on FCGI_STDIN.
     *      Repositions stream to the start of FCGI_DATA.
     *      If the preconditions are not met (e.g. FCGI_STDIN has not
     *      been read to EOF) sets the stream error code to
     *      FCGX_CALL_SEQ_ERROR.
     *
     * Results:
     *      0 for a normal return, << 0 for error
     *
     *----------------------------------------------------------------------
     */
    DLLAPI int FCGX_StartFilterData(FCGX_Stream *stream);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_SetExitStatus --
     *
     *      Sets the exit status for stream's request. The exit status
     *      is the status code the request would have exited with, had
     *      the request been run as a CGI program.  You can call
     *      SetExitStatus several times during a request; the last call
     *      before the request ends determines the value.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI void FCGX_SetExitStatus(int status, FCGX_Stream *stream);
    
    /*
     *======================================================================
     * Parameters
     *======================================================================
     */
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_GetParam -- obtain value of FCGI parameter in environment
     *
     *
     * Results:
     *	Value bound to name, NULL if name not present in the
     *      environment envp.  Caller must not mutate the result
     *      or retain it past the end of this request.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI char *FCGX_GetParam(const char *name, FCGX_ParamArray envp);
    
    /*
     *======================================================================
     * Readers
     *======================================================================
     */
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_GetChar --
     *
     *      Reads a byte from the input stream and returns it.
     *
     * Results:
     *	The byte, or EOF (-1) if the end of input has been reached.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI int FCGX_GetChar(FCGX_Stream *stream);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_UnGetChar --
     *
     *      Pushes back the character c onto the input stream.  One
     *      character of pushback is guaranteed once a character
     *      has been read.  No pushback is possible for EOF.
     *
     * Results:
     *	Returns c if the pushback succeeded, EOF if not.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI int FCGX_UnGetChar(int c, FCGX_Stream *stream);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_GetStr --
     *
     *      Reads up to n consecutive bytes from the input stream
     *      into the character array str.  Performs no interpretation
     *      of the input bytes.
     *
     * Results:
     *	Number of bytes read.  If result is smaller than n,
     *      the end of input has been reached.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI int FCGX_GetStr(char *str, int n, FCGX_Stream *stream);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_GetLine --
     *
     *      Reads up to n-1 consecutive bytes from the input stream
     *      into the character array str.  Stops before n-1 bytes
     *      have been read if '\n' or EOF is read.  The terminating '\n'
     *      is copied to str.  After copying the last byte into str,
     *      stores a '\0' terminator.
     *
     * Results:
     *	NULL if EOF is the first thing read from the input stream,
     *      str otherwise.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI char *FCGX_GetLine(char *str, int n, FCGX_Stream *stream);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_HasSeenEOF --
     *
     *      Returns EOF if end-of-file has been detected while reading
     *      from stream; otherwise returns 0.
     *
     *      Note that FCGX_HasSeenEOF(s) may return 0, yet an immediately
     *      following FCGX_GetChar(s) may return EOF.  This function, like
     *      the standard C stdio function feof, does not provide the
     *      ability to peek ahead.
     *
     * Results:
     *	EOF if end-of-file has been detected, 0 if not.
     *
     *----------------------------------------------------------------------
     */
    
    DLLAPI  int FCGX_HasSeenEOF(FCGX_Stream *stream);
    
    /*
     *======================================================================
     * Writers
     *======================================================================
     */
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_PutChar --
     *
     *      Writes a byte to the output stream.
     *
     * Results:
     *	The byte, or EOF (-1) if an error occurred.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI int FCGX_PutChar(int c, FCGX_Stream *stream);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_PutStr --
     *
     *      Writes n consecutive bytes from the character array str
     *      into the output stream.  Performs no interpretation
     *      of the output bytes.
     *
     * Results:
     *      Number of bytes written (n) for normal return,
     *      EOF (-1) if an error occurred.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI int FCGX_PutStr(const char *str, int n, FCGX_Stream *stream);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_PutS --
     *
     *      Writes a null-terminated character string to the output stream.
     *
     * Results:
     *      number of bytes written for normal return,
     *      EOF (-1) if an error occurred.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI int FCGX_PutS(const char *str, FCGX_Stream *stream);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_FPrintF, FCGX_VFPrintF --
     *
     *      Performs printf-style output formatting and writes the results
     *      to the output stream.
     *
     * Results:
     *      number of bytes written for normal return,
     *      EOF (-1) if an error occurred.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI int FCGX_FPrintF(FCGX_Stream *stream, const char *format, ...);
    
    DLLAPI int FCGX_VFPrintF(FCGX_Stream *stream, const char *format, va_list arg);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_FFlush --
     *
     *      Flushes any buffered output.
     *
     *      Server-push is a legitimate application of FCGX_FFlush.
     *      Otherwise, FCGX_FFlush is not very useful, since FCGX_Accept
     *      does it implicitly.  Calling FCGX_FFlush in non-push applications
     *      results in extra writes and therefore reduces performance.
     *
     * Results:
     *      EOF (-1) if an error occurred.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI int FCGX_FFlush(FCGX_Stream *stream);
    
    /*
     *======================================================================
     * Both Readers and Writers
     *======================================================================
     */
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_FClose --
     *
     *      Closes the stream.  For writers, flushes any buffered
     *      output.
     *
     *      Close is not a very useful operation since FCGX_Accept
     *      does it implicitly.  Closing the out stream before the
     *      err stream results in an extra write if there's nothing
     *      in the err stream, and therefore reduces performance.
     *
     * Results:
     *      EOF (-1) if an error occurred.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI int FCGX_FClose(FCGX_Stream *stream);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_GetError --
     *
     *      Return the stream error code.  0 means no error, > 0
     *      is an errno(2) error, < 0 is an FastCGI error.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI int FCGX_GetError(FCGX_Stream *stream);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_ClearError --
     *
     *      Clear the stream error code and end-of-file indication.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI void FCGX_ClearError(FCGX_Stream *stream);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_CreateWriter --
     *
     *      Create a FCGX_Stream (used by cgi-fcgi).  This shouldn't 
     *      be needed by a FastCGI applictaion.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI FCGX_Stream *FCGX_CreateWriter(
            int socket,
            int requestId,
            int bufflen,
            int streamType);
    
    /*
     *----------------------------------------------------------------------
     *
     * FCGX_FreeStream --
     *
     *      Free a FCGX_Stream (used by cgi-fcgi).  This shouldn't 
     *      be needed by a FastCGI applictaion.
     *
     *----------------------------------------------------------------------
     */
    DLLAPI void FCGX_FreeStream(FCGX_Stream **stream);
    
    /* ----------------------------------------------------------------------
     *
     *  Prevent the lib from accepting any new requests.  Signal handler safe.
     *
     * ----------------------------------------------------------------------
     */
    DLLAPI void FCGX_ShutdownPending(void);
    
    
    /*
     *  Attach/Detach an accepted request from its listen socket.
     *  XXX This is not fully implemented at this time (patch welcome).
     */
    DLLAPI int FCGX_Attach(FCGX_Request * r);
    DLLAPI int FCGX_Detach(FCGX_Request * r);
    
    
    #if defined (__cplusplus) || defined (c_plusplus)
    } /* terminate extern "C" { */
    #endif
    
    #endif	/* _FCGIAPP_H */
    

    read GET parameters

    you need: spawn-fcgi, fcgi, nginx

    nginx.conf file:

     server 
     {
        listen               8080;
        charset              utf-8;
    
        location /
        {
                root             /var/www;
                index            index.html index.htm;
        }
    
        location ~ \count.cgi
        {
                include          /etc/nginx/fastcgi_params;
                fastcgi_pass     127.0.0.1:7654;
        } 
     }

    fcgi code from file 'count.c' :

    #include "fcgiapp.h"
    
    int 
    main() 
    {
      int                  count = 0 ;
      FCGX_Stream          *in, *out, *err ;
      FCGX_ParamArray      envp ;
    
      while ( FCGX_Accept(&in, &out, &err, &envp) >= 0 ) 
      {
        char *query = FCGX_GetParam ("QUERY_STRING", envp) ;
                                      
        FCGX_FPrintF (out, "Content-type: text/plain\r\n\r\n") ;
        FCGX_FPrintF (out, "your query is %s\n", query) ;
        FCGX_FPrintF (out, "your visit is %i\n", ++count) ;
      }
    
      return 0 ;
    }

    now in shell:

     $> gcc -o a.out -lfcgi count.c
    
     $> spawn-fcgi -a 127.0.0.1 -p 7654 -n ./a.out  & 
    
    
     $> curl localhost:8080/count.cgi?foobar
      your query is foobar
      your visit is 1
    
     $> curl localhost:8080/count.cgi?bazqux
      your query is bazqux
      your visit is 2

    read POST parameters

    nginx config:

        location ~ \file.cgi
        {
                include          /etc/nginx/fastcgi_params;
                fastcgi_pass     127.0.0.1:9000;
        } 
    

    file with fcgi script :

    #include "fcgi_stdio.h"
    #include "fcgiapp.h"
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    int
    main (int argc, char** argv, char** env) 
    {
      FCGX_Stream       *in, *out, *err ;
      FCGX_ParamArray   envp ;
    
      while ( FCGX_Accept (&in, &out, &err, &envp) >= 0 ) 
      {
        FCGX_FPrintF (out, "content-type: text/plain\r\n\r\n") ;
    
        char* method = FCGX_GetParam ("REQUEST_METHOD", envp);
      
        if ( !strcmp (method, "POST") ) 
        {
          int len = atoi (FCGX_GetParam ("CONTENT_LENGTH", envp)) ;
          char *buf = malloc (len) ;
    
          FCGX_GetStr (buf, len, in) ;
    
          FCGX_FPrintF (out, "your POST data is %s\n", buf) ;
    
          free (buf);
        } 
        else 
        { 
          FCGX_FPrintF (out, "not POST request\n") ; 
        }
      } ;
    
      return 0;
    } 

    now in shell:

     $> gcc -o a.out -lfcgi postparams.c
        
     $> spawn-fcgi -a 127.0.0.1 -p 7654 -n ./a.out  & 
     
        
     $> curl -d "some params here" localhost:8080/file.cgi
    
     $> curl -d @file.dat localhost:8080/file.cgi 

    read from sqlite3 database

    you need: spawn-fcgi, fcgi, nginx, sqlite3

    nginx.conf file:

     server 
     {
        listen               8080;
        charset              utf-8;
    
        location /
        {
                root             /var/www;
                index            index.html index.htm;
        }
    
        location ~ \.cgi
        {
                include          /etc/nginx/fastcgi_params;
                fastcgi_pass     127.0.0.1:7654;
        } 
     }

    fcgi code:

    #include "fcgiapp.h"
    #include "sqlite3.h"
    #include <stdio.h>
    
    int 
    main (int argc, char* argv[]) 
    {
      sqlite3             *db ;
      sqlite3_stmt        *req ;
    
      FCGX_Stream         *in, *out, *err ;
      FCGX_ParamArray     envp ;
    
      if ( sqlite3_open_v2 ("mysqlite.db", &db, SQLITE_OPEN_READWRITE, NULL) ) 
      {
        FCGX_FPrintF ( err, "error in open db : %s\n", sqlite3_errmsg (db) ) ; 
      } ;
      
      char request_db[128] = "" ;
    
      while ( FCGX_Accept (&in, &out, &err, &envp) >= 0 ) 
      {
        char* query = FCGX_GetParam ("QUERY_STRING", envp) ;
        snprintf (request_db, sizeof request_db, "select f2 from tbl1 where f1=%s", query) ;
    
        FCGX_FPrintF (out, "content-type:text/html\n\n") ;
    
        if ( sqlite3_prepare_v2 (db, request_db, -1, &req, NULL) )
        {
          FCGX_FPrintF ( err, "error in reading db : %s\n", sqlite3_errmsg (db) ) ; 
        }
    
        while ( SQLITE_ROW == sqlite3_step (req) ) 
        {
          const char* ans = sqlite3_column_text (req, 0) ;
          FCGX_FPrintF (out, "%s\n", ans) ;
        }
    
        sqlite3_finalize (req);
      }
    
      sqlite3_close (db) ;
      return (0);
    }

    now in shell:

     $> gcc -o a.out -lfcgi -lsqlite3 read_db.c
        
     $> spawn-fcgi -a 127.0.0.1 -p 7654 -n ./a.out  & 
    
     $> curl 127.0.0.1:8080/read.cgi?1

    write to sqlite3 database

    nginx.conf file:

        server 
        {
            listen       8080;
            charset      utf-8;
            
            location / 
            {
                root    /var/www ;
                index   index.html index.htm ;
            }
        
            location ~ \.cgi$
            {
                  fastcgi_pass                  127.0.0.1:9000;
                  fastcgi_param QUERY_STRING    $query_string;
                  fastcgi_param REQUEST_METHOD  $request_method;
                  fastcgi_param CONTENT_TYPE    $content_type;
                  fastcgi_param CONTENT_LENGTH  $content_length;
            }
        }

    fcgi script source code:

    #include <fcgiapp.h>
    #include <sqlite3.h>
    #include <stdio.h>
    
    int
    main (int argc, char* argv[]) 
    {
      sqlite3             *db ;
      sqlite3_stmt        *req ;
    
      FCGX_Stream         *in, *out, *err ;
      FCGX_ParamArray     envp ;
    
      if ( sqlite3_open_v2("mytest.db", &db, SQLITE_OPEN_READWRITE, NULL) ) 
      {
        FCGX_FPrintF ( out, "\n%s\n", "error in open db : %s\n", sqlite3_errmsg(db) ) ; 
      }
    
      char *query;
      char qparam_name[16], qparam_body[128] ;
    
      while ( FCGX_Accept(&in, &out, &err, &envp) >= 0 ) 
      {
        query = FCGX_GetParam ("QUERY_STRING", envp) ;
        sscanf (query, "%15[^=]%*[=\"]%127[^\"]", &qparam_name, &qparam_body) ;
    
        FCGX_FPrintF (out, "content-type:text/html\n\n") ;
    
        if ( sqlite3_prepare_v2 (db, qparam_body, -1, &req, NULL) ) 
        {
          FCGX_FPrintF (out, "\nerror in prep func %s\n", sqlite3_errmsg (db)) ; 
          sqlite3_reset (req) ;
        } 
        else 
        {
          if ( sqlite3_step(req) != SQLITE_DONE ) 
          {
            FCGX_FPrintF (out, "\nstep func %s\n", sqlite3_errmsg (db)) ;
          }
          else 
          {
            FCGX_FPrintF (out, "\nwrite: ok\n") ;
          }
          sqlite3_finalize (req) ;
        }
      }
    
      sqlite3_close (db) ;
      return 0 ;
    }

    now in shell:

    $> curl localhost:8080/write.cgi?param="insert into tbl1 values (100,'zzz');" 
    write: ok 


    nginx - fastcgi.config file

    fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
    fastcgi_param  QUERY_STRING       $query_string;
    fastcgi_param  REQUEST_METHOD     $request_method;
    fastcgi_param  CONTENT_TYPE       $content_type;
    fastcgi_param  CONTENT_LENGTH     $content_length;
    
    fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
    fastcgi_param  REQUEST_URI        $request_uri;
    fastcgi_param  DOCUMENT_URI       $document_uri;
    fastcgi_param  DOCUMENT_ROOT      $document_root;
    fastcgi_param  SERVER_PROTOCOL    $server_protocol;
    fastcgi_param  REQUEST_SCHEME     $scheme;
    fastcgi_param  HTTPS              $https if_not_empty;
    
    fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
    fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;
    
    fastcgi_param  REMOTE_ADDR        $remote_addr;
    fastcgi_param  REMOTE_PORT        $remote_port;
    fastcgi_param  SERVER_ADDR        $server_addr;
    fastcgi_param  SERVER_PORT        $server_port;
    fastcgi_param  SERVER_NAME        $server_name;
    
    # PHP only, required if PHP was built with --enable-force-cgi-redirect
    fastcgi_param  REDIRECT_STATUS    200;
    

    nginx - fastcgi_params file

    scgi_param  REQUEST_METHOD     $request_method;
    scgi_param  REQUEST_URI        $request_uri;
    scgi_param  QUERY_STRING       $query_string;
    scgi_param  CONTENT_TYPE       $content_type;
    
    scgi_param  DOCUMENT_URI       $document_uri;
    scgi_param  DOCUMENT_ROOT      $document_root;
    scgi_param  SCGI               1;
    scgi_param  SERVER_PROTOCOL    $server_protocol;
    scgi_param  REQUEST_SCHEME     $scheme;
    scgi_param  HTTPS              $https if_not_empty;
    
    scgi_param  REMOTE_ADDR        $remote_addr;
    scgi_param  REMOTE_PORT        $remote_port;
    scgi_param  SERVER_PORT        $server_port;
    scgi_param  SERVER_NAME        $server_name;