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

📄 httpcore.cpp

📁 mini http server,可以集成嵌入到程序中,实现简单的web功能
💻 CPP
📖 第 1 页 / 共 5 页
字号:

/*____________________________________________________________________________*\
 *
 Function:
 Synopsis:
 Description:
\*____________________________________________________________________________*/
int Internal_RelativeToAbsolutePath( const char *pRoot,
    const char *pRelativePath, PIString &sResult )
{
	assert( pRoot );
	assert( pRelativePath );

    if ( !pRoot )
        { pRoot = ""; };
	if ( RelativeToAbsolutePath( pRoot, pRelativePath, sResult ) )
		{
#if WIN32
        /*
        ** Convert '/' to '\\' if this is WIN32
        */
        char *pStr = (char *)(const char *)sResult; /* break encapsulation! */
        int iLen = strlen( pStr );
        for( int j=0; j<iLen; j++ )
            {
            if ( pStr[j]=='/' ) { pStr[j]='\\'; };
            };
#endif

        return 1;
        };

	return 0;
}

/*____________________________________________________________________________*\
 *
 Function:
 Synopsis:
 Description:
	Return zero on success
\*____________________________________________________________________________*/
int HTTPCore_initServer( PIObject *pObject )
{
    if ( pSG )
        {
        /* already setup */
        return PIAPI_COMPLETED;
        };

    /*
    ** Make sure fast keys are setup
    */
    Internal_initFastKeys();

	pSG = PI_NEW( ServerGlobals() );

	assert( pObject );
	if ( !pObject )
        {
		CONFIG_ERR( pObject, "HTTPCore_initServer: NULL object \
(Internal Error)." );
		return -1;
        };

	/* ---
	Read the server root. Server root is mandatory
	--- */
	const char *pServerRoot = (const char *)PIConfig_lookupValue( 
		PIObject_getConfigurationDB( pObject ), KEY_CONF_SERVERROOT, 0, 0 );
	pSG->sServerRoot = pServerRoot;

	/* ---
	If the server root specified in the configuration file is relative
	then lookup the current directory and store it in absolute form,
	this avoids complications that may occur if the current directory
	is changed in the lifetime of the server
	--- */
	enum { DIR_BUF=1023 };
	char szBuf[DIR_BUF+1];
	*szBuf = '\0';
	PIPlatform_getCurrentDirectory( szBuf, DIR_BUF );
	szBuf[DIR_BUF] = '\0';
	if ( !RelativeToAbsolutePath( szBuf, pServerRoot,
		pSG->sServerRoot ) )
		{
		CONFIG_ERR( pObject, "HTTPCore_initServer: Could not set \
'ServerRoot' (Internal Error)." );
		return -1;
		};

	/* ---
	Contract the path to remove any '..' sequences 
	--- */
	strncpy( szBuf, pSG->sServerRoot, DIR_BUF );
	if ( HTTPUtil_contractPath( szBuf ) )
		{
		/* --- too many '..' sequences --- */
		CONFIG_ERR( pObject, "HTTPCore_initServer: 'ServerRoot' contains too \
many '..' sequences." );
		return -1;
		};
	pSG->sServerRoot = szBuf;

	if ( pSG->sServerRoot==PIString::Empty() )
		{
		CONFIG_ERR( pObject, "HTTPCore_initServer: No definition for \
'ServerRoot'" );
		return -1;
		};

	pSG->sServerStamp = (const char *)PIConfig_lookupValue( 
		PIObject_getConfigurationDB( pObject ), KEY_CONF_SERVERSTAMP, 0, 0 );

	/* ---
	open error log
	--- */
	const char *pErrorLog = (const char *)PIConfig_lookupValue(
		PIObject_getConfigurationDB( pObject ), KEY_CONF_ERRORLOGFILE, 0, 0 );
	if ( !pErrorLog )
		{
		CONFIG_ERR( pObject, "HTTPCore_initServer: No definition for \
'ErrorLogFile'" );
		return -1;
		};
	DeQuote tErrorLogFile( pErrorLog );
	PIString sErrorLogFile( pErrorLog );
	Internal_RelativeToAbsolutePath( pSG->sServerRoot,
        (const char *)tErrorLogFile, sErrorLogFile );
#if TEMP
	pSG->tErrorLog = PIFile_open( sErrorLogFile, "w" );
	if ( pSG->tErrorLog==PIPLATFORM_FD_INVALID )
#else
	pSG->pErrorLog = ::fopen( sErrorLogFile, "w" );
	if ( !pSG->pErrorLog )
#endif
		{
		PILog_addMessage(
			PIObject_getDB( pObject ), 
			PIObject_getConfigurationDB( pObject ),
			PILOG_ERROR,
			"HTTPCore_initServer: Could not open error logfile '%s'.",
			(const char *)sErrorLogFile );
		return -1;
		};
	/* ---
	Log initial message
	--- */
	HTTPCore_logError( 0, "Server error log started" );

	/* ---
	open debug log
	--- */
	const char *pDebugLog = (const char *)PIConfig_lookupValue(
		PIObject_getConfigurationDB( pObject ), KEY_CONF_DEBUGLOGFILE, 0, 0 );
	if ( pDebugLog )
		{
		DeQuote tDebugLogFile( pDebugLog );
		PIString sDebugLogFile( pDebugLog );
		Internal_RelativeToAbsolutePath( pSG->sServerRoot,
            (const char *)tDebugLogFile, sDebugLogFile );
		pSG->pDebugLog = ::fopen( sDebugLogFile, "w" );
		if ( !pSG->pDebugLog )
			{
			PILog_addMessage(
				PIObject_getDB( pObject ),
				PIObject_getConfigurationDB( pObject ),
				PILOG_ERROR,
				"HTTPCore_initServer: Could not open error logfile '%s'.",
					(const char *)sErrorLogFile );
			return -1;
			};
		HTTPCore_logDebug( DBG_HIGH, "Server debug log started" );
		};

	/* --- load the debug expressions --- */
	if ( Internal_LoadExpression( &(pSG->pBeforeHandler),
		KEY_CONF_DEBUGBEFOREHANDLER, pObject )==-1 )
		{ return -1; };
	if ( Internal_LoadExpression( &(pSG->pAfterHandler),
		KEY_CONF_DEBUGAFTERHANDLER, pObject )==-1 )
		{ return -1; };

	/* ---
	Create MIME DB and read in MIME file.
	--- */
	pSG->pMIMEDB = PIDB_new( 0, "MIME DB" );
	const char *pMIMEFile = (const char *)PIConfig_lookupValue( 
		PIObject_getConfigurationDB( pObject ), KEY_CONF_MIMEFILE, 0, 0);
	if ( pMIMEFile )
		{
		DeQuote tDeQuote( pMIMEFile );
		PIString sMIMEFile;
		Internal_RelativeToAbsolutePath( pSG->sServerRoot,
            (const char *)tDeQuote, sMIMEFile );
		if ( !HTTPCore_loadMIMEFile( pObject, pSG->pMIMEDB, sMIMEFile ) ) 
			{
			/* --- HTTPCore_loadMIMEFile() generates error messages --- */
			return -1;
			};
		};

	/* ---
	DefaultMIMEType
	--- */
	DeQuote tDefaultMIMEType( (const char *)PIConfig_lookupValue( 
		PIObject_getConfigurationDB( pObject ), KEY_CONF_DEFAULTMIMETYPE, 0,
		0 ) );
	pSG->sDefaultMIMEType = (const PIString &)tDefaultMIMEType;
	if ( pSG->sDefaultMIMEType==PIString::Empty() )
		{
		pSG->sDefaultMIMEType==HTTP_DEFAULT_MIME_TYPE;
		};

	/* ---
	Load other MIME types
	--- */
	if ( !Internal_loadAllMIMETypes( pSG->pMIMEDB, pObject,
		(PIDB *)PIObject_getConfigurationDB( pObject ) ) )
		{ return -1; /* --- error already given --- */ };

	PIDB *pDB = PIObject_getDB( pObject );

	/* ---
	Load top level handlers
	--- */
	const char *pHandlerNames = PIConfig_lookupValue(
		PIObject_getConfigurationDB( pObject ),
		KEY_CONF_HANDLERS, 0, 0 );
	if ( !pHandlerNames )
		{
		CONFIG_ERR( pObject, "HTTPCore_initServer: 'Handlers' not defined" );
		return -1;
		};
	/* --- Attempt to load all handler objects --- */
	StringTokenizer tTokens( pHandlerNames, " " );
	bool bIsOK = true;
	int i;
	for( i=0; bIsOK && i<tTokens.NumTokens(); i++ )
		{
		const char *pHandlerName = tTokens.GetToken( i );
		PIObject *pHandler = PIObject_load( pDB, 0, pHandlerName, 0, 0 );
		if ( !pHandler )
			{
			/* --- message is already set by 'PIObject_load()' --- */
			return -1;
			};
		pSG->lHandlers.Append( (DblList::type)pHandler );
		};

	if ( !bIsOK )	   
		{
		CONFIG_ERR( pObject, "HTTPCore_initServer: internal error adding \
handlers to DB" );
		return -1;
		};

	/* ---
	Sanity check
	--- */
	return !( pFKMethod && pFKURI && pFKPath && pFKQueryString &&
		pFKProtocol &&
		pFKMethodNumber && pFKProtocolNumber && 
		pFKProxyProtocol && pFKProxyHost && pFKProxyPort &&
		pFKKeepOpenO && pFKKeepOpenH
		);
}

/*____________________________________________________________________________*\
 *
 Function:
 Synopsis:
 Description:
	Return zero on success
\*____________________________________________________________________________*/
/* int HTTPCore_initClient( PIObject *pObject ) - LATER see note below */
int HTTPCore_initClient()
{
    if ( pCG )
        {
        /* already setup */
        return PIAPI_COMPLETED;
        };

    /*
    ** Make sure fast keys are setup
    */
    Internal_initFastKeys();

	pCG = PI_NEW( ClientGlobals() );

#if 0
/* LATER - perhaps */
	assert( pObject );

	if ( !pObject )
        {
		CONFIG_ERR( pObject, "HTTPCore_initClient: NULL object \
(Internal Error)." );
		return -1;
        };

	pCG->sClientStamp = (const char *)PIConfig_lookupValue( 
		PIObject_getConfigurationDB( pObject ), KEY_CONF_CLIENTSTAMP, 0, 0 );
#endif

    return 0;
}

/*____________________________________________________________________________*\
 *
 Function:
 Synopsis:
 Description:
	zero on success
\*____________________________________________________________________________*/
int HTTPCore_cleanupServer()
{
#if !defined(NDEBUG)
	PIProgram_dbgDump( pSG->pMIMEDB, "./mime.dbg" );
#endif
	PI_DELETE( pSG );
	return PIAPI_COMPLETED;
}

/*____________________________________________________________________________*\
 *
 Function:
 Synopsis:
 Description:
	zero on success
\*____________________________________________________________________________*/
int HTTPCore_cleanupClient()
{
	PI_DELETE( pCG );
	return PIAPI_COMPLETED;
}

/*____________________________________________________________________________*\
 *
 Function:
 Synopsis:
 Description:
	return 0 on success
\*____________________________________________________________________________*/
static int Internal_SendHeader_Date( PIIOBuffer &tB )
{
	PIString sTmp;
	time_t tT;
	PIPlatform_beforeUnsafeBlock();
	time( &tT );
	struct tm *pTms = gmtime( &tT );

	int iRet = HTTPUtil_rFC822Time( pTms, &sTmp );
	PIPlatform_afterUnsafeBlock();

	if ( iRet )
		{ return ST_INTERNALERROR; };

#define TMP "Date: "
	tB.Write( TMP, sizeof( TMP )-1 );
#undef TMP
	tB.WriteLn( sTmp, sTmp.Len() );

	return 0;
}

/*____________________________________________________________________________*\
 *
 Function:
 Synopsis:
 Description:
	return 0 on success
\*____________________________________________________________________________*/
static int Internal_SendHeader_Connection( PIHTTP &tPIHTTP )
{
	PIDB *pC = tPIHTTP.GetConnectionDB();
	PIDB *pQ = tPIHTTP.GetRequestDB();
	PIIOBuffer &tB = tPIHTTP.GetIOBuffer();
	
	/* ---
	Here's the connection related response headers we want to 
	send:-

		for HTTP/0.9, 	there are no headers and no keep open

		for HTTP/1.0, 
				Connection: Keep-Alive	
			to notify connection will be kept open

		for HTTP/1.1
				Connection: Close
			if connection is not going to be kept open

	--- */

	/* --- get protocol --- */
	int iProtocol = (int)PIDB_lookup( pQ, PIDBTYPE_OPAQUE, pFKProtocolNumber,
		PIDBFLAG_FASTKEY );

	/* --- get keep open flag --- */
	int iKeepOpen = (int)PIDB_lookup( pC, PIDBTYPE_OPAQUE, pFKKeepOpenO,
		PIDBFLAG_FASTKEY );
	
	if ( iProtocol == PR_HTTP10 && iKeepOpen )
		{
		/* --- notify that the connection will be kept open --- */
#define TMP "Connection: Keep-Alive"
		tB.WriteLn( TMP, sizeof( TMP )-1  );
#undef TMP
		}
	else if ( iProtocol == PR_HTTP11 && !iKeepOpen )
		{
		/* --- notify that the connection will be closed --- */
#define TMP "Connection: Close"
		tB.WriteLn( TMP, sizeof( TMP )-1  );
#undef TMP
		};

	return 0;
}

/*____________________________________________________________________________*\
 *
 Function:
 Synopsis:
 Description:
	Verify the HTTP response line and divide it into components. Returns
	INT_CONTINUE on success or an HTTP error status code on error.

	Assumes pLine is NULL terminated at pLine[iLineLen].

	On success instantiates all values to at least an empty string.

\*____________________________________________________________________________*/
static int Internal_SplitResponseLine(
	char *pLine, 
	int iLineLen,
	const char **ppProtocol,
	int *piStatusCode
	)
{
	assert( pLine );
	assert( iLineLen );
	assert( ppProtocol );
	assert( piStatusCode );

	*ppProtocol = "";	/* --- this is done because protcol is optional, i.e.
						HTTP/0.9 doesn't send one
						--- */
	/* ---
	protocol

⌨️ 快捷键说明

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