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

📄 wincgi.cpp

📁 mini http server,可以集成嵌入到程序中,实现简单的web功能
💻 CPP
📖 第 1 页 / 共 5 页
字号:
						PIIOBuffer_delete( pCGIBuffer );
						PIObject_delete( pChildIO, 0, 0 );
						PIFile_close( tFd );
						return bIgnoreStatus;
						}
					}

				PIIOBuffer_delete( pCGIBuffer );
				PIObject_delete( pChildIO, 0, 0 );
				};	
			};

		PIFile_close( tFd );

		/* ---
		If a datafile name pattern was specified write the data block
		to that file
		--- */
		if ( pDataFile && pDataBlock )
			{
			int iDataSize = 4096;	/* --- initial guess --- */
			int iLen = -1;
			char *pData = 0;
			for(;;)
				{
				pData = (char *)PIHTTP_allocMem( &tPIHTTP, iDataSize );
				iLen = Pi3Expression_write( pDataBlock, &tPIHTTP, &tContext,
					pData, iDataSize );

				if ( iLen==-1 )
					{ break; }; 

				/* --- try again if buffer was not big enough --- */
				if ( iLen>iDataSize ) {
					iDataSize = iLen; 
					continue;
					};

				break;
				};

			/* ---
			Error getting data block ?
			--- */
			if ( iLen==-1 )
				{
				assert( 0 );
				HTTPCore_logError( &tPIHTTP,  
						"WinCGI: Internal error getting data for datafile '%s'.",
					((const char *)tContext.sDataFile) );
				tPIHTTP.iStatus = ST_INTERNALERROR;
				return bIgnoreStatus;
				};

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

			int iFailed = ( tFd == PIPLATFORM_FD_INVALID ||
							PIFile_write( tFd, iLen, pData )!=0 );
			if ( tFd!=PIPLATFORM_FD_INVALID )
				{ PIFile_close( tFd ); };
			if ( iFailed )
				{
				HTTPCore_logError( &tPIHTTP,  
					"WinCGI: Failed to write datafile, path is '%s'.",
					((const char *)tContext.sDataFile) );
				tPIHTTP.iStatus = ST_INTERNALERROR;
				return bIgnoreStatus;
				};
			};

		/* ---
		Generate command line pattern
		--- */
		enum { CMD_BUF_SIZE=255 };/* --- this will fit most command lines --- */
		char szCmdBuf[CMD_BUF_SIZE+1];
		char *pCommandLine = szCmdBuf;
		int iLen = Pi3Expression_write( pCommandPattern, &tPIHTTP, &tContext,
			pCommandLine, CMD_BUF_SIZE );
		szCmdBuf[CMD_BUF_SIZE] = '\0';
		if ( iLen>CMD_BUF_SIZE )
			{
			/* --- automatic buffer not big enough, allocate a new one --- */
			pCommandLine = (char *)PIHTTP_allocMem( &tPIHTTP, iLen+1 );
			Pi3Expression_write( pCommandPattern, &tPIHTTP, &tContext, 
				pCommandLine, iLen );
			Pi3Expression_write( pCommandPattern, &tPIHTTP, &tContext,
				pCommandLine, iLen );
			};
		pCommandLine[iLen] = '\0';

#if VERBOSE_DEBUG
		cerr << "Executing commandline: '" << pCommandLine << "'" << endl;
#endif
		int iRCode = DoExecCGIChild( 
				pCommandLine, 
				pDirectory,
				&tProcess, 
				iDoStdin,
				&tStdout_Parent,
				&tStdout_CGI,
				&tStdin_Parent,
				&tStdin_CGI,
				&tStderr_Parent,
				&tStderr_CGI,
				tPIHTTP
#if VERBOSE_DEBUG
				, cerr
#endif
				);

		/* ---
		Error in CGI program
		--- */
		if ( iRCode )
			{
			HTTPCore_logError( &tPIHTTP,  
				"WinCGI: DoExecCGIChild() failed. Error code is %d. \
Start of command line is '%s'.", iRCode, szCmdBuf );
			tPIHTTP.iStatus = ST_INTERNALERROR;
			CLOSE_ALL_HANDLES;
			return bIgnoreStatus;
			};

		/*
		** pError serves as error flag
		*/
		int iRet = 0;
		const char *pError = 0;
		const char *pArgs[3];
		PIObject *pChildIO = 0;
		PIIOBuffer *pCGIBuffer = 0;

		CloseIfValidDesc( tStdin_CGI );
		CloseIfValidDesc( tStdin_Parent );

		/* ---
        Wait for process to die.
		---- */
		if ( !WaitForChild( szCmdBuf, tPIHTTP, tProcess ) )
			{ iRet = -1;	/* error message already given */ };
		CloseProcessDesc( tProcess );
		tProcess = INVALID_DESC;

		/* ---
		Close CGI side of pipe
		--- */
		CloseFileDesc( tStdout_CGI );

		/* ---
		Read and discard stderr, write this CGI error to server error file
		--- */
		enum { BUF_SIZE=2047 };
		char szBuf[BUF_SIZE+1];

		/* ---
		CGI output is from a file, open the file
		--- */
		assert( tStdout_Parent == INVALID_DESC );
		tStdout_Parent = (FILEDESC)PIFile_open( tContext.sOutputFile, "r" );

		/* ---
		Make a clone of the prototype pipe IO object for communication
		with this CGI process
		--- */
		pArgs[0] = (const char *)tStdout_Parent;
		pArgs[1] = (const char *)tStdin_Parent;
		pArgs[2] = (const char *)0;		/* handle is a pipe? - no */
		pChildIO = PIObject_copy( pPipeIO, 3, pArgs );
		if ( !pChildIO )
			{
			pError = "WinCGI: Failed to open communication channel to CGI \
program.";
			}
		else
			{
			/* ---
			Make CGI buffer object
			--- */
			pCGIBuffer = PIIOBuffer_new( pChildIO );
			assert( pCGIBuffer );
			};

		/* ---	
		Read CGI request headers
		--- */
		if ( !pError && !iRet )
			{
			if ( HTTPCore_readHeaders( pCGIBuffer, pR, RH_RESPONSE ) )
				{ pError = "Error reading response headers from CGI program"; };
			};

		if ( pError )
			{
			if ( *pError )
				{
				HTTPCore_logError( &tPIHTTP, "WinCGI: %s.\nStart of command line \
is '%s'.", pError, szCmdBuf );
				}
			else
				{
				HTTPCore_logError( &tPIHTTP, "WinCGI: Start of command line \
is '%s'.", szCmdBuf );
				};
			iRet = -1;
			};
#if VERBOSE_DEBUG
		cerr << dec << iRet << endl;
#endif
		
		/* ---
		Check the type of the response
			- Partial (usual case)
			- Full
			- or redirect
		--- */
		const char *pCLF = 0;
		const char *pLocation = 0;
		if ( !iRet && ( pCLF = (const char *)
			PIDB_lookup( pR, PIDBTYPE_STRING, KEY_HTTP_CLF, 0 ) ) ) 
			{

			/* ++++ __________________________ +++ *
				Full Response (Non-Parsed Headers)
			 * ++++ __________________________ +++ */

			/* --- grap the status code sent by the CGI --- */
			int i=0;
			for(; pCLF[i] && !(isspace(pCLF[i])); i++); /* advance to space */
			for(; pCLF[i] && (isspace(pCLF[i])); i++); /* advance past space */
			tPIHTTP.iStatus = atoi( &(pCLF[i]) );

			/* ---
			disable keep open, hope the CGI sent the appropriate 
			'Connection' headers for this HTTP version
			--- */
			PIDB_replace( tPIHTTP.pConnectionDB, PIDBTYPE_OPAQUE, 
				KEY_INT_KEEPOPEN, (void *)0, 0 );

			/* --- send status header from CGI --- */
			PIIOBuffer_writeLn( &tB, pCLF, -1, PIIOBUF_NONE );

			/* --- loop over RFC822 headers to send them --- */
			PIDBIterator *pIter = PIDB_getIterator( pR, PIDBTYPE_RFC822, 0, 0 );
			for( ;
				PIDBIterator_atValidElement( pIter );
				PIDBIterator_next( pIter ) )
				{
				const char *pHeader;
				const char *pContent = (const char *)
					PIDBIterator_current( pIter, &pHeader );
				PIIOBuffer_write( &tB, pHeader, -1, PIIOBUF_NONE );
				PIIOBuffer_write( &tB, ": ", 2, PIIOBUF_NONE );
				PIIOBuffer_writeLn( &tB, pContent, -1, PIIOBUF_NONE );
				};
			PIDBIterator_delete( pIter );
			
			/* --- empty CRLF --- */
			PIIOBuffer_writeLn( &tB, "", 0, PIIOBUF_NONE );

			/* ---
			for a full reponse no REDIRECT action should be
			taken based on the status code, as the CGI program is handling
			the status itself
			--- */
			bIgnoreStatus = true;

			/* --- continue to allow the content-body to be sent --- */
			}
		else if ( !iRet && (pLocation=(const char *)
			PIDB_lookup( pR, PIDBTYPE_RFC822, KEY_HTTP_LOCATION, 0 ) ) )
			{

			/* ++++ __________________________ +++ *
					  Location Response
			 * ++++ __________________________ +++ */

			/* --- determine if this is a URL path or a URI --- */
			if ( *pLocation=='/' )
				{
				/* ---
				URL path, expand to full URI and replace in Location
				--- */
				PIOStrStream ostr;
				if ( PIDB_lookup( pC, PIDBTYPE_STRING, KEY_HTTPS_KEYSIZE, 0 ) )
					{
					/*
					** Running under SSL
					*/
					ostr << "https://";
					}
				else
					{
					/*
					** Not running under SSL
					*/
					ostr << "http://";
					};
				const char *pHostName = HTTPUtil_getHostName( &tPIHTTP );
				if ( pHostName )
					{ ostr << pHostName; };
				const char *pPort = HTTPUtil_getHostPort( &tPIHTTP );
				if ( pPort )
					{ ostr << ':' << pPort; };

				ostr << pLocation;
				ostr << ends;

				PIDB_replace( pR, PIDBTYPE_RFC822, KEY_HTTP_LOCATION,
						(void *)ostr.str(), 0 );
				};

			/* --- change status to permanent redirect --- */
			tPIHTTP.iStatus = ST_PERMANENTREDIRECT;

			/* ---
			Has the CGI program sent any content ?
			--- */
			if ( !PIIOBuffer_pollBeforeRead( pCGIBuffer ) )
				{
				/* --- 
				No content 
				--- */
				if ( pCGIBuffer )
					{ PIIOBuffer_delete( pCGIBuffer ); };
				PIObject_delete( pChildIO, 0, 0 );
				CLOSE_ALL_HANDLES;
				return bIgnoreStatus;
				};

			/* ---
			for a location reponse with no content no REDIRECT action should be
			taken based on the status code, as the CGI program is handling
			the content itself
			--- */
			bIgnoreStatus = true;

			/* ---
			start to send the response and allow the 
			output from the CGI to be sent to the client as entity 
			body for the request.
			--- */
			PIDB_replace( tPIHTTP.pConnectionDB, PIDBTYPE_OPAQUE, 
				KEY_INT_KEEPOPEN, (void *)0, 0 );
			if (	HTTPCore_sendGeneralHeaders( &tPIHTTP ) ||
					HTTPCore_sendEntityHeaders( &tPIHTTP, pR ) ) 
				{ iRet = -1; };
			}
		else if ( !iRet )
			{

			/* ++++ __________________________ +++ *
			  Partial Response (aka Parsed Headers)
			 * ++++ __________________________ +++ */

			/* ---
				Make sure that at least 'Content-Type' exists.
			--- */
			if ( !PIDB_lookup( pR, PIDBTYPE_RFC822, KEY_HTTP_CONTENTTYPE, 0 ))
				{
				HTTPCore_logError( &tPIHTTP, "WinCGI: CGI program \
did not provide 'Content-Type' header. Start of command line is '%s'.", szCmdBuf );
				iRet = -1;

				/* ---
				if 'Status' header exists,
				then set the status appropriately
				--- */
				const char *pStatus = (const char *)PIDB_lookup( pR,
					PIDBTYPE_RFC822, KEY_HTTP_STATUS, 0 );
				if ( pStatus )
					{
					tPIHTTP.iStatus = atoi( pStatus );
					};	
				}
			else
				{
				/* --- start the response --- */
				tPIHTTP.iStatus = ST_OK;

				PIDB_replace( tPIHTTP.pConnectionDB, PIDBTYPE_OPAQUE, 
					KEY_INT_KEEPOPEN, (void *)0, 0 );
				if (	HTTPCore_sendGeneralHeaders( &tPIHTTP ) ||
						HTTPCore_sendEntityHeaders( &tPIHTTP, pR ) ) 
					{ iRet = -1; };
				};
			};

		if ( !iRet )
			{ iRet = WriteBufferToBuffer( *pCGIBuffer, tB ); };
		if ( pCGIBuffer )
			{ PIIOBuffer_delete( pCGIBuffer ); };


#if VERBOSE_DEBUG
		cerr << dec << iRet << endl;
#endif
		CloseIfValidDesc( tStdout_Parent );

		/* ---
		Swallow up stderr stream from CGI child
		--- */
		CloseFileDesc( tStderr_CGI );
		for(;;)
			{
			int iRead;

			int iRet = PIPlatform_pollPipeFD(
					(PIPLATFORM_FD)tStderr_Parent, PIPLATFORM_POLL_READ, 0 );

			if ( iRet != PIPLATFORM_POLL_READ )
				{
				if (iRet == PIAPI_ERROR)
					{
					iRet = PIPlatform_getLastError();
					if ((iRet != PIAPI_NOTSUPPORTED) && (iRet != PIAPI_EINVAL))
						{ break; };
					}
				else
					{ break; };
				};

//			if ( iRet!=PIPLATFORM_POLL_READ )
//				{ break; };

#if WIN32
			if ( !::ReadFile( tStderr_Parent, szBuf, BUF_SIZE, 
				(unsigned long *)&iRead, NULL ) || !iRead )
				{ break; };
#elif POSIX
			iRead = ::read( tStderr_Parent, szBuf, BUF_SIZE );
			if ( iRead==-1 && errno==EINTR )
				{ continue; };
			if ( iRead==-1 || !iRead )
				{ break; };
#endif
			szBuf[iRead] = '\0';

			/*
			** Write stderr output into the error logfile
			*/
			HTTPCore_logError( &tPIHTTP, "WinCGI: Stderr output from \
CGI program follows \n\
______________________________________________________________________________\
__\n%s\n\
______________________________________________________________________________\
__\nCGI program command line is '%s'.", szBuf, szCmdBuf );
			/* --- mark an error --- */

			iRet = -1;
			};
		CloseIfValidDesc( tStderr_Parent );

		PIObject_delete( pChildIO, 0, 0 );

		if ( iRet )
			{
			tPIHTTP.iStatus =

⌨️ 快捷键说明

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