📄 wincgi.cpp
字号:
Description:
\*____________________________________________________________________________*/
class WinCGI : HandlerBaseHTTP
{
private:
/* --- forbid copy constructor --- */
WinCGI( const WinCGI &t )
: HandlerBaseHTTP( t )
{ assert( 0 ); };
/* ---
Configuration data
--- */
PIObject *pPipeIO; /* the pipe IO object */
Pi3Expression *pDefaultCommandLine;
/* default command line */
DblList lCommandLineByExt; /* mappings of file extension to command line */
int iExtraHeaders; /* whether or not to send extra headers */
int iSendCRLF; /* send CRLF to CGI program after data */
enum { DEFAULT_ENVIRONMENT_SIZE=4094 };
PIString sExtraHeadersPrefix;
/* prefix for extra header information */
DblList lIgnoreHeaders; /* extra headers to ignore */
FnPi3Write aFunctions[256]; /* callback functions */
PIString sExternalPath; /* path for external form files */
Pi3Expression *pDataFile; /* datafile */
Pi3Expression *pStdinFile; /* file that CGI program reads input from */
Pi3Expression *pStdoutFile; /* file that CGI program writes output to */
Pi3Expression *pDataBlock; /* block of text written to datafile */
int iFlags; /* flags */
int iKillAfter; /* kill the CGI process after this time */
/* ---
FastKeys
--- */
const char *pFKContentType; /* RFC822: Content-Type */
const char *pFKFileInfo; /* OPAQUE: Pointer to fileinfo object */
const char *pFKPath; /* STRING: Translated path */
const char *pFKURI; /* RFC822: URI from request header */
/* ---
Class with context data for expressions
--- */
class CGIContextData
{
private:
static int iUniqueIndex;
public:
PIString sUniqueIndex;
PIString sDataFile;
PIString sInputFile;
PIString sOutputFile;
PIString sExePath;
PIString sIsIndexValue;
PIString sExtraHeaders;
PIString sAcceptHeader;
PIString sFormLiteral;
PIString sFormExternal;
PIString sFormHuge;
PIString sFormFile;
public:
CGIContextData()
{
enum { BUF_SIZE=63 };
char szBuf[BUF_SIZE+1];
PIPlatform_beforeUnsafeBlock();
int iIndex = iUniqueIndex++;
PIPlatform_afterUnsafeBlock();
sprintf( szBuf, "%lX", (long int)iIndex );
sUniqueIndex = szBuf;
};
};
/* ---
Class for fileextension to commandline
--- */
class FileExtToCommandLineMap
{
public:
PIString sFileExtension;
Pi3Expression *pExpr;
int iOK;
FileExtToCommandLineMap( const char *pPattern,
FnPi3Write *paFunctions, PIString &sError )
: pExpr( 0 ),
iOK( 0 )
{
StringTokenizer tTokens( pPattern, "=", 0 );
if ( tTokens.NumTokens()!=2 )
{ return; };
DeQuote tTmp( tTokens.GetToken( 0 ) );
const char *pExt = tTmp;
sFileExtension = (*pExt=='.') ? &(pExt[1]) : pExt;
DeQuote tTmp2( tTokens.GetToken( 1 ) );
const PIString &sTmp = (const PIString &)tTmp2;
Pi3String *pError = Pi3String_new( 0 );
pExpr = Pi3Expression_new( sTmp, paFunctions, pError );
if ( !pExpr )
{
sError = Pi3String_getPtr( pError );
Pi3String_delete( pError );
return;
};
Pi3String_delete( pError );
iOK = 1;
};
~FileExtToCommandLineMap()
{
Pi3Expression_delete( pExpr );
};
inline int IsOK() { return iOK; };
};
private:
int LoadExpression( const char *pName, Pi3Expression **ppExpression,
const char *pValue, PIOStrStream &os )
{
assert( pName );
assert( pValue );
assert( ppExpression );
Pi3Expression *pExpr = *ppExpression;
if ( pExpr )
{
os << "'" << pName << "' may only be specified once." << ends;
CONFIG_ERR( Object(), os.str() );
return 0;
};
Pi3String *pError = Pi3String_new( 0 );
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 << "WinCGI: ";
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_EXTERNALPATH, pVariable ) )
{
sExternalPath=(const char *)DeQuote( pValue );
}
else if ( !PIUtil_stricmp( KEY_CONF_DATAFILE, pVariable ) )
{
if ( !LoadExpression( KEY_CONF_DATAFILE, &pDataFile,
pValue, os ) )
{ return 0; };
}
else if ( !PIUtil_stricmp( KEY_CONF_STDINFILE, pVariable ) )
{
if ( !LoadExpression( KEY_CONF_STDINFILE, &pStdinFile,
pValue, os ) )
{ return 0; };
}
else if ( !PIUtil_stricmp( KEY_CONF_STDOUTFILE, pVariable ) )
{
if ( !LoadExpression( KEY_CONF_STDOUTFILE, &pStdoutFile,
pValue, os ) )
{ return 0; };
}
else if ( !PIUtil_stricmp( KEY_CONF_DATABLOCK, pVariable ) )
{
if ( !LoadExpression( KEY_CONF_DATABLOCK, &pDataBlock,
pValue, os ) )
{ return 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_d, tData.sDataFile, tData.sDataFile.Len() );
SC_CXT_FUNCTION( f_i, tData.sInputFile, tData.sInputFile.Len() );
SC_CXT_FUNCTION( f_o, tData.sOutputFile, tData.sOutputFile.Len() );
SC_CXT_FUNCTION( f_p, tData.sExePath, tData.sExePath.Len() );
SC_CXT_FUNCTION( f_u, tData.sUniqueIndex, tData.sUniqueIndex.Len() );
SC_CXT_FUNCTION( f_q, tData.sIsIndexValue, tData.sIsIndexValue.Len() );
SC_CXT_FUNCTION( f_h, tData.sExtraHeaders, tData.sExtraHeaders.Len() );
SC_CXT_FUNCTION( f_a, tData.sAcceptHeader, tData.sAcceptHeader.Len() );
SC_CXT_FUNCTION( f_l, tData.sFormLiteral, tData.sFormLiteral.Len() );
SC_CXT_FUNCTION( f_e, tData.sFormExternal, tData.sFormExternal.Len() );
SC_CXT_FUNCTION( f_g, tData.sFormHuge, tData.sFormHuge.Len() );
SC_CXT_FUNCTION( f_f, tData.sFormFile, tData.sFormFile.Len() );
#undef S
#undef F
#undef C
#undef Q
#undef R
public:
WinCGI( PIObject *pTheObject, int iArgc, const char *ppArgv[] )
:
HandlerBaseHTTP( pTheObject ),
pPipeIO( 0 ),
pDefaultCommandLine( 0 ),
iExtraHeaders( 1 ),
iSendCRLF( 0 ),
pDataFile( 0 ),
pStdinFile( 0 ),
pStdoutFile( 0 ),
pDataBlock( 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['d'] = f_d;
aFunctions['i'] = f_i;
aFunctions['o'] = f_o;
aFunctions['p'] = f_p;
aFunctions['u'] = f_u;
aFunctions['q'] = f_q;
aFunctions['h'] = f_h;
aFunctions['a'] = f_a;
aFunctions['l'] = f_l;
aFunctions['e'] = f_e;
aFunctions['g'] = f_g;
aFunctions['f'] = f_f;
/* --- read parameters --- */
ReadParameters( iArgc, ppArgv );
if ( !IsOK() )
{ return; };
if ( pDefaultCommandLine==0 )
{
CONFIG_ERR( Object(), "WinCGI: 'DefaultCommandLine' not \
defined" );
SetOK( 0 );
return;
};
/* ---
Load prototype Pipe IO object
--- */
pPipeIO = PIObject_loadEx( Object(), KEY_CONF_FILEIOOBJECT );
if ( !pPipeIO )
{
SetOK( 0 );
return;
};
};
~WinCGI()
{
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() ); };
Pi3Expression_delete( pDefaultCommandLine );
Pi3Expression_delete( pDataFile );
Pi3Expression_delete( pStdinFile );
Pi3Expression_delete( pStdoutFile );
Pi3Expression_delete( pDataBlock );
};
/* ---
Add client request headers to the buffer. Returns 0 on
success, 1 on buffer exhausted and -1 on error.
--- */
int AddClientRequestHeaders( PIHTTP *pPIHTTP, PIDB *pQ, char *pBuf, int iBufSize )
{
int i = 0;
/* --- 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 buffer
--- */
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..3 other characters, '=', ('\r'), '\n' for entry.
- one byte less for iBufSizedue to trailing '\0'
--- */
#if WIN32
# define ADDPSPACE 3
#else
# define ADDPSPACE 2
#endif
if ( (i+iVarPos+iVarLen+iValSize+ADDPSPACE) < iBufSize - 1 )
#undef ADDPSPACE
{
memcpy( &(pBuf[i]), sExtraHeadersPrefix, iVarPos );
i += iVarPos;
for( int j=0; j<iVarLen; j++, i++ )
{
if ( isalnum( pKey[j] ) )
{ pBuf[i]=toupper(pKey[j]); }
else
{ pBuf[i]='_'; };
};
pBuf[i++] = '=';
memcpy( &(pBuf[i]), pValue, iValSize ); i+=iValSize;
#if WIN32
pBuf[i++] = '\r';
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -