cgi-fcgi.c

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

C
850
字号
    }    if((int)bytesWritten < length) {        fromWS.next += bytesWritten;    } else {        fromWS.stop = fromWS.next = &fromWS.buff[0];    }    ScheduleIo();}/* * ScheduleIo -- * *      This functions is responsible for scheduling all I/O to move *      data between a web server and a FastCGI application. * * Results: *      None. * * Side effects: *      This routine will signal the ioEvent upon completion. * */static void ScheduleIo(void){    int length;    /*     * Move data between standard in and the FastCGI connection.     */    if(!fcgiWritePending && appServerSock != -1 &&       ((length = fromWS.stop - fromWS.next) != 0)) {	if(OS_AsyncWrite(appServerSock, 0, fromWS.next, length,			 AppServerWriteHandler,			 (ClientData)appServerSock) == -1) {	    FCGIexit(OS_Errno);	} else {	    fcgiWritePending = TRUE;	}    }    /*     * Schedule a read from the FastCGI application if there's not     * one pending and there's room in the buffer.     */    if(!fcgiReadPending && appServerSock != -1) {	fromAS.next = &fromAS.buff[0];	if(OS_AsyncRead(appServerSock, 0, fromAS.next, BUFFLEN,			AppServerReadHandler,			(ClientData)appServerSock) == -1) {	    FCGIexit(OS_Errno);	} else {	    fcgiReadPending = TRUE;	}    }    /*     * Schedule a read from standard in if necessary.     */    if((bytesToRead > 0) && !webServerReadHandlerEOF && !wsReadPending &&       !fcgiWritePending &&       fromWS.next == &fromWS.buff[0]) {	if(OS_AsyncReadStdin(fromWS.next + sizeof(FCGI_Header),			     BUFFLEN - sizeof(FCGI_Header),			     WebServerReadHandler, STDIN_FILENO)== -1) {	    FCGIexit(OS_Errno);	} else {	    wsReadPending = TRUE;	}    }}/* *---------------------------------------------------------------------- * * FCGI_Start -- * *      Starts nServers copies of FCGI application appPath, all *      listening to a Unix Domain socket at bindPath. * *---------------------------------------------------------------------- */static void FCGI_Start(char *bindPath, char *appPath, int nServers){    int listenFd, i;    /* @@@ Should be able to pick up the backlog as an arg */    if((listenFd = OS_CreateLocalIpcFd(bindPath, 5)) == -1) {        exit(OS_Errno);    }    if(access(appPath, X_OK) == -1) {	fprintf(stderr, "%s is not executable\n", appPath);	exit(1);    }    /*     * Create the server processes     */    for(i = 0; i < nServers; i++) {        if(OS_SpawnChild(appPath, listenFd) == -1) {            exit(OS_Errno);	}    }    OS_Close(listenFd);}/* *---------------------------------------------------------------------- * * FCGIUtil_BuildNameValueHeader -- * *      Builds a name-value pair header from the name length *      and the value length.  Stores the header into *headerBuffPtr, *      and stores the length of the header into *headerLenPtr. * * Side effects: *      Stores header's length (at most 8) into *headerLenPtr, *      and stores the header itself into *      headerBuffPtr[0 .. *headerLenPtr - 1]. * *---------------------------------------------------------------------- */static void FCGIUtil_BuildNameValueHeader(        int nameLen,        int valueLen,        unsigned char *headerBuffPtr,        int *headerLenPtr) {    unsigned char *startHeaderBuffPtr = headerBuffPtr;    ASSERT(nameLen >= 0);    if (nameLen < 0x80) {        *headerBuffPtr++ = (unsigned char) nameLen;    } else {        *headerBuffPtr++ = (unsigned char) ((nameLen >> 24) | 0x80);        *headerBuffPtr++ = (unsigned char) (nameLen >> 16);        *headerBuffPtr++ = (unsigned char) (nameLen >> 8);        *headerBuffPtr++ = (unsigned char) nameLen;    }    ASSERT(valueLen >= 0);    if (valueLen < 0x80) {        *headerBuffPtr++ = (unsigned char) valueLen;    } else {        *headerBuffPtr++ = (unsigned char) ((valueLen >> 24) | 0x80);        *headerBuffPtr++ = (unsigned char) (valueLen >> 16);        *headerBuffPtr++ = (unsigned char) (valueLen >> 8);        *headerBuffPtr++ = (unsigned char) valueLen;    }    *headerLenPtr = headerBuffPtr - startHeaderBuffPtr;}#define MAXARGS	16static int ParseArgs(int argc, char *argv[],        int *doBindPtr, int *doStartPtr,        char *connectPathPtr, char *appPathPtr, int *nServersPtr) {    int	    i,	    x,	    err = 0,	    ac;    char    *tp1,	    *tp2,	    *av[MAXARGS];    FILE    *fp;    char    line[BUFSIZ];    *doBindPtr = TRUE;    *doStartPtr = TRUE;    *connectPathPtr = '\0';    *appPathPtr = '\0';    *nServersPtr = 0;    for(i = 0; i < MAXARGS; i++)        av[i] = NULL;    for(i = 1; i < argc; i++) {        if(argv[i][0] == '-') {            if(!strcmp(argv[i], "-f")) {		if(++i == argc) {		    fprintf(stderr,                            "Missing command file name after -f\n");		    return 1;		}		if((fp = fopen(argv[i], "r")) == NULL) {		    fprintf(stderr, "Cannot open command file %s\n", argv[i]);		    return 1;		}		ac = 1;		while(fgets(line, BUFSIZ, fp)) {		    if(line[0] == '#') {			continue;		    }		    if((tp1 = (char *) strrchr(line,'\n')) != NULL) {			*tp1-- = 0;			while(*tp1 == ' ' || *tp1 =='\t') {			    *tp1-- = 0;		        }		    } else {			fprintf(stderr, "Line to long\n");			return 1;		    }		    tp1 = line;		    while(tp1) {			if((tp2 = strchr(tp1, ' ')) != NULL) {			    *tp2++ =  0;		        }    			if(ac >= MAXARGS) {			    fprintf(stderr,                                    "To many arguments, "                                    "%d is max from a file\n", MAXARGS);				exit(-1);			}			if((av[ac] = (char *)malloc(strlen(tp1)+1)) == NULL) {			    fprintf(stderr, "Cannot allocate %d bytes\n",				    strlen(tp1)+1);			    exit(-1);			}			strcpy(av[ac++], tp1);			tp1 = tp2;		    }		}		err = ParseArgs(ac, av, doBindPtr, doStartPtr,                        connectPathPtr, appPathPtr, nServersPtr);		for(x = 1; x < ac; x++) {		    ASSERT(av[x] != NULL);		    free(av[x]);	        }		return err;#ifdef _WIN32	    } else if (!strcmp(argv[i], "-jitcgi")) {	        DebugBreak();	    } else if (!strcmp(argv[i], "-dbgfcgi")) {	        putenv("DEBUG_FCGI=TRUE");#endif	    } else if(!strcmp(argv[i], "-start")) {		*doBindPtr = FALSE;	    } else if(!strcmp(argv[i], "-bind")) {		*doStartPtr = FALSE;	    } else if(!strcmp(argv[i], "-connect")) {                if(++i == argc) {	            fprintf(stderr,                            "Missing connection name after -connect\n");                    err++;                } else {                    strcpy(connectPathPtr, argv[i]);                }	    } else {		fprintf(stderr, "Unknown option %s\n", argv[i]);		err++;	    }	} else if(*appPathPtr == '\0') {            strcpy(appPathPtr, argv[i]);        } else if(isdigit((int)argv[i][0]) && *nServersPtr == 0) {            *nServersPtr = atoi(argv[i]);            if(*nServersPtr <= 0) {                fprintf(stderr, "Number of servers must be greater than 0\n");                err++;            }        } else {            fprintf(stderr, "Unknown argument %s\n", argv[i]);            err++;        }    }    if(*doStartPtr && *appPathPtr == 0) {        fprintf(stderr, "Missing application pathname\n");        err++;    }    if(*connectPathPtr == 0) {	fprintf(stderr, "Missing -connect <connName>\n");	err++;    } else if(strchr(connectPathPtr, ':')) {/* * XXX: Test to see if we can use IP connect locally...        This hack lets me test the ability to create a local process listening	to a TCP/IP port for connections and subsequently connect to the app	like we do for Unix domain and named pipes.        if(*doStartPtr && *doBindPtr) {	    fprintf(stderr,                    "<connName> of form hostName:portNumber "                    "requires -start or -bind\n");	    err++;        } */    }    if(*nServersPtr == 0) {        *nServersPtr = 1;    }    return err;}int main(int argc, char **argv){    char **envp = environ;    int count;    FCGX_Stream *paramsStream;    int numFDs;    unsigned char headerBuff[8];    int headerLen, valueLen;    char *equalPtr;    FCGI_BeginRequestRecord beginRecord;    int	doBind, doStart, nServers;    char appPath[MAXPATHLEN], bindPath[MAXPATHLEN];    if(ParseArgs(argc, argv, &doBind, &doStart,		   (char *) &bindPath, (char *) &appPath, &nServers)) {	fprintf(stderr,"Usage:\n""    cgi-fcgi -f <cmdPath> , or\n""    cgi-fcgi -connect <connName> <appPath> [<nServers>] , or\n""    cgi-fcgi -start -connect <connName> <appPath> [<nServers>] , or\n""    cgi-fcgi -bind -connect <connName> ,\n""where <connName> is either the pathname of a UNIX domain socket\n""or (if -bind is given) a hostName:portNumber specification\n""or (if -start is given) a :portNumber specification (uses local host).\n");	exit(1);    }    if(OS_LibInit(stdinFds)) {        fprintf(stderr, "Error initializing OS library: %d\n", OS_Errno);	exit(0);    }    equalPtr = getenv("CONTENT_LENGTH");    if(equalPtr != NULL) {        bytesToRead = atoi(equalPtr);    } else {        bytesToRead = 0;    }    if(doBind) {        appServerSock = OS_FcgiConnect(bindPath);    }    if(doStart && (!doBind || appServerSock < 0)) {        FCGI_Start(bindPath, appPath, nServers);        if(!doBind) {            exit(0);        } else {            appServerSock = OS_FcgiConnect(bindPath);	}    }    if(appServerSock < 0) {        fprintf(stderr, "Could not connect to %s\n", bindPath);        exit(OS_Errno);    }    /*     * Set an arbitrary non-null FCGI RequestId     */    requestId = 1;    /*     * XXX: Send FCGI_GET_VALUES     */    /*     * XXX: Receive FCGI_GET_VALUES_RESULT     */    /*     * Send FCGI_BEGIN_REQUEST (XXX: hack, separate write)     */    beginRecord.header = MakeHeader(FCGI_BEGIN_REQUEST, requestId,            sizeof(beginRecord.body), 0);    beginRecord.body = MakeBeginRequestBody(FCGI_RESPONDER, FALSE);    count = OS_Write(appServerSock, (char *)&beginRecord, sizeof(beginRecord));    if(count != sizeof(beginRecord)) {        exit(OS_Errno);    }    /*     * Send environment to the FCGI application server     */    paramsStream = FCGX_CreateWriter(appServerSock, requestId, 8192, FCGI_PARAMS);    for( ; *envp != NULL; envp++) {        equalPtr = strchr(*envp, '=');        if(equalPtr  == NULL) {            exit(1000);        }        valueLen = strlen(equalPtr + 1);        FCGIUtil_BuildNameValueHeader(                equalPtr - *envp,                valueLen,                &headerBuff[0],                &headerLen);        if(FCGX_PutStr((char *) &headerBuff[0], headerLen, paramsStream) < 0                || FCGX_PutStr(*envp, equalPtr - *envp, paramsStream) < 0                || FCGX_PutStr(equalPtr + 1, valueLen, paramsStream) < 0) {            exit(FCGX_GetError(paramsStream));        }    }    FCGX_FClose(paramsStream);    FCGX_FreeStream(&paramsStream);    /*     * Perform the event loop until AppServerReadHander sees FCGI_END_REQUEST     */    fromWS.stop = fromWS.next = &fromWS.buff[0];    webServerReadHandlerEOF = FALSE;    /*     * XXX: might want to use numFDs in the os library.     */    numFDs = max(appServerSock, STDIN_FILENO) + 1;    OS_SetFlags(appServerSock, O_NONBLOCK);    if (bytesToRead <= 0)	WriteStdinEof();    ScheduleIo();    while(!exitStatusSet) {        /*	 * NULL = wait forever (or at least until there's something	 *        to do.	 */        OS_DoIo(NULL);    }    if(exitStatusSet) {        FCGIexit(exitStatus);    } else {        FCGIexit(999);    }    return 0;}

⌨️ 快捷键说明

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