You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2198 lines
62 KiB
2198 lines
62 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name :
|
|
ExtLogC.cpp
|
|
|
|
Abstract:
|
|
W3C Extended LogFile Format Implementation
|
|
|
|
Author:
|
|
|
|
Terence Kwan ( terryk ) 18-Sep-1996
|
|
|
|
Project:
|
|
|
|
IIS Logging 3.0
|
|
|
|
--*/
|
|
|
|
#include "precomp.hxx"
|
|
#include <stdio.h>
|
|
#include "ilogobj.hxx"
|
|
#include "script.h"
|
|
#include "LogScript.hxx"
|
|
#include "filectl.hxx"
|
|
#include "lkrhash.h"
|
|
#include "iisver.h"
|
|
#include "iis64.h"
|
|
|
|
#include "extlogc.hxx"
|
|
|
|
const CHAR szExtNoPeriodPattern[] = "extend*.log";
|
|
const CHAR G_PSZ_DELIMITER[2] = { ' ', '\0'};
|
|
|
|
CHAR szDotDot[] = "...";
|
|
CHAR szDash [] = "-";
|
|
CHAR szHTTPOk[] = "200\r\n";
|
|
|
|
CCustomPropHashTable *g_pGlobalLoggingProperties=NULL;
|
|
|
|
|
|
/* ************************************************************************************ */
|
|
/* Helper functions */
|
|
/* ************************************************************************************ */
|
|
|
|
inline VOID
|
|
BuildHeader(
|
|
IN OUT STR * strHeader,
|
|
IN DWORD dwMask,
|
|
IN DWORD dwField,
|
|
IN LPCSTR szFieldHeader
|
|
)
|
|
{
|
|
if (dwMask & dwField)
|
|
{
|
|
strHeader->Append(szFieldHeader);
|
|
strHeader->Append(' ');
|
|
}
|
|
}
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
inline BOOL
|
|
CopyFieldToBuffer(
|
|
IN PCHAR Field,
|
|
IN DWORD FieldSize,
|
|
IN PCHAR * ppchOutBuffer,
|
|
IN OUT PDWORD SpaceNeeded,
|
|
IN DWORD SpaceProvided
|
|
)
|
|
{
|
|
if ( 0 == FieldSize )
|
|
{
|
|
Field = "-";
|
|
FieldSize = 1;
|
|
}
|
|
|
|
//
|
|
// Remove the NULL terminator
|
|
//
|
|
|
|
(*SpaceNeeded) += FieldSize + 1; // +1 for trailing space
|
|
|
|
if ( (*SpaceNeeded) <= SpaceProvided )
|
|
{
|
|
CopyMemory( (*ppchOutBuffer), Field, FieldSize );
|
|
(*ppchOutBuffer) += FieldSize;
|
|
(**ppchOutBuffer) = ' ';
|
|
(*ppchOutBuffer)++;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
} // CopyFieldToBuffer
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
inline BOOL WriteHTTPHeader(
|
|
IN OUT PCHAR * ppchHeader,
|
|
IN PCHAR * ppchOutBuffer,
|
|
IN OUT PDWORD SpaceNeeded,
|
|
IN DWORD SpaceProvided
|
|
)
|
|
{
|
|
DWORD cbTmp = 0;
|
|
|
|
if ( (NULL != ppchHeader ) && ( NULL != *ppchHeader))
|
|
{
|
|
|
|
CHAR * pTmp = *ppchHeader;
|
|
|
|
cbTmp = (DWORD)strlen(pTmp);
|
|
*ppchHeader = pTmp + cbTmp + 1;
|
|
|
|
if ((cbTmp > MAX_LOG_TARGET_FIELD_LEN ) ||
|
|
(((*SpaceNeeded)+cbTmp) > MAX_LOG_RECORD_LEN)
|
|
)
|
|
{
|
|
pTmp = szDotDot;
|
|
cbTmp = 3;
|
|
}
|
|
else
|
|
{
|
|
ConvertSpacesToPlus(pTmp);
|
|
}
|
|
|
|
return CopyFieldToBuffer( pTmp, cbTmp, ppchOutBuffer, SpaceNeeded, SpaceProvided);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* ************************************************************************************ */
|
|
/* CCustomPropHashTable Class */
|
|
/* ************************************************************************************ */
|
|
|
|
|
|
VOID
|
|
CCustomPropHashTable::ClearTableAndStorage()
|
|
{
|
|
|
|
//
|
|
// Clear the Hash Table & free any previous LOG_PROPERTY_INFO entries
|
|
//
|
|
|
|
Clear();
|
|
|
|
if (NULL != m_pLogPropArray)
|
|
{
|
|
delete [] m_pLogPropArray;
|
|
m_pLogPropArray = NULL;
|
|
}
|
|
m_cLogPropItems = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL CCustomPropHashTable::InitializeFromMB (MB &mb,const char *path)
|
|
{
|
|
BOOL retVal = TRUE;
|
|
if (!m_fInitialized)
|
|
{
|
|
if (mb.Open(path))
|
|
{
|
|
retVal = m_fInitialized = FillHashTable(mb);
|
|
mb.Close();
|
|
}
|
|
else
|
|
{
|
|
retVal = FALSE;
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CCustomPropHashTable::PopulateHash(MB& mb, LPCSTR szPath, DWORD& cItems, bool fCountOnly)
|
|
{
|
|
BOOL retVal = TRUE;
|
|
|
|
//
|
|
// Retrieve all required fields for all Custom Properties and store in the hash table.
|
|
//
|
|
|
|
int index = 0;
|
|
|
|
CHAR szChildName[256];
|
|
CHAR szW3CHeader[256] = "";
|
|
|
|
STR strNewPath;
|
|
|
|
while( mb.EnumObjects(szPath, szChildName, index) )
|
|
{
|
|
DWORD size;
|
|
DWORD dwPropertyID, dwPropertyMask, dwPropertyDataType;
|
|
LPCSTR szNewPath;
|
|
|
|
|
|
//
|
|
// Create the new path.
|
|
//
|
|
|
|
if ((NULL != szPath) && ( '\0' != *szPath))
|
|
{
|
|
if ( !(strNewPath.Copy(szPath) &&
|
|
strNewPath.Append("/") &&
|
|
strNewPath.Append(szChildName)) )
|
|
{
|
|
retVal = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( !strNewPath.Copy(szChildName) )
|
|
{
|
|
retVal = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
szNewPath = strNewPath.QueryStr();
|
|
|
|
//
|
|
// Copy configuration information into internal structures
|
|
//
|
|
|
|
szW3CHeader[0] = 0;
|
|
size = 256;
|
|
|
|
if ( mb.GetString( szNewPath, MD_LOGCUSTOM_PROPERTY_HEADER, IIS_MD_UT_SERVER,
|
|
szW3CHeader, &size) &&
|
|
mb.GetDword( szNewPath, MD_LOGCUSTOM_PROPERTY_ID, IIS_MD_UT_SERVER,
|
|
&dwPropertyID) &&
|
|
mb.GetDword( szNewPath, MD_LOGCUSTOM_PROPERTY_MASK, IIS_MD_UT_SERVER,
|
|
&dwPropertyMask) &&
|
|
mb.GetDword( szNewPath, MD_LOGCUSTOM_PROPERTY_DATATYPE, IIS_MD_UT_SERVER,
|
|
&dwPropertyDataType)
|
|
|
|
)
|
|
{
|
|
if (! fCountOnly)
|
|
{
|
|
PLOG_PROPERTY_INFO pRec = &m_pLogPropArray[cItems];
|
|
|
|
if ( ! (pRec->strKeyPath.Copy(szNewPath) &&
|
|
pRec->strW3CHeader.Copy(szW3CHeader)) )
|
|
{
|
|
retVal = FALSE;
|
|
break;
|
|
}
|
|
|
|
pRec->dwPropertyID = dwPropertyID;
|
|
pRec->dwPropertyMask = dwPropertyMask;
|
|
pRec->dwPropertyDataType = dwPropertyDataType;
|
|
|
|
if (LK_SUCCESS != InsertRecord(pRec))
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT, "PopulateHash: Unable to insert Property %s\n", pRec->strKeyPath.QueryStr()));
|
|
retVal = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
cItems++;
|
|
}
|
|
|
|
//
|
|
// Enumerate children
|
|
//
|
|
|
|
if (!PopulateHash(mb, szNewPath, cItems, fCountOnly))
|
|
{
|
|
retVal = FALSE;
|
|
break;
|
|
}
|
|
index++;
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
BOOL
|
|
CCustomPropHashTable::FillHashTable(MB& mb)
|
|
{
|
|
BOOL retVal = FALSE;
|
|
DWORD cItems = 0;
|
|
|
|
//
|
|
// Find out the number of items in the Custom Logging Tree
|
|
//
|
|
|
|
if (PopulateHash(mb, NULL, cItems, true))
|
|
{
|
|
|
|
ClearTableAndStorage ();
|
|
|
|
if (cItems)
|
|
{
|
|
m_pLogPropArray = new LOG_PROPERTY_INFO[cItems];
|
|
|
|
if ( NULL != m_pLogPropArray)
|
|
{
|
|
m_cLogPropItems = cItems;
|
|
cItems = 0;
|
|
retVal = PopulateHash(mb, NULL, cItems, false);
|
|
if ( !retVal )
|
|
{
|
|
ClearTableAndStorage ();
|
|
}
|
|
DBG_ASSERT(m_cLogPropItems == cItems);
|
|
}
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
VOID
|
|
CCustomPropHashTable::SetPopulationState(MB& mb)
|
|
{
|
|
CIterator iter;
|
|
DWORD dwValue;
|
|
|
|
LK_RETCODE lkrc = InitializeIterator(&iter);
|
|
|
|
while (LK_SUCCESS == lkrc)
|
|
{
|
|
Record* pRec = iter.Record();
|
|
|
|
if ( mb.GetDword("", pRec->dwPropertyID, IIS_MD_UT_SERVER, &dwValue) &&
|
|
(dwValue & pRec->dwPropertyMask))
|
|
{
|
|
pRec->fEnabled = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pRec->fEnabled = FALSE;
|
|
}
|
|
|
|
lkrc = IncrementIterator(&iter);
|
|
}
|
|
|
|
CloseIterator(&iter);
|
|
}
|
|
|
|
|
|
BOOL
|
|
CCustomPropHashTable::InitFrom(CCustomPropHashTable& src)
|
|
{
|
|
CIterator iter;
|
|
DWORD i;
|
|
BOOL retVal = FALSE;
|
|
|
|
ClearTableAndStorage ();
|
|
|
|
if (src.m_cLogPropItems)
|
|
{
|
|
m_pLogPropArray = new LOG_PROPERTY_INFO[src.m_cLogPropItems];
|
|
|
|
if ( NULL != m_pLogPropArray)
|
|
{
|
|
m_cLogPropItems = src.m_cLogPropItems;
|
|
retVal = TRUE;
|
|
for (i=0; i<m_cLogPropItems;i++)
|
|
{
|
|
PLOG_PROPERTY_INFO pRec = &m_pLogPropArray[i];
|
|
PLOG_PROPERTY_INFO pRecOriginal = &src.m_pLogPropArray[i];
|
|
|
|
if ( pRec->strKeyPath.Copy(pRecOriginal->strKeyPath) &&
|
|
pRec->strW3CHeader.Copy(pRecOriginal->strW3CHeader) )
|
|
{
|
|
pRec->dwPropertyID = pRecOriginal->dwPropertyID;
|
|
pRec->dwPropertyMask = pRecOriginal->dwPropertyMask;
|
|
pRec->dwPropertyDataType = pRecOriginal->dwPropertyDataType;
|
|
|
|
if (LK_SUCCESS != InsertRecord(pRec))
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT, "InitFrom: Unable to insert Property %s\n", pRec->strKeyPath.QueryStr()));
|
|
retVal = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
retVal = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
/* ************************************************************************************ */
|
|
/* CEXTLOG Class */
|
|
/* ************************************************************************************ */
|
|
|
|
CEXTLOG::CEXTLOG() :
|
|
m_lMask (DEFAULT_EXTLOG_FIELDS),
|
|
m_fHashTablePopulated ( FALSE),
|
|
m_fWriteHeadersInitialized ( FALSE),
|
|
m_cPrevCustLogItems ( 0),
|
|
m_pLogFields ( NULL ),
|
|
m_fUseLocalTimeForRollover ( 0),
|
|
m_pLocalTimeCache ( NULL)
|
|
{
|
|
if ( !g_pGlobalLoggingProperties)
|
|
{
|
|
g_pGlobalLoggingProperties = new CCustomPropHashTable;
|
|
}
|
|
else
|
|
{
|
|
g_pGlobalLoggingProperties->AddRef();
|
|
}
|
|
}
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
CEXTLOG::~CEXTLOG()
|
|
{
|
|
m_HashTable.ClearTableAndStorage ();
|
|
|
|
if ( NULL != m_pLocalTimeCache)
|
|
{
|
|
delete m_pLocalTimeCache;
|
|
m_pLocalTimeCache = NULL;
|
|
}
|
|
|
|
if (NULL != m_pLogFields)
|
|
{
|
|
delete [] m_pLogFields;
|
|
m_pLogFields = NULL;
|
|
}
|
|
if ( g_pGlobalLoggingProperties)
|
|
{
|
|
if ( g_pGlobalLoggingProperties->Release () == 0)
|
|
{
|
|
delete g_pGlobalLoggingProperties;
|
|
g_pGlobalLoggingProperties = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
STDMETHODIMP
|
|
CEXTLOG::InitializeLog(
|
|
LPCSTR szInstanceName,
|
|
LPCSTR pszMetabasePath,
|
|
CHAR* pvIMDCOM
|
|
)
|
|
{
|
|
HRESULT retVal = RETURNCODETOHRESULT ( MD_ERROR_DATA_NOT_FOUND );
|
|
|
|
MB mb( (IMDCOM*) pvIMDCOM );
|
|
|
|
|
|
if ( g_pGlobalLoggingProperties )
|
|
{
|
|
m_fHashTablePopulated = g_pGlobalLoggingProperties->InitializeFromMB(mb,"/LM/Logging/Custom Logging");
|
|
if ( m_fHashTablePopulated )
|
|
{
|
|
if (m_HashTable.InitFrom (*g_pGlobalLoggingProperties))
|
|
{
|
|
if ( mb.Open(pszMetabasePath))
|
|
{
|
|
m_HashTable.SetPopulationState(mb);
|
|
if ( mb.Close())
|
|
{
|
|
retVal = CLogFileCtrl::InitializeLog(szInstanceName, pszMetabasePath, pvIMDCOM);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
retVal = HRESULTTOWIN32( GetLastError());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
retVal = RETURNCODETOHRESULT ( ERROR_OUTOFMEMORY );
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
DBG_ASSERT (FALSE);
|
|
retVal = RETURNCODETOHRESULT ( ERROR_OUTOFMEMORY );
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
STDMETHODIMP
|
|
CEXTLOG::TerminateLog(
|
|
VOID
|
|
)
|
|
{
|
|
return CLogFileCtrl::TerminateLog();
|
|
}
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
DWORD
|
|
CEXTLOG::GetRegParameters(
|
|
LPCSTR pszRegKey,
|
|
LPVOID pvIMDCOM
|
|
)
|
|
{
|
|
// let the parent object get the default parameter first
|
|
|
|
CLogFileCtrl::GetRegParameters( pszRegKey, pvIMDCOM );
|
|
|
|
MB mb( (IMDCOM*) pvIMDCOM );
|
|
|
|
if ( !mb.Open("") ) {
|
|
DBGPRINTF((DBG_CONTEXT, "Error %x on mb open\n",GetLastError()));
|
|
goto exit;
|
|
}
|
|
|
|
if ( !mb.GetDword(
|
|
pszRegKey,
|
|
MD_LOGEXT_FIELD_MASK,
|
|
IIS_MD_UT_SERVER,
|
|
&m_lMask ) )
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT, "Error %x on FieldMask GetDword\n",GetLastError()));
|
|
}
|
|
|
|
//
|
|
// Get time to be used for logfile rollover
|
|
//
|
|
|
|
if ( !mb.GetDword( pszRegKey,
|
|
MD_LOGFILE_LOCALTIME_ROLLOVER,
|
|
IIS_MD_UT_SERVER,
|
|
&m_fUseLocalTimeForRollover
|
|
) )
|
|
{
|
|
m_fUseLocalTimeForRollover = 0;
|
|
}
|
|
|
|
if (m_fUseLocalTimeForRollover && ( NULL == m_pLocalTimeCache))
|
|
{
|
|
m_pLocalTimeCache = new ASCLOG_DATETIME_CACHE;
|
|
}
|
|
|
|
exit:
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
VOID
|
|
CEXTLOG::GetFormatHeader(
|
|
IN OUT STR * strHeader
|
|
)
|
|
{
|
|
strHeader->Reset();
|
|
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_DATE, EXTLOG_DATE_ID);
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_TIME, EXTLOG_TIME_ID);
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_CLIENT_IP, EXTLOG_CLIENT_IP_ID);
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_USERNAME, EXTLOG_USERNAME_ID);
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_SITE_NAME, EXTLOG_SITE_NAME_ID);
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_COMPUTER_NAME, EXTLOG_COMPUTER_NAME_ID);
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_SERVER_IP, EXTLOG_SERVER_IP_ID);
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_SERVER_PORT, EXTLOG_SERVER_PORT_ID);
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_METHOD, EXTLOG_METHOD_ID);
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_URI_STEM, EXTLOG_URI_STEM_ID);
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_URI_QUERY, EXTLOG_URI_QUERY_ID);
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_HTTP_STATUS, EXTLOG_HTTP_STATUS_ID);
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_WIN32_STATUS, EXTLOG_WIN32_STATUS_ID);
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_BYTES_SENT, EXTLOG_BYTES_SENT_ID);
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_BYTES_RECV, EXTLOG_BYTES_RECV_ID);
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_TIME_TAKEN, EXTLOG_TIME_TAKEN_ID);
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_PROTOCOL_VERSION, EXTLOG_PROTOCOL_VERSION_ID);
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_HOST, EXTLOG_HOST_ID);
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_USER_AGENT, EXTLOG_USER_AGENT_ID);
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_COOKIE, EXTLOG_COOKIE_ID);
|
|
BuildHeader(strHeader, m_lMask, EXTLOG_REFERER, EXTLOG_REFERER_ID);
|
|
|
|
if ( ! strHeader->IsEmpty())
|
|
{
|
|
//
|
|
// Remove the trailing space
|
|
//
|
|
|
|
strHeader->SetLen(strHeader->QuerySize()-1);
|
|
}
|
|
|
|
return;
|
|
|
|
} // CEXTLOG::GetFormatHeader
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
BOOL
|
|
CEXTLOG::WriteLogDirectives(
|
|
IN DWORD Sludge
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Function to write the Extended logging directives
|
|
|
|
Arguments:
|
|
|
|
Sludge - number of additional bytes that needs to be written
|
|
together with the directives
|
|
|
|
Return Value:
|
|
|
|
TRUE, ok
|
|
FALSE, not enough space to write.
|
|
|
|
--*/
|
|
{
|
|
BOOL fRetVal = TRUE;
|
|
|
|
if ( m_pLogFile != NULL)
|
|
{
|
|
|
|
CHAR buf[1024];
|
|
CHAR szDateTime[32];
|
|
|
|
STACK_STR (header,256);
|
|
DWORD len;
|
|
|
|
GetFormatHeader(&header );
|
|
|
|
(VOID)m_DateTimeCache.GetFormattedCurrentDateTime(szDateTime);
|
|
|
|
len = wsprintf( buf,
|
|
"#Software: Microsoft %s %d.%d\r\n"
|
|
"#Version: %s\r\n"
|
|
"#Date: %s %s\r\n"
|
|
"#Fields: %s\r\n",
|
|
VER_IISPRODUCTNAME_STR, VER_IISMAJORVERSION, VER_IISMINORVERSION,
|
|
EXTLOG_VERSION, szDateTime, szDateTime+strlen(szDateTime)+1, header.QueryStr());
|
|
|
|
DBG_ASSERT(len == strlen(buf));
|
|
|
|
if ( !IsFileOverFlowForCB(len + Sludge))
|
|
{
|
|
m_pLogFile->Write(buf, len) ? IncrementBytesWritten(len) : (fRetVal = FALSE);
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
DBGPRINTF((DBG_CONTEXT, "WriteLogDirectives: Unable to write directives\n"));
|
|
fRetVal = FALSE;
|
|
}
|
|
}
|
|
|
|
return(fRetVal);
|
|
|
|
} // CLogFileCtrl::WriteLogDirectives
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
BOOL
|
|
CEXTLOG::FormatLogBuffer(
|
|
IN IInetLogInformation *pLogObj,
|
|
IN LPSTR pBuf,
|
|
IN DWORD *pcbSize,
|
|
OUT SYSTEMTIME *pSystemTime
|
|
)
|
|
{
|
|
PCHAR pTmp;
|
|
DWORD cbTmp;
|
|
DWORD nRequired;
|
|
DWORD status;
|
|
PCHAR pBuffer = pBuf;
|
|
CHAR rgchDateTime[32];
|
|
|
|
//
|
|
// We need system time
|
|
//
|
|
|
|
m_DateTimeCache.SetSystemTime( pSystemTime );
|
|
|
|
//
|
|
// if default go through fast path
|
|
//
|
|
|
|
if ( m_lMask != DEFAULT_EXTLOG_FIELDS )
|
|
{
|
|
BOOL fRet = NormalFormatBuffer(
|
|
pLogObj,
|
|
pBuf,
|
|
pcbSize,
|
|
pSystemTime
|
|
);
|
|
|
|
if (fRet && m_fUseLocalTimeForRollover )
|
|
{
|
|
m_pLocalTimeCache ? m_pLocalTimeCache->SetLocalTime(pSystemTime):
|
|
GetLocalTime(pSystemTime);
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
//
|
|
// Default format is:
|
|
// Time ClientIP Operation Target HTTPStatus
|
|
//
|
|
// Time 8 HH:MM:SS
|
|
// delimiters 4
|
|
// EOL 2
|
|
//
|
|
|
|
nRequired = 8 + 4 + 2;
|
|
|
|
(VOID) m_DateTimeCache.GetFormattedDateTime(pSystemTime,rgchDateTime);
|
|
pTmp = rgchDateTime + 11;
|
|
|
|
CopyMemory(pBuffer, pTmp, 8);
|
|
pBuffer += 8;
|
|
*(pBuffer++) = ' ';
|
|
|
|
//
|
|
// IP Address
|
|
//
|
|
|
|
pTmp = pLogObj->GetClientHostName( NULL, &cbTmp );
|
|
if ( cbTmp == 0 )
|
|
{
|
|
cbTmp = 1;
|
|
pTmp = "-";
|
|
}
|
|
|
|
nRequired += cbTmp;
|
|
if ( nRequired <= *pcbSize )
|
|
{
|
|
CopyMemory(pBuffer, pTmp, cbTmp);
|
|
pBuffer += cbTmp;
|
|
*(pBuffer++) = ' ';
|
|
}
|
|
|
|
//
|
|
// Operation
|
|
//
|
|
|
|
pTmp = pLogObj->GetOperation( NULL, &cbTmp );
|
|
if ( cbTmp == 0 )
|
|
{
|
|
cbTmp = 1;
|
|
pTmp = "-";
|
|
}
|
|
|
|
nRequired += cbTmp;
|
|
if ( nRequired <= *pcbSize )
|
|
{
|
|
CopyMemory(pBuffer, pTmp, cbTmp);
|
|
pBuffer += cbTmp;
|
|
*(pBuffer++) = ' ';
|
|
}
|
|
|
|
//
|
|
// Target
|
|
//
|
|
|
|
pTmp = pLogObj->GetTarget( NULL, &cbTmp );
|
|
|
|
if ( cbTmp == 0 )
|
|
{
|
|
cbTmp = 1;
|
|
pTmp = "-";
|
|
}
|
|
else if ( (cbTmp > MAX_LOG_TARGET_FIELD_LEN ) ||
|
|
((nRequired + cbTmp) > MAX_LOG_RECORD_LEN))
|
|
{
|
|
cbTmp = 3;
|
|
pTmp = szDotDot;
|
|
}
|
|
|
|
nRequired += cbTmp;
|
|
if ( nRequired <= *pcbSize )
|
|
{
|
|
for (DWORD i=0; i<cbTmp;i++ )
|
|
{
|
|
if ( (*pBuffer = pTmp[i]) == ' ' )
|
|
{
|
|
*pBuffer = '+';
|
|
}
|
|
pBuffer++;
|
|
}
|
|
*(pBuffer++) = ' ';
|
|
}
|
|
|
|
status = pLogObj->GetProtocolStatus( );
|
|
|
|
if ( (status == 200) && (nRequired + 5 <= *pcbSize) )
|
|
{
|
|
|
|
CopyMemory( pBuffer, szHTTPOk, 5);
|
|
pBuffer += 5;
|
|
nRequired += 3;
|
|
}
|
|
else
|
|
{
|
|
|
|
CHAR tmpBuf[32];
|
|
|
|
cbTmp = FastDwToA( tmpBuf, status );
|
|
|
|
nRequired += cbTmp;
|
|
if ( nRequired <= *pcbSize )
|
|
{
|
|
CopyMemory(pBuffer, tmpBuf, cbTmp);
|
|
pBuffer += cbTmp;
|
|
}
|
|
|
|
*(pBuffer++) = '\r';
|
|
*pBuffer = '\n';
|
|
}
|
|
|
|
if ( nRequired > *pcbSize )
|
|
{
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
*pcbSize = nRequired;
|
|
return(FALSE);
|
|
}
|
|
|
|
*pcbSize = nRequired;
|
|
|
|
//
|
|
// To allow filenames & rollover based on either local or GMT time
|
|
//
|
|
|
|
if ( m_fUseLocalTimeForRollover )
|
|
{
|
|
m_pLocalTimeCache ? m_pLocalTimeCache->SetLocalTime(pSystemTime):
|
|
GetLocalTime(pSystemTime);
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
} // CEXTLOG::FormatLogBuffer
|
|
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
BOOL
|
|
CEXTLOG::NormalFormatBuffer(
|
|
IN IInetLogInformation *pLogObj,
|
|
IN LPSTR pBuf,
|
|
IN DWORD *pcbSize,
|
|
IN SYSTEMTIME *pSystemTime
|
|
)
|
|
{
|
|
|
|
BOOL fSucceeded = FALSE;
|
|
DWORD spaceNeeded = 0;
|
|
|
|
CHAR tmpBuf[32];
|
|
PCHAR pTmp;
|
|
DWORD cbTmp;
|
|
|
|
//
|
|
// Format is:
|
|
// Date Time ClientIP UserName Service Server ServerIP
|
|
// Method Target parameters httpstatus win32 bytes timetaken
|
|
// user-agent cookies
|
|
//
|
|
|
|
PCHAR outBuffer = pBuf;
|
|
*outBuffer = 0;
|
|
|
|
if ( m_lMask & (EXTLOG_DATE | EXTLOG_TIME) )
|
|
{
|
|
|
|
DWORD cchDateTime;
|
|
DWORD cchDate;
|
|
DWORD cchTime;
|
|
CHAR rgchDateTime[ 32];
|
|
|
|
cchDateTime = m_DateTimeCache.GetFormattedDateTime(
|
|
pSystemTime,
|
|
rgchDateTime);
|
|
|
|
cchDate = (DWORD)strlen(rgchDateTime);
|
|
cchTime = cchDateTime - cchDate - 1;
|
|
|
|
if (m_lMask & EXTLOG_DATE)
|
|
{
|
|
// Date is in YYYY-MM-DD format (GMT)
|
|
|
|
fSucceeded = CopyFieldToBuffer( rgchDateTime, cchDate, &outBuffer,
|
|
&spaceNeeded, *pcbSize);
|
|
}
|
|
|
|
if (m_lMask & EXTLOG_TIME)
|
|
{
|
|
// Time in HH:MM:SS format (GMT)
|
|
|
|
fSucceeded = CopyFieldToBuffer( rgchDateTime+cchDate+1, cchTime, &outBuffer,
|
|
&spaceNeeded, *pcbSize);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Fill up the buffer
|
|
//
|
|
|
|
if (m_lMask & EXTLOG_CLIENT_IP )
|
|
{
|
|
pTmp = pLogObj->GetClientHostName( NULL, &cbTmp );
|
|
fSucceeded = CopyFieldToBuffer( pTmp, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
|
|
}
|
|
|
|
if (m_lMask & EXTLOG_USERNAME )
|
|
{
|
|
pTmp = pLogObj->GetClientUserName( NULL, &cbTmp );
|
|
fSucceeded = CopyFieldToBuffer( pTmp, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
|
|
}
|
|
|
|
if (m_lMask & EXTLOG_SITE_NAME)
|
|
{
|
|
pTmp = pLogObj->GetSiteName( NULL, &cbTmp );
|
|
fSucceeded = CopyFieldToBuffer( pTmp, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
|
|
}
|
|
|
|
if (m_lMask & EXTLOG_COMPUTER_NAME)
|
|
{
|
|
pTmp = pLogObj->GetComputerName( NULL, &cbTmp );
|
|
fSucceeded = CopyFieldToBuffer( pTmp, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
|
|
}
|
|
|
|
if (m_lMask & EXTLOG_SERVER_IP )
|
|
{
|
|
pTmp = pLogObj->GetServerAddress( NULL, &cbTmp );
|
|
fSucceeded = CopyFieldToBuffer( pTmp, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
|
|
}
|
|
|
|
if (m_lMask & EXTLOG_SERVER_PORT )
|
|
{
|
|
cbTmp = FastDwToA( tmpBuf, pLogObj->GetPortNumber() );
|
|
fSucceeded = CopyFieldToBuffer( tmpBuf, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
|
|
}
|
|
|
|
if (m_lMask & EXTLOG_METHOD )
|
|
{
|
|
pTmp = pLogObj->GetOperation( NULL, &cbTmp );
|
|
fSucceeded = CopyFieldToBuffer( pTmp, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
|
|
}
|
|
|
|
if (m_lMask & EXTLOG_URI_STEM )
|
|
{
|
|
pTmp = pLogObj->GetTarget( NULL, &cbTmp );
|
|
|
|
if ((cbTmp > MAX_LOG_TARGET_FIELD_LEN ) || ((spaceNeeded + cbTmp) > MAX_LOG_RECORD_LEN))
|
|
{
|
|
cbTmp = 3;
|
|
pTmp = szDotDot;
|
|
}
|
|
else
|
|
{
|
|
ConvertSpacesToPlus(pTmp);
|
|
}
|
|
|
|
fSucceeded = CopyFieldToBuffer( pTmp, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
|
|
}
|
|
|
|
if (m_lMask & EXTLOG_URI_QUERY )
|
|
{
|
|
pTmp = pLogObj->GetParameters( NULL, &cbTmp );
|
|
|
|
if ((cbTmp > MAX_LOG_TARGET_FIELD_LEN ) || ((spaceNeeded + cbTmp) > MAX_LOG_RECORD_LEN))
|
|
{
|
|
cbTmp = 3;
|
|
pTmp = szDotDot;
|
|
}
|
|
else
|
|
{
|
|
ConvertSpacesToPlus(pTmp);
|
|
}
|
|
|
|
fSucceeded = CopyFieldToBuffer( pTmp, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
|
|
}
|
|
|
|
if (m_lMask & EXTLOG_HTTP_STATUS )
|
|
{
|
|
cbTmp = FastDwToA( tmpBuf, pLogObj->GetProtocolStatus() );
|
|
fSucceeded = CopyFieldToBuffer( tmpBuf, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
|
|
}
|
|
|
|
if (m_lMask & EXTLOG_WIN32_STATUS )
|
|
{
|
|
cbTmp = FastDwToA( tmpBuf, pLogObj->GetWin32Status() );
|
|
fSucceeded = CopyFieldToBuffer( tmpBuf, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
|
|
}
|
|
|
|
if (m_lMask & EXTLOG_BYTES_SENT )
|
|
{
|
|
cbTmp = FastDwToA( tmpBuf, pLogObj->GetBytesSent() );
|
|
fSucceeded = CopyFieldToBuffer( tmpBuf, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
|
|
}
|
|
|
|
if (m_lMask & EXTLOG_BYTES_RECV )
|
|
{
|
|
cbTmp = FastDwToA( tmpBuf, pLogObj->GetBytesRecvd() );
|
|
fSucceeded = CopyFieldToBuffer( tmpBuf, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
|
|
}
|
|
|
|
if (m_lMask & EXTLOG_TIME_TAKEN )
|
|
{
|
|
cbTmp = FastDwToA( tmpBuf, pLogObj->GetTimeForProcessing() );
|
|
fSucceeded = CopyFieldToBuffer( tmpBuf, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
|
|
}
|
|
|
|
if (m_lMask & EXTLOG_PROTOCOL_VERSION )
|
|
{
|
|
pTmp = pLogObj->GetVersionString( NULL, &cbTmp );
|
|
fSucceeded = CopyFieldToBuffer( pTmp, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
|
|
}
|
|
|
|
//
|
|
// See if we need to get the extra header
|
|
//
|
|
|
|
if ( (m_lMask & (EXTLOG_HOST |
|
|
EXTLOG_USER_AGENT |
|
|
EXTLOG_COOKIE |
|
|
EXTLOG_REFERER )) != NULL )
|
|
{
|
|
|
|
pTmp = pLogObj->GetExtraHTTPHeaders( NULL, &cbTmp );
|
|
|
|
if ( m_lMask & EXTLOG_HOST )
|
|
fSucceeded = WriteHTTPHeader(&pTmp, &outBuffer, &spaceNeeded, *pcbSize);
|
|
|
|
if ( m_lMask & EXTLOG_USER_AGENT )
|
|
fSucceeded = WriteHTTPHeader(&pTmp, &outBuffer, &spaceNeeded, *pcbSize);
|
|
|
|
if ( m_lMask & EXTLOG_COOKIE )
|
|
fSucceeded = WriteHTTPHeader(&pTmp, &outBuffer, &spaceNeeded, *pcbSize);
|
|
|
|
if ( m_lMask & EXTLOG_REFERER )
|
|
fSucceeded = WriteHTTPHeader(&pTmp, &outBuffer, &spaceNeeded, *pcbSize);
|
|
}
|
|
|
|
//
|
|
// remove the trailing space
|
|
//
|
|
|
|
if ('\0' != *pBuf)
|
|
{
|
|
outBuffer--;
|
|
spaceNeeded--;
|
|
}
|
|
|
|
//
|
|
// add line terminator
|
|
//
|
|
|
|
spaceNeeded += 2;
|
|
if ( spaceNeeded <= *pcbSize)
|
|
{
|
|
outBuffer[0] = '\r';
|
|
outBuffer[1] = '\n';
|
|
fSucceeded = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fSucceeded = FALSE;
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
*pcbSize = spaceNeeded;
|
|
return fSucceeded;
|
|
|
|
} // CEXTLOG::FormatLogBuffer
|
|
|
|
/* ************************************************************************************ */
|
|
/* Custom Logging Functions */
|
|
/* ************************************************************************************ */
|
|
|
|
BOOL
|
|
CEXTLOG::WriteCustomLogDirectives(
|
|
IN DWORD Sludge
|
|
)
|
|
{
|
|
BOOL fRetVal = TRUE;
|
|
|
|
if ( m_pLogFile != NULL)
|
|
{
|
|
CHAR szDateTime[32];
|
|
DWORD dwLen;
|
|
|
|
STACK_STR( strHeader, 512 );
|
|
|
|
m_DateTimeCache.GetFormattedCurrentDateTime(szDateTime);
|
|
|
|
BuildCustomLogHeader(m_cPrevCustLogItems, m_pPrevCustLogItems, szDateTime,
|
|
m_strHeaderSuffix.QueryStr(), strHeader);
|
|
|
|
dwLen = strHeader.QueryCB();
|
|
|
|
if ( !IsFileOverFlowForCB(dwLen + Sludge) )
|
|
{
|
|
m_pLogFile->Write(strHeader.QueryStr(), dwLen) ?
|
|
IncrementBytesWritten(dwLen) : (fRetVal = FALSE);
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
DBGPRINTF((DBG_CONTEXT, "WriteCustomLogDirectives: Unable to write directives\n"));
|
|
fRetVal = FALSE;
|
|
}
|
|
}
|
|
|
|
return fRetVal;
|
|
}
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
DWORD
|
|
CEXTLOG::ConvertDataToString(
|
|
IN DWORD dwPropertyType,
|
|
IN PVOID pData,
|
|
IN PCHAR pBuffer,
|
|
IN DWORD dwBufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Function to convert Custom Logging data to string
|
|
|
|
Arguments:
|
|
|
|
dwPropertyType - type information regarding the data to convert.
|
|
pData - pointer to data.
|
|
pBuffer - pointer to buffer to store the result.
|
|
dwBufferSize - byte count of space remaining in the buffer. If 0 or -ve
|
|
=> buffer is full
|
|
|
|
Return Value:
|
|
|
|
Number of bytes in the string representation of the data +1 (for space at end).
|
|
The output buffer (pBuffer) is not NULL terminated.
|
|
|
|
--*/
|
|
{
|
|
CHAR szBuf[64];
|
|
PCHAR pChString;
|
|
DWORD dwLength;
|
|
|
|
USES_CONVERSION; // To enable W2A
|
|
|
|
DBG_ASSERT(NULL != pBuffer);
|
|
|
|
if ( NULL != pData)
|
|
{
|
|
pChString = szBuf;
|
|
|
|
switch (dwPropertyType)
|
|
{
|
|
|
|
case MD_LOGCUSTOM_DATATYPE_INT:
|
|
{
|
|
int i = *((int *)pData);
|
|
_itoa(i, pChString, 10);
|
|
dwLength = (DWORD)strlen(pChString);
|
|
break;
|
|
}
|
|
|
|
case MD_LOGCUSTOM_DATATYPE_UINT:
|
|
{
|
|
unsigned int ui = *((unsigned int *)pData);
|
|
unsigned long ul = ui;
|
|
_ultoa(ul, pChString, 10);
|
|
dwLength = (DWORD)strlen(pChString);
|
|
break;
|
|
}
|
|
|
|
case MD_LOGCUSTOM_DATATYPE_LONG:
|
|
{
|
|
long l = *((long *)pData);
|
|
_ltoa(l, pChString, 10);
|
|
dwLength = (DWORD)strlen(pChString);
|
|
break;
|
|
}
|
|
|
|
case MD_LOGCUSTOM_DATATYPE_ULONG:
|
|
{
|
|
unsigned long ul = *((unsigned long *)pData);
|
|
_ultoa(ul, pChString, 10);
|
|
dwLength = (DWORD)strlen(pChString);
|
|
break;
|
|
}
|
|
|
|
case MD_LOGCUSTOM_DATATYPE_FLOAT:
|
|
{
|
|
float f = *((float *)pData);
|
|
dwLength = sprintf(pChString,"%f",f);
|
|
break;
|
|
}
|
|
|
|
case MD_LOGCUSTOM_DATATYPE_DOUBLE:
|
|
{
|
|
double d = *((double *)pData);
|
|
dwLength = sprintf(pChString,"%f",d);
|
|
break;
|
|
}
|
|
|
|
case MD_LOGCUSTOM_DATATYPE_LPSTR:
|
|
{
|
|
pChString = (LPSTR)pData;
|
|
dwLength = (DWORD)strlen(pChString);
|
|
|
|
if (dwLength > MAX_LOG_TARGET_FIELD_LEN )
|
|
{
|
|
pChString = szDotDot;
|
|
dwLength = 3;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case MD_LOGCUSTOM_DATATYPE_LPWSTR:
|
|
{
|
|
dwLength = (DWORD)wcslen( (LPWSTR)pData);
|
|
|
|
if (dwLength <= MAX_LOG_TARGET_FIELD_LEN)
|
|
{
|
|
pChString = W2A((LPWSTR)pData);
|
|
}
|
|
else
|
|
{
|
|
pChString = szDotDot;
|
|
dwLength = 3;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
dwLength = 0;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pChString = szDash;
|
|
dwLength = 1;
|
|
}
|
|
|
|
//
|
|
// Copy over the charaters to the output buffer and append a ' '
|
|
//
|
|
|
|
if (dwLength < dwBufferSize)
|
|
{
|
|
CopyMemory(pBuffer, pChString, dwLength);
|
|
pBuffer[dwLength] = ' ';
|
|
}
|
|
else if (dwBufferSize > 3)
|
|
{
|
|
//
|
|
// Not enough memory to copy the field. Use ... instead
|
|
//
|
|
|
|
dwLength = 3;
|
|
CopyMemory(pBuffer, szDotDot, 3);
|
|
pBuffer[dwLength] = ' ';
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Can't even copy ... Just punt on the remaining part of the log line
|
|
//
|
|
|
|
dwLength = (DWORD)-1;
|
|
}
|
|
|
|
return dwLength+1;
|
|
}
|
|
/* ************************************************************************************ */
|
|
|
|
DWORD
|
|
CEXTLOG::FormatCustomLogBuffer(
|
|
DWORD cItems,
|
|
PPLOG_PROPERTY_INFO pPropInfo,
|
|
PPVOID pPropData,
|
|
LPCSTR szDateTime,
|
|
LPSTR szLogLine,
|
|
DWORD cchLogLine
|
|
)
|
|
{
|
|
DWORD cchUsed;
|
|
PCHAR pCh = szLogLine;
|
|
|
|
cchLogLine -= 1; // Reserve space for trailing \r\n
|
|
|
|
//
|
|
// Add date & time if enabled
|
|
//
|
|
|
|
if ( m_lMask & (EXTLOG_DATE | EXTLOG_TIME) )
|
|
{
|
|
|
|
DWORD cch = (DWORD)strlen(szDateTime);
|
|
|
|
if (m_lMask & EXTLOG_DATE)
|
|
{
|
|
memcpy(pCh, szDateTime, cch);
|
|
*(pCh+cch) = ' ';
|
|
pCh += cch+1;
|
|
}
|
|
|
|
if (m_lMask & EXTLOG_TIME)
|
|
{
|
|
szDateTime += cch+1;
|
|
cch = (DWORD)strlen(szDateTime);
|
|
memcpy(pCh, szDateTime, cch);
|
|
*(pCh+cch) = ' ';
|
|
pCh += cch+1;
|
|
}
|
|
}
|
|
|
|
cchLogLine -= (DWORD)DIFF(pCh - szLogLine);
|
|
|
|
for (DWORD i=0; i< cItems; i++)
|
|
{
|
|
// Convert data to string
|
|
|
|
cchUsed = ConvertDataToString(pPropInfo[i]->dwPropertyDataType,
|
|
pPropData[i],
|
|
pCh, cchLogLine);
|
|
pCh += cchUsed;
|
|
|
|
cchLogLine -= cchUsed;
|
|
}
|
|
|
|
*(pCh-1) = '\r';
|
|
*(pCh) = '\n';
|
|
|
|
return (DWORD)DIFF(pCh+1-szLogLine);
|
|
}
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
void
|
|
CEXTLOG::BuildCustomLogHeader(
|
|
DWORD cItems,
|
|
PPLOG_PROPERTY_INFO pPropInfo,
|
|
LPCSTR szDateTime,
|
|
LPCSTR szHeaderSuffix,
|
|
STR& strHeader
|
|
)
|
|
{
|
|
DWORD cchHeader;
|
|
LPSTR szHeader = strHeader.QueryStr();
|
|
|
|
cchHeader = wsprintf( szHeader,
|
|
"#Software: Microsoft %s %d.%d\r\n"
|
|
"#Version: %s\r\n"
|
|
"#Date: %s %s\r\n",
|
|
VER_IISPRODUCTNAME_STR, VER_IISMAJORVERSION, VER_IISMINORVERSION,
|
|
EXTLOG_VERSION,
|
|
szDateTime,
|
|
szDateTime+strlen(szDateTime)+1
|
|
);
|
|
|
|
if ( (NULL != szHeaderSuffix) && ('\0' != *szHeaderSuffix))
|
|
{
|
|
DWORD cchSuffix;
|
|
|
|
// Make sure that the header begins with a #
|
|
|
|
if ( *szHeaderSuffix != '#')
|
|
{
|
|
szHeader[cchHeader++] = '#';
|
|
}
|
|
|
|
cchSuffix = (DWORD)strlen(szHeaderSuffix);
|
|
memcpy(szHeader+cchHeader, szHeaderSuffix, cchSuffix);
|
|
cchHeader += cchSuffix;
|
|
|
|
szHeader[cchHeader++] = '\r';
|
|
szHeader[cchHeader++] = '\n';
|
|
}
|
|
|
|
memcpy(szHeader+cchHeader, "#Fields:", sizeof("#Fields:"));
|
|
cchHeader += sizeof("#Fields:");
|
|
strHeader.SetLen(cchHeader-1);
|
|
|
|
//
|
|
// Fill in W3C Headers for all fields.
|
|
//
|
|
if ( m_lMask & EXTLOG_DATE )
|
|
{
|
|
strHeader.Append(" date");
|
|
}
|
|
if (m_lMask & EXTLOG_TIME)
|
|
{
|
|
strHeader.Append(" time");
|
|
}
|
|
|
|
for (DWORD i=0; i< cItems; i++)
|
|
{
|
|
// Add header to header string
|
|
|
|
strHeader.Append(' ');
|
|
strHeader.Append(pPropInfo[i]->strW3CHeader);
|
|
}
|
|
|
|
strHeader.Append("\r\n");
|
|
}
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
STDMETHODIMP
|
|
CEXTLOG::LogCustomInformation(
|
|
IN DWORD cItems,
|
|
IN PCUSTOM_LOG_DATA pCustomLogData,
|
|
IN LPSTR szHeaderSuffix
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Function to write Custom Logging information for Extended logging
|
|
|
|
Arguments:
|
|
|
|
cItems - number of fields to log
|
|
(elements in the array pointed to by pCustomLogData)
|
|
|
|
pCustomLogData - pointer to array of CUSTOM_LOG_DATA
|
|
|
|
Return Value:
|
|
|
|
HRESULT indicating whether function Succeeded or Failed.
|
|
|
|
--*/
|
|
{
|
|
|
|
SYSTEMTIME sysTime;
|
|
DWORD i, j, cchLogLine;
|
|
BOOL fResetHeaders;
|
|
CHAR szDateTime[32];
|
|
CHAR szLogLine[MAX_LOG_RECORD_LEN+1];
|
|
|
|
DBG_ASSERT( 0 != cItems);
|
|
DBG_ASSERT( NULL != pCustomLogData);
|
|
DBG_ASSERT( MAX_CUSTLOG_FIELDS >= cItems);
|
|
|
|
PLOG_PROPERTY_INFO pPropInfo[MAX_CUSTLOG_FIELDS];
|
|
PVOID pPropData[MAX_CUSTLOG_FIELDS];
|
|
|
|
//
|
|
// Lock Shared. Ensures that shared variables are not modified unknowst to this thread.
|
|
//
|
|
|
|
LockCustLogShared();
|
|
|
|
fResetHeaders = FALSE;
|
|
|
|
//
|
|
// Build list of enabled keys. Simultaneously check if headr needs resetting.
|
|
//
|
|
|
|
for (i=0, j=0 ; i< cItems; i++)
|
|
{
|
|
|
|
if ( (LK_SUCCESS == m_HashTable.FindKey(pCustomLogData[i].szPropertyPath, pPropInfo+j)) &&
|
|
(pPropInfo[j]->fEnabled)
|
|
)
|
|
{
|
|
fResetHeaders |= ( pPropInfo[j] != m_pPrevCustLogItems[j] );
|
|
pPropData[j] = pCustomLogData[i].pData;
|
|
j++;
|
|
}
|
|
}
|
|
|
|
cItems = j;
|
|
|
|
//
|
|
// Header needs resetting if # items is different or Header Suffix has changed.
|
|
//
|
|
|
|
fResetHeaders |= (m_cPrevCustLogItems != cItems);
|
|
|
|
if (szHeaderSuffix != NULL)
|
|
{
|
|
fResetHeaders |= ( 0 != strcmp(m_strHeaderSuffix.QueryStr(), szHeaderSuffix));
|
|
}
|
|
|
|
m_DateTimeCache.SetSystemTime( &sysTime );
|
|
m_DateTimeCache.GetFormattedDateTime(&sysTime, szDateTime);
|
|
|
|
cchLogLine = FormatCustomLogBuffer( cItems,
|
|
pPropInfo,
|
|
pPropData,
|
|
szDateTime,
|
|
szLogLine,
|
|
MAX_LOG_RECORD_LEN+1);
|
|
|
|
if (fResetHeaders)
|
|
{
|
|
//
|
|
// Convert Lock to Exclusive before setting the class wide variable.
|
|
//
|
|
|
|
LockCustLogConvertExclusive();
|
|
|
|
m_cPrevCustLogItems = cItems;
|
|
|
|
for (i=0; i <cItems; i++)
|
|
{
|
|
m_pPrevCustLogItems[i] = pPropInfo[i];
|
|
}
|
|
|
|
m_strHeaderSuffix.Copy(szHeaderSuffix);
|
|
}
|
|
|
|
//
|
|
// Write out the log to file
|
|
//
|
|
|
|
if ( m_fUseLocalTimeForRollover )
|
|
{
|
|
m_pLocalTimeCache ? m_pLocalTimeCache->SetLocalTime(&sysTime):
|
|
GetLocalTime(&sysTime);
|
|
}
|
|
|
|
WriteLogInformation(sysTime, szLogLine, cchLogLine, TRUE, fResetHeaders);
|
|
|
|
UnlockCustLog();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/* ************************************************************************************ */
|
|
/* ILogScripting Functions */
|
|
/* ************************************************************************************ */
|
|
|
|
HRESULT
|
|
CEXTLOG::ReadFileLogRecord(
|
|
IN FILE *fpLogFile,
|
|
IN LPINET_LOGLINE pInetLogLine,
|
|
IN PCHAR pszLogLine,
|
|
IN DWORD dwLogLineSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Function to read a log line from an open log file
|
|
|
|
Arguments:
|
|
|
|
fpLogFile - FILE * to open file
|
|
pInetLogLine - pointer to INET_LOGLINE structure where parsed info is stored
|
|
pszLogLine - buffer to store the log line
|
|
dwLogLineSize - size of pszLogLine
|
|
|
|
Return Value:
|
|
|
|
HRESULT indicating whether function Succeeded or Failed.
|
|
|
|
--*/
|
|
{
|
|
CHAR * pCh;
|
|
DWORD pos, custompos;
|
|
CHAR * szDateString, * szTimeString;
|
|
|
|
getnewline:
|
|
|
|
pCh = pszLogLine;
|
|
|
|
if (fgets(pCh, dwLogLineSize, fpLogFile) == NULL)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
pCh = SkipWhite(pCh);
|
|
|
|
if (('\n' == *pCh) || ('\0' == *pCh))
|
|
{
|
|
// Empty line. Get Next line
|
|
|
|
goto getnewline;
|
|
}
|
|
|
|
if ( '#' == *pCh )
|
|
{
|
|
|
|
pCh = strstr(pszLogLine, "#Date:");
|
|
|
|
if (NULL != pCh)
|
|
{
|
|
//
|
|
// Copy the date & time into member variables
|
|
//
|
|
|
|
pCh = strtok(pCh+6," \t\r\n");
|
|
if (NULL == pCh)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
strcpy(m_szDate, pCh);
|
|
|
|
pCh = strtok(NULL," \t\r\n");
|
|
if (NULL == pCh)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
strcpy(m_szTime, pCh);
|
|
|
|
goto getnewline;
|
|
}
|
|
|
|
//
|
|
// Not the date line. Check if the fields are being reset
|
|
//
|
|
|
|
pCh = strstr(pszLogLine, "#Fields:");
|
|
|
|
if (NULL != pCh)
|
|
{
|
|
// Headers are being defined or redefined
|
|
|
|
dwDatePos = 0;
|
|
dwTimePos = 0;
|
|
dwClientIPPos = 0;
|
|
dwUserNamePos = 0;
|
|
dwSiteNamePos = 0;
|
|
dwComputerNamePos = 0;
|
|
dwServerIPPos = 0;
|
|
dwMethodPos = 0;
|
|
dwURIStemPos = 0;
|
|
dwURIQueryPos = 0;
|
|
dwHTTPStatusPos = 0;
|
|
dwWin32StatusPos = 0;
|
|
dwBytesSentPos = 0;
|
|
dwBytesRecvPos = 0;
|
|
dwTimeTakenPos = 0;
|
|
dwServerPortPos = 0;
|
|
dwVersionPos = 0;
|
|
dwCookiePos = 0;
|
|
dwUserAgentPos = 0;
|
|
dwRefererPos = 0;
|
|
|
|
pInetLogLine->iCustomFieldsCount = 0;
|
|
|
|
pCh = strtok(pCh+8," \t\r\n");
|
|
|
|
for (pos = 1; pCh != NULL; pos++, pCh = strtok(NULL," \t\r\n"))
|
|
{
|
|
|
|
if (0 == _stricmp(pCh, EXTLOG_DATE_ID)) {
|
|
dwDatePos = pos;
|
|
} else if (0 == _stricmp(pCh, EXTLOG_TIME_ID)) {
|
|
dwTimePos = pos;
|
|
} else if (0 == _stricmp(pCh, EXTLOG_CLIENT_IP_ID)) {
|
|
dwClientIPPos = pos;
|
|
} else if (0 == _stricmp(pCh, EXTLOG_USERNAME_ID)) {
|
|
dwUserNamePos = pos;
|
|
} else if (0 == _stricmp(pCh, EXTLOG_SITE_NAME_ID)) {
|
|
dwSiteNamePos = pos;
|
|
} else if (0 == _stricmp(pCh, EXTLOG_COMPUTER_NAME_ID)) {
|
|
dwComputerNamePos = pos;
|
|
} else if (0 == _stricmp(pCh, EXTLOG_SERVER_IP_ID)) {
|
|
dwServerIPPos = pos;
|
|
} else if (0 == _stricmp(pCh, EXTLOG_METHOD_ID)) {
|
|
dwMethodPos = pos;
|
|
} else if (0 == _stricmp(pCh, EXTLOG_URI_STEM_ID)) {
|
|
dwURIStemPos = pos;
|
|
} else if (0 == _stricmp(pCh, EXTLOG_URI_QUERY_ID)) {
|
|
dwURIQueryPos = pos;
|
|
} else if (0 == _stricmp(pCh, EXTLOG_HTTP_STATUS_ID)) {
|
|
dwHTTPStatusPos = pos;
|
|
} else if (0 == _stricmp(pCh, EXTLOG_WIN32_STATUS_ID)) {
|
|
dwWin32StatusPos = pos;
|
|
} else if (0 == _stricmp(pCh, EXTLOG_BYTES_SENT_ID)) {
|
|
dwBytesSentPos = pos;
|
|
} else if (0 == _stricmp(pCh, EXTLOG_BYTES_RECV_ID)) {
|
|
dwBytesRecvPos = pos;
|
|
} else if (0 == _stricmp(pCh, EXTLOG_TIME_TAKEN_ID)) {
|
|
dwTimeTakenPos = pos;
|
|
} else if (0 == _stricmp(pCh, EXTLOG_SERVER_PORT_ID)) {
|
|
dwServerPortPos = pos;
|
|
} else if (0 == _stricmp(pCh, EXTLOG_PROTOCOL_VERSION_ID)){
|
|
dwVersionPos = pos;
|
|
} else if (0 == _stricmp(pCh, EXTLOG_COOKIE_ID)) {
|
|
dwCookiePos = pos;
|
|
} else if (0 == _stricmp(pCh, EXTLOG_USER_AGENT_ID)) {
|
|
dwUserAgentPos = pos;
|
|
} else if (0 == _stricmp(pCh, EXTLOG_REFERER_ID)) {
|
|
dwRefererPos = pos;
|
|
} else if ( pInetLogLine->iCustomFieldsCount < MAX_CUSTOM_FIELDS) {
|
|
|
|
// Unidentified header. Add to custom header list
|
|
|
|
strcpy(pInetLogLine->CustomFields[pInetLogLine->iCustomFieldsCount++].szHeader, pCh);
|
|
}
|
|
}
|
|
}
|
|
|
|
goto getnewline;
|
|
}
|
|
|
|
//
|
|
// We have a log line. Parse it.
|
|
//
|
|
|
|
szDateString = m_szDate;
|
|
szTimeString = m_szTime;
|
|
|
|
pCh = strtok(pszLogLine," \t\r\n");
|
|
|
|
for (pos = 1, custompos = 0; pCh != NULL; pos++, pCh= strtok(NULL, " \t\r\n"))
|
|
{
|
|
if ( pos == dwDatePos ) {
|
|
szDateString = pCh;
|
|
} else if (pos == dwTimePos) {
|
|
szTimeString = pCh;
|
|
} else if (pos == dwClientIPPos) {
|
|
pInetLogLine->pszClientHostName = pCh;
|
|
} else if (pos == dwUserNamePos) {
|
|
pInetLogLine->pszClientUserName = pCh;
|
|
} else if (pos == dwSiteNamePos) {
|
|
pInetLogLine->pszSiteName = pCh;
|
|
} else if (pos == dwComputerNamePos){
|
|
pInetLogLine->pszComputerName = pCh;
|
|
} else if (pos == dwServerIPPos) {
|
|
pInetLogLine->pszServerAddress = pCh;
|
|
} else if (pos == dwMethodPos) {
|
|
pInetLogLine->pszOperation = pCh;
|
|
} else if (pos == dwURIStemPos) {
|
|
pInetLogLine->pszTarget = pCh;
|
|
} else if (pos == dwURIQueryPos) {
|
|
pInetLogLine->pszParameters = pCh;
|
|
} else if (pos == dwHTTPStatusPos) {
|
|
pInetLogLine->pszProtocolStatus = pCh;
|
|
} else if (pos == dwWin32StatusPos) {
|
|
pInetLogLine->pszWin32Status = pCh;
|
|
} else if (pos == dwBytesSentPos) {
|
|
pInetLogLine->pszBytesSent = pCh;
|
|
} else if (pos == dwBytesRecvPos) {
|
|
pInetLogLine->pszBytesRecvd = pCh;
|
|
} else if (pos == dwTimeTakenPos) {
|
|
pInetLogLine->pszTimeForProcessing= pCh;
|
|
} else if (pos == dwServerPortPos) {
|
|
pInetLogLine->pszPort = pCh;
|
|
} else if (pos == dwVersionPos) {
|
|
pInetLogLine->pszVersion = pCh;
|
|
} else if (pos == dwCookiePos) {
|
|
pInetLogLine->pszCookie = pCh;
|
|
} else if (pos == dwUserAgentPos) {
|
|
pInetLogLine->pszUserAgent = pCh;
|
|
} else if (pos == dwRefererPos) {
|
|
pInetLogLine->pszReferer = pCh;
|
|
} else if ( custompos < (DWORD)pInetLogLine->iCustomFieldsCount) {
|
|
pInetLogLine->CustomFields[custompos++].pchData = pCh;
|
|
}
|
|
}
|
|
|
|
if ( ! ConvertW3CDateToVariantDate(szDateString, szTimeString, &(pInetLogLine->DateTime)) )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
} // CEXTLOG::ReadFileLogRecord
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
HRESULT
|
|
CEXTLOG::WriteFileLogRecord(
|
|
IN FILE *fpLogFile,
|
|
IN ILogScripting *pILogScripting,
|
|
IN bool fWriteHeader
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Function to write a log line to an open log file
|
|
|
|
Arguments:
|
|
|
|
fpLogFile - FILE * to open file
|
|
pILogScripting - ILogScripting interface for getting information to write
|
|
fWriteHeader - Flag to indicate that log header must be written.
|
|
|
|
Return Value:
|
|
|
|
HRESULT indicating whether function Succeeded or Failed.
|
|
|
|
--*/
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
HRESULT hr = E_FAIL;
|
|
CHAR szLogLine[4096];
|
|
long i = 0;
|
|
|
|
VARIANT DateTime;
|
|
VARIANT varCustomFieldsArray;
|
|
|
|
SYSTEMTIME sysTime;
|
|
CHAR rgchDateTime[ 32];
|
|
|
|
const int cFields = 18;
|
|
|
|
//
|
|
// Populate Headers
|
|
//
|
|
|
|
if (!m_fWriteHeadersInitialized)
|
|
{
|
|
LPSTR szFieldNames[cFields] = {
|
|
EXTLOG_CLIENT_IP_ID,
|
|
EXTLOG_USERNAME_ID,
|
|
EXTLOG_SITE_NAME_ID,
|
|
EXTLOG_COMPUTER_NAME_ID,
|
|
EXTLOG_SERVER_IP_ID,
|
|
EXTLOG_METHOD_ID,
|
|
EXTLOG_URI_STEM_ID,
|
|
EXTLOG_URI_QUERY_ID,
|
|
EXTLOG_HTTP_STATUS_ID,
|
|
EXTLOG_WIN32_STATUS_ID,
|
|
EXTLOG_BYTES_SENT_ID,
|
|
EXTLOG_BYTES_RECV_ID,
|
|
EXTLOG_TIME_TAKEN_ID,
|
|
EXTLOG_SERVER_PORT_ID,
|
|
EXTLOG_PROTOCOL_VERSION_ID,
|
|
EXTLOG_USER_AGENT_ID,
|
|
EXTLOG_COOKIE_ID,
|
|
EXTLOG_REFERER_ID
|
|
};
|
|
|
|
m_fWriteHeadersInitialized = TRUE;
|
|
|
|
if ( NULL != (m_pLogFields = new LOG_FIELDS[cFields]))
|
|
{
|
|
for (i =0; i < cFields; i++)
|
|
{
|
|
strcpy(m_pLogFields[i].szW3CHeader, szFieldNames[i]);
|
|
m_pLogFields[i].varData.lVal = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NULL == m_pLogFields)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (SUCCEEDED( pILogScripting->get_ClientIP ( & m_pLogFields[0].varData) ) &&
|
|
SUCCEEDED( pILogScripting->get_UserName ( & m_pLogFields[1].varData) ) &&
|
|
SUCCEEDED( pILogScripting->get_ServiceName ( & m_pLogFields[2].varData) ) &&
|
|
SUCCEEDED( pILogScripting->get_ServerName ( & m_pLogFields[3].varData) ) &&
|
|
SUCCEEDED( pILogScripting->get_ServerIP ( & m_pLogFields[4].varData) ) &&
|
|
SUCCEEDED( pILogScripting->get_Method ( & m_pLogFields[5].varData) ) &&
|
|
SUCCEEDED( pILogScripting->get_URIStem ( & m_pLogFields[6].varData) ) &&
|
|
SUCCEEDED( pILogScripting->get_URIQuery ( & m_pLogFields[7].varData) ) &&
|
|
SUCCEEDED( pILogScripting->get_ProtocolStatus ( & m_pLogFields[8].varData) ) &&
|
|
SUCCEEDED( pILogScripting->get_Win32Status ( & m_pLogFields[9].varData) ) &&
|
|
SUCCEEDED( pILogScripting->get_BytesSent ( & m_pLogFields[10].varData) ) &&
|
|
SUCCEEDED( pILogScripting->get_BytesReceived ( & m_pLogFields[11].varData) ) &&
|
|
SUCCEEDED( pILogScripting->get_TimeTaken ( & m_pLogFields[12].varData) ) &&
|
|
SUCCEEDED( pILogScripting->get_ServerPort ( & m_pLogFields[13].varData) ) &&
|
|
SUCCEEDED( pILogScripting->get_ProtocolVersion( & m_pLogFields[14].varData) ) &&
|
|
SUCCEEDED( pILogScripting->get_UserAgent ( & m_pLogFields[15].varData) ) &&
|
|
SUCCEEDED( pILogScripting->get_Cookie ( & m_pLogFields[16].varData) ) &&
|
|
SUCCEEDED( pILogScripting->get_Referer ( & m_pLogFields[17].varData) ) &&
|
|
|
|
SUCCEEDED( pILogScripting->get_CustomFields ( & varCustomFieldsArray ) ) &&
|
|
SUCCEEDED( pILogScripting->get_DateTime ( & DateTime) ) &&
|
|
VariantTimeToSystemTime ( DateTime.date, &sysTime)
|
|
)
|
|
{
|
|
SAFEARRAY * psaCustom = NULL;
|
|
long cItems = 0;
|
|
BSTR HUGEP *pbstr;
|
|
|
|
//
|
|
// Build Header
|
|
//
|
|
|
|
strcpy(szLogLine, "date time");
|
|
|
|
for ( i = 0; i < cFields; i++)
|
|
{
|
|
if ( VT_NULL != m_pLogFields[i].varData.vt)
|
|
{
|
|
strcat(szLogLine, " ");
|
|
strcat(szLogLine, m_pLogFields[i].szW3CHeader);
|
|
}
|
|
}
|
|
|
|
if ( (VT_BSTR|VT_ARRAY) == varCustomFieldsArray.vt)
|
|
{
|
|
psaCustom = varCustomFieldsArray.parray;
|
|
|
|
if (NULL != psaCustom)
|
|
{
|
|
cItems = psaCustom->rgsabound[1].cElements;
|
|
}
|
|
|
|
if ( SUCCEEDED(SafeArrayAccessData(psaCustom, (void HUGEP* FAR*)&pbstr)) )
|
|
{
|
|
for ( i = 0; i < cItems; i++)
|
|
{
|
|
strcat(szLogLine, " ");
|
|
strcat(szLogLine, W2A(pbstr[i]));
|
|
}
|
|
|
|
SafeArrayUnaccessData(psaCustom);
|
|
}
|
|
}
|
|
|
|
m_DateTimeCache.GetFormattedDateTime( &sysTime, rgchDateTime);
|
|
|
|
if ( fWriteHeader || strcmp( szLogLine, m_szWriteHeader.QueryStr()) )
|
|
{
|
|
// Need to write headers
|
|
|
|
m_szWriteHeader.Copy(szLogLine);
|
|
|
|
wsprintf(szLogLine,
|
|
"#Software: Microsoft Internet Information Services 5.0\n"
|
|
"#Version: %s\n"
|
|
"#Date: %s %s\n"
|
|
"#Fields: %s\n",
|
|
EXTLOG_VERSION,
|
|
rgchDateTime,
|
|
rgchDateTime+strlen(rgchDateTime)+1,
|
|
m_szWriteHeader.QueryStr()
|
|
);
|
|
}
|
|
else
|
|
{
|
|
szLogLine[0] = '\0';
|
|
}
|
|
|
|
//
|
|
// Write the fields to the log line
|
|
//
|
|
|
|
strcat(szLogLine, rgchDateTime);
|
|
strcat(szLogLine, " ");
|
|
strcat(szLogLine, rgchDateTime+strlen(rgchDateTime)+1);
|
|
|
|
for ( i = 0; i < cFields; i++)
|
|
{
|
|
switch (m_pLogFields[i].varData.vt)
|
|
{
|
|
case VT_BSTR:
|
|
strcat(szLogLine, " ");
|
|
strcat( szLogLine, W2A(GetBstrFromVariant( &m_pLogFields[i].varData)) );
|
|
break;
|
|
|
|
case VT_I4:
|
|
strcat(szLogLine, " ");
|
|
GetLongFromVariant( &m_pLogFields[i].varData, szLogLine+strlen(szLogLine));
|
|
break;
|
|
|
|
case VT_EMPTY:
|
|
strcat (szLogLine, " -");
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( (0 < cItems) && SUCCEEDED(SafeArrayAccessData(psaCustom, (void HUGEP* FAR*)&pbstr)) )
|
|
{
|
|
for ( i = 0; i < cItems; i++)
|
|
{
|
|
strcat(szLogLine, " ");
|
|
strcat(szLogLine, W2A(pbstr[cItems + i]));
|
|
}
|
|
|
|
SafeArrayUnaccessData(psaCustom);
|
|
}
|
|
|
|
fprintf(fpLogFile, "%s\n", szLogLine);
|
|
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
BOOL
|
|
CEXTLOG::ConvertW3CDateToVariantDate(
|
|
IN PCHAR szDateString,
|
|
IN PCHAR szTimeString,
|
|
OUT DATE * pDateTime)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Convert a Date & Time string in the W3C Format to DATE type
|
|
|
|
Arguments:
|
|
|
|
szDateString - String representing date in format Year-Month-Day
|
|
szTimeString - String representing time in format HH:MM:SS
|
|
pDateTime - Output DATE
|
|
|
|
Return Value:
|
|
|
|
TRUE - Succeeded
|
|
FALSE - Failed
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
WORD iVal;
|
|
PCHAR pCh;
|
|
|
|
SYSTEMTIME sysTime;
|
|
|
|
//
|
|
// Process the Date. Format is 1998-01-27 ( Year-Month-Day )
|
|
//
|
|
|
|
memset (&sysTime,0,sizeof(sysTime));
|
|
pCh = szDateString;
|
|
|
|
sysTime.wYear = (*pCh-'0')*1000 + ( *(pCh+1)-'0' )*100 +
|
|
( *(pCh+2)-'0')*10 + ( *(pCh+3)-'0');
|
|
|
|
pCh += 5;
|
|
|
|
iVal = *pCh -'0';
|
|
if ( *(pCh+1) != '/')
|
|
{
|
|
iVal = iVal*10 + *(pCh+1) - '0';
|
|
pCh++;
|
|
}
|
|
sysTime.wMonth = iVal;
|
|
|
|
pCh+=2;
|
|
|
|
iVal = *pCh -'0';
|
|
if ( *(pCh+1) != '/')
|
|
{
|
|
iVal = iVal*10 + *(pCh+1) - '0';
|
|
}
|
|
sysTime.wDay = iVal;
|
|
|
|
//
|
|
// Process the Time. Format is 10:47:44 ( HH:MM:SS )
|
|
//
|
|
|
|
pCh = szTimeString;
|
|
|
|
iVal = *pCh -'0';
|
|
if ( *(pCh+1) != ':')
|
|
{
|
|
iVal = iVal*10 + *(pCh+1) - '0';
|
|
pCh++;
|
|
}
|
|
sysTime.wHour = iVal;
|
|
|
|
pCh += 2;
|
|
|
|
iVal = *pCh -'0';
|
|
if ( *(pCh+1) != ':')
|
|
{
|
|
iVal = iVal*10 + *(pCh+1) - '0';
|
|
pCh++;
|
|
}
|
|
sysTime.wMinute = iVal;
|
|
|
|
pCh += 2;
|
|
|
|
iVal = *pCh -'0';
|
|
if ( *(pCh+1) != '\0')
|
|
{
|
|
iVal = iVal*10 + *(pCh+1) - '0';
|
|
}
|
|
sysTime.wSecond = iVal;
|
|
|
|
return SystemTimeToVariantTime(&sysTime, pDateTime);
|
|
}
|
|
|
|
/* ************************************************************************************ */
|
|
/* Support Functions */
|
|
/* ************************************************************************************ */
|
|
|
|
VOID
|
|
CEXTLOG::FormNewLogFileName(
|
|
IN LPSYSTEMTIME pstNow
|
|
)
|
|
/*++
|
|
This function that forms the new log file name based on
|
|
type of periodic logging done.
|
|
|
|
Arguments:
|
|
pstNow pointer to SystemTime which contains the current time.
|
|
fBackup flag indicating if we want to make current file a backup.
|
|
|
|
Returns:
|
|
TRUE on success in forming the name or FALSE if there is any error.
|
|
|
|
--*/
|
|
{
|
|
|
|
I_FormNewLogFileName(pstNow,DEFAULT_EXTENDED_LOG_FILE_NAME);
|
|
|
|
} // INET_FILE_LOG::FormNewLogFileName()
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
LPCSTR
|
|
CEXTLOG::QueryNoPeriodPattern(
|
|
VOID
|
|
)
|
|
{
|
|
return szExtNoPeriodPattern;
|
|
} // CEXTLOG::QueryNoPeriodPattern
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
VOID
|
|
CEXTLOG::InternalGetConfig(
|
|
PINETLOG_CONFIGURATIONA pLogConfig
|
|
)
|
|
{
|
|
CLogFileCtrl::InternalGetConfig( pLogConfig );
|
|
pLogConfig->u.logFile.dwFieldMask = m_lMask;
|
|
}
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
VOID
|
|
CEXTLOG::InternalGetExtraLoggingFields(
|
|
PDWORD pcbSize,
|
|
PCHAR pszFieldsList
|
|
)
|
|
{
|
|
TCHAR *pszTmp = pszFieldsList;
|
|
DWORD dwSize = 0;
|
|
DWORD dwFieldSize;
|
|
|
|
if (m_lMask & EXTLOG_HOST ) {
|
|
lstrcpy( pszTmp, "Host:");
|
|
dwFieldSize = (DWORD)strlen(pszTmp)+1;
|
|
pszTmp += dwFieldSize;
|
|
dwSize += dwFieldSize;
|
|
}
|
|
|
|
if (m_lMask & EXTLOG_USER_AGENT ) {
|
|
lstrcpy( pszTmp, "User-Agent:");
|
|
dwFieldSize = (DWORD)strlen(pszTmp)+1;
|
|
pszTmp += dwFieldSize;
|
|
dwSize += dwFieldSize;
|
|
}
|
|
|
|
if (m_lMask & EXTLOG_COOKIE ) {
|
|
lstrcpy( pszTmp, "Cookie:");
|
|
dwFieldSize = (DWORD)strlen(pszTmp)+1;
|
|
pszTmp += dwFieldSize;
|
|
dwSize += dwFieldSize;
|
|
}
|
|
|
|
if (m_lMask & EXTLOG_REFERER ) {
|
|
lstrcpy( pszTmp, "Referer:");
|
|
dwFieldSize = (DWORD)strlen(pszTmp)+1;
|
|
pszTmp += dwFieldSize;
|
|
dwSize += dwFieldSize;
|
|
}
|
|
pszTmp[0]='\0';
|
|
dwSize++;
|
|
*pcbSize = dwSize;
|
|
return;
|
|
|
|
} // CEXTLOG::InternalGetExtraLoggingFields
|
|
|
|
/* ************************************************************************************ */
|
|
|
|
|
|
|