Leaked source code of windows server 2003
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

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name :
  4. ExtLogC.cpp
  5. Abstract:
  6. W3C Extended LogFile Format Implementation
  7. Author:
  8. Terence Kwan ( terryk ) 18-Sep-1996
  9. Project:
  10. IIS Logging 3.0
  11. --*/
  12. #include "precomp.hxx"
  13. #include <stdio.h>
  14. #include "ilogobj.hxx"
  15. #include "script.h"
  16. #include "LogScript.hxx"
  17. #include "filectl.hxx"
  18. #include "lkrhash.h"
  19. #include "iisver.h"
  20. #include "iis64.h"
  21. #include "extlogc.hxx"
  22. const CHAR szExtNoPeriodPattern[] = "extend*.log";
  23. const CHAR G_PSZ_DELIMITER[2] = { ' ', '\0'};
  24. CHAR szDotDot[] = "...";
  25. CHAR szDash [] = "-";
  26. CHAR szHTTPOk[] = "200\r\n";
  27. CCustomPropHashTable *g_pGlobalLoggingProperties=NULL;
  28. /* ************************************************************************************ */
  29. /* Helper functions */
  30. /* ************************************************************************************ */
  31. inline VOID
  32. BuildHeader(
  33. IN OUT STR * strHeader,
  34. IN DWORD dwMask,
  35. IN DWORD dwField,
  36. IN LPCSTR szFieldHeader
  37. )
  38. {
  39. if (dwMask & dwField)
  40. {
  41. strHeader->Append(szFieldHeader);
  42. strHeader->Append(' ');
  43. }
  44. }
  45. /* ************************************************************************************ */
  46. inline BOOL
  47. CopyFieldToBuffer(
  48. IN PCHAR Field,
  49. IN DWORD FieldSize,
  50. IN PCHAR * ppchOutBuffer,
  51. IN OUT PDWORD SpaceNeeded,
  52. IN DWORD SpaceProvided
  53. )
  54. {
  55. if ( 0 == FieldSize )
  56. {
  57. Field = "-";
  58. FieldSize = 1;
  59. }
  60. //
  61. // Remove the NULL terminator
  62. //
  63. (*SpaceNeeded) += FieldSize + 1; // +1 for trailing space
  64. if ( (*SpaceNeeded) <= SpaceProvided )
  65. {
  66. CopyMemory( (*ppchOutBuffer), Field, FieldSize );
  67. (*ppchOutBuffer) += FieldSize;
  68. (**ppchOutBuffer) = ' ';
  69. (*ppchOutBuffer)++;
  70. return(TRUE);
  71. }
  72. return FALSE;
  73. } // CopyFieldToBuffer
  74. /* ************************************************************************************ */
  75. inline BOOL WriteHTTPHeader(
  76. IN OUT PCHAR * ppchHeader,
  77. IN PCHAR * ppchOutBuffer,
  78. IN OUT PDWORD SpaceNeeded,
  79. IN DWORD SpaceProvided
  80. )
  81. {
  82. DWORD cbTmp = 0;
  83. if ( (NULL != ppchHeader ) && ( NULL != *ppchHeader))
  84. {
  85. CHAR * pTmp = *ppchHeader;
  86. cbTmp = (DWORD)strlen(pTmp);
  87. *ppchHeader = pTmp + cbTmp + 1;
  88. if ((cbTmp > MAX_LOG_TARGET_FIELD_LEN ) ||
  89. (((*SpaceNeeded)+cbTmp) > MAX_LOG_RECORD_LEN)
  90. )
  91. {
  92. pTmp = szDotDot;
  93. cbTmp = 3;
  94. }
  95. else
  96. {
  97. ConvertSpacesToPlus(pTmp);
  98. }
  99. return CopyFieldToBuffer( pTmp, cbTmp, ppchOutBuffer, SpaceNeeded, SpaceProvided);
  100. }
  101. return FALSE;
  102. }
  103. /* ************************************************************************************ */
  104. /* CCustomPropHashTable Class */
  105. /* ************************************************************************************ */
  106. VOID
  107. CCustomPropHashTable::ClearTableAndStorage()
  108. {
  109. //
  110. // Clear the Hash Table & free any previous LOG_PROPERTY_INFO entries
  111. //
  112. Clear();
  113. if (NULL != m_pLogPropArray)
  114. {
  115. delete [] m_pLogPropArray;
  116. m_pLogPropArray = NULL;
  117. }
  118. m_cLogPropItems = 0;
  119. }
  120. BOOL CCustomPropHashTable::InitializeFromMB (MB &mb,const char *path)
  121. {
  122. BOOL retVal = TRUE;
  123. if (!m_fInitialized)
  124. {
  125. if (mb.Open(path))
  126. {
  127. retVal = m_fInitialized = FillHashTable(mb);
  128. mb.Close();
  129. }
  130. else
  131. {
  132. retVal = FALSE;
  133. }
  134. }
  135. return retVal;
  136. }
  137. BOOL
  138. CCustomPropHashTable::PopulateHash(MB& mb, LPCSTR szPath, DWORD& cItems, bool fCountOnly)
  139. {
  140. BOOL retVal = TRUE;
  141. //
  142. // Retrieve all required fields for all Custom Properties and store in the hash table.
  143. //
  144. int index = 0;
  145. CHAR szChildName[256];
  146. CHAR szW3CHeader[256] = "";
  147. STR strNewPath;
  148. while( mb.EnumObjects(szPath, szChildName, index) )
  149. {
  150. DWORD size;
  151. DWORD dwPropertyID, dwPropertyMask, dwPropertyDataType;
  152. LPCSTR szNewPath;
  153. //
  154. // Create the new path.
  155. //
  156. if ((NULL != szPath) && ( '\0' != *szPath))
  157. {
  158. if ( !(strNewPath.Copy(szPath) &&
  159. strNewPath.Append("/") &&
  160. strNewPath.Append(szChildName)) )
  161. {
  162. retVal = FALSE;
  163. break;
  164. }
  165. }
  166. else
  167. {
  168. if ( !strNewPath.Copy(szChildName) )
  169. {
  170. retVal = FALSE;
  171. break;
  172. }
  173. }
  174. szNewPath = strNewPath.QueryStr();
  175. //
  176. // Copy configuration information into internal structures
  177. //
  178. szW3CHeader[0] = 0;
  179. size = 256;
  180. if ( mb.GetString( szNewPath, MD_LOGCUSTOM_PROPERTY_HEADER, IIS_MD_UT_SERVER,
  181. szW3CHeader, &size) &&
  182. mb.GetDword( szNewPath, MD_LOGCUSTOM_PROPERTY_ID, IIS_MD_UT_SERVER,
  183. &dwPropertyID) &&
  184. mb.GetDword( szNewPath, MD_LOGCUSTOM_PROPERTY_MASK, IIS_MD_UT_SERVER,
  185. &dwPropertyMask) &&
  186. mb.GetDword( szNewPath, MD_LOGCUSTOM_PROPERTY_DATATYPE, IIS_MD_UT_SERVER,
  187. &dwPropertyDataType)
  188. )
  189. {
  190. if (! fCountOnly)
  191. {
  192. PLOG_PROPERTY_INFO pRec = &m_pLogPropArray[cItems];
  193. if ( ! (pRec->strKeyPath.Copy(szNewPath) &&
  194. pRec->strW3CHeader.Copy(szW3CHeader)) )
  195. {
  196. retVal = FALSE;
  197. break;
  198. }
  199. pRec->dwPropertyID = dwPropertyID;
  200. pRec->dwPropertyMask = dwPropertyMask;
  201. pRec->dwPropertyDataType = dwPropertyDataType;
  202. if (LK_SUCCESS != InsertRecord(pRec))
  203. {
  204. DBGPRINTF((DBG_CONTEXT, "PopulateHash: Unable to insert Property %s\n", pRec->strKeyPath.QueryStr()));
  205. retVal = FALSE;
  206. break;
  207. }
  208. }
  209. cItems++;
  210. }
  211. //
  212. // Enumerate children
  213. //
  214. if (!PopulateHash(mb, szNewPath, cItems, fCountOnly))
  215. {
  216. retVal = FALSE;
  217. break;
  218. }
  219. index++;
  220. }
  221. return retVal;
  222. }
  223. /* ************************************************************************************ */
  224. BOOL
  225. CCustomPropHashTable::FillHashTable(MB& mb)
  226. {
  227. BOOL retVal = FALSE;
  228. DWORD cItems = 0;
  229. //
  230. // Find out the number of items in the Custom Logging Tree
  231. //
  232. if (PopulateHash(mb, NULL, cItems, true))
  233. {
  234. ClearTableAndStorage ();
  235. if (cItems)
  236. {
  237. m_pLogPropArray = new LOG_PROPERTY_INFO[cItems];
  238. if ( NULL != m_pLogPropArray)
  239. {
  240. m_cLogPropItems = cItems;
  241. cItems = 0;
  242. retVal = PopulateHash(mb, NULL, cItems, false);
  243. if ( !retVal )
  244. {
  245. ClearTableAndStorage ();
  246. }
  247. DBG_ASSERT(m_cLogPropItems == cItems);
  248. }
  249. }
  250. }
  251. return retVal;
  252. }
  253. /* ************************************************************************************ */
  254. VOID
  255. CCustomPropHashTable::SetPopulationState(MB& mb)
  256. {
  257. CIterator iter;
  258. DWORD dwValue;
  259. LK_RETCODE lkrc = InitializeIterator(&iter);
  260. while (LK_SUCCESS == lkrc)
  261. {
  262. Record* pRec = iter.Record();
  263. if ( mb.GetDword("", pRec->dwPropertyID, IIS_MD_UT_SERVER, &dwValue) &&
  264. (dwValue & pRec->dwPropertyMask))
  265. {
  266. pRec->fEnabled = TRUE;
  267. }
  268. else
  269. {
  270. pRec->fEnabled = FALSE;
  271. }
  272. lkrc = IncrementIterator(&iter);
  273. }
  274. CloseIterator(&iter);
  275. }
  276. BOOL
  277. CCustomPropHashTable::InitFrom(CCustomPropHashTable& src)
  278. {
  279. CIterator iter;
  280. DWORD i;
  281. BOOL retVal = FALSE;
  282. ClearTableAndStorage ();
  283. if (src.m_cLogPropItems)
  284. {
  285. m_pLogPropArray = new LOG_PROPERTY_INFO[src.m_cLogPropItems];
  286. if ( NULL != m_pLogPropArray)
  287. {
  288. m_cLogPropItems = src.m_cLogPropItems;
  289. retVal = TRUE;
  290. for (i=0; i<m_cLogPropItems;i++)
  291. {
  292. PLOG_PROPERTY_INFO pRec = &m_pLogPropArray[i];
  293. PLOG_PROPERTY_INFO pRecOriginal = &src.m_pLogPropArray[i];
  294. if ( pRec->strKeyPath.Copy(pRecOriginal->strKeyPath) &&
  295. pRec->strW3CHeader.Copy(pRecOriginal->strW3CHeader) )
  296. {
  297. pRec->dwPropertyID = pRecOriginal->dwPropertyID;
  298. pRec->dwPropertyMask = pRecOriginal->dwPropertyMask;
  299. pRec->dwPropertyDataType = pRecOriginal->dwPropertyDataType;
  300. if (LK_SUCCESS != InsertRecord(pRec))
  301. {
  302. DBGPRINTF((DBG_CONTEXT, "InitFrom: Unable to insert Property %s\n", pRec->strKeyPath.QueryStr()));
  303. retVal = FALSE;
  304. break;
  305. }
  306. }
  307. else
  308. {
  309. retVal = FALSE;
  310. break;
  311. }
  312. }
  313. }
  314. }
  315. return retVal;
  316. }
  317. /* ************************************************************************************ */
  318. /* CEXTLOG Class */
  319. /* ************************************************************************************ */
  320. CEXTLOG::CEXTLOG() :
  321. m_lMask (DEFAULT_EXTLOG_FIELDS),
  322. m_fHashTablePopulated ( FALSE),
  323. m_fWriteHeadersInitialized ( FALSE),
  324. m_cPrevCustLogItems ( 0),
  325. m_pLogFields ( NULL ),
  326. m_fUseLocalTimeForRollover ( 0),
  327. m_pLocalTimeCache ( NULL)
  328. {
  329. if ( !g_pGlobalLoggingProperties)
  330. {
  331. g_pGlobalLoggingProperties = new CCustomPropHashTable;
  332. }
  333. else
  334. {
  335. g_pGlobalLoggingProperties->AddRef();
  336. }
  337. }
  338. /* ************************************************************************************ */
  339. CEXTLOG::~CEXTLOG()
  340. {
  341. m_HashTable.ClearTableAndStorage ();
  342. if ( NULL != m_pLocalTimeCache)
  343. {
  344. delete m_pLocalTimeCache;
  345. m_pLocalTimeCache = NULL;
  346. }
  347. if (NULL != m_pLogFields)
  348. {
  349. delete [] m_pLogFields;
  350. m_pLogFields = NULL;
  351. }
  352. if ( g_pGlobalLoggingProperties)
  353. {
  354. if ( g_pGlobalLoggingProperties->Release () == 0)
  355. {
  356. delete g_pGlobalLoggingProperties;
  357. g_pGlobalLoggingProperties = NULL;
  358. }
  359. }
  360. }
  361. /* ************************************************************************************ */
  362. STDMETHODIMP
  363. CEXTLOG::InitializeLog(
  364. LPCSTR szInstanceName,
  365. LPCSTR pszMetabasePath,
  366. CHAR* pvIMDCOM
  367. )
  368. {
  369. HRESULT retVal = RETURNCODETOHRESULT ( MD_ERROR_DATA_NOT_FOUND );
  370. MB mb( (IMDCOM*) pvIMDCOM );
  371. if ( g_pGlobalLoggingProperties )
  372. {
  373. m_fHashTablePopulated = g_pGlobalLoggingProperties->InitializeFromMB(mb,"/LM/Logging/Custom Logging");
  374. if ( m_fHashTablePopulated )
  375. {
  376. if (m_HashTable.InitFrom (*g_pGlobalLoggingProperties))
  377. {
  378. if ( mb.Open(pszMetabasePath))
  379. {
  380. m_HashTable.SetPopulationState(mb);
  381. if ( mb.Close())
  382. {
  383. retVal = CLogFileCtrl::InitializeLog(szInstanceName, pszMetabasePath, pvIMDCOM);
  384. }
  385. }
  386. else
  387. {
  388. retVal = HRESULTTOWIN32( GetLastError());
  389. }
  390. }
  391. else
  392. {
  393. retVal = RETURNCODETOHRESULT ( ERROR_OUTOFMEMORY );
  394. }
  395. }
  396. }
  397. else
  398. {
  399. DBG_ASSERT (FALSE);
  400. retVal = RETURNCODETOHRESULT ( ERROR_OUTOFMEMORY );
  401. }
  402. return retVal;
  403. }
  404. /* ************************************************************************************ */
  405. STDMETHODIMP
  406. CEXTLOG::TerminateLog(
  407. VOID
  408. )
  409. {
  410. return CLogFileCtrl::TerminateLog();
  411. }
  412. /* ************************************************************************************ */
  413. DWORD
  414. CEXTLOG::GetRegParameters(
  415. LPCSTR pszRegKey,
  416. LPVOID pvIMDCOM
  417. )
  418. {
  419. // let the parent object get the default parameter first
  420. CLogFileCtrl::GetRegParameters( pszRegKey, pvIMDCOM );
  421. MB mb( (IMDCOM*) pvIMDCOM );
  422. if ( !mb.Open("") ) {
  423. DBGPRINTF((DBG_CONTEXT, "Error %x on mb open\n",GetLastError()));
  424. goto exit;
  425. }
  426. if ( !mb.GetDword(
  427. pszRegKey,
  428. MD_LOGEXT_FIELD_MASK,
  429. IIS_MD_UT_SERVER,
  430. &m_lMask ) )
  431. {
  432. DBGPRINTF((DBG_CONTEXT, "Error %x on FieldMask GetDword\n",GetLastError()));
  433. }
  434. //
  435. // Get time to be used for logfile rollover
  436. //
  437. if ( !mb.GetDword( pszRegKey,
  438. MD_LOGFILE_LOCALTIME_ROLLOVER,
  439. IIS_MD_UT_SERVER,
  440. &m_fUseLocalTimeForRollover
  441. ) )
  442. {
  443. m_fUseLocalTimeForRollover = 0;
  444. }
  445. if (m_fUseLocalTimeForRollover && ( NULL == m_pLocalTimeCache))
  446. {
  447. m_pLocalTimeCache = new ASCLOG_DATETIME_CACHE;
  448. }
  449. exit:
  450. return(NO_ERROR);
  451. }
  452. /* ************************************************************************************ */
  453. VOID
  454. CEXTLOG::GetFormatHeader(
  455. IN OUT STR * strHeader
  456. )
  457. {
  458. strHeader->Reset();
  459. BuildHeader(strHeader, m_lMask, EXTLOG_DATE, EXTLOG_DATE_ID);
  460. BuildHeader(strHeader, m_lMask, EXTLOG_TIME, EXTLOG_TIME_ID);
  461. BuildHeader(strHeader, m_lMask, EXTLOG_CLIENT_IP, EXTLOG_CLIENT_IP_ID);
  462. BuildHeader(strHeader, m_lMask, EXTLOG_USERNAME, EXTLOG_USERNAME_ID);
  463. BuildHeader(strHeader, m_lMask, EXTLOG_SITE_NAME, EXTLOG_SITE_NAME_ID);
  464. BuildHeader(strHeader, m_lMask, EXTLOG_COMPUTER_NAME, EXTLOG_COMPUTER_NAME_ID);
  465. BuildHeader(strHeader, m_lMask, EXTLOG_SERVER_IP, EXTLOG_SERVER_IP_ID);
  466. BuildHeader(strHeader, m_lMask, EXTLOG_SERVER_PORT, EXTLOG_SERVER_PORT_ID);
  467. BuildHeader(strHeader, m_lMask, EXTLOG_METHOD, EXTLOG_METHOD_ID);
  468. BuildHeader(strHeader, m_lMask, EXTLOG_URI_STEM, EXTLOG_URI_STEM_ID);
  469. BuildHeader(strHeader, m_lMask, EXTLOG_URI_QUERY, EXTLOG_URI_QUERY_ID);
  470. BuildHeader(strHeader, m_lMask, EXTLOG_HTTP_STATUS, EXTLOG_HTTP_STATUS_ID);
  471. BuildHeader(strHeader, m_lMask, EXTLOG_WIN32_STATUS, EXTLOG_WIN32_STATUS_ID);
  472. BuildHeader(strHeader, m_lMask, EXTLOG_BYTES_SENT, EXTLOG_BYTES_SENT_ID);
  473. BuildHeader(strHeader, m_lMask, EXTLOG_BYTES_RECV, EXTLOG_BYTES_RECV_ID);
  474. BuildHeader(strHeader, m_lMask, EXTLOG_TIME_TAKEN, EXTLOG_TIME_TAKEN_ID);
  475. BuildHeader(strHeader, m_lMask, EXTLOG_PROTOCOL_VERSION, EXTLOG_PROTOCOL_VERSION_ID);
  476. BuildHeader(strHeader, m_lMask, EXTLOG_HOST, EXTLOG_HOST_ID);
  477. BuildHeader(strHeader, m_lMask, EXTLOG_USER_AGENT, EXTLOG_USER_AGENT_ID);
  478. BuildHeader(strHeader, m_lMask, EXTLOG_COOKIE, EXTLOG_COOKIE_ID);
  479. BuildHeader(strHeader, m_lMask, EXTLOG_REFERER, EXTLOG_REFERER_ID);
  480. if ( ! strHeader->IsEmpty())
  481. {
  482. //
  483. // Remove the trailing space
  484. //
  485. strHeader->SetLen(strHeader->QuerySize()-1);
  486. }
  487. return;
  488. } // CEXTLOG::GetFormatHeader
  489. /* ************************************************************************************ */
  490. BOOL
  491. CEXTLOG::WriteLogDirectives(
  492. IN DWORD Sludge
  493. )
  494. /*++
  495. Routine Description:
  496. Function to write the Extended logging directives
  497. Arguments:
  498. Sludge - number of additional bytes that needs to be written
  499. together with the directives
  500. Return Value:
  501. TRUE, ok
  502. FALSE, not enough space to write.
  503. --*/
  504. {
  505. BOOL fRetVal = TRUE;
  506. if ( m_pLogFile != NULL)
  507. {
  508. CHAR buf[1024];
  509. CHAR szDateTime[32];
  510. STACK_STR (header,256);
  511. DWORD len;
  512. GetFormatHeader(&header );
  513. (VOID)m_DateTimeCache.GetFormattedCurrentDateTime(szDateTime);
  514. len = wsprintf( buf,
  515. "#Software: Microsoft %s %d.%d\r\n"
  516. "#Version: %s\r\n"
  517. "#Date: %s %s\r\n"
  518. "#Fields: %s\r\n",
  519. VER_IISPRODUCTNAME_STR, VER_IISMAJORVERSION, VER_IISMINORVERSION,
  520. EXTLOG_VERSION, szDateTime, szDateTime+strlen(szDateTime)+1, header.QueryStr());
  521. DBG_ASSERT(len == strlen(buf));
  522. if ( !IsFileOverFlowForCB(len + Sludge))
  523. {
  524. m_pLogFile->Write(buf, len) ? IncrementBytesWritten(len) : (fRetVal = FALSE);
  525. }
  526. else
  527. {
  528. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  529. DBGPRINTF((DBG_CONTEXT, "WriteLogDirectives: Unable to write directives\n"));
  530. fRetVal = FALSE;
  531. }
  532. }
  533. return(fRetVal);
  534. } // CLogFileCtrl::WriteLogDirectives
  535. /* ************************************************************************************ */
  536. BOOL
  537. CEXTLOG::FormatLogBuffer(
  538. IN IInetLogInformation *pLogObj,
  539. IN LPSTR pBuf,
  540. IN DWORD *pcbSize,
  541. OUT SYSTEMTIME *pSystemTime
  542. )
  543. {
  544. PCHAR pTmp;
  545. DWORD cbTmp;
  546. DWORD nRequired;
  547. DWORD status;
  548. PCHAR pBuffer = pBuf;
  549. CHAR rgchDateTime[32];
  550. //
  551. // We need system time
  552. //
  553. m_DateTimeCache.SetSystemTime( pSystemTime );
  554. //
  555. // if default go through fast path
  556. //
  557. if ( m_lMask != DEFAULT_EXTLOG_FIELDS )
  558. {
  559. BOOL fRet = NormalFormatBuffer(
  560. pLogObj,
  561. pBuf,
  562. pcbSize,
  563. pSystemTime
  564. );
  565. if (fRet && m_fUseLocalTimeForRollover )
  566. {
  567. m_pLocalTimeCache ? m_pLocalTimeCache->SetLocalTime(pSystemTime):
  568. GetLocalTime(pSystemTime);
  569. }
  570. return fRet;
  571. }
  572. //
  573. // Default format is:
  574. // Time ClientIP Operation Target HTTPStatus
  575. //
  576. // Time 8 HH:MM:SS
  577. // delimiters 4
  578. // EOL 2
  579. //
  580. nRequired = 8 + 4 + 2;
  581. (VOID) m_DateTimeCache.GetFormattedDateTime(pSystemTime,rgchDateTime);
  582. pTmp = rgchDateTime + 11;
  583. CopyMemory(pBuffer, pTmp, 8);
  584. pBuffer += 8;
  585. *(pBuffer++) = ' ';
  586. //
  587. // IP Address
  588. //
  589. pTmp = pLogObj->GetClientHostName( NULL, &cbTmp );
  590. if ( cbTmp == 0 )
  591. {
  592. cbTmp = 1;
  593. pTmp = "-";
  594. }
  595. nRequired += cbTmp;
  596. if ( nRequired <= *pcbSize )
  597. {
  598. CopyMemory(pBuffer, pTmp, cbTmp);
  599. pBuffer += cbTmp;
  600. *(pBuffer++) = ' ';
  601. }
  602. //
  603. // Operation
  604. //
  605. pTmp = pLogObj->GetOperation( NULL, &cbTmp );
  606. if ( cbTmp == 0 )
  607. {
  608. cbTmp = 1;
  609. pTmp = "-";
  610. }
  611. nRequired += cbTmp;
  612. if ( nRequired <= *pcbSize )
  613. {
  614. CopyMemory(pBuffer, pTmp, cbTmp);
  615. pBuffer += cbTmp;
  616. *(pBuffer++) = ' ';
  617. }
  618. //
  619. // Target
  620. //
  621. pTmp = pLogObj->GetTarget( NULL, &cbTmp );
  622. if ( cbTmp == 0 )
  623. {
  624. cbTmp = 1;
  625. pTmp = "-";
  626. }
  627. else if ( (cbTmp > MAX_LOG_TARGET_FIELD_LEN ) ||
  628. ((nRequired + cbTmp) > MAX_LOG_RECORD_LEN))
  629. {
  630. cbTmp = 3;
  631. pTmp = szDotDot;
  632. }
  633. nRequired += cbTmp;
  634. if ( nRequired <= *pcbSize )
  635. {
  636. for (DWORD i=0; i<cbTmp;i++ )
  637. {
  638. if ( (*pBuffer = pTmp[i]) == ' ' )
  639. {
  640. *pBuffer = '+';
  641. }
  642. pBuffer++;
  643. }
  644. *(pBuffer++) = ' ';
  645. }
  646. status = pLogObj->GetProtocolStatus( );
  647. if ( (status == 200) && (nRequired + 5 <= *pcbSize) )
  648. {
  649. CopyMemory( pBuffer, szHTTPOk, 5);
  650. pBuffer += 5;
  651. nRequired += 3;
  652. }
  653. else
  654. {
  655. CHAR tmpBuf[32];
  656. cbTmp = FastDwToA( tmpBuf, status );
  657. nRequired += cbTmp;
  658. if ( nRequired <= *pcbSize )
  659. {
  660. CopyMemory(pBuffer, tmpBuf, cbTmp);
  661. pBuffer += cbTmp;
  662. }
  663. *(pBuffer++) = '\r';
  664. *pBuffer = '\n';
  665. }
  666. if ( nRequired > *pcbSize )
  667. {
  668. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  669. *pcbSize = nRequired;
  670. return(FALSE);
  671. }
  672. *pcbSize = nRequired;
  673. //
  674. // To allow filenames & rollover based on either local or GMT time
  675. //
  676. if ( m_fUseLocalTimeForRollover )
  677. {
  678. m_pLocalTimeCache ? m_pLocalTimeCache->SetLocalTime(pSystemTime):
  679. GetLocalTime(pSystemTime);
  680. }
  681. return TRUE;
  682. } // CEXTLOG::FormatLogBuffer
  683. /* ************************************************************************************ */
  684. BOOL
  685. CEXTLOG::NormalFormatBuffer(
  686. IN IInetLogInformation *pLogObj,
  687. IN LPSTR pBuf,
  688. IN DWORD *pcbSize,
  689. IN SYSTEMTIME *pSystemTime
  690. )
  691. {
  692. BOOL fSucceeded = FALSE;
  693. DWORD spaceNeeded = 0;
  694. CHAR tmpBuf[32];
  695. PCHAR pTmp;
  696. DWORD cbTmp;
  697. //
  698. // Format is:
  699. // Date Time ClientIP UserName Service Server ServerIP
  700. // Method Target parameters httpstatus win32 bytes timetaken
  701. // user-agent cookies
  702. //
  703. PCHAR outBuffer = pBuf;
  704. *outBuffer = 0;
  705. if ( m_lMask & (EXTLOG_DATE | EXTLOG_TIME) )
  706. {
  707. DWORD cchDateTime;
  708. DWORD cchDate;
  709. DWORD cchTime;
  710. CHAR rgchDateTime[ 32];
  711. cchDateTime = m_DateTimeCache.GetFormattedDateTime(
  712. pSystemTime,
  713. rgchDateTime);
  714. cchDate = (DWORD)strlen(rgchDateTime);
  715. cchTime = cchDateTime - cchDate - 1;
  716. if (m_lMask & EXTLOG_DATE)
  717. {
  718. // Date is in YYYY-MM-DD format (GMT)
  719. fSucceeded = CopyFieldToBuffer( rgchDateTime, cchDate, &outBuffer,
  720. &spaceNeeded, *pcbSize);
  721. }
  722. if (m_lMask & EXTLOG_TIME)
  723. {
  724. // Time in HH:MM:SS format (GMT)
  725. fSucceeded = CopyFieldToBuffer( rgchDateTime+cchDate+1, cchTime, &outBuffer,
  726. &spaceNeeded, *pcbSize);
  727. }
  728. }
  729. //
  730. // Fill up the buffer
  731. //
  732. if (m_lMask & EXTLOG_CLIENT_IP )
  733. {
  734. pTmp = pLogObj->GetClientHostName( NULL, &cbTmp );
  735. fSucceeded = CopyFieldToBuffer( pTmp, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
  736. }
  737. if (m_lMask & EXTLOG_USERNAME )
  738. {
  739. pTmp = pLogObj->GetClientUserName( NULL, &cbTmp );
  740. fSucceeded = CopyFieldToBuffer( pTmp, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
  741. }
  742. if (m_lMask & EXTLOG_SITE_NAME)
  743. {
  744. pTmp = pLogObj->GetSiteName( NULL, &cbTmp );
  745. fSucceeded = CopyFieldToBuffer( pTmp, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
  746. }
  747. if (m_lMask & EXTLOG_COMPUTER_NAME)
  748. {
  749. pTmp = pLogObj->GetComputerName( NULL, &cbTmp );
  750. fSucceeded = CopyFieldToBuffer( pTmp, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
  751. }
  752. if (m_lMask & EXTLOG_SERVER_IP )
  753. {
  754. pTmp = pLogObj->GetServerAddress( NULL, &cbTmp );
  755. fSucceeded = CopyFieldToBuffer( pTmp, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
  756. }
  757. if (m_lMask & EXTLOG_SERVER_PORT )
  758. {
  759. cbTmp = FastDwToA( tmpBuf, pLogObj->GetPortNumber() );
  760. fSucceeded = CopyFieldToBuffer( tmpBuf, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
  761. }
  762. if (m_lMask & EXTLOG_METHOD )
  763. {
  764. pTmp = pLogObj->GetOperation( NULL, &cbTmp );
  765. fSucceeded = CopyFieldToBuffer( pTmp, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
  766. }
  767. if (m_lMask & EXTLOG_URI_STEM )
  768. {
  769. pTmp = pLogObj->GetTarget( NULL, &cbTmp );
  770. if ((cbTmp > MAX_LOG_TARGET_FIELD_LEN ) || ((spaceNeeded + cbTmp) > MAX_LOG_RECORD_LEN))
  771. {
  772. cbTmp = 3;
  773. pTmp = szDotDot;
  774. }
  775. else
  776. {
  777. ConvertSpacesToPlus(pTmp);
  778. }
  779. fSucceeded = CopyFieldToBuffer( pTmp, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
  780. }
  781. if (m_lMask & EXTLOG_URI_QUERY )
  782. {
  783. pTmp = pLogObj->GetParameters( NULL, &cbTmp );
  784. if ((cbTmp > MAX_LOG_TARGET_FIELD_LEN ) || ((spaceNeeded + cbTmp) > MAX_LOG_RECORD_LEN))
  785. {
  786. cbTmp = 3;
  787. pTmp = szDotDot;
  788. }
  789. else
  790. {
  791. ConvertSpacesToPlus(pTmp);
  792. }
  793. fSucceeded = CopyFieldToBuffer( pTmp, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
  794. }
  795. if (m_lMask & EXTLOG_HTTP_STATUS )
  796. {
  797. cbTmp = FastDwToA( tmpBuf, pLogObj->GetProtocolStatus() );
  798. fSucceeded = CopyFieldToBuffer( tmpBuf, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
  799. }
  800. if (m_lMask & EXTLOG_WIN32_STATUS )
  801. {
  802. cbTmp = FastDwToA( tmpBuf, pLogObj->GetWin32Status() );
  803. fSucceeded = CopyFieldToBuffer( tmpBuf, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
  804. }
  805. if (m_lMask & EXTLOG_BYTES_SENT )
  806. {
  807. cbTmp = FastDwToA( tmpBuf, pLogObj->GetBytesSent() );
  808. fSucceeded = CopyFieldToBuffer( tmpBuf, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
  809. }
  810. if (m_lMask & EXTLOG_BYTES_RECV )
  811. {
  812. cbTmp = FastDwToA( tmpBuf, pLogObj->GetBytesRecvd() );
  813. fSucceeded = CopyFieldToBuffer( tmpBuf, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
  814. }
  815. if (m_lMask & EXTLOG_TIME_TAKEN )
  816. {
  817. cbTmp = FastDwToA( tmpBuf, pLogObj->GetTimeForProcessing() );
  818. fSucceeded = CopyFieldToBuffer( tmpBuf, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
  819. }
  820. if (m_lMask & EXTLOG_PROTOCOL_VERSION )
  821. {
  822. pTmp = pLogObj->GetVersionString( NULL, &cbTmp );
  823. fSucceeded = CopyFieldToBuffer( pTmp, cbTmp, &outBuffer, &spaceNeeded, *pcbSize);
  824. }
  825. //
  826. // See if we need to get the extra header
  827. //
  828. if ( (m_lMask & (EXTLOG_HOST |
  829. EXTLOG_USER_AGENT |
  830. EXTLOG_COOKIE |
  831. EXTLOG_REFERER )) != NULL )
  832. {
  833. pTmp = pLogObj->GetExtraHTTPHeaders( NULL, &cbTmp );
  834. if ( m_lMask & EXTLOG_HOST )
  835. fSucceeded = WriteHTTPHeader(&pTmp, &outBuffer, &spaceNeeded, *pcbSize);
  836. if ( m_lMask & EXTLOG_USER_AGENT )
  837. fSucceeded = WriteHTTPHeader(&pTmp, &outBuffer, &spaceNeeded, *pcbSize);
  838. if ( m_lMask & EXTLOG_COOKIE )
  839. fSucceeded = WriteHTTPHeader(&pTmp, &outBuffer, &spaceNeeded, *pcbSize);
  840. if ( m_lMask & EXTLOG_REFERER )
  841. fSucceeded = WriteHTTPHeader(&pTmp, &outBuffer, &spaceNeeded, *pcbSize);
  842. }
  843. //
  844. // remove the trailing space
  845. //
  846. if ('\0' != *pBuf)
  847. {
  848. outBuffer--;
  849. spaceNeeded--;
  850. }
  851. //
  852. // add line terminator
  853. //
  854. spaceNeeded += 2;
  855. if ( spaceNeeded <= *pcbSize)
  856. {
  857. outBuffer[0] = '\r';
  858. outBuffer[1] = '\n';
  859. fSucceeded = TRUE;
  860. }
  861. else
  862. {
  863. fSucceeded = FALSE;
  864. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  865. }
  866. *pcbSize = spaceNeeded;
  867. return fSucceeded;
  868. } // CEXTLOG::FormatLogBuffer
  869. /* ************************************************************************************ */
  870. /* Custom Logging Functions */
  871. /* ************************************************************************************ */
  872. BOOL
  873. CEXTLOG::WriteCustomLogDirectives(
  874. IN DWORD Sludge
  875. )
  876. {
  877. BOOL fRetVal = TRUE;
  878. if ( m_pLogFile != NULL)
  879. {
  880. CHAR szDateTime[32];
  881. DWORD dwLen;
  882. STACK_STR( strHeader, 512 );
  883. m_DateTimeCache.GetFormattedCurrentDateTime(szDateTime);
  884. BuildCustomLogHeader(m_cPrevCustLogItems, m_pPrevCustLogItems, szDateTime,
  885. m_strHeaderSuffix.QueryStr(), strHeader);
  886. dwLen = strHeader.QueryCB();
  887. if ( !IsFileOverFlowForCB(dwLen + Sludge) )
  888. {
  889. m_pLogFile->Write(strHeader.QueryStr(), dwLen) ?
  890. IncrementBytesWritten(dwLen) : (fRetVal = FALSE);
  891. }
  892. else
  893. {
  894. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  895. DBGPRINTF((DBG_CONTEXT, "WriteCustomLogDirectives: Unable to write directives\n"));
  896. fRetVal = FALSE;
  897. }
  898. }
  899. return fRetVal;
  900. }
  901. /* ************************************************************************************ */
  902. DWORD
  903. CEXTLOG::ConvertDataToString(
  904. IN DWORD dwPropertyType,
  905. IN PVOID pData,
  906. IN PCHAR pBuffer,
  907. IN DWORD dwBufferSize
  908. )
  909. /*++
  910. Routine Description:
  911. Function to convert Custom Logging data to string
  912. Arguments:
  913. dwPropertyType - type information regarding the data to convert.
  914. pData - pointer to data.
  915. pBuffer - pointer to buffer to store the result.
  916. dwBufferSize - byte count of space remaining in the buffer. If 0 or -ve
  917. => buffer is full
  918. Return Value:
  919. Number of bytes in the string representation of the data +1 (for space at end).
  920. The output buffer (pBuffer) is not NULL terminated.
  921. --*/
  922. {
  923. CHAR szBuf[64];
  924. PCHAR pChString;
  925. DWORD dwLength;
  926. USES_CONVERSION; // To enable W2A
  927. DBG_ASSERT(NULL != pBuffer);
  928. if ( NULL != pData)
  929. {
  930. pChString = szBuf;
  931. switch (dwPropertyType)
  932. {
  933. case MD_LOGCUSTOM_DATATYPE_INT:
  934. {
  935. int i = *((int *)pData);
  936. _itoa(i, pChString, 10);
  937. dwLength = (DWORD)strlen(pChString);
  938. break;
  939. }
  940. case MD_LOGCUSTOM_DATATYPE_UINT:
  941. {
  942. unsigned int ui = *((unsigned int *)pData);
  943. unsigned long ul = ui;
  944. _ultoa(ul, pChString, 10);
  945. dwLength = (DWORD)strlen(pChString);
  946. break;
  947. }
  948. case MD_LOGCUSTOM_DATATYPE_LONG:
  949. {
  950. long l = *((long *)pData);
  951. _ltoa(l, pChString, 10);
  952. dwLength = (DWORD)strlen(pChString);
  953. break;
  954. }
  955. case MD_LOGCUSTOM_DATATYPE_ULONG:
  956. {
  957. unsigned long ul = *((unsigned long *)pData);
  958. _ultoa(ul, pChString, 10);
  959. dwLength = (DWORD)strlen(pChString);
  960. break;
  961. }
  962. case MD_LOGCUSTOM_DATATYPE_FLOAT:
  963. {
  964. float f = *((float *)pData);
  965. dwLength = sprintf(pChString,"%f",f);
  966. break;
  967. }
  968. case MD_LOGCUSTOM_DATATYPE_DOUBLE:
  969. {
  970. double d = *((double *)pData);
  971. dwLength = sprintf(pChString,"%f",d);
  972. break;
  973. }
  974. case MD_LOGCUSTOM_DATATYPE_LPSTR:
  975. {
  976. pChString = (LPSTR)pData;
  977. dwLength = (DWORD)strlen(pChString);
  978. if (dwLength > MAX_LOG_TARGET_FIELD_LEN )
  979. {
  980. pChString = szDotDot;
  981. dwLength = 3;
  982. }
  983. break;
  984. }
  985. case MD_LOGCUSTOM_DATATYPE_LPWSTR:
  986. {
  987. dwLength = (DWORD)wcslen( (LPWSTR)pData);
  988. if (dwLength <= MAX_LOG_TARGET_FIELD_LEN)
  989. {
  990. pChString = W2A((LPWSTR)pData);
  991. }
  992. else
  993. {
  994. pChString = szDotDot;
  995. dwLength = 3;
  996. }
  997. break;
  998. }
  999. default:
  1000. dwLength = 0;
  1001. break;
  1002. }
  1003. }
  1004. else
  1005. {
  1006. pChString = szDash;
  1007. dwLength = 1;
  1008. }
  1009. //
  1010. // Copy over the charaters to the output buffer and append a ' '
  1011. //
  1012. if (dwLength < dwBufferSize)
  1013. {
  1014. CopyMemory(pBuffer, pChString, dwLength);
  1015. pBuffer[dwLength] = ' ';
  1016. }
  1017. else if (dwBufferSize > 3)
  1018. {
  1019. //
  1020. // Not enough memory to copy the field. Use ... instead
  1021. //
  1022. dwLength = 3;
  1023. CopyMemory(pBuffer, szDotDot, 3);
  1024. pBuffer[dwLength] = ' ';
  1025. }
  1026. else
  1027. {
  1028. //
  1029. // Can't even copy ... Just punt on the remaining part of the log line
  1030. //
  1031. dwLength = (DWORD)-1;
  1032. }
  1033. return dwLength+1;
  1034. }
  1035. /* ************************************************************************************ */
  1036. DWORD
  1037. CEXTLOG::FormatCustomLogBuffer(
  1038. DWORD cItems,
  1039. PPLOG_PROPERTY_INFO pPropInfo,
  1040. PPVOID pPropData,
  1041. LPCSTR szDateTime,
  1042. LPSTR szLogLine,
  1043. DWORD cchLogLine
  1044. )
  1045. {
  1046. DWORD cchUsed;
  1047. PCHAR pCh = szLogLine;
  1048. cchLogLine -= 1; // Reserve space for trailing \r\n
  1049. //
  1050. // Add date & time if enabled
  1051. //
  1052. if ( m_lMask & (EXTLOG_DATE | EXTLOG_TIME) )
  1053. {
  1054. DWORD cch = (DWORD)strlen(szDateTime);
  1055. if (m_lMask & EXTLOG_DATE)
  1056. {
  1057. memcpy(pCh, szDateTime, cch);
  1058. *(pCh+cch) = ' ';
  1059. pCh += cch+1;
  1060. }
  1061. if (m_lMask & EXTLOG_TIME)
  1062. {
  1063. szDateTime += cch+1;
  1064. cch = (DWORD)strlen(szDateTime);
  1065. memcpy(pCh, szDateTime, cch);
  1066. *(pCh+cch) = ' ';
  1067. pCh += cch+1;
  1068. }
  1069. }
  1070. cchLogLine -= (DWORD)DIFF(pCh - szLogLine);
  1071. for (DWORD i=0; i< cItems; i++)
  1072. {
  1073. // Convert data to string
  1074. cchUsed = ConvertDataToString(pPropInfo[i]->dwPropertyDataType,
  1075. pPropData[i],
  1076. pCh, cchLogLine);
  1077. pCh += cchUsed;
  1078. cchLogLine -= cchUsed;
  1079. }
  1080. *(pCh-1) = '\r';
  1081. *(pCh) = '\n';
  1082. return (DWORD)DIFF(pCh+1-szLogLine);
  1083. }
  1084. /* ************************************************************************************ */
  1085. void
  1086. CEXTLOG::BuildCustomLogHeader(
  1087. DWORD cItems,
  1088. PPLOG_PROPERTY_INFO pPropInfo,
  1089. LPCSTR szDateTime,
  1090. LPCSTR szHeaderSuffix,
  1091. STR& strHeader
  1092. )
  1093. {
  1094. DWORD cchHeader;
  1095. LPSTR szHeader = strHeader.QueryStr();
  1096. cchHeader = wsprintf( szHeader,
  1097. "#Software: Microsoft %s %d.%d\r\n"
  1098. "#Version: %s\r\n"
  1099. "#Date: %s %s\r\n",
  1100. VER_IISPRODUCTNAME_STR, VER_IISMAJORVERSION, VER_IISMINORVERSION,
  1101. EXTLOG_VERSION,
  1102. szDateTime,
  1103. szDateTime+strlen(szDateTime)+1
  1104. );
  1105. if ( (NULL != szHeaderSuffix) && ('\0' != *szHeaderSuffix))
  1106. {
  1107. DWORD cchSuffix;
  1108. // Make sure that the header begins with a #
  1109. if ( *szHeaderSuffix != '#')
  1110. {
  1111. szHeader[cchHeader++] = '#';
  1112. }
  1113. cchSuffix = (DWORD)strlen(szHeaderSuffix);
  1114. memcpy(szHeader+cchHeader, szHeaderSuffix, cchSuffix);
  1115. cchHeader += cchSuffix;
  1116. szHeader[cchHeader++] = '\r';
  1117. szHeader[cchHeader++] = '\n';
  1118. }
  1119. memcpy(szHeader+cchHeader, "#Fields:", sizeof("#Fields:"));
  1120. cchHeader += sizeof("#Fields:");
  1121. strHeader.SetLen(cchHeader-1);
  1122. //
  1123. // Fill in W3C Headers for all fields.
  1124. //
  1125. if ( m_lMask & EXTLOG_DATE )
  1126. {
  1127. strHeader.Append(" date");
  1128. }
  1129. if (m_lMask & EXTLOG_TIME)
  1130. {
  1131. strHeader.Append(" time");
  1132. }
  1133. for (DWORD i=0; i< cItems; i++)
  1134. {
  1135. // Add header to header string
  1136. strHeader.Append(' ');
  1137. strHeader.Append(pPropInfo[i]->strW3CHeader);
  1138. }
  1139. strHeader.Append("\r\n");
  1140. }
  1141. /* ************************************************************************************ */
  1142. STDMETHODIMP
  1143. CEXTLOG::LogCustomInformation(
  1144. IN DWORD cItems,
  1145. IN PCUSTOM_LOG_DATA pCustomLogData,
  1146. IN LPSTR szHeaderSuffix
  1147. )
  1148. /*++
  1149. Routine Description:
  1150. Function to write Custom Logging information for Extended logging
  1151. Arguments:
  1152. cItems - number of fields to log
  1153. (elements in the array pointed to by pCustomLogData)
  1154. pCustomLogData - pointer to array of CUSTOM_LOG_DATA
  1155. Return Value:
  1156. HRESULT indicating whether function Succeeded or Failed.
  1157. --*/
  1158. {
  1159. SYSTEMTIME sysTime;
  1160. DWORD i, j, cchLogLine;
  1161. BOOL fResetHeaders;
  1162. CHAR szDateTime[32];
  1163. CHAR szLogLine[MAX_LOG_RECORD_LEN+1];
  1164. DBG_ASSERT( 0 != cItems);
  1165. DBG_ASSERT( NULL != pCustomLogData);
  1166. DBG_ASSERT( MAX_CUSTLOG_FIELDS >= cItems);
  1167. PLOG_PROPERTY_INFO pPropInfo[MAX_CUSTLOG_FIELDS];
  1168. PVOID pPropData[MAX_CUSTLOG_FIELDS];
  1169. //
  1170. // Lock Shared. Ensures that shared variables are not modified unknowst to this thread.
  1171. //
  1172. LockCustLogShared();
  1173. fResetHeaders = FALSE;
  1174. //
  1175. // Build list of enabled keys. Simultaneously check if headr needs resetting.
  1176. //
  1177. for (i=0, j=0 ; i< cItems; i++)
  1178. {
  1179. if ( (LK_SUCCESS == m_HashTable.FindKey(pCustomLogData[i].szPropertyPath, pPropInfo+j)) &&
  1180. (pPropInfo[j]->fEnabled)
  1181. )
  1182. {
  1183. fResetHeaders |= ( pPropInfo[j] != m_pPrevCustLogItems[j] );
  1184. pPropData[j] = pCustomLogData[i].pData;
  1185. j++;
  1186. }
  1187. }
  1188. cItems = j;
  1189. //
  1190. // Header needs resetting if # items is different or Header Suffix has changed.
  1191. //
  1192. fResetHeaders |= (m_cPrevCustLogItems != cItems);
  1193. if (szHeaderSuffix != NULL)
  1194. {
  1195. fResetHeaders |= ( 0 != strcmp(m_strHeaderSuffix.QueryStr(), szHeaderSuffix));
  1196. }
  1197. m_DateTimeCache.SetSystemTime( &sysTime );
  1198. m_DateTimeCache.GetFormattedDateTime(&sysTime, szDateTime);
  1199. cchLogLine = FormatCustomLogBuffer( cItems,
  1200. pPropInfo,
  1201. pPropData,
  1202. szDateTime,
  1203. szLogLine,
  1204. MAX_LOG_RECORD_LEN+1);
  1205. if (fResetHeaders)
  1206. {
  1207. //
  1208. // Convert Lock to Exclusive before setting the class wide variable.
  1209. //
  1210. LockCustLogConvertExclusive();
  1211. m_cPrevCustLogItems = cItems;
  1212. for (i=0; i <cItems; i++)
  1213. {
  1214. m_pPrevCustLogItems[i] = pPropInfo[i];
  1215. }
  1216. m_strHeaderSuffix.Copy(szHeaderSuffix);
  1217. }
  1218. //
  1219. // Write out the log to file
  1220. //
  1221. if ( m_fUseLocalTimeForRollover )
  1222. {
  1223. m_pLocalTimeCache ? m_pLocalTimeCache->SetLocalTime(&sysTime):
  1224. GetLocalTime(&sysTime);
  1225. }
  1226. WriteLogInformation(sysTime, szLogLine, cchLogLine, TRUE, fResetHeaders);
  1227. UnlockCustLog();
  1228. return S_OK;
  1229. }
  1230. /* ************************************************************************************ */
  1231. /* ILogScripting Functions */
  1232. /* ************************************************************************************ */
  1233. HRESULT
  1234. CEXTLOG::ReadFileLogRecord(
  1235. IN FILE *fpLogFile,
  1236. IN LPINET_LOGLINE pInetLogLine,
  1237. IN PCHAR pszLogLine,
  1238. IN DWORD dwLogLineSize
  1239. )
  1240. /*++
  1241. Routine Description:
  1242. Function to read a log line from an open log file
  1243. Arguments:
  1244. fpLogFile - FILE * to open file
  1245. pInetLogLine - pointer to INET_LOGLINE structure where parsed info is stored
  1246. pszLogLine - buffer to store the log line
  1247. dwLogLineSize - size of pszLogLine
  1248. Return Value:
  1249. HRESULT indicating whether function Succeeded or Failed.
  1250. --*/
  1251. {
  1252. CHAR * pCh;
  1253. DWORD pos, custompos;
  1254. CHAR * szDateString, * szTimeString;
  1255. getnewline:
  1256. pCh = pszLogLine;
  1257. if (fgets(pCh, dwLogLineSize, fpLogFile) == NULL)
  1258. {
  1259. return E_FAIL;
  1260. }
  1261. pCh = SkipWhite(pCh);
  1262. if (('\n' == *pCh) || ('\0' == *pCh))
  1263. {
  1264. // Empty line. Get Next line
  1265. goto getnewline;
  1266. }
  1267. if ( '#' == *pCh )
  1268. {
  1269. pCh = strstr(pszLogLine, "#Date:");
  1270. if (NULL != pCh)
  1271. {
  1272. //
  1273. // Copy the date & time into member variables
  1274. //
  1275. pCh = strtok(pCh+6," \t\r\n");
  1276. if (NULL == pCh)
  1277. {
  1278. return E_FAIL;
  1279. }
  1280. strcpy(m_szDate, pCh);
  1281. pCh = strtok(NULL," \t\r\n");
  1282. if (NULL == pCh)
  1283. {
  1284. return E_FAIL;
  1285. }
  1286. strcpy(m_szTime, pCh);
  1287. goto getnewline;
  1288. }
  1289. //
  1290. // Not the date line. Check if the fields are being reset
  1291. //
  1292. pCh = strstr(pszLogLine, "#Fields:");
  1293. if (NULL != pCh)
  1294. {
  1295. // Headers are being defined or redefined
  1296. dwDatePos = 0;
  1297. dwTimePos = 0;
  1298. dwClientIPPos = 0;
  1299. dwUserNamePos = 0;
  1300. dwSiteNamePos = 0;
  1301. dwComputerNamePos = 0;
  1302. dwServerIPPos = 0;
  1303. dwMethodPos = 0;
  1304. dwURIStemPos = 0;
  1305. dwURIQueryPos = 0;
  1306. dwHTTPStatusPos = 0;
  1307. dwWin32StatusPos = 0;
  1308. dwBytesSentPos = 0;
  1309. dwBytesRecvPos = 0;
  1310. dwTimeTakenPos = 0;
  1311. dwServerPortPos = 0;
  1312. dwVersionPos = 0;
  1313. dwCookiePos = 0;
  1314. dwUserAgentPos = 0;
  1315. dwRefererPos = 0;
  1316. pInetLogLine->iCustomFieldsCount = 0;
  1317. pCh = strtok(pCh+8," \t\r\n");
  1318. for (pos = 1; pCh != NULL; pos++, pCh = strtok(NULL," \t\r\n"))
  1319. {
  1320. if (0 == _stricmp(pCh, EXTLOG_DATE_ID)) {
  1321. dwDatePos = pos;
  1322. } else if (0 == _stricmp(pCh, EXTLOG_TIME_ID)) {
  1323. dwTimePos = pos;
  1324. } else if (0 == _stricmp(pCh, EXTLOG_CLIENT_IP_ID)) {
  1325. dwClientIPPos = pos;
  1326. } else if (0 == _stricmp(pCh, EXTLOG_USERNAME_ID)) {
  1327. dwUserNamePos = pos;
  1328. } else if (0 == _stricmp(pCh, EXTLOG_SITE_NAME_ID)) {
  1329. dwSiteNamePos = pos;
  1330. } else if (0 == _stricmp(pCh, EXTLOG_COMPUTER_NAME_ID)) {
  1331. dwComputerNamePos = pos;
  1332. } else if (0 == _stricmp(pCh, EXTLOG_SERVER_IP_ID)) {
  1333. dwServerIPPos = pos;
  1334. } else if (0 == _stricmp(pCh, EXTLOG_METHOD_ID)) {
  1335. dwMethodPos = pos;
  1336. } else if (0 == _stricmp(pCh, EXTLOG_URI_STEM_ID)) {
  1337. dwURIStemPos = pos;
  1338. } else if (0 == _stricmp(pCh, EXTLOG_URI_QUERY_ID)) {
  1339. dwURIQueryPos = pos;
  1340. } else if (0 == _stricmp(pCh, EXTLOG_HTTP_STATUS_ID)) {
  1341. dwHTTPStatusPos = pos;
  1342. } else if (0 == _stricmp(pCh, EXTLOG_WIN32_STATUS_ID)) {
  1343. dwWin32StatusPos = pos;
  1344. } else if (0 == _stricmp(pCh, EXTLOG_BYTES_SENT_ID)) {
  1345. dwBytesSentPos = pos;
  1346. } else if (0 == _stricmp(pCh, EXTLOG_BYTES_RECV_ID)) {
  1347. dwBytesRecvPos = pos;
  1348. } else if (0 == _stricmp(pCh, EXTLOG_TIME_TAKEN_ID)) {
  1349. dwTimeTakenPos = pos;
  1350. } else if (0 == _stricmp(pCh, EXTLOG_SERVER_PORT_ID)) {
  1351. dwServerPortPos = pos;
  1352. } else if (0 == _stricmp(pCh, EXTLOG_PROTOCOL_VERSION_ID)){
  1353. dwVersionPos = pos;
  1354. } else if (0 == _stricmp(pCh, EXTLOG_COOKIE_ID)) {
  1355. dwCookiePos = pos;
  1356. } else if (0 == _stricmp(pCh, EXTLOG_USER_AGENT_ID)) {
  1357. dwUserAgentPos = pos;
  1358. } else if (0 == _stricmp(pCh, EXTLOG_REFERER_ID)) {
  1359. dwRefererPos = pos;
  1360. } else if ( pInetLogLine->iCustomFieldsCount < MAX_CUSTOM_FIELDS) {
  1361. // Unidentified header. Add to custom header list
  1362. strcpy(pInetLogLine->CustomFields[pInetLogLine->iCustomFieldsCount++].szHeader, pCh);
  1363. }
  1364. }
  1365. }
  1366. goto getnewline;
  1367. }
  1368. //
  1369. // We have a log line. Parse it.
  1370. //
  1371. szDateString = m_szDate;
  1372. szTimeString = m_szTime;
  1373. pCh = strtok(pszLogLine," \t\r\n");
  1374. for (pos = 1, custompos = 0; pCh != NULL; pos++, pCh= strtok(NULL, " \t\r\n"))
  1375. {
  1376. if ( pos == dwDatePos ) {
  1377. szDateString = pCh;
  1378. } else if (pos == dwTimePos) {
  1379. szTimeString = pCh;
  1380. } else if (pos == dwClientIPPos) {
  1381. pInetLogLine->pszClientHostName = pCh;
  1382. } else if (pos == dwUserNamePos) {
  1383. pInetLogLine->pszClientUserName = pCh;
  1384. } else if (pos == dwSiteNamePos) {
  1385. pInetLogLine->pszSiteName = pCh;
  1386. } else if (pos == dwComputerNamePos){
  1387. pInetLogLine->pszComputerName = pCh;
  1388. } else if (pos == dwServerIPPos) {
  1389. pInetLogLine->pszServerAddress = pCh;
  1390. } else if (pos == dwMethodPos) {
  1391. pInetLogLine->pszOperation = pCh;
  1392. } else if (pos == dwURIStemPos) {
  1393. pInetLogLine->pszTarget = pCh;
  1394. } else if (pos == dwURIQueryPos) {
  1395. pInetLogLine->pszParameters = pCh;
  1396. } else if (pos == dwHTTPStatusPos) {
  1397. pInetLogLine->pszProtocolStatus = pCh;
  1398. } else if (pos == dwWin32StatusPos) {
  1399. pInetLogLine->pszWin32Status = pCh;
  1400. } else if (pos == dwBytesSentPos) {
  1401. pInetLogLine->pszBytesSent = pCh;
  1402. } else if (pos == dwBytesRecvPos) {
  1403. pInetLogLine->pszBytesRecvd = pCh;
  1404. } else if (pos == dwTimeTakenPos) {
  1405. pInetLogLine->pszTimeForProcessing= pCh;
  1406. } else if (pos == dwServerPortPos) {
  1407. pInetLogLine->pszPort = pCh;
  1408. } else if (pos == dwVersionPos) {
  1409. pInetLogLine->pszVersion = pCh;
  1410. } else if (pos == dwCookiePos) {
  1411. pInetLogLine->pszCookie = pCh;
  1412. } else if (pos == dwUserAgentPos) {
  1413. pInetLogLine->pszUserAgent = pCh;
  1414. } else if (pos == dwRefererPos) {
  1415. pInetLogLine->pszReferer = pCh;
  1416. } else if ( custompos < (DWORD)pInetLogLine->iCustomFieldsCount) {
  1417. pInetLogLine->CustomFields[custompos++].pchData = pCh;
  1418. }
  1419. }
  1420. if ( ! ConvertW3CDateToVariantDate(szDateString, szTimeString, &(pInetLogLine->DateTime)) )
  1421. {
  1422. return E_FAIL;
  1423. }
  1424. return S_OK;
  1425. } // CEXTLOG::ReadFileLogRecord
  1426. /* ************************************************************************************ */
  1427. HRESULT
  1428. CEXTLOG::WriteFileLogRecord(
  1429. IN FILE *fpLogFile,
  1430. IN ILogScripting *pILogScripting,
  1431. IN bool fWriteHeader
  1432. )
  1433. /*++
  1434. Routine Description:
  1435. Function to write a log line to an open log file
  1436. Arguments:
  1437. fpLogFile - FILE * to open file
  1438. pILogScripting - ILogScripting interface for getting information to write
  1439. fWriteHeader - Flag to indicate that log header must be written.
  1440. Return Value:
  1441. HRESULT indicating whether function Succeeded or Failed.
  1442. --*/
  1443. {
  1444. USES_CONVERSION;
  1445. HRESULT hr = E_FAIL;
  1446. CHAR szLogLine[4096];
  1447. long i = 0;
  1448. VARIANT DateTime;
  1449. VARIANT varCustomFieldsArray;
  1450. SYSTEMTIME sysTime;
  1451. CHAR rgchDateTime[ 32];
  1452. const int cFields = 18;
  1453. //
  1454. // Populate Headers
  1455. //
  1456. if (!m_fWriteHeadersInitialized)
  1457. {
  1458. LPSTR szFieldNames[cFields] = {
  1459. EXTLOG_CLIENT_IP_ID,
  1460. EXTLOG_USERNAME_ID,
  1461. EXTLOG_SITE_NAME_ID,
  1462. EXTLOG_COMPUTER_NAME_ID,
  1463. EXTLOG_SERVER_IP_ID,
  1464. EXTLOG_METHOD_ID,
  1465. EXTLOG_URI_STEM_ID,
  1466. EXTLOG_URI_QUERY_ID,
  1467. EXTLOG_HTTP_STATUS_ID,
  1468. EXTLOG_WIN32_STATUS_ID,
  1469. EXTLOG_BYTES_SENT_ID,
  1470. EXTLOG_BYTES_RECV_ID,
  1471. EXTLOG_TIME_TAKEN_ID,
  1472. EXTLOG_SERVER_PORT_ID,
  1473. EXTLOG_PROTOCOL_VERSION_ID,
  1474. EXTLOG_USER_AGENT_ID,
  1475. EXTLOG_COOKIE_ID,
  1476. EXTLOG_REFERER_ID
  1477. };
  1478. m_fWriteHeadersInitialized = TRUE;
  1479. if ( NULL != (m_pLogFields = new LOG_FIELDS[cFields]))
  1480. {
  1481. for (i =0; i < cFields; i++)
  1482. {
  1483. strcpy(m_pLogFields[i].szW3CHeader, szFieldNames[i]);
  1484. m_pLogFields[i].varData.lVal = NULL;
  1485. }
  1486. }
  1487. }
  1488. if (NULL == m_pLogFields)
  1489. {
  1490. return E_OUTOFMEMORY;
  1491. }
  1492. if (SUCCEEDED( pILogScripting->get_ClientIP ( & m_pLogFields[0].varData) ) &&
  1493. SUCCEEDED( pILogScripting->get_UserName ( & m_pLogFields[1].varData) ) &&
  1494. SUCCEEDED( pILogScripting->get_ServiceName ( & m_pLogFields[2].varData) ) &&
  1495. SUCCEEDED( pILogScripting->get_ServerName ( & m_pLogFields[3].varData) ) &&
  1496. SUCCEEDED( pILogScripting->get_ServerIP ( & m_pLogFields[4].varData) ) &&
  1497. SUCCEEDED( pILogScripting->get_Method ( & m_pLogFields[5].varData) ) &&
  1498. SUCCEEDED( pILogScripting->get_URIStem ( & m_pLogFields[6].varData) ) &&
  1499. SUCCEEDED( pILogScripting->get_URIQuery ( & m_pLogFields[7].varData) ) &&
  1500. SUCCEEDED( pILogScripting->get_ProtocolStatus ( & m_pLogFields[8].varData) ) &&
  1501. SUCCEEDED( pILogScripting->get_Win32Status ( & m_pLogFields[9].varData) ) &&
  1502. SUCCEEDED( pILogScripting->get_BytesSent ( & m_pLogFields[10].varData) ) &&
  1503. SUCCEEDED( pILogScripting->get_BytesReceived ( & m_pLogFields[11].varData) ) &&
  1504. SUCCEEDED( pILogScripting->get_TimeTaken ( & m_pLogFields[12].varData) ) &&
  1505. SUCCEEDED( pILogScripting->get_ServerPort ( & m_pLogFields[13].varData) ) &&
  1506. SUCCEEDED( pILogScripting->get_ProtocolVersion( & m_pLogFields[14].varData) ) &&
  1507. SUCCEEDED( pILogScripting->get_UserAgent ( & m_pLogFields[15].varData) ) &&
  1508. SUCCEEDED( pILogScripting->get_Cookie ( & m_pLogFields[16].varData) ) &&
  1509. SUCCEEDED( pILogScripting->get_Referer ( & m_pLogFields[17].varData) ) &&
  1510. SUCCEEDED( pILogScripting->get_CustomFields ( & varCustomFieldsArray ) ) &&
  1511. SUCCEEDED( pILogScripting->get_DateTime ( & DateTime) ) &&
  1512. VariantTimeToSystemTime ( DateTime.date, &sysTime)
  1513. )
  1514. {
  1515. SAFEARRAY * psaCustom = NULL;
  1516. long cItems = 0;
  1517. BSTR HUGEP *pbstr;
  1518. //
  1519. // Build Header
  1520. //
  1521. strcpy(szLogLine, "date time");
  1522. for ( i = 0; i < cFields; i++)
  1523. {
  1524. if ( VT_NULL != m_pLogFields[i].varData.vt)
  1525. {
  1526. strcat(szLogLine, " ");
  1527. strcat(szLogLine, m_pLogFields[i].szW3CHeader);
  1528. }
  1529. }
  1530. if ( (VT_BSTR|VT_ARRAY) == varCustomFieldsArray.vt)
  1531. {
  1532. psaCustom = varCustomFieldsArray.parray;
  1533. if (NULL != psaCustom)
  1534. {
  1535. cItems = psaCustom->rgsabound[1].cElements;
  1536. }
  1537. if ( SUCCEEDED(SafeArrayAccessData(psaCustom, (void HUGEP* FAR*)&pbstr)) )
  1538. {
  1539. for ( i = 0; i < cItems; i++)
  1540. {
  1541. strcat(szLogLine, " ");
  1542. strcat(szLogLine, W2A(pbstr[i]));
  1543. }
  1544. SafeArrayUnaccessData(psaCustom);
  1545. }
  1546. }
  1547. m_DateTimeCache.GetFormattedDateTime( &sysTime, rgchDateTime);
  1548. if ( fWriteHeader || strcmp( szLogLine, m_szWriteHeader.QueryStr()) )
  1549. {
  1550. // Need to write headers
  1551. m_szWriteHeader.Copy(szLogLine);
  1552. wsprintf(szLogLine,
  1553. "#Software: Microsoft Internet Information Services 5.0\n"
  1554. "#Version: %s\n"
  1555. "#Date: %s %s\n"
  1556. "#Fields: %s\n",
  1557. EXTLOG_VERSION,
  1558. rgchDateTime,
  1559. rgchDateTime+strlen(rgchDateTime)+1,
  1560. m_szWriteHeader.QueryStr()
  1561. );
  1562. }
  1563. else
  1564. {
  1565. szLogLine[0] = '\0';
  1566. }
  1567. //
  1568. // Write the fields to the log line
  1569. //
  1570. strcat(szLogLine, rgchDateTime);
  1571. strcat(szLogLine, " ");
  1572. strcat(szLogLine, rgchDateTime+strlen(rgchDateTime)+1);
  1573. for ( i = 0; i < cFields; i++)
  1574. {
  1575. switch (m_pLogFields[i].varData.vt)
  1576. {
  1577. case VT_BSTR:
  1578. strcat(szLogLine, " ");
  1579. strcat( szLogLine, W2A(GetBstrFromVariant( &m_pLogFields[i].varData)) );
  1580. break;
  1581. case VT_I4:
  1582. strcat(szLogLine, " ");
  1583. GetLongFromVariant( &m_pLogFields[i].varData, szLogLine+strlen(szLogLine));
  1584. break;
  1585. case VT_EMPTY:
  1586. strcat (szLogLine, " -");
  1587. break;
  1588. default:
  1589. break;
  1590. }
  1591. }
  1592. if ( (0 < cItems) && SUCCEEDED(SafeArrayAccessData(psaCustom, (void HUGEP* FAR*)&pbstr)) )
  1593. {
  1594. for ( i = 0; i < cItems; i++)
  1595. {
  1596. strcat(szLogLine, " ");
  1597. strcat(szLogLine, W2A(pbstr[cItems + i]));
  1598. }
  1599. SafeArrayUnaccessData(psaCustom);
  1600. }
  1601. fprintf(fpLogFile, "%s\n", szLogLine);
  1602. hr = S_OK;
  1603. }
  1604. return hr;
  1605. }
  1606. /* ************************************************************************************ */
  1607. BOOL
  1608. CEXTLOG::ConvertW3CDateToVariantDate(
  1609. IN PCHAR szDateString,
  1610. IN PCHAR szTimeString,
  1611. OUT DATE * pDateTime)
  1612. /*++
  1613. Routine Description:
  1614. Convert a Date & Time string in the W3C Format to DATE type
  1615. Arguments:
  1616. szDateString - String representing date in format Year-Month-Day
  1617. szTimeString - String representing time in format HH:MM:SS
  1618. pDateTime - Output DATE
  1619. Return Value:
  1620. TRUE - Succeeded
  1621. FALSE - Failed
  1622. --*/
  1623. {
  1624. WORD iVal;
  1625. PCHAR pCh;
  1626. SYSTEMTIME sysTime;
  1627. //
  1628. // Process the Date. Format is 1998-01-27 ( Year-Month-Day )
  1629. //
  1630. memset (&sysTime,0,sizeof(sysTime));
  1631. pCh = szDateString;
  1632. sysTime.wYear = (*pCh-'0')*1000 + ( *(pCh+1)-'0' )*100 +
  1633. ( *(pCh+2)-'0')*10 + ( *(pCh+3)-'0');
  1634. pCh += 5;
  1635. iVal = *pCh -'0';
  1636. if ( *(pCh+1) != '/')
  1637. {
  1638. iVal = iVal*10 + *(pCh+1) - '0';
  1639. pCh++;
  1640. }
  1641. sysTime.wMonth = iVal;
  1642. pCh+=2;
  1643. iVal = *pCh -'0';
  1644. if ( *(pCh+1) != '/')
  1645. {
  1646. iVal = iVal*10 + *(pCh+1) - '0';
  1647. }
  1648. sysTime.wDay = iVal;
  1649. //
  1650. // Process the Time. Format is 10:47:44 ( HH:MM:SS )
  1651. //
  1652. pCh = szTimeString;
  1653. iVal = *pCh -'0';
  1654. if ( *(pCh+1) != ':')
  1655. {
  1656. iVal = iVal*10 + *(pCh+1) - '0';
  1657. pCh++;
  1658. }
  1659. sysTime.wHour = iVal;
  1660. pCh += 2;
  1661. iVal = *pCh -'0';
  1662. if ( *(pCh+1) != ':')
  1663. {
  1664. iVal = iVal*10 + *(pCh+1) - '0';
  1665. pCh++;
  1666. }
  1667. sysTime.wMinute = iVal;
  1668. pCh += 2;
  1669. iVal = *pCh -'0';
  1670. if ( *(pCh+1) != '\0')
  1671. {
  1672. iVal = iVal*10 + *(pCh+1) - '0';
  1673. }
  1674. sysTime.wSecond = iVal;
  1675. return SystemTimeToVariantTime(&sysTime, pDateTime);
  1676. }
  1677. /* ************************************************************************************ */
  1678. /* Support Functions */
  1679. /* ************************************************************************************ */
  1680. VOID
  1681. CEXTLOG::FormNewLogFileName(
  1682. IN LPSYSTEMTIME pstNow
  1683. )
  1684. /*++
  1685. This function that forms the new log file name based on
  1686. type of periodic logging done.
  1687. Arguments:
  1688. pstNow pointer to SystemTime which contains the current time.
  1689. fBackup flag indicating if we want to make current file a backup.
  1690. Returns:
  1691. TRUE on success in forming the name or FALSE if there is any error.
  1692. --*/
  1693. {
  1694. I_FormNewLogFileName(pstNow,DEFAULT_EXTENDED_LOG_FILE_NAME);
  1695. } // INET_FILE_LOG::FormNewLogFileName()
  1696. /* ************************************************************************************ */
  1697. LPCSTR
  1698. CEXTLOG::QueryNoPeriodPattern(
  1699. VOID
  1700. )
  1701. {
  1702. return szExtNoPeriodPattern;
  1703. } // CEXTLOG::QueryNoPeriodPattern
  1704. /* ************************************************************************************ */
  1705. VOID
  1706. CEXTLOG::InternalGetConfig(
  1707. PINETLOG_CONFIGURATIONA pLogConfig
  1708. )
  1709. {
  1710. CLogFileCtrl::InternalGetConfig( pLogConfig );
  1711. pLogConfig->u.logFile.dwFieldMask = m_lMask;
  1712. }
  1713. /* ************************************************************************************ */
  1714. VOID
  1715. CEXTLOG::InternalGetExtraLoggingFields(
  1716. PDWORD pcbSize,
  1717. PCHAR pszFieldsList
  1718. )
  1719. {
  1720. TCHAR *pszTmp = pszFieldsList;
  1721. DWORD dwSize = 0;
  1722. DWORD dwFieldSize;
  1723. if (m_lMask & EXTLOG_HOST ) {
  1724. lstrcpy( pszTmp, "Host:");
  1725. dwFieldSize = (DWORD)strlen(pszTmp)+1;
  1726. pszTmp += dwFieldSize;
  1727. dwSize += dwFieldSize;
  1728. }
  1729. if (m_lMask & EXTLOG_USER_AGENT ) {
  1730. lstrcpy( pszTmp, "User-Agent:");
  1731. dwFieldSize = (DWORD)strlen(pszTmp)+1;
  1732. pszTmp += dwFieldSize;
  1733. dwSize += dwFieldSize;
  1734. }
  1735. if (m_lMask & EXTLOG_COOKIE ) {
  1736. lstrcpy( pszTmp, "Cookie:");
  1737. dwFieldSize = (DWORD)strlen(pszTmp)+1;
  1738. pszTmp += dwFieldSize;
  1739. dwSize += dwFieldSize;
  1740. }
  1741. if (m_lMask & EXTLOG_REFERER ) {
  1742. lstrcpy( pszTmp, "Referer:");
  1743. dwFieldSize = (DWORD)strlen(pszTmp)+1;
  1744. pszTmp += dwFieldSize;
  1745. dwSize += dwFieldSize;
  1746. }
  1747. pszTmp[0]='\0';
  1748. dwSize++;
  1749. *pcbSize = dwSize;
  1750. return;
  1751. } // CEXTLOG::InternalGetExtraLoggingFields
  1752. /* ************************************************************************************ */