📄 cgi.cpp
字号:
pExpr = Pi3Expression_new( pValue, aFunctions, pError );
if ( !pExpr )
{
os << Pi3String_getPtr( pError ) << ends;
Pi3String_delete( pError );
CONFIG_ERR( Object(), os.str() );
return 0;
};
Pi3String_delete( pError );
*ppExpression = pExpr;
return 1;
};
protected:
int Parameter( const char *pVariable, const char *pValue,
const char *pWhere )
{
assert( pVariable && pValue );
if ( !pVariable || !pValue )
{ return 0; };
PIOStrStream os; /* in case of error */
os << pWhere << "CGI: ";
if ( !PIUtil_stricmp( KEY_CONF_DEFAULTCOMMANDLINE, pVariable ) )
{
if ( pDefaultCommandLine )
{
os << "'DefaultCommandLine' may only be specified once."
<< ends;
CONFIG_ERR( Object(), os.str() );
return 0;
};
Pi3String *pError = Pi3String_new( 0 );
Pi3Expression *pExpr = Pi3Expression_new( pValue, aFunctions,
pError );
if ( !pExpr )
{
os << Pi3String_getPtr( pError ) << ends;
Pi3String_delete( pError );
CONFIG_ERR( Object(), os.str() );
return 0;
};
Pi3String_delete( pError );
pDefaultCommandLine = pExpr;
}
else if ( !PIUtil_stricmp( KEY_CONF_COMMANDLINEBYEXT, pVariable ) )
{
PIString sError;
FileExtToCommandLineMap *pMap =
PI_NEW( FileExtToCommandLineMap( pValue, aFunctions, sError ) );
if ( !pMap || !pMap->IsOK() )
{
PI_DELETE( pMap );
CONFIG_ERR( Object(), os.str() );
return 0;
};
lCommandLineByExt.Append( (DblList::type)pMap );
}
else if ( !PIUtil_stricmp( KEY_CONF_ENVIRONMENTSIZE, pVariable ) )
{ iEnvironmentSize = atoi( pValue ); }
else if ( !PIUtil_stricmp( KEY_CONF_VARIABLE, pVariable ) )
{
Pi3String *pError = Pi3String_new( 0 );
Pi3Expression *pExpr = Pi3Expression_new( pValue, aFunctions,
pError );
if ( !pExpr )
{
os << Pi3String_getPtr( pError ) << ends;
Pi3String_delete( pError );
CONFIG_ERR( Object(), os.str() );
return 0;
};
Pi3String_delete( pError );
lVariables.Append( (DblList::type)pExpr );
}
else if ( !PIUtil_stricmp( KEY_CONF_INCLUDEPARENTSENVIRONMENT,
pVariable ) )
{
if ( !PIUtil_stricmp( VALUE_NO, pValue ) )
{ iIncludeParentsEnvironment = 0; };
}
else if ( !PIUtil_stricmp( KEY_CONF_EXTRAHEADERS, pVariable ) )
{
if ( !PIUtil_stricmp( VALUE_NO, pValue ) )
{ iExtraHeaders = 0; };
}
else if ( !PIUtil_stricmp( KEY_CONF_SENDCRLF, pVariable ) )
{
if ( !PIUtil_stricmp( VALUE_YES, pValue ) )
{ iSendCRLF = 1; };
}
else if ( !PIUtil_stricmp( KEY_CONF_EXTRAHEADERSPREFIX, pVariable ) )
{ sExtraHeadersPrefix = (const char *)DeQuote( pValue ); }
else if ( !PIUtil_stricmp( KEY_CONF_FLAG, pVariable ) )
{
if ( !PIUtil_stricmp( pValue, VALUE_16BIT ) )
{ iFlags |= FLG_16BIT; }
else
{
os << "Unknown flag '" << pValue << "'" << ends;
CONFIG_ERR( Object(), os.str() );
return 0;
};
}
else if ( !PIUtil_stricmp( KEY_CONF_EXTRAHEADERSIGNORE, pVariable ) )
{
StringTokenizer tTokens( (const char *)DeQuote(pValue), " " );
for( int i=0; i<tTokens.NumTokens(); i++)
{
lIgnoreHeaders.Append( (DblList::type)
PI_NEW( PIString( tTokens.GetToken( i ) ) ) );
};
}
else if ( !PIUtil_stricmp( KEY_CONF_FILEIOOBJECT, pVariable ) )
{ /* --- read from CGI constructor --- */ }
else if ( !PIUtil_stricmp( KEY_CONF_KILLAFTER, pVariable ) )
{ iKillAfter = atoi( pValue ); }
else
{
os << "Unknown parameter '" << pVariable << "'" << ends;
CONFIG_ERR( Object(), os.str() );
return 0;
};
return 1;
};
/* --- callback functions for values --- */
/* --- macros to simplify parameter functions --- */
#define O PIDBTYPE_OPAQUE
#define S PIDBTYPE_STRING
#define F PIDBTYPE_RFC822
#define C(x,y) PIDB_lookup( pPIHTTP->pConnectionDB, x, y, 0 )
#define Q(x,y) PIDB_lookup( pPIHTTP->pRequestDB, x, y, 0 )
#define R(x,y) PIDB_lookup( pPIHTTP->pResponseDB, x, y, 0 )
#define V(x,y) PIDB_lookup( pPIHTTP->pHostDB, x, y, 0 )
#define SC_STR_FUNCTION(fn, value)\
static int (fn)( PIHTTP *pPIHTTP, void *, char *pszBuffer, int iLength ) \
{ \
(void)pPIHTTP; \
assert( pszBuffer ); \
const char *pString = (const char *)(value); \
if ( !pString ) { return 0; }; \
int iValueLen = strlen( pString ); \
int iLen = iValueLen < iLength ? iValueLen : iLength; \
if ( iValueLen>0 ) \
{ strncpy( pszBuffer, pString, iLen ); }; \
return iValueLen; \
}
# define SC_CXT_FUNCTION(fn, value, valuelen )\
static int (fn)( PIHTTP *pPIHTTP, void *pData, char *pszBuffer, int iLength ) \
{ \
(void)pPIHTTP; \
CGIContextData &tData = *( (CGIContextData *)pData ); \
assert( pszBuffer ); \
int iValueLen = (valuelen); \
int iLen = iValueLen < iLength ? iValueLen : iLength; \
if ( iLen>0 ) \
{ strncpy( pszBuffer, value, iLen ); }; \
return iValueLen; \
}
/* ---
some of these are just repeat of stuff from shortcuts
--- */
SC_CXT_FUNCTION( f_p, tData.sExePath, tData.sExePath.Len() );
SC_CXT_FUNCTION( f_q, tData.sIsIndexValue, tData.sIsIndexValue.Len() );
#undef S
#undef F
#undef C
#undef Q
#undef R
public:
CGI( PIObject *pTheObject, int iArgc, const char *ppArgv[] )
:
HandlerBaseHTTP( pTheObject ),
pPipeIO( 0 ),
pDefaultCommandLine( 0 ),
iIncludeParentsEnvironment( 1 ),
iEnvironmentSize( DEFAULT_ENVIRONMENT_SIZE ),
iExtraHeaders( 1 ),
iSendCRLF( 0 ),
iFlags( 0 ),
iKillAfter( -1 ),
pFKContentType( PIDB_getFastKey( KEY_HTTP_CONTENTTYPE,PIDBTYPE_RFC822)),
pFKFileInfo( PIDB_getFastKey( KEY_DS_FILEINFO, PIDBTYPE_OPAQUE ) ),
pFKPath( PIDB_getFastKey( KEY_INT_PATH, PIDBTYPE_STRING ) ),
pFKURI( PIDB_getFastKey( KEY_HTTP_URI, PIDBTYPE_STRING ) )
{
/* --- clear out callback functions --- */
memset( aFunctions, 0, sizeof( FnPi3Write ) * 256 );
aFunctions['p'] = f_p;
aFunctions['q'] = f_q;
/* --- read parameters --- */
ReadParameters( iArgc, ppArgv );
if ( !IsOK() )
{ return; };
if ( pDefaultCommandLine==0 )
{
CONFIG_ERR( Object(), "CGI: 'DefaultCommandLine' not \
defined" );
SetOK( 0 );
return;
};
/* ---
Load prototype Pipe IO object
--- */
pPipeIO = PIObject_loadEx( Object(), KEY_CONF_FILEIOOBJECT );
if ( !pPipeIO )
{
SetOK( 0 );
return;
};
};
~CGI()
{
PIObject_delete( pPipeIO, 0, 0 );
for( DblListIterator i( lIgnoreHeaders ); !i.BadIndex(); i++ )
{ PI_DELETE( (PIString *)i.Current() ); };
for( DblListIterator j( lCommandLineByExt ); !j.BadIndex(); j++ )
{ PI_DELETE( (FileExtToCommandLineMap *)j.Current() ); };
for( DblListIterator k( lVariables ); !k.BadIndex(); k++ )
{ Pi3Expression_delete( (Pi3Expression *)k.Current() ); };
Pi3Expression_delete( pDefaultCommandLine );
};
/* ---
Add client request headers to the environment block. Returns 0 on
success, 1 on environment block exhausted and -1 on error.
--- */
int AddClientRequestHeaders( PIHTTP *pPIHTTP, PIDB *pQ, char *pEnv,
int &i, int iEnvSize, int &iNumberOfEnvironmentVariables )
{
/* --- loop over all RFC822 headers in request block --- */
PIDBIterator *pIter = PIDB_getIterator( pQ, PIDBTYPE_RFC822, 0, 0 );
if ( !pIter )
{ return -1; };
const char *pKey;
const char *pValue;
for(; PIDBIterator_atValidElement( pIter ); PIDBIterator_next( pIter ) )
{
pValue = (const char *)PIDBIterator_current( pIter, &pKey );
assert( pKey && pValue );
if ( !pKey || !pValue )
{ /* sanity */ continue; };
/* ---
If the key matches one of the keys in the ignore list, then
skip to the end of the loop
--- */
DblListIterator k( lIgnoreHeaders );
for(; !k.BadIndex(); k++ )
{
PIString &tTmp = *( (PIString *)k.Current() );
if ( !PIUtil_stricmp( tTmp, pKey ) )
{ break; };
};
if ( !k.BadIndex() )
{ continue; };
/* ---
pKey is a variable that is not on the ignore list,
therefore it should be added to the environment block
--- */
int iVarLen = strlen( pKey );
int iVarPos = sExtraHeadersPrefix.Len();
int iValSize = strlen( pValue );
/* ---
Size available must be able to fit
- Variable name (iVarPos)
- Value (iValPos)
- 2 other characters, '=', '\0' for entry.
--- */
if ( (i+iVarPos+iVarLen+iValSize+2) < iEnvSize )
{
memcpy( &(pEnv[i]), sExtraHeadersPrefix, iVarPos );
i += iVarPos;
for( int j=0; j<iVarLen; j++, i++ )
{
/* ---
alphanumerics in the variable name are capitalized, other
characters are converted to '_'
--- */
if ( isalnum( pKey[j] ) )
{ pEnv[i]=toupper(pKey[j]); }
else
{ pEnv[i]='_'; };
};
pEnv[i++] = '=';
memcpy( &(pEnv[i]), pValue, iValSize ); i+=iValSize;
pEnv[i++] = '\0';
iNumberOfEnvironmentVariables++;
}
else
{
PIDBIterator_delete( pIter );
return 1;
};
};
PIDBIterator_delete( pIter );
return 0;
};
/* ---
Add the environment variables to the list of environment variables
Returns non-zero on success, 0 on error.
--- */
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; }
/*
** Skip empty variable fields, this allows an environment
** variable to be added conditionally
*/
else if ( iWritten>0 )
{
if ( iWritten>=iBlockSize )
{
*pBlock = '\0';
return 0;
};
pBlock[iWritten++] = '\0';
pBlock = &( pBlock[iWritten] );
iBlockSize -= iWritten;
iNumberOfVariables++;
};
};
return 1;
};
/* ---
Create the CGI environment
--- */
ENVIRONMENT CreateCGIEnvironment(
PIHTTP &tPIHTTP
)
{
PIDB *pQ = tPIHTTP.pRequestDB;
/* ---
Create additional DB variables
--- */
int iNumberOfEnvironmentVariables = 0;
char *pEnv = (char *)PIHTTP_allocMem( &tPIHTTP, iEnvironmentSize+2 );
int iBlockSize = iEnvironmentSize;
AddEnvironmentVariables(
tPIHTTP,
pEnv,
iBlockSize,
iNumberOfEnvironmentVariables );
int i = iEnvironmentSize - iBlockSize;
/* ---
i is the index of the next character space in the environment
block, when it is ==iEnvironmentSize, the block has been
exhausted
--- */
if ( iExtraHeaders )
{
AddClientRequestHeaders( &tPIHTTP, pQ, pEnv, i, iEnvironmentSize+1,
iNumberOfEnvironmentVariables );
};
if ( iIncludeParentsEnvironment )
{
#if WIN32
char *pEnvStrings = ::GetEnvironmentStrings();
const char *pParentEnv = (const char *)pEnvStrings;
if ( pParentEnv )
{
for(;;)
{
int iLen = strlen( pParentEnv );
if ( !iLen || iEnvironmentSize<=(i+iLen) )
{ break; };
strcpy( &(pEnv[i]), pParentEnv );
i+=iLen;
pEnv[i++] = '\0';
pParentEnv = &( pParentEnv[iLen+1] );
};
::FreeEnvironmentStrings( pEnvStrings );
};
#endif
};
pEnv[i] = '\0';
#if WIN32
return pEnv;
#elif POSIX
char **ppEnv = (char **)PIHTTP_allocMem( &tPIHTTP,
sizeof( char * ) * ( iNumberOfEnvironmentVariables+1 ) );
int iTmp = 0;
do
{
ppEnv[iTmp++] = pEnv;
for( ; *pEnv; pEnv++ ); /* --- skip to next variable --- */
pEnv++;
} while( *pEnv );
assert( iTmp==iNumberOfEnvironmentVariables );
ppEnv[iTmp] = 0;
return (ENVIRONMENT)ppEnv;
#endif
};
/* ---
Generate pipes and execute CGI program.
return 0 on success, otherwise error code
--- */
int DoExecCGIChild(
char *pPath, /* exec command line */
const char *pDirectory, /* CGI program current directory */
PROCDESC *pProcess, /* child process id value argument */
int iDoStdin, /* do standard input standard handle */
FILEDESC *pStdout_Parent,
FILEDESC *pStdout_CGI,
FILEDESC *pStdin_Parent,
FILEDESC *pStdin_CGI,
FILEDESC *pStderr_Parent,
FILEDESC *pStderr_CGI,
PIHTTP &tPIHTTP
#if VERBOSE_DEBUG
, ostream &os
#endif
)
{
int iSanity = pPath && pProcess && pStdin_Parent && pStdout_Parent &&
pStdout_CGI && pStdin_CGI;
assert( iSanity );
if ( !iSanity )
{ return -1; };
ENVIRONMENT ppEnv = 0;
/* --- CGI stdout handles --- */
FILEDESC tStdout_CGI = INVALID_DESC;
FILEDESC tStdout_Parent = INVALID_DESC;
FILEDESC tStdout_ParentDup = INVALID_DESC;
/* --- CGI stdin handles --- */
FILEDESC tStdin_CGI = INVALID_DESC;
FILEDESC tStdin_Parent = INVALID_DESC;
FILEDESC tStdin_ParentDup = INVALID_DESC;
/* --- CGI stderr handles --- */
FILEDESC tStderr_CGI = INVALID_DESC;
FILEDESC tStderr_Parent = INVALID_DESC;
FILEDESC tStderr_ParentDup = INVALID_DESC;
#if WIN32
BOOL bProcessCreated = FALSE;
DWORD dwFlags = 0;
char *AppName = 0;
STARTUPINFO tStartUp;
memset(&tStartUp, 0, sizeof(tStartUp));
tStartUp.cb=sizeof(tStartUp);
tStartUp.dwFlags = STARTF_USESHOWWINDOW;
if ( HTTPCore_debugEnabled() )
{ tStartUp.wShowWindow=SW_SHOW; }
else
{ tStartUp.wShowWindow=SW_HIDE; };
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = 0;
PROCDESC tProc = ::GetCurrentProcess();
/* --- setup pipes (stdout) --- */
if ( !::CreatePipe( &tStdout_Parent, &tStdout_CGI, &saAttr, 0 ) )
{ goto nt_error_return; };
if ( !::DuplicateHandle(
tProc,
tStdout_Parent,
tProc,
&tStdout_ParentDup,
0,
FALSE,
DUPLICATE_SAME_ACCESS
) )
{ goto nt_error_return; };
CloseFileDesc( tStdout_Parent );
tStdout_Parent = INVALID_DESC;
/* --- setup pipes (stdin) --- */
if ( iDoStdin )
{
if ( !::CreatePipe( &tStdin_CGI, &tStdin_Parent, &saAttr, 0 ) )
{ goto nt_error_return; };
if ( !::DuplicateHandle(
tProc,
tStdin_Parent,
tProc,
&tStdin_ParentDup,
0,
FALSE,
DUPLICATE_SAME_ACCESS
) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -