📄 fastcgi.cpp
字号:
};
if ( eRecordState == RECORD )
{
/* ---
Read fast cgi record
--- */
assert( iReadSoFar<iRecordLength );
int iToRead = iRecordLength - iReadSoFar;
// Can't read more than in the buffer at once
if (iToRead > iLen - tHeader.paddingLength) {
// Cut padding bytes
iToRead = iLen - tHeader.paddingLength;
};
memcpy( &(pBuffer[iReadSoFar]), pData, iToRead );
iReadSoFar += iToRead;
if ( iReadSoFar<iRecordLength )
{ /* --- read more into buffer --- */; continue; };
/* ---
Record fully read
--- */
};
HTTPCore_logDebug( DBG_MED, "FastCGI: %s, Read header of type %d.",
szIdent, (int)tHeader.type );
/* ---
Process this fcgi record
--- */
switch( tHeader.type )
{
case FCGI_STDERR:
{
/* ---
Append to the stderr message
--- */
PIString sTmp( pBuffer, iRecordLength );
sStdErr.Concatenate( sTmp );
};
break;
case FCGI_STDOUT:
if ( HandleFcgiStdout( tPIHTTP, pBuffer, iRecordLength,
iVariablePos, iReadingVariables, szIdent )==-1)
{
iExit = -1;
};
break;
case FCGI_END_REQUEST:
iExit = 0;
break;
case FCGI_GET_VALUES_RESULT:
/* not implemented */
case FCGI_UNKNOWN_TYPE:
/* not implemented */
default:
iExit = -1;
};
/* ---
Done with this record
--- */
PI_DELETE( [] pBuffer );
/* ---
Reset state to read next fcgi header
--- */
iReadSoFar = 0;
eRecordState = HEADER;
};
HTTPCore_logDebug( DBG_LOW, "FastCGI: %s, done reading response.",
szIdent );
/* ---
At this point the protocol headers should have been sent to the
client and we should have been reading the data to send to the
client
--- */
if ( iReadingVariables )
{
/* --- but I guess it didn't work out that way... --- */
HTTPCore_logError( &tPIHTTP, "FastCGI: Failure to read \
proper fcgi STDOUT response from fcgi application '%s'.", szIdent );
iExit = -1;
};
/* ---
If the CGI application wrote stderr log it
Log stderr message
--- */
if ( sStdErr.Len()>0 )
{
HTTPCore_logError( &tPIHTTP, "FastCGI: Fast cgi \
application '%s' wrote STDERR output. Output follows:\n\
______________________________________________________________________________\
__\n%s\n\
______________________________________________________________________________\
__", szIdent, (const char *)sStdErr );
iExit = -1;
};
return iExit;
};
/* -------------- +++++++++++++++++++++++++++++++ ------------------ *\
Guts
\* -------------- +++++++++++++++++++++++++++++++ ------------------ */
/* ---
GetFcgiConnection(), get a connection to the Fcgi application. This
function can copy a new connection or reuse an existing one.
For simplicity this function creates a new connection right now.
--- */
PIObject *GetFcgiConnection( PIHTTP &tPIHTTP, const PIString &sFcgiHost,
int iFcgiPort )
{
(void)tPIHTTP;
/* --- establish a connection to the remote Fcgi app. server --- */
const char *ppConnectParameters[2];
ppConnectParameters[0] = (const char *)sFcgiHost;
ppConnectParameters[1] = (const char *)iFcgiPort;
PIObject *pConn = PIObject_copy( pIO, 2, ppConnectParameters );
return pConn;
};
/* ---
ReleaseFcgiConnection(), release a connection to the fast cgi application,
in the future this could be used to allow connection reuse.
--- */
void ReleaseFcgiConnection( PIObject *pConnection )
{
/* --- always destroy the connection --- */
if ( pConnection )
{ PIObject_delete( pConnection, 0, 0 ); };
};
/* ---
Top level proxy server stuff
--- */
int DoFastCGI( PIHTTP &tPIHTTP, PIIOBuffer *pIOBuffer,
const char *szIdent )
{
assert( pIO );
/* PIDB *pR = tPIHTTP.pResponseDB; */
PIDB *pQ = tPIHTTP.pRequestDB;
/* ---
Send Fcgi begin message
--- */
FCGI_BeginRequestBody tBody;
tBody.roleB1 = ( FCGI_RESPONDER >> 8 ) & 0xff;
tBody.roleB0 = ( FCGI_RESPONDER ) & 0xff;
tBody.flags = 0;
memset( tBody.reserved, 0, sizeof( tBody.reserved ) );
if ( SendFcgiBody( pIOBuffer, &tBody, sizeof( tBody ),
FCGI_BEGIN_REQUEST, 1 )==-1 )
{
/* --- error sending begin request --- */
HTTPCore_logError( &tPIHTTP, "FastCGI: Error sending \
FCGI_BEGIN_REQUEST \
to fast cgi application '%s'.", szIdent );
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );
};
/* ---
Send Fcgi parameters,
--- */
char *pParamsBlock = PI_NEW( char[PARAM_BLOCK_SIZE] );
int iParamsBlockSize = PARAM_BLOCK_SIZE;
int iNumVariables = 0;
int iOK = AddEnvironmentVariables( tPIHTTP, pParamsBlock,
iParamsBlockSize, iNumVariables );
int iToSend = PARAM_BLOCK_SIZE - iParamsBlockSize;
assert( iToSend>0 );
if ( iOK && iToSend )
{
iOK = ( SendFcgiBody( pIOBuffer, pParamsBlock,
iToSend, FCGI_PARAMS, 1 )!=-1 );
};
PI_DELETE( [] pParamsBlock );
if ( !iOK )
{
HTTPCore_logError( &tPIHTTP, "FastCGI: Error \
generating or sending \
FCGI_PARAMS to fast cgi application '%s'.", szIdent );
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );
};
/* ---
Determine whether or not there is any input to be sent to the
fcgi application server.
--- */
const char *pContentLength = (const char *)PIDB_lookup( pQ,
PIDBTYPE_RFC822, KEY_HTTP_CONTENTLENGTH, 0 );
int iStdinLen = pContentLength ? atoi( pContentLength ) : 0;
if ( iStdinLen>0 )
{
/* ---
Generate header record
--- */
FCGI_Header tHeader;
GenerateFcgiHeader( tHeader, FCGI_STDIN, 1, iStdinLen );
/* ---
Send header
--- */
if ( PIIOBuffer_write( pIOBuffer, (const char *)&tHeader,
sizeof( tHeader ), PIIOBUF_NONE )!=sizeof( tHeader ) )
{
HTTPCore_logError( &tPIHTTP, "FastCGI: Error \
sending FCGI_STDIN header to fast cgi application '%s'.", szIdent );
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );
};
/* ---
Write iStdinLen bytes from browser buffer to the fcgi buffer.
--- */
if ( WriteBufferToBuffer( *pIOBuffer, *(tPIHTTP.pBuffer),
iStdinLen ) )
{
/* --- error --- */
HTTPCore_logError( &tPIHTTP, "FastCGI: Error \
sending %d bytes of STDIN from browser to fast \
cgi application '%s'.", iStdinLen, szIdent );
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );
};
}
else
{
/* ---
Send an empty fcgi record
--- */
if ( SendFcgiBody( pIOBuffer, 0, 0, FCGI_STDIN, 1 )==-1 )
{
HTTPCore_logError( &tPIHTTP, "FastCGI: Error sending \
empty FCGI_STDIN \
to fast cgi application '%s'.", szIdent );
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );
};
};
/* ---
Flush output to fcgi application
--- */
PIIOBuffer_flush( pIOBuffer );
/* ---
Read Fcgi stdout and stderr or Fcgi end request
--- */
if ( ReadFcgiResponse( tPIHTTP, pIOBuffer, szIdent )==-1 )
{
/* ---
Error message already given
--- */
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );
};
/* --- done --- */
return PIAPI_COMPLETED;
};
/* -------------- +++++++++++++++++++++++++++++++ ------------------ *\
Standard Handle Function
\* -------------- +++++++++++++++++++++++++++++++ ------------------ */
int Handle( int iPhase, PIHTTP &tPIHTTP, PIIOBuffer &/* tBuffer */ )
{
if ( iPhase!=PH_HANDLE )
{ return PIAPI_ERROR; };
assert( pIO );
const char *pPath = (const char *)PIDB_lookup( tPIHTTP.pResponseDB,
PIDBTYPE_STRING, KEY_INT_PATH, 0 );
/* ---
Check if the filename matches
--- */
if ( sFile!=PIString::Empty() )
{
if ( !pPath )
{ return PIAPI_CONTINUE; };
PIFInfo *pFInfo = HTTPCore_getCachedFile( pPath );
int iPathMatches = ( sFile==PIFInfo_getName( pFInfo ) );
HTTPCore_releaseCachedFile( pFInfo );
if ( !iPathMatches )
{ return PIAPI_CONTINUE; };
};
/* ---
If this is a real file then attempt to read the host and port
information from it
--- */
PIString sFcgiHost( sHost );
int iFcgiPort = iPort;
PIFInfo *pFInfo = HTTPCore_getCachedFile( pPath );
if ( pFInfo && PIFInfo_exists( pFInfo ) )
{
if ( !PIFInfo_isRegular( pFInfo ) ||
!PIFInfo_isReadable( pFInfo ) )
{
HTTPCore_logError( &tPIHTTP, "FastCGI: Fast CGI information \
file '%s' is not readable.", PIFInfo_getPath( pFInfo ) );
HTTPCore_releaseCachedFile( pFInfo );
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );
};
HTTPCore_releaseCachedFile( pFInfo );
/* ---
Read host and port information
--- */
ifstream ifs( pPath );
if ( !ifs.good() || ifs.eof() )
{
HTTPCore_logError( &tPIHTTP, "FastCGI: Error opening \
fast CGI information file '%s'.", pPath );
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );
};
enum { BUF_SIZE=1023 };
char szBuf[BUF_SIZE+1];
szBuf[BUF_SIZE] = '\0';
*szBuf = '\0';
/* XXX, buffer overrun risk, be careful with lengths! */
ifs >> szBuf;
sFcgiHost = szBuf;
*szBuf = '\0';
ifs >> szBuf;
iFcgiPort = atoi( szBuf );
if ( sFcgiHost==PIString::Empty() || iFcgiPort<=0 )
{
HTTPCore_logError( &tPIHTTP, "FastCGI: Bad \
host:port pair (%s:%d) from fast CGI information file '%s'.",
(const char *)sFcgiHost, iFcgiPort, pPath );
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );
};
}
else
{
HTTPCore_releaseCachedFile( pFInfo );
};
/* ---
Make identification string for error messages and logging
-- */
PIString sIdent( "host:port=" );
sIdent.Concatenate( sFcgiHost );
enum { SMALL_BUF=63 };
char szSmall[SMALL_BUF+1];
sprintf( szSmall, ":%d", iFcgiPort );
sIdent.Concatenate( szSmall );
/* ---
Get Connection Object
--- */
PIObject *pIOObject = GetFcgiConnection( tPIHTTP,
sFcgiHost, iFcgiPort );
if ( !pIOObject )
{
HTTPCore_logError( &tPIHTTP, "FastCGI: Failed to \
establish connection \
to fast cgi application '%s'.", (const char *)sIdent );
return HTTPUtil_doHTTPError( &tPIHTTP, ST_INTERNALERROR );
};
/* ---
Make buffer object
--- */
PIIOBuffer *pIOBuffer = PIIOBuffer_new( pIOObject );
int iRet = DoFastCGI( tPIHTTP, pIOBuffer, sIdent );
PIIOBuffer_delete( pIOBuffer );
ReleaseFcgiConnection( pIOObject );
return iRet;
};
};
/*____________________________________________________________________________*\
Function:
Synopsis:
Description:
\*____________________________________________________________________________*/
PUBLIC_PIAPI int FastCGI_constructor( PIObject *pObj,
int iArgc, const char *ppArgv[] )
{
return HandlerBaseFcgi_constructor( pObj, PI_NEW( FastCGI( pObj,
iArgc, ppArgv ) ) );
}
#if 0
/*___+++CNF_BEGIN+++___*/
<Class>
Name FastCGIClass
Type LogicExtension
Library Fcgi
OnClassLoad HandlerBaseFcgi_onClassLoad
Constructor FastCGI_constructor
CopyConstructor HandlerBaseFcgi_copyConstructor
Destructor HandlerBaseFcgi_destructor
Execute HandlerBaseFcgi_execute
</Class>
<Object>
Name FastCGI
Class FastCGIClass
</Object>
/*___+++CNF_END+++___*/
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -