📄 httpcore.cpp
字号:
/*____________________________________________________________________________*\
*
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 + -