cgi-fcgi.c

来自「FastCGI,语言无关的、可伸缩架构的CGI开放扩展」· C语言 代码 · 共 850 行 · 第 1/2 页

C
850
字号
/* * cgifcgi.c -- * *	CGI to FastCGI bridge * * * 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. * */#ifndef lintstatic const char rcsid[] = "$Id: cgi-fcgi.c,v 1.15 2001/09/01 01:14:28 robs Exp $";#endif /* not lint */#include <assert.h>#include <ctype.h>#include <errno.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include "fcgi_config.h"#ifdef HAVE_NETDB_H#include <netdb.h>#endif#ifdef _WIN32#include <stdlib.h>#include <io.h>#elseextern char **environ;#endif#ifdef HAVE_SYS_PARAM_H#include <sys/param.h>#endif#ifdef HAVE_SYS_TIME_H#include <sys/time.h>#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include "fcgimisc.h"#include "fcgiapp.h"#include "fastcgi.h"#include "fcgios.h"static int wsReadPending = 0;static int fcgiReadPending = 0;static int fcgiWritePending = 0;static void ScheduleIo(void);/* * Simple buffer (not ring buffer) type, used by all event handlers. */#define BUFFLEN 8192typedef struct {    char *next;    char *stop;    char buff[BUFFLEN];} Buffer;/* *---------------------------------------------------------------------- * * GetPtr -- * *      Returns a count of the number of characters available *      in the buffer (at most n) and advances past these *      characters.  Stores a pointer to the first of these *      characters in *ptr. * *---------------------------------------------------------------------- */static int GetPtr(char **ptr, int n, Buffer *pBuf){    int result;    *ptr = pBuf->next;    result = min(n, pBuf->stop - pBuf->next);    pBuf->next += result;    return result;}/* *---------------------------------------------------------------------- * * MakeHeader -- * *      Constructs an FCGI_Header struct. * *---------------------------------------------------------------------- */static FCGI_Header MakeHeader(        int type,        int requestId,        int contentLength,        int paddingLength){    FCGI_Header header;    ASSERT(contentLength >= 0 && contentLength <= FCGI_MAX_LENGTH);    ASSERT(paddingLength >= 0 && paddingLength <= 0xff);    header.version = FCGI_VERSION_1;    header.type             = (unsigned char) type;    header.requestIdB1      = (unsigned char) ((requestId     >> 8) & 0xff);    header.requestIdB0      = (unsigned char) ((requestId         ) & 0xff);    header.contentLengthB1  = (unsigned char) ((contentLength >> 8) & 0xff);    header.contentLengthB0  = (unsigned char) ((contentLength     ) & 0xff);    header.paddingLength    = (unsigned char) paddingLength;    header.reserved         =  0;    return header;}/* *---------------------------------------------------------------------- * * MakeBeginRequestBody -- * *      Constructs an FCGI_BeginRequestBody record. * *---------------------------------------------------------------------- */static FCGI_BeginRequestBody MakeBeginRequestBody(        int role,        int keepConnection){    FCGI_BeginRequestBody body;    ASSERT((role >> 16) == 0);    body.roleB1 = (unsigned char) ((role >>  8) & 0xff);    body.roleB0 = (unsigned char) (role         & 0xff);    body.flags  = (unsigned char) ((keepConnection) ? FCGI_KEEP_CONN : 0);    memset(body.reserved, 0, sizeof(body.reserved));    return body;}static int bytesToRead;    /* number of bytes to read from Web Server */static int appServerSock = -1;  /* Socket connected to FastCGI application,                                 * used by AppServerReadHandler and                                 * AppServerWriteHandler. */static Buffer fromAS;      /* Bytes read from the FCGI application server. */static FCGI_Header header; /* Header of the current record.  Is global                            * since read may return a partial header. */static int headerLen = 0;  /* Number of valid bytes contained in header.                            * If headerLen < sizeof(header),                            * AppServerReadHandler is reading a record header;                            * otherwise it is reading bytes of record content                            * or padding. */static int contentLen;     /* If headerLen == sizeof(header), contentLen                            * is the number of content bytes still to be                            * read. */static int paddingLen;     /* If headerLen == sizeof(header), paddingLen                            * is the number of padding bytes still                            * to be read. */static int requestId;      /* RequestId of the current request.                            * Set by main. */static FCGI_EndRequestBody erBody;static int readingEndRequestBody = FALSE;                           /* If readingEndRequestBody, erBody contains                            * partial content: contentLen more bytes need                            * to be read. */static int exitStatus = 0;static int exitStatusSet = FALSE;static int stdinFds[3];/* *---------------------------------------------------------------------- * * FCGIexit -- * *      FCGIexit provides a single point of exit.  It's main use is for *      application debug when porting to other operating systems. * *---------------------------------------------------------------------- */static void FCGIexit(int exitCode){    if(appServerSock != -1) {        OS_Close(appServerSock);	appServerSock = -1;    }    OS_LibShutdown();    exit(exitCode);}#undef exit#define exit FCGIexit/* *---------------------------------------------------------------------- * * AppServerReadHandler -- * *      Reads data from the FCGI application server and (blocking) *      writes all of it to the Web server.  Exits the program upon *      reading EOF from the FCGI application server.  Called only when *      there's data ready to read from the application server. * *---------------------------------------------------------------------- */static void AppServerReadHandler(ClientData dc, int bytesRead){    int count, outFD;    char *ptr;    /* Touch unused parameters to avoid warnings */    dc = NULL;    assert(fcgiReadPending == TRUE);    fcgiReadPending = FALSE;    count = bytesRead;    if(count <= 0) {        if(count < 0) {            exit(OS_Errno);        }        if(headerLen > 0 || paddingLen > 0) {            exit(FCGX_PROTOCOL_ERROR);        }	if(appServerSock != -1) {	    OS_Close(appServerSock);	    appServerSock = -1;	}        /*         * XXX: Shouldn't be here if exitStatusSet.         */        exit((exitStatusSet) ? exitStatus : FCGX_PROTOCOL_ERROR);    }    fromAS.stop = fromAS.next + count;    while(fromAS.next != fromAS.stop) {        /*         * fromAS is not empty.  What to do with the contents?         */        if(headerLen < sizeof(header)) {            /*             * First priority is to complete the header.             */            count = GetPtr(&ptr, sizeof(header) - headerLen, &fromAS);            assert(count > 0);            memcpy(&header + headerLen, ptr, count);            headerLen += count;            if(headerLen < sizeof(header)) {                break;            }            if(header.version != FCGI_VERSION_1) {                exit(FCGX_UNSUPPORTED_VERSION);	    }            if((header.requestIdB1 << 8) + header.requestIdB0 != requestId) {                exit(FCGX_PROTOCOL_ERROR);	    }            contentLen = (header.contentLengthB1 << 8)                         + header.contentLengthB0;            paddingLen =  header.paddingLength;	} else {            /*             * Header is complete (possibly from previous call).  What now?             */            switch(header.type) {	        case FCGI_STDOUT:                case FCGI_STDERR:                    /*                     * Write the buffered content to stdout or stderr.                     * Blocking writes are OK here; can't prevent a slow                     * client from tying up the app server without buffering                     * output in temporary files.                     */                    count = GetPtr(&ptr, contentLen, &fromAS);                    contentLen -= count;                    if(count > 0) {                        outFD = (header.type == FCGI_STDOUT) ?                                    STDOUT_FILENO : STDERR_FILENO;                        if(OS_Write(outFD, ptr, count) < 0) {                            exit(OS_Errno);                        }	            }                    break;                case FCGI_END_REQUEST:                    if(!readingEndRequestBody) {                        if(contentLen != sizeof(erBody)) {                            exit(FCGX_PROTOCOL_ERROR);		        }                        readingEndRequestBody = TRUE;		    }                    count = GetPtr(&ptr, contentLen, &fromAS);                    if(count > 0) {                        memcpy(&erBody + sizeof(erBody) - contentLen,                                ptr, count);                        contentLen -= count;		    }                    if(contentLen == 0) {                        if(erBody.protocolStatus != FCGI_REQUEST_COMPLETE) {                            /*                             * XXX: What to do with FCGI_OVERLOADED?                             */                            exit(FCGX_PROTOCOL_ERROR);			}                        exitStatus = (erBody.appStatusB3 << 24)                                   + (erBody.appStatusB2 << 16)                                   + (erBody.appStatusB1 <<  8)                                   + (erBody.appStatusB0      );                        exitStatusSet = TRUE;                        readingEndRequestBody = FALSE;	            }                    break;                case FCGI_GET_VALUES_RESULT:                    /* coming soon */                case FCGI_UNKNOWN_TYPE:                    /* coming soon */                default:                    exit(FCGX_PROTOCOL_ERROR);	    }            if(contentLen == 0) {                if(paddingLen > 0) {                    paddingLen -= GetPtr(&ptr, paddingLen, &fromAS);		}                /*                 * If we've processed all the data and skipped all the                 * padding, discard the header and look for the next one.                 */                if(paddingLen == 0) {                    headerLen = 0;	        }	    }        } /* headerLen >= sizeof(header) */    } /*while*/    ScheduleIo();}static Buffer fromWS;   /* Buffer for data read from Web server                         * and written to FastCGI application. Used                         * by WebServerReadHandler and                         * AppServerWriteHandler. */static int webServerReadHandlerEOF;                        /* TRUE iff WebServerReadHandler has read EOF from                         * the Web server. Used in main to prevent                         * rescheduling WebServerReadHandler. */static void WriteStdinEof(void){    static int stdin_eof_sent = 0;    if (stdin_eof_sent)    	return;    *((FCGI_Header *)fromWS.stop) = MakeHeader(FCGI_STDIN, requestId, 0, 0);    fromWS.stop += sizeof(FCGI_Header);    stdin_eof_sent = 1;}/* *---------------------------------------------------------------------- * * WebServerReadHandler -- * *      Non-blocking reads data from the Web server into the fromWS *      buffer.  Called only when fromWS is empty, no EOF has been *      received from the Web server, and there's data available to read. * *---------------------------------------------------------------------- */static void WebServerReadHandler(ClientData dc, int bytesRead){    /* Touch unused parameters to avoid warnings */    dc = NULL;    assert(fromWS.next == fromWS.stop);    assert(fromWS.next == &fromWS.buff[0]);    assert(wsReadPending == TRUE);    wsReadPending = FALSE;    if(bytesRead < 0) {        exit(OS_Errno);    }    *((FCGI_Header *) &fromWS.buff[0])            = MakeHeader(FCGI_STDIN, requestId, bytesRead, 0);    bytesToRead -= bytesRead;    fromWS.stop = &fromWS.buff[sizeof(FCGI_Header) + bytesRead];    webServerReadHandlerEOF = (bytesRead == 0);    if (bytesToRead <= 0)	WriteStdinEof();    ScheduleIo();}/* *---------------------------------------------------------------------- * * AppServerWriteHandler -- * *      Non-blocking writes data from the fromWS buffer to the FCGI *      application server.  Called only when fromWS is non-empty *      and the socket is ready to accept some data. * *---------------------------------------------------------------------- */static void AppServerWriteHandler(ClientData dc, int bytesWritten){    int length = fromWS.stop - fromWS.next;    /* Touch unused parameters to avoid warnings */    dc = NULL;    assert(length > 0);    assert(fcgiWritePending == TRUE);    fcgiWritePending = FALSE;    if(bytesWritten < 0) {        exit(OS_Errno);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?