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 + -
显示快捷键?