⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wincgi.cpp

📁 mini http server,可以集成嵌入到程序中,实现简单的web功能
💻 CPP
📖 第 1 页 / 共 5 页
字号:
 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 + -