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 toFCGI_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:
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:
fcgi_stdio.h
fcgiapp.h
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
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_fprintfso 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.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 */
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
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
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
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
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;
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;