📄 fcgi_stdio.c
字号:
/* * fcgi_stdio.c -- * * 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. * */#ifndef lintstatic const char rcsid[] = "$Id: fcgi_stdio.c,v 1.14 2001/09/01 01:09:30 robs Exp $";#endif /* not lint */#include <errno.h> /* for errno */#include <stdarg.h> /* for va_arg */#include <stdlib.h> /* for malloc */#include <string.h> /* for strerror */#include "fcgi_config.h"#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#ifdef _WIN32#define DLLAPI __declspec(dllexport)#endif#include "fcgiapp.h"#include "fcgios.h"#include "fcgimisc.h"#define NO_FCGI_DEFINES#include "fcgi_stdio.h"#undef NO_FCGI_DEFINES#ifndef _WIN32extern char **environ;#ifdef HAVE_FILENO_PROTO#include <stdio.h>#elseextern int fileno(FILE *stream);#endifextern FILE *fdopen(int fildes, const char *type);extern FILE *popen(const char *command, const char *type);extern int pclose(FILE *stream);#else /* _WIN32 */#define popen _popen#define pclose _pclose#endif /* _WIN32 */FCGI_FILE _fcgi_sF[3];/* *---------------------------------------------------------------------- * * FCGI_Accept -- * * Accepts a new request from the HTTP server and creates * a conventional execution environment for the request. * * If the application was invoked as a FastCGI server, * the first call to FCGI_Accept indicates that the application * has completed its initialization and is ready to accept * a request. Subsequent calls to FCGI_Accept indicate that * the application has completed its processing of the * current request and is ready to accept a new request. * * If the application was invoked as a CGI program, the first * call to FCGI_Accept is essentially a no-op and the second * call returns EOF (-1). * * Results: * 0 for successful call, -1 for error (application should exit). * * Side effects: * If the application was invoked as a FastCGI server, * and this is not the first call to this procedure, * FCGI_Accept first performs the equivalent of FCGI_Finish. * * On every call, FCGI_Accept accepts the new request and * reads the FCGI_PARAMS stream into an environment array, * i.e. a NULL-terminated array of strings of the form * ``name=value''. It assigns a pointer to this array * to the global variable environ, used by the standard * library function getenv. It creates new FCGI_FILE *s * representing input from the HTTP server, output to the HTTP * server, and error output to the HTTP server, and assigns these * new files to stdin, stdout, and stderr respectively. * * DO NOT mutate or retain pointers to environ or any values * contained in it (e.g. to the result of calling getenv(3)), * since these are freed by the next call to FCGI_Finish or * FCGI_Accept. In particular do not use setenv(3) or putenv(3) * in conjunction with FCGI_Accept. * *---------------------------------------------------------------------- */static int acceptCalled = FALSE;static int isCGI = FALSE;int FCGI_Accept(void){ if(!acceptCalled) { /* * First call to FCGI_Accept. Is application running * as FastCGI or as CGI? */ isCGI = FCGX_IsCGI(); acceptCalled = TRUE; atexit(&FCGI_Finish); } else if(isCGI) { /* * Not first call to FCGI_Accept and running as CGI means * application is done. */ return(EOF); } if(isCGI) { FCGI_stdin->stdio_stream = stdin; FCGI_stdin->fcgx_stream = NULL; FCGI_stdout->stdio_stream = stdout; FCGI_stdout->fcgx_stream = NULL; FCGI_stderr->stdio_stream = stderr; FCGI_stderr->fcgx_stream = NULL; } else { FCGX_Stream *in, *out, *error; FCGX_ParamArray envp; int acceptResult = FCGX_Accept(&in, &out, &error, &envp); if(acceptResult < 0) { return acceptResult; } FCGI_stdin->stdio_stream = NULL; FCGI_stdin->fcgx_stream = in; FCGI_stdout->stdio_stream = NULL; FCGI_stdout->fcgx_stream = out; FCGI_stderr->stdio_stream = NULL; FCGI_stderr->fcgx_stream = error; environ = envp; } return 0;}/* *---------------------------------------------------------------------- * * FCGI_Finish -- * * Finishes the current request from the HTTP server. * * Side effects: * * Flushes any buffered output to the HTTP server. Then frees * all storage allocated by the previous call, including all * storage reachable from the value of environ set by the previous * call to FCGI_Accept. * * DO NOT use stdin, stdout, stderr, or environ between calling * FCGI_Finish and calling FCGI_Accept. * * DO NOT mutate or retain pointers to environ or any values * contained in it (e.g. to the result of calling getenv(3)), * since these are freed by the next call to FCGI_Finish or * FCGI_Accept. In particular do not use setenv(3) or putenv(3) * in conjunction with FCGI_Accept. * *---------------------------------------------------------------------- */void FCGI_Finish(void){ if(!acceptCalled || isCGI) { return; } FCGX_Finish(); FCGI_stdin->fcgx_stream = NULL; FCGI_stdout->fcgx_stream = NULL; FCGI_stderr->fcgx_stream = NULL; environ = NULL;}/* *---------------------------------------------------------------------- * * FCGI_StartFilterData -- * * * The current request is for the filter role, and stdin is * positioned at EOF of FCGI_STDIN. The call repositions * stdin to the start of FCGI_DATA. * If the preconditions are not met (e.g. FCGI_STDIN has not * been read to EOF), the call sets the stream error code to * FCGX_CALL_SEQ_ERROR. * * Results: * 0 for a normal return, < 0 for error * *---------------------------------------------------------------------- */int FCGI_StartFilterData(void){ if(FCGI_stdin->stdio_stream) { return -1; } else { return FCGX_StartFilterData(FCGI_stdin->fcgx_stream); }}/* *---------------------------------------------------------------------- * * FCGI_SetExitStatus -- * * Sets the exit status for the current 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 * FCGI_SetExitStatus several times during a request; the last call * before the request ends (by calling FCGI_Accept) determines the * value. * *---------------------------------------------------------------------- */void FCGI_SetExitStatus(int status){ if(FCGI_stdin->fcgx_stream) { FCGX_SetExitStatus(status, FCGI_stdin->fcgx_stream); }}/* *---------------------------------------------------------------------- * * FCGI_perror -- * * Wrapper for function defined in H&S Section 11.2 * *---------------------------------------------------------------------- */void FCGI_perror(const char *str){ FCGI_fputs(str, FCGI_stderr); FCGI_fputs(": ", FCGI_stderr); FCGI_fputs(strerror(OS_Errno), FCGI_stderr); return;}/* *---------------------------------------------------------------------- * * FCGI_OpenFromFILE -- * * Constructs a new FCGI_FILE * from the FILE *stream. * * Results: * NULL if stream == NULL or storage could not be allocated, * otherwise the new FCGI_FILE *. * *---------------------------------------------------------------------- */static FCGI_FILE *FCGI_OpenFromFILE(FILE *stream){ FCGI_FILE *fp; if (stream == NULL) return NULL; fp = (FCGI_FILE *) malloc(sizeof(FCGI_FILE)); if (fp != NULL) { fp->stdio_stream = stream; fp->fcgx_stream = NULL; } return fp;}/* *---------------------------------------------------------------------- * * FCGI_fopen, FCGI_fclose, FCGI_fflush, FCGI_freopen -- * * Wrappers for functions defined in H&S Section 15.2 * *---------------------------------------------------------------------- */FCGI_FILE *FCGI_fopen(const char *path, const char *mode){ FILE * file = fopen(path, mode); FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file); if (file && !fcgi_file) fclose(file); return fcgi_file;}int FCGI_fclose(FCGI_FILE *fp){ int n = EOF; if(fp->stdio_stream) { n = fclose(fp->stdio_stream); fp->stdio_stream = NULL; } else if(fp->fcgx_stream) { n = FCGX_FClose(fp->fcgx_stream); fp->fcgx_stream = NULL; } if((fp != FCGI_stdin) && (fp != FCGI_stdout) && (fp != FCGI_stderr)) { free(fp); } return n;}int FCGI_fflush(FCGI_FILE *fp){ if(fp == NULL) return fflush(NULL); if(fp->stdio_stream) return fflush(fp->stdio_stream); else if(fp->fcgx_stream) return FCGX_FFlush(fp->fcgx_stream); return EOF;}FCGI_FILE *FCGI_freopen(const char *path, const char *mode, FCGI_FILE *fp){ if(fp->stdio_stream) { if(freopen(path, mode, fp->stdio_stream) == NULL) return NULL; else return fp; } else if(fp->fcgx_stream) { (void) FCGX_FClose(fp->fcgx_stream); fp->stdio_stream = fopen(path, mode); if(fp->stdio_stream == NULL) return NULL; else { fp->fcgx_stream = NULL; return fp; } } return NULL;}/* *---------------------------------------------------------------------- * * FCGI_setvbuf, FCGI_setbuf -- * * Wrappers for functions defined in H&S Section 15.3 * *---------------------------------------------------------------------- */int FCGI_setvbuf(FCGI_FILE *fp, char *buf, int bufmode, size_t size){ if(fp->stdio_stream) return setvbuf(fp->stdio_stream, buf, bufmode, size); else { return -1; }}void FCGI_setbuf(FCGI_FILE *fp, char *buf){ if(fp->stdio_stream) setbuf(fp->stdio_stream, buf);}/* *---------------------------------------------------------------------- * * FCGI_fseek, FCGI_ftell, FCGI_rewind, FCGI_fgetpos, FCGI_fsetpos -- * * Wrappers for functions defined in H&S Section 15.5 * *---------------------------------------------------------------------- */int FCGI_fseek(FCGI_FILE *fp, long offset, int whence){ if(fp->stdio_stream) return fseek(fp->stdio_stream, offset, whence); else { OS_SetErrno(ESPIPE); return -1; }}int FCGI_ftell(FCGI_FILE *fp){ if(fp->stdio_stream) return ftell(fp->stdio_stream);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -