📄 fastcgi.cpp
字号:
#endif
assert( pIO );
};
~FastCGI()
{
for( DblListIterator i( lVariables ); !i.BadIndex(); i++ )
{ Pi3Expression_delete( (Pi3Expression *)i.Current() ); };
PIObject_delete( pIO, 0, 0 );
};
/* -------------- +++++++++++++++++++++++++++++++ ------------------ *\
Utilities
\* -------------- +++++++++++++++++++++++++++++++ ------------------ */
/* ---
Write environment variables (params) into the supplied block.
Returns 1 on success, 0 on failure.
--- */
int AddEnvironmentVariables(
PIHTTP &tPIHTTP,
char *pBlock,
int &iBlockSize,
int &iNumberOfVariables )
{
for( DblListIterator i( lVariables ); !i.BadIndex(); i++ )
{
Pi3Expression *pExpr = (Pi3Expression *)i.Current();
assert( pExpr );
int iWritten = Pi3Expression_write( pExpr, &tPIHTTP, this, pBlock,
iBlockSize );
if ( iWritten==-1 )
{
return 0;
}
/*
** Only add non empty variable patterns
*/
else if ( iWritten > 0 )
{
/* ---
Check first, before looking at contents.
--- */
if ( iWritten>=iBlockSize )
{
*pBlock = '\0';
return 0;
};
/* --- buffer for lengths --- */
unsigned char szLengths[8];
int iLengthPos=0;
/* --- get index of '=' --- */
int i=0;
for( ; i<iWritten && pBlock[i]!='='; i++ );
int iNameLen = i;
if ( i<iWritten ) { i++; };
int iValueLen = iWritten - i;
/* --- i is index of first character of value in pBlock --- */
/* --- lengths --- */
if ( iNameLen < 0x80 )
{ szLengths[iLengthPos++] = iNameLen; }
else
{
iNameLen &= 0xFFFFFFFF;
szLengths[iLengthPos++] = ( iNameLen >> 24 ) | 0x80;
szLengths[iLengthPos++] = ( iNameLen >> 16 );
szLengths[iLengthPos++] = ( iNameLen >> 8 );
};
if ( iValueLen < 0x80 )
{ szLengths[iLengthPos++] = iValueLen; }
else
{
iValueLen &= 0xFFFFFFFF;
szLengths[iLengthPos++] = ( iValueLen >> 24 ) | 0x80;
szLengths[iLengthPos++] = ( iValueLen >> 16 );
szLengths[iLengthPos++] = ( iValueLen >> 8 );
};
/* ---
Check again because we've expanded the size
--- */
if ( iWritten>=iBlockSize )
{
*pBlock = '\0';
return 0;
};
iWritten = iLengthPos + iNameLen + iValueLen;
/* --- sanity --- */
assert( ((iWritten==(iNameLen+iValueLen))==i) ||
((iWritten>(iNameLen+iValueLen))&&(i<iWritten)) );
memmove(
&(pBlock[iWritten-iValueLen]),
&(pBlock[i]),
iValueLen );
memmove(
&(pBlock[(iWritten-iValueLen)-iNameLen]),
pBlock,
iNameLen );
memcpy( pBlock, szLengths, iLengthPos );
pBlock = &( pBlock[iWritten] );
iBlockSize -= iWritten;
iNumberOfVariables++;
};
};
return 1;
};
/* ---
Write output from one buffer into another.
iReadLen gives number of bytes to transfer, must be > 0
Returns 0 on success.
--- */
int WriteBufferToBuffer( PIIOBuffer &tInBuffer, PIIOBuffer &tOutBuffer,
int iReadLen )
{
assert( iReadLen>0 );
if ( iReadLen<=0 )
{ return 0; };
enum { BUF_SIZE=4096 };
char szBuffer[BUF_SIZE];
int iAttemptToRead = (iReadLen >= BUF_SIZE) ? BUF_SIZE : iReadLen;
int iLen;
iLen = PIIOBuffer_readToBuffer( &tInBuffer, szBuffer, iAttemptToRead );
while( iLen>0 )
{
if ( PIIOBuffer_write( &tOutBuffer, szBuffer, iLen,
PIIOBUF_NONE )<=0 )
{ return -1; };
iAttemptToRead -= iLen;
if ( !iAttemptToRead )
{ return 0; };
iLen = PIIOBuffer_readToBuffer( &tInBuffer, szBuffer,
iAttemptToRead );
};
/* ---
Done
--- */
return iLen;
};
/* ---
Initialize a fast CGI header record
--- */
void GenerateFcgiHeader( FCGI_Header &tHeader, int iType,
int iRequestId, int iContentLength )
{
tHeader.version = FCGI_VERSION_1;
tHeader.type = iType;
tHeader.requestIdB1 = (iRequestId >> 8 ) & 0xff;
tHeader.requestIdB0 = (iRequestId ) & 0xff;
tHeader.contentLengthB1 = (iContentLength >> 8 ) & 0xff;
tHeader.contentLengthB0 = (iContentLength ) & 0xff;
tHeader.paddingLength = 0;
};
/* ---
Wrap a Fcgi body in a record and send it into the specified
IO buffer object.
Returns 0 on success, -1 on failure.
--- */
int SendFcgiBody( PIIOBuffer *pIOBuffer, void *pBody, int iBodyLength,
int iType, int iRequestId )
{
assert( pIOBuffer );
/* ---
Generate header record
--- */
FCGI_Header tHeader;
GenerateFcgiHeader( tHeader, iType, iRequestId, iBodyLength );
/* ---
Send header
--- */
if ( PIIOBuffer_write( pIOBuffer, (const char *)&tHeader,
sizeof( tHeader ), PIIOBUF_NONE )!=sizeof( tHeader ) )
{
return -1;
};
/* ---
Send body and flush
--- */
if ( iBodyLength>0 && PIIOBuffer_write( pIOBuffer, (const char *)pBody,
iBodyLength, PIIOBUF_NONE )!=iBodyLength )
{
return -1;
};
return 0; /* --- OK --- */
};
/* ---
Correct response variables just before they're sent
--- */
void CorrectResponseVariables( PIHTTP &tPIHTTP )
{
/* --- disable keep alive --- */
PIDB_replace( tPIHTTP.pConnectionDB, PIDBTYPE_OPAQUE,
KEY_INT_KEEPOPEN, (void *)0, 0 );
/* --- set response status code --- */
tPIHTTP.iStatus = ST_OK;
};
/* ---
Handle stdout from an FCGI application server
Return 0 on success, -1 on error.
--- */
int HandleFcgiStdout(
PIHTTP &tPIHTTP,
char *pData,
int iDataLength,
int &iVariablePos, /* --- note pass by reference --- */
int &iReadingVariables, /* --- note pass by reference --- */
const char *szIdent )
{
assert( pData );
if ( iReadingVariables )
{
/* ---
reading CGI response headers
--- */
assert( iVariablePos<iDataLength );
/* --- get index of EOL (\r\n) --- */
int iEOL = 0;
for( ;
(iEOL<iDataLength) &&
(pData[iEOL]!='\r') &&
(pData[iEOL+1]!='\n');
iEOL++ );
if ( iEOL==iDataLength )
{
/* --- end of variables --- */
iReadingVariables = 0;
}
else
{
/* ---
EOL reached read in the variable.
--- */
assert( iEOL<=iDataLength );
if ( iEOL )
{
/* ---
Seperate variable from value
--- */
int i=0;
for( ; i<iEOL && pData[i]!=':'; i++); /* scan to ':' */
/* ---
real rfc822 variable, value pair
--- */
if ( i < iEOL - 3 /* : x\0 */)
{
pData[iEOL] = '\0';
pData[i]='\0';
const char *pVariable = pData;
if ( i<iEOL ) { i++; };
for( ; i<iEOL && isspace(pData[i]); i++);/* scan to !ws */
const char *pValue = &(pData[i]);
/* ---
Place variable value pair in response DB
--- */
assert( pVariable );
assert( *pVariable );
assert( pValue );
PIDB_replace( tPIHTTP.pResponseDB, PIDBTYPE_RFC822, pVariable,
(void *)pValue, 0 );
/* --- reset variable buffer --- */
iEOL+=2; /* --- increment to next character --- */
assert( iEOL<=iDataLength );
iVariablePos += iEOL;
iReadingVariables = iVariablePos<iDataLength;
/* ---
Recurse to read the rest of the buffer if there's more
--- */
iDataLength -= iEOL;
pData = &(pData[iEOL]);
}
else
{
iReadingVariables = 0;
};
}
else
{
/* --- end of variables --- */
if ( iVariablePos )
{
iDataLength -= 2;
pData = &(pData[2]);
};
iReadingVariables = 0;
};
};
/* ---
Recurse to read more headers
--- */
if ( iDataLength && iReadingVariables )
{
return HandleFcgiStdout( tPIHTTP, pData, iDataLength,
iVariablePos, iReadingVariables, szIdent );
};
};
if (!iReadingVariables )
{
/* ---
End of the stdout variables
start the http response
--- */
PIDB *pR = tPIHTTP.pResponseDB;
CorrectResponseVariables( tPIHTTP );
if ( HTTPCore_sendGeneralHeaders( &tPIHTTP ) ||
HTTPCore_sendEntityHeaders( &tPIHTTP, pR ) )
{
HTTPCore_logError( &tPIHTTP, "FastCGI: Failed \
to start HTTP response from fast cgi application '%s'.", szIdent );
return -1;
};
/* ---
reading CGI response data
Just ship it straight back to the client browser.
--- */
int iRet = 1;
if ( iDataLength )
{
iRet = PIIOBuffer_write( tPIHTTP.pBuffer, pData, iDataLength,
PIIOBUF_NONE );
};
if ( iRet<=0 )
{
HTTPCore_logError( &tPIHTTP, "FastCGI: Error sending \
response to browser from fast cgi application '%s'.", szIdent );
return -1;
};
};
return 0; /* --- OK --- */
};
/* ---
Read a Fcgi response.
returns 0 on success, -1 on failure.
--- */
int ReadFcgiResponse( PIHTTP &tPIHTTP, PIIOBuffer *pIOBuffer,
const char *szIdent )
{
PIString sStdErr; /* for stderr responses */
const char *pData; /* pointer to current data block */
FCGI_Header tHeader; /* for reading FCGI headers */
int iReadSoFar = 0; /* offset into record or data */
int iRecordLength; /* length of current fcgi record */
char *pBuffer = 0; /* buffer for record data */
int iExit = 1; /* exit code or 1 for no exit */
int iVariablePos=0; /* current pos in HTTP vars */
int iReadingVariables = 1;
/* initially reading variables */
enum { HEADER=1, RECORD } eRecordState = HEADER;
int iLen; /* length of data read from fcgi */
for( ; (pData = PIIOBuffer_read( pIOBuffer, &iLen ))!=0 &&
iExit == 1; )
{
HTTPCore_logDebug( DBG_LOW, "FastCGI: %s, Read %d bytes from fcgi.",
szIdent, iLen );
if ( eRecordState == HEADER )
{
/* ---
Read fast cgi header
--- */
assert( iReadSoFar<(int)sizeof( FCGI_Header ) );
int iToRead = sizeof( FCGI_Header ) - iReadSoFar;
if ( iToRead>iLen )
{ iToRead = iLen; };
memcpy( &(((char *)&tHeader)[iReadSoFar]), pData, iToRead );
iReadSoFar += iToRead;
if ( iReadSoFar<(int)sizeof( FCGI_Header ) )
{ /* --- read more into buffer --- */; continue; };
/* ---
Reset buffer pointers
--- */
pData = &(pData[iToRead]);
iLen -= (int)sizeof( FCGI_Header );
iReadSoFar = 0;
eRecordState = RECORD;
/* ---
prepare for record data
--- */
iRecordLength = ( tHeader.contentLengthB1 << 8 ) +
tHeader.contentLengthB0;
pBuffer = PI_NEW( char[iRecordLength] );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -