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.
698 lines
16 KiB
698 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 1995-1996 Microsoft Corporation
|
|
|
|
Module Name :
|
|
nsclogp.cpp
|
|
|
|
Abstract:
|
|
NCSA Logging Format implementation
|
|
|
|
Author:
|
|
|
|
Terence Kwan ( terryk ) 18-Sep-1996
|
|
|
|
Project:
|
|
|
|
IIS Logging 3.0
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.hxx"
|
|
#include <stdio.h>
|
|
#include <script.h>
|
|
#include "LogScript.hxx"
|
|
#include <ilogobj.hxx>
|
|
#include "filectl.hxx"
|
|
#include "ncslogc.hxx"
|
|
|
|
CHAR szNCSANoPeriodPattern[] = "ncsa*.log";
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------------
|
|
|
|
CNCSALOG::CNCSALOG()
|
|
{
|
|
//
|
|
// set the time zone offset
|
|
//
|
|
|
|
{
|
|
TIME_ZONE_INFORMATION tzTimeZone;
|
|
DWORD dwError;
|
|
DWORD minutes;
|
|
DWORD hours;
|
|
LONG bias;
|
|
CHAR szTmp[MAX_PATH];
|
|
|
|
dwError = GetTimeZoneInformation(&tzTimeZone);
|
|
|
|
if ( dwError == 0xffffffff ) {
|
|
|
|
bias = 0;
|
|
} else {
|
|
|
|
bias = tzTimeZone.Bias;
|
|
}
|
|
|
|
if ( bias > 0 )
|
|
{
|
|
lstrcpyA(m_szGMTOffset,"-");
|
|
m_GMTDateCorrection = -1;
|
|
|
|
}
|
|
else
|
|
{
|
|
lstrcpyA(m_szGMTOffset,"+");
|
|
m_GMTDateCorrection = 1;
|
|
bias *= -1;
|
|
}
|
|
|
|
hours = bias/60;
|
|
minutes = bias % 60;
|
|
|
|
//
|
|
// set up the "+0800" or "-0800" NCSA information
|
|
//
|
|
|
|
wsprintfA(szTmp,"%02lu",hours);
|
|
lstrcatA(m_szGMTOffset,szTmp);
|
|
|
|
wsprintfA(szTmp,"%02lu",minutes);
|
|
lstrcatA(m_szGMTOffset,szTmp);
|
|
|
|
m_GMTDateCorrection = m_GMTDateCorrection * ( hours/24.0 + minutes/60.0 );
|
|
|
|
}
|
|
} // CNCSALOG::CNCSALOG()
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------------
|
|
|
|
CNCSALOG::~CNCSALOG()
|
|
{
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------------
|
|
|
|
LPCSTR
|
|
CNCSALOG::QueryNoPeriodPattern(
|
|
VOID
|
|
)
|
|
{
|
|
return szNCSANoPeriodPattern;
|
|
} // CNCSALOG::QueryNoPeriodPattern
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CNCSALOG::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.
|
|
|
|
Returns:
|
|
TRUE on success in forming the name or FALSE if there is any error.
|
|
|
|
--*/
|
|
{
|
|
|
|
I_FormNewLogFileName(pstNow,DEFAULT_NCSA_LOG_FILE_NAME);
|
|
return;
|
|
|
|
} // INET_FILE_LOG::FormNewLogFileName()
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CNCSALOG::FormatLogBuffer(
|
|
IN IInetLogInformation *pLogObj,
|
|
IN LPSTR pBuf,
|
|
IN DWORD *pcbSize,
|
|
OUT SYSTEMTIME *pLocalTime
|
|
)
|
|
{
|
|
CHAR rgchDateTime[32];
|
|
PCHAR pBuffer = pBuf;
|
|
DWORD nRequired = 0;
|
|
|
|
PCHAR pTmp;
|
|
DWORD cbTmp;
|
|
BOOL fUseBytesSent = TRUE;
|
|
|
|
if ( pBuf == NULL ) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// We use local time
|
|
//
|
|
|
|
GetLocalTime(pLocalTime);
|
|
|
|
INT cchDateTime = wsprintf( rgchDateTime,
|
|
_T(" [%02d/%s/%d:%02d:%02d:%02d %s] "),
|
|
pLocalTime->wDay,
|
|
Month3CharNames(pLocalTime->wMonth-1),
|
|
pLocalTime->wYear,
|
|
pLocalTime->wHour,
|
|
pLocalTime->wMinute,
|
|
pLocalTime->wSecond,
|
|
m_szGMTOffset
|
|
);
|
|
|
|
//
|
|
// Format is:
|
|
// Host - UserName [date] Operation Target status bytes
|
|
//
|
|
|
|
//
|
|
// HostName
|
|
//
|
|
|
|
pTmp = pLogObj->GetClientHostName( NULL, &cbTmp );
|
|
if ( cbTmp == 0 ) {
|
|
cbTmp = 1;
|
|
pTmp = "-";
|
|
}
|
|
|
|
nRequired += cbTmp;
|
|
if ( nRequired <= *pcbSize ) {
|
|
CopyMemory(pBuffer, pTmp, cbTmp);
|
|
pBuffer += cbTmp;
|
|
}
|
|
|
|
//
|
|
// Append " - "
|
|
//
|
|
|
|
cbTmp = 3;
|
|
pTmp = " - ";
|
|
|
|
nRequired += cbTmp;
|
|
if ( nRequired <= *pcbSize ) {
|
|
CopyMemory(pBuffer, pTmp, cbTmp);
|
|
pBuffer += cbTmp;
|
|
}
|
|
|
|
//
|
|
// append user name
|
|
//
|
|
|
|
pTmp = pLogObj->GetClientUserName( NULL, &cbTmp );
|
|
if ( cbTmp == 0 ) {
|
|
cbTmp = 1;
|
|
pTmp = "-";
|
|
}
|
|
|
|
nRequired += cbTmp;
|
|
if ( nRequired <= *pcbSize ) {
|
|
CopyMemory(pBuffer, pTmp, cbTmp);
|
|
pBuffer += cbTmp;
|
|
}
|
|
|
|
//
|
|
// append date time
|
|
//
|
|
|
|
pTmp = rgchDateTime;
|
|
cbTmp = cchDateTime;
|
|
|
|
nRequired += cbTmp;
|
|
if ( nRequired <= *pcbSize ) {
|
|
CopyMemory(pBuffer, pTmp, cbTmp);
|
|
pBuffer += cbTmp;
|
|
}
|
|
|
|
//
|
|
// Operation
|
|
//
|
|
|
|
pTmp = pLogObj->GetOperation( NULL, &cbTmp );
|
|
if ( cbTmp == 0 ) {
|
|
cbTmp = 1;
|
|
pTmp = "-";
|
|
} else {
|
|
if ( (_stricmp(pTmp,"PUT") == 0) ||
|
|
(_stricmp(pTmp,"POST") == 0) ) {
|
|
fUseBytesSent = FALSE;
|
|
}
|
|
}
|
|
|
|
nRequired += (cbTmp + 1 + 1); // +1 for delimeter, +1 for \"
|
|
if ( nRequired <= *pcbSize ) {
|
|
|
|
*(pBuffer++) = '\"';
|
|
CopyMemory(pBuffer, pTmp, cbTmp);
|
|
pBuffer += cbTmp;
|
|
|
|
//
|
|
// Add space delimiter
|
|
//
|
|
|
|
*(pBuffer++) = ' ';
|
|
}
|
|
|
|
//
|
|
// Target
|
|
//
|
|
|
|
pTmp = pLogObj->GetTarget( NULL, &cbTmp );
|
|
if ( cbTmp == 0 ) {
|
|
cbTmp = 1;
|
|
pTmp = "-";
|
|
}
|
|
|
|
nRequired += cbTmp;
|
|
if ( nRequired <= *pcbSize ) {
|
|
CopyMemory(pBuffer, pTmp, cbTmp);
|
|
pBuffer += cbTmp;
|
|
}
|
|
|
|
//
|
|
// Parameters
|
|
//
|
|
|
|
pTmp = pLogObj->GetParameters( NULL, &cbTmp );
|
|
|
|
if ( cbTmp != 0 ) {
|
|
|
|
nRequired += cbTmp + 1; // 1 for ?
|
|
if ( nRequired <= *pcbSize ) {
|
|
*(pBuffer++) = '?';
|
|
CopyMemory(pBuffer, pTmp, cbTmp);
|
|
pBuffer += cbTmp;
|
|
}
|
|
}
|
|
|
|
//
|
|
// close request block version + status + bytes
|
|
//
|
|
|
|
{
|
|
CHAR tmpBuf[MAX_PATH];
|
|
DWORD bytes;
|
|
|
|
PCHAR pVersion = pLogObj->GetVersionString(NULL, &cbTmp);
|
|
|
|
if (cbTmp ==0) {
|
|
pVersion = "HTTP/1.0";
|
|
cbTmp = 8;
|
|
}
|
|
|
|
nRequired += cbTmp + 1 + 1 + 1; // 1 for beginning delimiter, 1 for ", 1 for ending delimiter
|
|
|
|
if ( nRequired <= *pcbSize ) {
|
|
*(pBuffer++) = ' ';
|
|
CopyMemory(pBuffer, pVersion, cbTmp);
|
|
pBuffer += cbTmp;
|
|
*(pBuffer++) = '"';
|
|
*(pBuffer++) = ' ';
|
|
}
|
|
|
|
cbTmp = FastDwToA(tmpBuf, pLogObj->GetProtocolStatus());
|
|
*(tmpBuf+cbTmp) = ' ';
|
|
cbTmp++;
|
|
|
|
bytes = fUseBytesSent ? pLogObj->GetBytesSent( ) :
|
|
pLogObj->GetBytesRecvd( );
|
|
cbTmp += FastDwToA( tmpBuf+cbTmp, bytes);
|
|
|
|
*(tmpBuf+cbTmp) = '\r';
|
|
*(tmpBuf+cbTmp+1) = '\n';
|
|
cbTmp += 2;
|
|
|
|
nRequired += cbTmp;
|
|
if ( nRequired <= *pcbSize ) {
|
|
CopyMemory(pBuffer, tmpBuf, cbTmp);
|
|
pBuffer += cbTmp;
|
|
}
|
|
}
|
|
|
|
if ( nRequired > *pcbSize ) {
|
|
*pcbSize = nRequired;
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return(FALSE);
|
|
} else {
|
|
*pcbSize = nRequired;
|
|
return(TRUE);
|
|
}
|
|
} // CNCSALOG::FormatLogBuffer
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CNCSALOG::ReadFileLogRecord(
|
|
IN FILE *fpLogFile,
|
|
IN LPINET_LOGLINE pInetLogLine,
|
|
IN PCHAR pszLogLine,
|
|
IN DWORD dwLogLineSize
|
|
)
|
|
{
|
|
CHAR * pszTimeZone;
|
|
CHAR * pCh;
|
|
|
|
CHAR * szDateString, * szTimeString;
|
|
double GMTCorrection;
|
|
int iSign = 1;
|
|
|
|
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;
|
|
}
|
|
|
|
//
|
|
// We have a log line.
|
|
//
|
|
// Format is:
|
|
// Host - UserName [date] Operation Target status bytes
|
|
//
|
|
|
|
if ( NULL == (pCh = strtok(pCh," \t\r\n")) )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
pInetLogLine->pszClientHostName = pCh;
|
|
|
|
//
|
|
// This field is always "-"
|
|
//
|
|
if ( ( NULL == (pCh = strtok(NULL," \t\r\n")) )||
|
|
('-' != *pCh) )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
if ( NULL == (pCh = strtok(NULL," \t\r\n")) )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
pInetLogLine->pszClientUserName = pCh;
|
|
|
|
//
|
|
// This is the date field. It starts with a [, followed by date:time timezone]
|
|
//
|
|
|
|
pCh += strlen(pCh)+1;
|
|
if (*pCh != '[')
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
pCh++;
|
|
|
|
|
|
if ( NULL == (pCh = strtok(pCh,":")) )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
szDateString = pCh;
|
|
|
|
|
|
if ( NULL == (pCh = strtok(NULL," \t\r\n")) )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
szTimeString = pCh;
|
|
|
|
pCh = strtok(NULL," \t\r\n");
|
|
if ( (NULL == pCh) || ( ']' != *(pCh+strlen(pCh)-1)) || (strlen(pCh) < 4))
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
pszTimeZone = pCh;
|
|
|
|
//
|
|
// Time Zone is in format [+/-]HHMM. Convert this to GMT and DATE format
|
|
//
|
|
|
|
if ( ! ConvertNCSADateToVariantDate(szDateString, szTimeString, &(pInetLogLine->DateTime)) )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (*pCh == '-')
|
|
{
|
|
iSign = -1;
|
|
pszTimeZone = pCh+1;
|
|
}
|
|
else if (*pCh == '+')
|
|
{
|
|
iSign = 1;
|
|
pszTimeZone = pCh+1;
|
|
}
|
|
|
|
GMTCorrection = (pszTimeZone[0]-'0' +pszTimeZone[1]-'0')/24.0 +
|
|
(pszTimeZone[2]-'0' +pszTimeZone[3]-'0')/60.0;
|
|
|
|
pInetLogLine->DateTime -= iSign*GMTCorrection;
|
|
|
|
//
|
|
// The Query String. Starts with " followed by method target version"
|
|
//
|
|
|
|
pCh += strlen(pCh)+1;
|
|
*(pCh-2)='\0'; // Zero out the ] for the time zone
|
|
if ('"' != *pCh)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
pCh++;
|
|
|
|
|
|
if ( NULL == (pCh = strtok(pCh," \t\r\n")) )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
pInetLogLine->pszOperation = pCh;
|
|
|
|
if ( NULL == (pCh = strtok(NULL," \t\r\n")) )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
pInetLogLine->pszTarget = pCh;
|
|
|
|
//
|
|
// In the Target, Parameters are separated by ?
|
|
//
|
|
pInetLogLine->pszParameters = strchr(pCh, '?');
|
|
|
|
if (pInetLogLine->pszParameters != NULL)
|
|
{
|
|
*(pInetLogLine->pszParameters)='\0';
|
|
(pInetLogLine->pszParameters)++;
|
|
}
|
|
|
|
pCh = strtok(NULL," \t\r\n");
|
|
if ( (NULL == pCh) || ('"' != *(pCh+strlen(pCh)-1)) )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
pInetLogLine->pszVersion = pCh;
|
|
|
|
//
|
|
// Now the status code & bytes sent
|
|
//
|
|
|
|
pCh += strlen(pCh)+1;
|
|
*(pCh-2)='\0'; // Zero out the " for the version string
|
|
|
|
if ( NULL == (pCh = strtok(pCh," \t\r\n")) )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
pInetLogLine->pszProtocolStatus = pCh;
|
|
|
|
if ( NULL == (pCh = strtok(NULL," \t\r\n")) )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
pInetLogLine->pszBytesSent = pCh;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CNCSALOG::WriteFileLogRecord(
|
|
IN FILE *fpLogFile,
|
|
IN ILogScripting *pILogScripting,
|
|
IN bool
|
|
)
|
|
{
|
|
|
|
HRESULT hr = E_FAIL;
|
|
CHAR szLogLine[4096];
|
|
DWORD dwIndex = 0;
|
|
|
|
//
|
|
// Format is:
|
|
// Host - UserName [date] Operation Target status bytes
|
|
//
|
|
|
|
VARIANT szHostName, szUserName, szOperation, szTarget, szParameters, szProtocolVersion;
|
|
VARIANT DateTime;
|
|
VARIANT lBytesSent, lProtocolStatus;
|
|
|
|
SYSTEMTIME localTime;
|
|
|
|
if (SUCCEEDED(pILogScripting->get_ClientIP ( &szHostName)) &&
|
|
SUCCEEDED(pILogScripting->get_UserName ( &szUserName)) &&
|
|
SUCCEEDED(pILogScripting->get_DateTime ( &DateTime)) &&
|
|
SUCCEEDED(pILogScripting->get_Method ( &szOperation)) &&
|
|
SUCCEEDED(pILogScripting->get_URIStem ( &szTarget)) &&
|
|
SUCCEEDED(pILogScripting->get_URIQuery ( &szParameters)) &&
|
|
SUCCEEDED(pILogScripting->get_BytesSent ( &lBytesSent)) &&
|
|
SUCCEEDED(pILogScripting->get_ProtocolStatus( &lProtocolStatus))&&
|
|
SUCCEEDED(pILogScripting->get_ProtocolVersion( &szProtocolVersion))&&
|
|
VariantTimeToSystemTime( DateTime.date+m_GMTDateCorrection, &localTime)
|
|
)
|
|
{
|
|
|
|
|
|
sprintf(szLogLine, "%ws - %ws [%02d/%s/%d:%02d:%02d:%02d %s] \"%ws %ws",
|
|
GetBstrFromVariant( &szHostName),
|
|
GetBstrFromVariant( &szUserName),
|
|
localTime.wDay,
|
|
Month3CharNames(localTime.wMonth-1),
|
|
localTime.wYear,
|
|
localTime.wHour,
|
|
localTime.wMinute,
|
|
localTime.wSecond,
|
|
m_szGMTOffset,
|
|
GetBstrFromVariant( &szOperation),
|
|
GetBstrFromVariant( &szTarget)
|
|
);
|
|
|
|
if ( ( VT_NULL != szParameters.vt) &&
|
|
( VT_EMPTY != szParameters.vt )
|
|
)
|
|
{
|
|
sprintf(szLogLine+strlen(szLogLine), "?%ws", GetBstrFromVariant( &szParameters));
|
|
}
|
|
|
|
sprintf(szLogLine+strlen(szLogLine), " %ws\"", GetBstrFromVariant( &szProtocolVersion));
|
|
|
|
dwIndex = (DWORD)strlen(szLogLine);
|
|
|
|
szLogLine[dwIndex++] = ' ';
|
|
dwIndex += GetLongFromVariant( &lProtocolStatus, szLogLine+dwIndex );
|
|
|
|
szLogLine[dwIndex++] = ' ';
|
|
dwIndex += GetLongFromVariant( &lBytesSent, szLogLine+dwIndex );
|
|
szLogLine[dwIndex++] = '\0';
|
|
|
|
fprintf(fpLogFile, "%s\n", szLogLine);
|
|
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CNCSALOG::ConvertNCSADateToVariantDate(PCHAR szDateString, PCHAR szTimeString, DATE * pDateTime)
|
|
{
|
|
|
|
PCHAR pCh;
|
|
WORD iVal;
|
|
CHAR *szMonths[12] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
|
|
|
|
SYSTEMTIME sysTime;
|
|
|
|
//
|
|
// Process the Date. Format is 23/Sep/1997 ( Day/Month/Year )
|
|
//
|
|
|
|
pCh = szDateString;
|
|
|
|
iVal = *pCh -'0';
|
|
if ( *(pCh+1) != '/')
|
|
{
|
|
iVal = iVal*10 + *(pCh+1) - '0';
|
|
pCh++;
|
|
}
|
|
sysTime.wDay = iVal;
|
|
|
|
pCh += 2;
|
|
|
|
for (WORD i=0; i<12;i++)
|
|
{
|
|
if ( 0 == strncmp(pCh,szMonths[i],3) )
|
|
{
|
|
sysTime.wMonth = i+1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pCh += 4;
|
|
|
|
sysTime.wYear = (*pCh-'0')*1000 + ( *(pCh+1)-'0' )*100 +
|
|
( *(pCh+2)-'0')*10 + ( *(pCh+3)-'0');
|
|
|
|
//
|
|
// 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);
|
|
}
|
|
|
|
|