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

📄 cgi.cpp

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