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

📄 wincgi.cpp

📁 mini http server,可以集成嵌入到程序中,实现简单的web功能
💻 CPP
📖 第 1 页 / 共 5 页
字号:
				pBuf[i++] = '\n';
				}
			else
				{
				PIDBIterator_delete( pIter );
				pBuf[i++] = '\0';
				return 1;
				};
			};
		pBuf[i++] = '\0';
		PIDBIterator_delete( pIter );
		return 0;
		};

	/* ---
	Add client accept header to the buffer. Returns 0 on
	success, 1 buffer exhausted and -1 on error.
	--- */
	int AddClientAcceptHeader( PIHTTP *pPIHTTP, PIDB *pQ, char *pBuf, int iBufSize )
		{
		int i = 0;
		const char *pKey;
		const char *pValue = (const char *)PIDB_lookup( pQ,
			PIDBTYPE_RFC822, KEY_HTTP_ACCEPT, 0);
		if (!pValue) return 0;

		/* --- loop over all mime types in Accept header --- */
		StringTokenizer tTokens( pValue, "," );
		for( int j=0; j<tTokens.NumTokens(); j++)
			{
			pKey = tTokens.GetToken( j );
			pValue = VALUE_YES;
			assert( pKey && pValue );
			if ( !pKey || !pValue )
				{ /* sanity */ continue; };

			/* ---
			test for additional parameters
			--- */
			if ( char *pPos = strchr( pKey, ';' ))
				{
				memset (pPos, '\0', 1);
				pValue = ++pPos;
				if ( pPos = strchr( pValue, '=' ))
					{
					pValue = ++pPos;
					}
				}

			int iVarSize = strlen( pKey );
			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+iVarSize+iValSize+ADDPSPACE) < iBufSize - 1 )
#undef ADDPSPACE
				{
				memcpy( &(pBuf[i]), pKey, iVarSize ); i+=iVarSize;
				pBuf[i++] = '=';
				memcpy( &(pBuf[i]), pValue, iValSize );	i+=iValSize;
#if WIN32
				pBuf[i++] = '\r';
#endif
				pBuf[i++] = '\n';
				}
			else
				{
				return 1;
				};
			};
		pBuf[i++] = '\0';
		return 0;
		};

	/* ---
	Write client form data to an external temporary file. Returns 0 on
	success, -1 on error. The key for the [Form External] section is in pResult.
	--- */
	int WriteExternal( PIHTTP *pPIHTTP, Pi3String *pDecoded, PIString &tResult )
		{
		PIDB *pH = pPIHTTP->pHostDB;
		PIDB *pR = pPIHTTP->pResponseDB;

		/* --- separate the value to be written into external file --- */
		const char *pValue = strchr(Pi3String_getPtr(pDecoded), '=');
		pValue++;

		/* --- generate the unique path for the temporary file --- */
		enum { BUFSIZE=68 };
		char szBuf[BUFSIZE+1];
		PIPlatform_getUniqueId(szBuf, BUFSIZE-4);
		PIString sTmp(sExternalPath);
		sTmp.Concatenate(szBuf);
		sTmp.Concatenate(".tmp");

		Pi3String *pPath = Pi3String_new( sTmp );
		HTTPCore_relativeToAbsolutePath( pH, (const char *)sTmp, pPath );

		/* --- Caclulate the result string 'key=pathname length' --- */
		StringTokenizer tTokens( Pi3String_getPtr(pDecoded), "=" );
		tResult = (const char *)tTokens.GetToken( 0 );
		tResult.Concatenate('=');
		tResult.Concatenate(Pi3String_getPtr(pPath));
		tResult.Concatenate(' ');
		sprintf( szBuf, "%lu", strlen(pValue) );
		tResult.Concatenate( szBuf );

		/* --- try to write this data block to the datafile --- */
		PIPLATFORM_FD tFd = PIFile_open( Pi3String_getPtr(pPath), "w" );
			
		if ( tFd!=PIPLATFORM_FD_INVALID )
			{
			/* --- mark datafile as a temporary file --- */
			PIDB_add( pR, PIDBTYPE_STRING, KEY_INT_TEMPORARYFILE,
				(void *)Pi3String_getPtr(pPath), 0 );
			};

		int iFailed = ( tFd == PIPLATFORM_FD_INVALID ||
			PIFile_write( tFd, strlen(pValue), pValue )!=0 );

		if ( tFd!=PIPLATFORM_FD_INVALID )
			{ PIFile_close( tFd ); };

		if ( iFailed )
			{
			HTTPCore_logError( pPIHTTP,  
				"WinCGI: Failed to write temporary file \
for external form data, path is '%s'.",	Pi3String_getPtr(pPath) );
			Pi3String_delete(pPath);
			return -1;
			};

		Pi3String_delete(pPath);
		return 0;
		};

	/* ---
	Add client form data to the buffer. Returns 0 on
	success and -1 on error.
	--- */
	int AddClientFormData( PIHTTP *pPIHTTP, PIDB *pQ, char *pBuf,
		int iBufSize, PIString &tDecoded, PIString &tExternal )
		{
		Pi3String *pDecoded = Pi3String_new("");
		PIString pEncoded(pBuf, iBufSize);
		const char *pValue;

		/* --- loop over all form fields --- */
		StringTokenizer tTokens( pEncoded, "&" );
		for( int j=0; j<tTokens.NumTokens(); j++)
			{
			pEncoded = tTokens.GetToken( j );
			HTTPUtil_urlDecode( (Pi3String *)&pEncoded, pDecoded );
			pValue = strchr(Pi3String_getPtr(pDecoded), '=');
			if ( pValue )
				{
				if ( strlen(++pValue)>254
				  || strcspn(pValue,"=\"\n") < strlen(pValue) )
					{
					if (WriteExternal(pPIHTTP, pDecoded, pEncoded))
						{
						Pi3String_delete( pDecoded );
						return -1;
						};
					tExternal.Concatenate(pEncoded);
					tExternal.Concatenate("\r\n");
					continue;
					}
				};
			tDecoded.Concatenate(Pi3String_getPtr(pDecoded));
			tDecoded.Concatenate("\r\n");
			}
		Pi3String_delete( pDecoded );
		return 0;
		};

	/* ---
	Generate pipes and exeute 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; };

		/* --- 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; };

		/*
		** Execution flags
		*/
		if ( iFlags & FLG_16BIT )
			{ dwFlags |= CREATE_SEPARATE_WOW_VDM; };

		PROCESS_INFORMATION tProcessInfo;

		/*
		** complete command line for associations
		*/
		AppName = (char *)PIUtil_malloc(_MAX_PATH); 
		// Set AppName if the script name in pPath is associated
		if ((int)FindExecutable(pPath, NULL, AppName) < 33)
			{
			PIUtil_free(AppName);
			AppName = NULL;
			};

		/* --- spawn the CGI program --- */
		bProcessCreated = CreateProcess(
				AppName,			/* address of module name */
				(char *)pPath,		/* address of command line */
				NULL,				/* address of process security attributes */
				NULL,				/* address of thread security attributes */
				FALSE,              /* new process inherits handles */
				dwFlags,			/* creation flags */
				NULL,				/* address of new environment block */
				pDirectory,			/* address of current directory name */
				&tStartUp,			/* address of STARTUPINFO */
				&tProcessInfo		/* address of PROCESS_INFORMATION */
				);

		PIUtil_free(AppName);

		if ( !bProcessCreated )
			{ goto nt_error_return; };

		/* --- log debug information about the process --- */
		HTTPCore_logDebug( DBG_MED, "Process created!, \n\thProcess %p\
\n\thThread %p\n\tdwProcessId %lu\t\n\tdwThreadId %lu",
			tProcessInfo.dwThreadId,
			tProcessInfo.dwProcessId,
			tProcessInfo.hThread,
			tProcessInfo.hProcess );

#	if VERBOSE_DEBUG
		os << "Process created!" << endl;
		os << "	hProcess " << hex << tProcessInfo.hProcess << endl;
		os << "	hThread " << hex << tProcessInfo.hThread << endl;
		os << "	dwProcessId " << hex << tProcessInfo.dwProcessId << endl;
		os << "	dwThreadId " << hex << tProcessInfo.dwThreadId << endl;
#	endif

		/* --- Handle to main thread in new process --- */
		::CloseHandle( tProcessInfo.hThread );

		*pProcess = tProcessInfo.hProcess;
		*pStdout_Parent = tStdout_ParentDup;
		*pStdout_CGI = tStdout_CGI;
		if ( iDoStdin )
			{
			*pStdin_Parent = tStdin_ParentDup;
			*pStdin_CGI = tStdin_CGI;
			};
		*pStderr_Parent = tStderr_ParentDup;
		*pStderr_CGI = tStderr_CGI;

		/* --- OK --- */
		return 0;

nt_error_return:
		/* --- restore handles --- */
		int iTmp = GetLastError();
		goto generic_error_return;

#elif POSIX
		const char **ppCommandArgs=0;
		register int iPid = 0;

		/* ---
		Create command line
		--- */
		{
		/* --- scan once and NULL seperate path components --- */
		int i;
		int j = strlen( pPath );
		int k=0;
		for( i=0; i<j; i++ )
			{
			if ( (isspace(pPath[i])) )
				{
				pPath[i]='\0';
				k++;
				};
			}; 
	
		/* ---
		k contains number of spaces in command line.

		cmd1[sp]cmd2[sp]cmd3[sp]cmd4[0],

			increment k to include command terminated by final null.
			increment k again to allow NULL command at end of array.
		--- */
		k += 2;

		/* --- allocate and assign argument array --- */
		ppCommandArgs = (const char **)PIHTTP_allocMem( &tPIHTTP,
			sizeof( const char * ) * k ); 
		int x = 0;
		const char *pLastArg = 0;
		for( i=0; i<=j; i++ )
			{
			if ( pLastArg==0 )
				{ pLastArg=&(pPath[i]); };
			if ( pPath[i]=='\0' )
				{
				ppCommandArgs[x++] = pLastArg;
				pLastArg = 0;
				};
			};
		ppCommandArgs[x++] = 0;
		assert( x==k );
		};

		/* ---
		Try not to write any data to the processes data space to avoid
		copy-on-write penalty for CGI child process. 
		iPid is declared register so its assignment on fork in the child
		process will not write to the child process data space.
		--- */
#if 0
/*
** NOTE
*/
#define P ( PIThread_getSystemHandle( PIThread_getCurrent() ) )
cerr << P << " 1.." << tStdin_Parent << endl;
cerr << P << " 2.." << tStdin_CGI << endl;
cerr << P << " 3.." << tStdout_Parent << endl;
cerr << P << " 4.." << tStdout_CGI << endl;
cerr << P << " 5.." << tStderr_Parent << endl;
cerr << P << " 6.." << tStderr_CGI << endl;
#endif
		iPid = ::fork();
		switch( iPid )
			{
			case -1:
				break;

			case 0:
				/* --- change current directory --- */
				if ( pDirectory )
					{ ::chdir( pDirectory ); };
				extern char **environ;
				if ( ::execve( pPath, (char *const *)ppCommandArgs,
					environ )==-1 )
					{
					perror( "CGI child, execve() failed" );
					fprintf( stderr, "Path is '%s'\n", pPath );
					fflush( stderr );
					goto cgi_error;
					};
cgi_error:
				::_exit( 1 );

				/* none of the following should happen */
				::_exit( -1 );
				assert( 0 );
				break;

			default:
				/* --- this is the parent --- */
				*pProcess = iPid;
				*pStdout_CGI = tStdout_CGI;
				*pStdout_Parent = tStdout_Parent;
				*pStderr_CGI = tStderr_CGI;
				*pStderr_Parent = tStderr_Parent;
				if ( iDoStdin )
					{
					*pStdin_CGI = tStdin_CGI;
					*pStdin_Parent = tStdin_Parent;
					};

				/* --- log debug information about the process --- */
				HTTPCore_logDebug( DBG_MED, "Process created!, \n\tPid %d\
\n\tStdout_Parent %d\n\tStdout_CGI %d\n\tStderr_Parent %d\n\tStderr_CGI %d",
					iPid, tStdout_Parent, tStdout_CGI, tStderr_Parent,
					tStderr_CGI );

				/* --- OK --- */
				return 0;
			};

		/* --- error --- */
posix_error_return:
		int iTmp = errno;
		goto generic_error_return;

#endif


generic_error_return:
		/* --- stdout handles --- */
		CloseIfValidDesc( tStdout_CGI );
		CloseIfValidDesc( tStdout_Parent );
		CloseIfValidDesc( tStdout_ParentDup );

		/* --- stdin handles --- */
		CloseIfValidDesc( tStdin_CGI );
		CloseIfValidDesc( tStdin_Parent );
		CloseIfValidDesc( tStdin_ParentDup );

		/* --- stdin handles --- */
		CloseIfValidDesc( tStderr_CGI );
		CloseIfValidDesc( tStderr_Parent );
		CloseIfValidDesc( tStderr_ParentDup );

		HTTPCore_logError( &tPIHTTP, "WinCGI: error executing CGI program \
system specific error code is '%d'.", iTmp );

		/* --- return error --- */
		return iTmp ? iTmp : -1;
		};

	/* ---
	Wait for a child process to terminate

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -