⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fcgiapp.c

📁 FastCGI,语言无关的、可伸缩架构的CGI开放扩展
💻 C
📖 第 1 页 / 共 5 页
字号:
 *---------------------------------------------------------------------- */static int AlignInt8(unsigned n) {    return (n + 7) & (UINT_MAX - 7);}/* *---------------------------------------------------------------------- * * AlignPtr8 -- * *      Returns the smallest pointer greater than or equal to p *      that's a multiple of 8. * *---------------------------------------------------------------------- */static unsigned char *AlignPtr8(unsigned char *p) {    unsigned long u = (unsigned long) p;    u = ((u + 7) & (ULONG_MAX - 7)) - u;    return p + u;}/* * State associated with a stream */typedef struct FCGX_Stream_Data {    unsigned char *buff;      /* buffer after alignment */    int bufflen;              /* number of bytes buff can store */    unsigned char *mBuff;     /* buffer as returned by Malloc */    unsigned char *buffStop;  /* reader: last valid byte + 1 of entire buffer.                               * stop generally differs from buffStop for                               * readers because of record structure.                               * writer: buff + bufflen */    int type;                 /* reader: FCGI_PARAMS or FCGI_STDIN                               * writer: FCGI_STDOUT or FCGI_STDERR */    int eorStop;              /* reader: stop stream at end-of-record */    int skip;                 /* reader: don't deliver content bytes */    int contentLen;           /* reader: bytes of unread content */    int paddingLen;           /* reader: bytes of unread padding */    int isAnythingWritten;    /* writer: data has been written to ipcFd */    int rawWrite;             /* writer: write data without stream headers */    FCGX_Request *reqDataPtr; /* request data not specific to one stream */} FCGX_Stream_Data;/* *---------------------------------------------------------------------- * * WriteCloseRecords -- * *      Writes an EOF record for the stream content if necessary. *      If this is the last writer to close, writes an FCGI_END_REQUEST *      record. * *---------------------------------------------------------------------- */static void WriteCloseRecords(struct FCGX_Stream *stream){    FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;    /*     * Enter rawWrite mode so final records won't be encapsulated as     * stream data.     */    data->rawWrite = TRUE;    /*     * Generate EOF for stream content if needed.     */    if(!(data->type == FCGI_STDERR            && stream->wrNext == data->buff            && !data->isAnythingWritten)) {        FCGI_Header header;        header = MakeHeader(data->type, data->reqDataPtr->requestId, 0, 0);        FCGX_PutStr((char *) &header, sizeof(header), stream);    };    /*     * Generate FCGI_END_REQUEST record if needed.     */    if(data->reqDataPtr->nWriters == 1) {        FCGI_EndRequestRecord endRequestRecord;        endRequestRecord.header = MakeHeader(FCGI_END_REQUEST,                data->reqDataPtr->requestId,                sizeof(endRequestRecord.body), 0);        endRequestRecord.body = MakeEndRequestBody(                data->reqDataPtr->appStatus, FCGI_REQUEST_COMPLETE);        FCGX_PutStr((char *) &endRequestRecord,                sizeof(endRequestRecord), stream);    }    data->reqDataPtr->nWriters--;}static int write_it_all(int fd, char *buf, int len){    int wrote;    while (len) {        wrote = OS_Write(fd, buf, len);        if (wrote < 0)            return wrote;        len -= wrote;        buf += wrote;    }    return len;}/* *---------------------------------------------------------------------- * * EmptyBuffProc -- * *      Encapsulates any buffered stream content in a FastCGI *      record.  Writes the data, making the buffer empty. * *---------------------------------------------------------------------- */static void EmptyBuffProc(struct FCGX_Stream *stream, int doClose){    FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;    int cLen, eLen;    /*     * If the buffer contains stream data, fill in the header.     * Pad the record to a multiple of 8 bytes in length.  Padding     * can't overflow the buffer because the buffer is a multiple     * of 8 bytes in length.  If the buffer contains no stream     * data, reclaim the space reserved for the header.     */    if(!data->rawWrite) {        cLen = stream->wrNext - data->buff - sizeof(FCGI_Header);        if(cLen > 0) {            eLen = AlignInt8(cLen);            /*             * Giving the padding a well-defined value keeps Purify happy.             */            memset(stream->wrNext, 0, eLen - cLen);            stream->wrNext += eLen - cLen;            *((FCGI_Header *) data->buff)                    = MakeHeader(data->type,                            data->reqDataPtr->requestId, cLen, eLen - cLen);        } else {            stream->wrNext = data->buff;	}    }    if(doClose) {        WriteCloseRecords(stream);    };    if (stream->wrNext != data->buff) {        data->isAnythingWritten = TRUE;        if (write_it_all(data->reqDataPtr->ipcFd, (char *)data->buff, stream->wrNext - data->buff) < 0) {            SetError(stream, OS_Errno);            return;        }        stream->wrNext = data->buff;    }    /*     * The buffer is empty.     */    if(!data->rawWrite) {        stream->wrNext += sizeof(FCGI_Header);    }}/* * Return codes for Process* functions */#define STREAM_RECORD 0#define SKIP          1#define BEGIN_RECORD  2#define MGMT_RECORD   3/* *---------------------------------------------------------------------- * * ProcessManagementRecord -- * *      Reads and responds to a management record.  The only type of *      management record this library understands is FCGI_GET_VALUES. *      The only variables that this library's FCGI_GET_VALUES *      understands are FCGI_MAX_CONNS, FCGI_MAX_REQS, and FCGI_MPXS_CONNS. *      Ignore other FCGI_GET_VALUES variables; respond to other *      management records with a FCGI_UNKNOWN_TYPE record. * *---------------------------------------------------------------------- */static int ProcessManagementRecord(int type, FCGX_Stream *stream){    FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;    ParamsPtr paramsPtr = NewParams(3);    char **pPtr;    char response[64]; /* 64 = 8 + 3*(1+1+14+1)* + padding */    char *responseP = &response[FCGI_HEADER_LEN];    char *name, value = '\0';    int len, paddedLen;    if(type == FCGI_GET_VALUES) {        ReadParams(paramsPtr, stream);        if((FCGX_GetError(stream) != 0) || (data->contentLen != 0)) {            FreeParams(&paramsPtr);            return FCGX_PROTOCOL_ERROR;        }        for (pPtr = paramsPtr->vec; pPtr < paramsPtr->cur; pPtr++) {            name = *pPtr;            *(strchr(name, '=')) = '\0';            if(strcmp(name, FCGI_MAX_CONNS) == 0) {                value = '1';            } else if(strcmp(name, FCGI_MAX_REQS) == 0) {                value = '1';            } else if(strcmp(name, FCGI_MPXS_CONNS) == 0) {                value = '0';            } else {                name = NULL;            }            if(name != NULL) {                len = strlen(name);                sprintf(responseP, "%c%c%s%c", len, 1, name, value);                responseP += len + 3;	    }        }        len = responseP - &response[FCGI_HEADER_LEN];        paddedLen = AlignInt8(len);        *((FCGI_Header *) response)            = MakeHeader(FCGI_GET_VALUES_RESULT, FCGI_NULL_REQUEST_ID,                         len, paddedLen - len);        FreeParams(&paramsPtr);    } else {        paddedLen = len = sizeof(FCGI_UnknownTypeBody);        ((FCGI_UnknownTypeRecord *) response)->header            = MakeHeader(FCGI_UNKNOWN_TYPE, FCGI_NULL_REQUEST_ID,                         len, 0);        ((FCGI_UnknownTypeRecord *) response)->body            = MakeUnknownTypeBody(type);    }    if (write_it_all(data->reqDataPtr->ipcFd, response, FCGI_HEADER_LEN + paddedLen) < 0) {        SetError(stream, OS_Errno);        return -1;    }    return MGMT_RECORD;}/* *---------------------------------------------------------------------- * * ProcessBeginRecord -- * *      Reads an FCGI_BEGIN_REQUEST record. * * Results: *      BEGIN_RECORD for normal return.  FCGX_PROTOCOL_ERROR for *      protocol error.  SKIP for attempt to multiplex *      connection.  -1 for error from write (errno in stream). * * Side effects: *      In case of BEGIN_RECORD return, stores requestId, role, *      keepConnection values, and sets isBeginProcessed = TRUE. * *---------------------------------------------------------------------- */static int ProcessBeginRecord(int requestId, FCGX_Stream *stream){    FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;    FCGI_BeginRequestBody body;    if(requestId == 0 || data->contentLen != sizeof(body)) {        return FCGX_PROTOCOL_ERROR;    }    if(data->reqDataPtr->isBeginProcessed) {        /*         * The Web server is multiplexing the connection.  This library         * doesn't know how to handle multiplexing, so respond with         * FCGI_END_REQUEST{protocolStatus = FCGI_CANT_MPX_CONN}         */        FCGI_EndRequestRecord endRequestRecord;        endRequestRecord.header = MakeHeader(FCGI_END_REQUEST,                requestId, sizeof(endRequestRecord.body), 0);        endRequestRecord.body                = MakeEndRequestBody(0, FCGI_CANT_MPX_CONN);        if (write_it_all(data->reqDataPtr->ipcFd, (char *)&endRequestRecord, sizeof(endRequestRecord)) < 0) {            SetError(stream, OS_Errno);            return -1;        }        return SKIP;    }    /*     * Accept this new request.  Read the record body.     */    data->reqDataPtr->requestId = requestId;    if(FCGX_GetStr((char *) &body, sizeof(body), stream)            != sizeof(body)) {        return FCGX_PROTOCOL_ERROR;    }    data->reqDataPtr->keepConnection = (body.flags & FCGI_KEEP_CONN);    data->reqDataPtr->role = (body.roleB1 << 8) + body.roleB0;    data->reqDataPtr->isBeginProcessed = TRUE;    return BEGIN_RECORD;}/* *---------------------------------------------------------------------- * * ProcessHeader -- * *      Interprets FCGI_Header.  Processes FCGI_BEGIN_REQUEST and *      management records here; extracts information from stream *      records (FCGI_PARAMS, FCGI_STDIN) into stream. * * Results: *      >= 0 for a normal return, < 0 for error * * Side effects: *      XXX: Many (more than there used to be). *      If !stream->isRequestIdSet, ProcessHeader initializes *      stream->requestId from header and sets stream->isRequestIdSet *      to TRUE.  ProcessHeader also sets stream->contentLen to header's *      contentLength, and sets stream->paddingLen to the header's *      paddingLength. * *---------------------------------------------------------------------- */static int ProcessHeader(FCGI_Header header, FCGX_Stream *stream){    FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;    int requestId;    if(header.version != FCGI_VERSION_1) {        return FCGX_UNSUPPORTED_VERSION;    }    requestId =        (header.requestIdB1 << 8)                         + header.requestIdB0;    data->contentLen = (header.contentLengthB1 << 8)                         + header.contentLengthB0;    data->paddingLen = header.paddingLength;    if(header.type == FCGI_BEGIN_REQUEST) {        return ProcessBeginRecord(requestId, stream);    }    if(requestId  == FCGI_NULL_REQUEST_ID) {        return ProcessManagementRecord(header.type, stream);    }    if(requestId != data->reqDataPtr->requestId) {        return SKIP;    }    if(header.type != data->type) {        return FCGX_PROTOCOL_ERROR;    }    return STREAM_RECORD;}/* *---------------------------------------------------------------------- * * FillBuffProc -- * *      Reads bytes from the ipcFd, supplies bytes to a stream client. * *---------------------------------------------------------------------- */static void FillBuffProc(FCGX_Stream *stream){    FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;    FCGI_Header header;    int headerLen = 0;    int status, count;    for (;;) {        /*         * If data->buff is empty, do a read.         */        if(stream->rdNext == data->buffStop) {            count = OS_Read(data->reqDataPtr->ipcFd, (char *)data->buff,                            data->bufflen);            if(count <= 0) {                SetError(stream, (count == 0 ? FCGX_PROTOCOL_ERROR : OS_Errno));                return;            }            stream->rdNext = data->buff;            data->buffStop = data->buff + count;	}        /*         * Now data->buff is not empty.  If the current record contains         * more content bytes, deliver all that are present in data->buff.         */        if(data->contentLen > 0) {            count = min(data->contentLen, data->buffStop - stream->rdNext);            data->contentLen -= count;            if(!data->skip) {                stream->wrNext = stream->stop = stream->rdNext + count;                return;	    } else {                stream->rdNext += count;                if(data->contentLen > 0) {                    continue;	        } else {                    data->skip = FALSE;	        }	    }	}        /*         * If the current record (whose content has been fully consumed by         * the client) was padded, skip over the padding bytes.         */        if(data->paddingLen > 0) {            count = min(data->paddingLen, data->buffStop - stream->rdNext);            data->paddingLen -= count;            stream->rdNext += count;            if(data->paddingLen > 0) {                continue;	    }	}        /*         * All done with the current record, including the padding.         * If we're in a recursive call from ProcessHeader, deliver EOF.         */        if(data->eorStop) {            stream->stop = stream->rdNext;            stream->isClosed = TRUE;            return;        }        /*         * Fill header with bytes from the input buffer.         */        count = min((int)sizeof(header) - headerLen,                        data->buffStop - stream->rdNext);        memcpy(((char *)(&header)) + headerLen, stream->rdNext, count);        headerLen += count;        stream->rdNext += count;

⌨️ 快捷键说明

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