urltrack.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 17k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. /*-------------------------------------------------------*/
  2. //Copyright (c) 1997  Microsoft Corporation
  3. //
  4. //Module Name: Url Tracking Log Interfaces
  5. //
  6. //    Urltrack.cpp
  7. //
  8. //
  9. //Author:
  10. //
  11. //    Pei-Hwa Lin (peihwal)  19-March-97
  12. //
  13. //Environment:
  14. //
  15. //    User Mode - Win32
  16. //
  17. //Revision History:
  18. //    5/13/97   due to cache container type change, allow
  19. //              OPEN_ALWAYS when CreateFile
  20. //    5/14/97   remove IsOnTracking, TRACK_ALL, unused code
  21. /*-------------------------------------------------------*/
  22. #include "priv.h"
  23. #include "wininet.h"
  24. #include "basesb.h"
  25. #include "bindcb.h"
  26. const WCHAR c_szPropURL[] = L"HREF";
  27. const WCHAR c_szProptagName[] = L"Item";
  28. const TCHAR c_szLogContainer[] = TEXT("Log");
  29. #define MY_MAX_STRING_LEN           512
  30. //---------------------------------------------------------------------------
  31. //
  32. // IUnknown interfaces
  33. //
  34. //---------------------------------------------------------------------------
  35. HRESULT
  36. CUrlTrackingStg :: QueryInterface(REFIID riid, PVOID *ppvObj)
  37. {
  38.     HRESULT hr = E_NOINTERFACE;
  39.     *ppvObj = NULL;
  40.     if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IUrlTrackingStg))
  41.     {
  42.         AddRef();
  43.         *ppvObj = (LPVOID) SAFECAST(this, IUrlTrackingStg *);
  44.         hr = S_OK;
  45.     }
  46.     return hr;
  47. }
  48. ULONG
  49. CUrlTrackingStg :: AddRef(void)
  50. {
  51.     _cRef ++;
  52.     return _cRef;
  53. }
  54. ULONG
  55. CUrlTrackingStg :: Release(void)
  56. {
  57.     ASSERT(_cRef > 0);
  58.     _cRef--;
  59.     if (!_cRef)
  60.     {
  61.         //time to go bye bye
  62.         delete this;
  63.         return 0;
  64.     }
  65.     return _cRef;
  66. }
  67. //---------------------------------------------------------------------------
  68. //
  69. // C'tor/D'tor
  70. //
  71. //---------------------------------------------------------------------------
  72. CUrlTrackingStg :: CUrlTrackingStg()
  73. {
  74.     _hFile = NULL;
  75.     _pRecords = NULL;
  76.     _lpPfx = NULL;
  77. }
  78. CUrlTrackingStg :: ~CUrlTrackingStg()
  79. {
  80.     // browser exit
  81.     while (_pRecords)
  82.     {
  83.         OnUnload(_pRecords->pthisUrl);
  84.     };
  85. //    DeleteAllNode();    
  86.     if (_lpPfx)
  87.         GlobalFree(_lpPfx);
  88.     if (_hFile)
  89.     {
  90.         CloseHandle(_hFile);
  91.         _hFile = NULL;
  92.     }
  93. }
  94. //---------------------------------------------------------------------------
  95. //
  96. // Helper functions
  97. //
  98. //---------------------------------------------------------------------------
  99. LRecord *
  100. CUrlTrackingStg :: AddNode()
  101. {
  102.     LRecord* pTemp;
  103.     LRecord* pNew = NULL;
  104.     
  105.     pNew = (LRecord *)LocalAlloc(LPTR, sizeof(LRecord));
  106.     if (pNew == NULL)
  107.         return NULL;
  108.     
  109.     pNew->pNext = NULL;
  110.     if (_pRecords == NULL)
  111.     {
  112.         //special case for first node
  113.         _pRecords = pNew;
  114.     }
  115.     else
  116.     {
  117.         for (pTemp = _pRecords; pTemp->pNext; pTemp = pTemp->pNext);
  118.         pTemp->pNext = pNew;
  119.     }
  120.     
  121.     return pNew;
  122. }
  123. void 
  124. CUrlTrackingStg :: DeleteAllNode()
  125. {
  126.    
  127.     do
  128.     {
  129.         DeleteFirstNode();
  130.     }
  131.     while (_pRecords);
  132.     return;
  133. }
  134. void
  135. CUrlTrackingStg :: DeleteFirstNode()
  136. {
  137.     LRecord *pTemp;
  138.     if (!_pRecords)
  139.         return;
  140.     pTemp = _pRecords;
  141.     _pRecords = pTemp->pNext;
  142.     delete [] pTemp->pthisUrl;
  143.     LocalFree(pTemp);
  144.     return;
  145. }
  146. void
  147. CUrlTrackingStg :: DeleteCurrentNode(LRecord *pThis)
  148. {
  149.     LRecord *pPrev;
  150.     
  151.     if (_pRecords == pThis)
  152.     {
  153.         DeleteFirstNode();
  154.         return;
  155.     }
  156.     pPrev = _pRecords;
  157.     do
  158.     {
  159.         if (pPrev->pNext == pThis)
  160.         {
  161.             pPrev->pNext = pThis->pNext;
  162.             delete [] pThis->pthisUrl;
  163.             LocalFree(pThis);
  164.             break;
  165.         }
  166.         pPrev = pPrev->pNext;
  167.     }
  168.     while (pPrev);
  169.     return;
  170. }
  171. //
  172. // return Current node by comparing url strings
  173. //
  174. LRecord*
  175. CUrlTrackingStg :: FindCurrentNode
  176. (
  177.     IN  LPCTSTR       lpUrl
  178. )
  179. {
  180.     LRecord* pThis = NULL;
  181.     ASSERT(_pRecords);
  182.     if (!_pRecords)                 // missed OnLoad
  183.         return NULL;
  184.     pThis = _pRecords;
  185.     do
  186.     {
  187.         if (!StrCmpI(lpUrl, pThis->pthisUrl))
  188.             break;
  189.         pThis = pThis->pNext;
  190.     }
  191.     while (pThis);
  192.     return pThis;
  193. }
  194. void
  195. CUrlTrackingStg :: cleanup()
  196. {
  197.     return;
  198. }
  199. void
  200. CUrlTrackingStg :: DetermineAppModule()
  201. {
  202.     TCHAR   szModule[MAX_PATH];
  203.     LPTSTR  szExt;
  204.         
  205.     if (GetModuleFileName(NULL, szModule, MAX_PATH))        
  206.     {
  207.         szExt = PathFindExtension(szModule);
  208.         TraceMsg(0, "tracking: AppModule %s", szModule);
  209.             
  210.         if (StrCmpI(szExt, TEXT(".SCR")) == 0)
  211.             _fScreenSaver = TRUE;
  212.         else
  213.             _fScreenSaver = FALSE;
  214.                 
  215.     }
  216.     else
  217.         _fScreenSaver = FALSE;
  218.     _fModule = TRUE;
  219. }
  220.             
  221. //---------------------------------------------------------------------------
  222. //
  223. // OnLoad(LPTSTR lpUrl, BRMODE context, BOOL fUseCache)
  224. //      a new page is loaded
  225. //      this function will remember time entering this page, context browsing
  226. //      from and page URL string.
  227. //      (lpUrl does NOT contain "track:" prefix)
  228. //---------------------------------------------------------------------------
  229. HRESULT
  230. CUrlTrackingStg :: OnLoad
  231. (
  232.     IN  LPCTSTR    lpUrl,
  233.     IN  BRMODE     ContextMode,
  234.     IN  BOOL       fUseCache
  235. )
  236. {
  237.     HRESULT     hr = E_OUTOFMEMORY;
  238.     SYSTEMTIME  st;
  239.     LRecord*    pNewNode = NULL;
  240.     GetLocalTime(&st);
  241.     pNewNode = AddNode();
  242.     if (!pNewNode)
  243.         return hr;
  244.     int cch = lstrlen(lpUrl)+1;
  245.     pNewNode->pthisUrl = (LPTSTR)LocalAlloc(LPTR, cch * sizeof(TCHAR));
  246.     if (pNewNode->pthisUrl == NULL)
  247.         return hr;
  248.     // store log info
  249.     StrCpyN(pNewNode->pthisUrl, lpUrl, cch);
  250.     
  251.     if (!_fModule)
  252.         DetermineAppModule();
  253.     // if it's from SS, the fullscreen flag will be set,
  254.     // need to override ContextMode passed in
  255.     if (_fScreenSaver)
  256.         pNewNode->Context = BM_SCREENSAVER;
  257.     else
  258.         pNewNode->Context = (ContextMode > BM_THEATER) ? BM_UNKNOWN : ContextMode;
  259. #if 0   //do not open till urlmon support wininet query flag
  260.     DWORD dwOptions = 0;
  261.     DWORD dwSize;
  262.     WCHAR wszURL[MAX_URL_STRING];
  263.     AnsiToUnicode(lpUrl, wszURL, ARRAYSIZE(wszURL));
  264.     if (SUCCEEDED(CoInitialize(NULL)) && 
  265.         SUCCEEDED(CoInternetQueryInfo(wszURL, (QUERYOPTION)INTERNET_OPTION_REQUEST_FLAGS, 
  266.                             0, &dwOptions, sizeof(DWORD), &dwSize, 0)))
  267.     {
  268.         pNewNode->fuseCache = dwOptions & INTERNET_REQFLAG_FROM_CACHE;
  269.         CoUninitialize();
  270.     }
  271.     else
  272. #endif
  273.     {
  274.         BYTE cei[MAX_CACHE_ENTRY_INFO_SIZE];
  275.         LPINTERNET_CACHE_ENTRY_INFO pcei = (LPINTERNET_CACHE_ENTRY_INFO)cei;
  276.         DWORD       cbcei = MAX_CACHE_ENTRY_INFO_SIZE;
  277.         if (GetUrlCacheEntryInfo(lpUrl, pcei, &cbcei))
  278.             pNewNode->fuseCache = (pcei->dwHitRate - 1) ? TRUE : FALSE;     // off 1 by download
  279.         else
  280.             pNewNode->fuseCache = 0;
  281.     }
  282.     SystemTimeToFileTime(&st, &(pNewNode->ftIn));
  283.     return S_OK; 
  284. }
  285. //---------------------------------------------------------------------------
  286. //
  287. // OnUnLoad(LPTSTR lpUrl)
  288. //      current page is unloaded
  289. //      1)find url cache entry and get file handle
  290. //      2)calculate total time duration visiting this page
  291. //      3)commit delta log string to file cache entry
  292. //      (lpUrl contains "Tracking: " prefix)
  293. //
  294. //---------------------------------------------------------------------------
  295. HRESULT
  296. CUrlTrackingStg :: OnUnload
  297. (
  298.     IN  LPCTSTR   lpUrl
  299. )
  300. {
  301.     HRESULT     hr = E_FAIL;
  302.     LPTSTR       lpPfxUrl = NULL;
  303.     LRecord*    pNode = NULL;;
  304.     SYSTEMTIME  st;
  305.     LPINTERNET_CACHE_ENTRY_INFO pce = NULL;
  306.     TCHAR       lpFile[MAX_PATH];
  307.     
  308.     // 
  309.     GetLocalTime(&st);
  310.     pNode = FindCurrentNode(lpUrl);
  311.     if (!pNode)
  312.     {
  313.         TraceMsg(DM_ERROR, "CUrlTrackingStg: OnUnload (cannot find internal tracking log");
  314.         return hr;
  315.     }
  316.     //QueryCacheEntry() and OpenLogFile() can be combined in one if CacheAPI supports
  317.     //WriteUrlCacheEntryStream()
  318.     ConvertToPrefixedURL(lpUrl, &lpPfxUrl);
  319.     if (!lpPfxUrl)
  320.     {
  321.         return E_OUTOFMEMORY;
  322.     }
  323.     pce = QueryCacheEntry(lpPfxUrl);
  324.     if (!pce)
  325.     {
  326.         TraceMsg(DM_ERROR, "CUrlTrackingStg: OnUnload (cannot find url cache entry)");
  327.         DeleteCurrentNode(pNode);
  328.     
  329.         // free pce
  330.         GlobalFree(lpPfxUrl);
  331.         return hr;
  332.     }
  333.     // work around -- begin
  334.     hr = WininetWorkAround(lpPfxUrl, pce->lpszLocalFileName, &lpFile[0]);
  335.     if (FAILED(hr))
  336.     {
  337.         TraceMsg(DM_ERROR, "CUrlTrackingStg: OnUnload (failed to work around wininet)");
  338.         DeleteCurrentNode(pNode);
  339.         CloseHandle(_hFile);   
  340.         GlobalFree(lpPfxUrl);
  341.         return hr;
  342.     }
  343.     
  344.     hr = UpdateLogFile(pNode, &st);
  345.     // commit change to cache
  346.     if(SUCCEEDED(hr))
  347.     {
  348.         hr = (CommitUrlCacheEntry(lpPfxUrl, 
  349.                 lpFile,    //
  350.                 pce->ExpireTime,                    //ExpireTime
  351.                 pce->LastModifiedTime,              //LastModifiedTime
  352.                 pce->CacheEntryType,
  353.                 NULL,                               //lpHeaderInfo
  354.                 0,                                  //dwHeaderSize
  355.                 NULL,                               //lpszFileExtension
  356.                 0) ) ?                              //reserved
  357.                 S_OK : E_FAIL;
  358.     }
  359.     
  360.     // work around -- end
  361.     DeleteCurrentNode(pNode);
  362.     
  363.     // free pce
  364.     GlobalFree(pce);
  365.     GlobalFree(lpPfxUrl);
  366.     return hr;
  367. }
  368. //---------------------------------------------------------------------------
  369. // 
  370. // Cache helper funcitons
  371. // This is a workaround for Wininet cache
  372. // Later when we commit change to URL cache will fail if localFile size is changed
  373. //  [IN] lpszSourceUrlName and lpszLocalFileName remain the same when calling 
  374. //       this routine
  375. //  [OUT] new local file name 
  376. //
  377. //---------------------------------------------------------------------------
  378. HRESULT CUrlTrackingStg :: WininetWorkAround(LPCTSTR lpszUrl, LPCTSTR lpOldFile, LPTSTR lpFile)
  379. {
  380.     HRESULT  hr = E_FAIL;
  381.     ASSERT(!_hFile);
  382.     if (!CreateUrlCacheEntry(lpszUrl, 512, TEXT("log"), lpFile, 0))
  383.         return E_FAIL;
  384.     
  385.     if (lpOldFile)
  386.     {
  387.         if (!CopyFile(lpOldFile, lpFile, FALSE))
  388.             return E_FAIL;
  389.         DeleteFile(lpOldFile);
  390.     }
  391.     _hFile = OpenLogFile(lpFile);
  392.     return (_hFile != INVALID_HANDLE_VALUE) ? S_OK : E_FAIL;        
  393. }
  394. LPINTERNET_CACHE_ENTRY_INFO
  395. CUrlTrackingStg :: QueryCacheEntry
  396. (
  397.     IN  LPCTSTR     lpUrl
  398. )
  399. {
  400.     // get cache entry info
  401.     LPINTERNET_CACHE_ENTRY_INFO       lpCE = NULL;
  402.     DWORD    dwEntrySize;
  403.     BOOL     bret = FALSE;
  404.     lpCE = (LPINTERNET_CACHE_ENTRY_INFO)GlobalAlloc(LPTR, MAX_CACHE_ENTRY_INFO_SIZE);
  405.     if (lpCE)
  406.     {
  407.         dwEntrySize = MAX_CACHE_ENTRY_INFO_SIZE;
  408.         while (!(bret = GetUrlCacheEntryInfo(lpUrl, lpCE, &dwEntrySize)))
  409.         {
  410.             if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  411.             {
  412.                 GlobalFree(lpCE);
  413.                 lpCE = (LPINTERNET_CACHE_ENTRY_INFO)GlobalAlloc(LPTR, dwEntrySize);
  414.                 if (!lpCE)
  415.                     break;
  416.             }
  417.             else
  418.                 break;
  419.         }
  420.     }
  421.     if (!bret && lpCE)
  422.     {
  423.         GlobalFree(lpCE);
  424.         lpCE = NULL;
  425.         SetLastError(ERROR_FILE_NOT_FOUND);
  426.     }
  427.     return lpCE;
  428. }
  429. //---------------------------------------------------------------------------
  430. // 
  431. // File helper funcitons
  432. //
  433. //---------------------------------------------------------------------------
  434. //
  435. // 1)open log file 
  436. // 2)move file pointer to end of file
  437. //
  438. HANDLE
  439. CUrlTrackingStg :: OpenLogFile
  440. (
  441.     IN LPCTSTR  lpFileName
  442. )
  443. {
  444.     HANDLE hFile = NULL;
  445.     
  446.     hFile = CreateFile(lpFileName,
  447.             GENERIC_WRITE,
  448.             FILE_SHARE_READ,
  449.             NULL,
  450.             OPEN_ALWAYS,
  451.             FILE_ATTRIBUTE_NORMAL,  // | FILE_FLAG_SEQUENTIAL_SCAN,  
  452.             NULL);
  453.     
  454.     if (hFile == INVALID_HANDLE_VALUE)
  455.         return NULL;        
  456.     return hFile;
  457.     
  458. }
  459. const TCHAR c_szLogFormat[] = TEXT("hh':'mm':'ss");
  460. const LPTSTR c_szMode[] = { TEXT("N"),       // normal browsing
  461.                             TEXT("S"),       // screen saver
  462.                             TEXT("D"),       // desktop component
  463.                             TEXT("T"),       // theater mode
  464.                             TEXT("U"),       // unknown
  465.                           };     
  466. HRESULT
  467. CUrlTrackingStg :: UpdateLogFile
  468. (
  469.     IN LRecord*     pNode,
  470.     IN SYSTEMTIME*  pst
  471. )
  472. {
  473.     FILETIME    ftOut;
  474.     DWORD       dwWritten= 0;
  475.     HRESULT     hr = E_FAIL;
  476.     ULARGE_INTEGER ulIn, ulOut, ulTotal;
  477.     ASSERT(_hFile);
  478.     
  479.     // calculate delta of time
  480.     SystemTimeToFileTime(pst, &ftOut);
  481.     // #34829: use 64-bit calculation
  482. ulIn.LowPart = pNode->ftIn.dwLowDateTime;
  483. ulIn.HighPart = pNode->ftIn.dwHighDateTime;
  484. ulOut.LowPart = ftOut.dwLowDateTime;
  485. ulOut.HighPart = ftOut.dwHighDateTime;
  486. QUAD_PART(ulTotal) = QUAD_PART(ulOut) - QUAD_PART(ulIn);
  487.     
  488.     ftOut.dwLowDateTime = ulTotal.LowPart;
  489.     ftOut.dwHighDateTime = ulTotal.HighPart;
  490.     // log string: timeEnter+Duration
  491.     SYSTEMTIME  stOut, stIn;
  492.     TCHAR   lpLogString[MY_MAX_STRING_LEN];
  493.     TCHAR   pTimeIn[10], pTimeOut[10];
  494.     
  495.     FileTimeToSystemTime(&ftOut, &stOut);
  496.     FileTimeToSystemTime(&(pNode->ftIn), &stIn);
  497.     
  498.     GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, &stIn, c_szLogFormat, pTimeIn, 10);
  499.     GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, &stOut, c_szLogFormat, pTimeOut, 10);
  500.     // #34832: add Date in logs
  501.     // #28266: add LFCR in logs
  502.     lpLogString[0] = '';
  503.     wnsprintf(lpLogString, ARRAYSIZE(lpLogString), TEXT("%s %d %.2d-%.2d-%d %s %srn"), 
  504.                                 c_szMode[pNode->Context], 
  505.                                 pNode->fuseCache, 
  506.                                 stIn.wMonth, stIn.wDay, stIn.wYear,
  507.                                 pTimeIn, pTimeOut);
  508.     
  509.     // move file pointer to end
  510.     if (0xFFFFFFFF == SetFilePointer(_hFile, 0, 0, FILE_END))
  511.     {
  512.         CloseHandle(_hFile);
  513.         _hFile = NULL;
  514.         return hr;
  515.     }
  516.     
  517.     // write ANSI string to file
  518.     char szLogInfo[MY_MAX_STRING_LEN];
  519.     SHTCharToAnsi(lpLogString, szLogInfo, ARRAYSIZE(szLogInfo));
  520.     hr = (WriteFile(_hFile, szLogInfo, lstrlenA(szLogInfo), &dwWritten, NULL)) ?
  521.              S_OK : E_FAIL;
  522.        
  523.     CloseHandle(_hFile);
  524.     _hFile = NULL;
  525.     return hr;  
  526. }
  527. //-----------------------------------------------------------------------------
  528. //
  529. // ReadTrackingPrefix
  530. //
  531. // read prefix string from registry
  532. //-----------------------------------------------------------------------------
  533. void
  534. CUrlTrackingStg :: ReadTrackingPrefix(void)
  535. {
  536.     DWORD   cbPfx = 0;
  537.     struct {
  538.         INTERNET_CACHE_CONTAINER_INFO cInfo;
  539.         TCHAR  szBuffer[MAX_PATH+MAX_PATH];
  540.     } ContainerInfo;
  541.     DWORD   dwModified, dwContainer;
  542.     HANDLE  hEnum;
  543.   
  544.     dwContainer = sizeof(ContainerInfo);
  545.     hEnum = FindFirstUrlCacheContainer(&dwModified,
  546.                                        &ContainerInfo.cInfo,
  547.                                        &dwContainer,
  548.                                        0);
  549.     if (hEnum)
  550.     {
  551.         for (;;)
  552.         {
  553.             if (!StrCmpI(ContainerInfo.cInfo.lpszName, c_szLogContainer))
  554.             {
  555.                 DWORD cch = lstrlen(ContainerInfo.cInfo.lpszCachePrefix)+1;
  556.                 ASSERT(ContainerInfo.cInfo.lpszCachePrefix[0]);
  557.                 _lpPfx = (LPTSTR)GlobalAlloc(LPTR, cch * sizeof(TCHAR));
  558.                 if (!_lpPfx)
  559.                     SetLastError(ERROR_OUTOFMEMORY);
  560.                 StrCpyN(_lpPfx, ContainerInfo.cInfo.lpszCachePrefix, cch);
  561.                 break;
  562.             }
  563.             dwContainer = sizeof(ContainerInfo);
  564.             if (!FindNextUrlCacheContainer(hEnum, &ContainerInfo.cInfo, &dwContainer))
  565.             {
  566.                 if (GetLastError() == ERROR_NO_MORE_ITEMS)
  567.                     break;
  568.             }
  569.         }
  570.         FindCloseUrlCache(hEnum);
  571.     }
  572. }
  573. // caller must free lplpPrefixedUrl
  574. BOOL 
  575. CUrlTrackingStg :: ConvertToPrefixedURL(LPCTSTR lpszUrl, LPTSTR *lplpPrefixedUrl)
  576. {
  577.     BOOL    bret = FALSE;
  578.     ASSERT(lpszUrl);
  579.     if (!lpszUrl)
  580.         return bret;
  581.     //ASSERT(lplpPrefixedUrl);
  582.     if (!_lpPfx)
  583.         ReadTrackingPrefix();
  584.     
  585.     if (_lpPfx)
  586.     {
  587.         int len = lstrlen(lpszUrl) + lstrlen(_lpPfx) + 1;
  588.         
  589.         *lplpPrefixedUrl = (LPTSTR)GlobalAlloc(LPTR, len * sizeof(TCHAR));
  590.         if (*lplpPrefixedUrl)
  591.         {
  592.             wnsprintf(*lplpPrefixedUrl, len, TEXT("%s%s"), _lpPfx, lpszUrl);
  593.             bret = TRUE;
  594.         }
  595.     }
  596.     return bret;
  597. }