/*++ 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 #include #include "LogScript.hxx" #include #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); }