Source code of Windows XP (NT5)
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.

604 lines
12 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name :
  4. ulcache.cxx
  5. Abstract:
  6. UL cache entries
  7. Author:
  8. Bilal Alam (balam) 11-Nov-2000
  9. Environment:
  10. Win32 - User Mode
  11. Project:
  12. ULW3.DLL
  13. --*/
  14. #include "precomp.hxx"
  15. ALLOC_CACHE_HANDLER * UL_RESPONSE_CACHE_ENTRY::sm_pachUlResponseCache;
  16. HRESULT
  17. UL_RESPONSE_CACHE_KEY::CreateCacheKey(
  18. WCHAR * pszKey,
  19. DWORD cchKey,
  20. BOOL fCopy
  21. )
  22. /*++
  23. Description:
  24. Setup a UL response cache key
  25. Arguments:
  26. pszKey - URL of cache key
  27. cchKey - size of URL
  28. fCopy - Set to TRUE if we should copy the URL, else we just keep a ref
  29. Return:
  30. HRESULT
  31. --*/
  32. {
  33. HRESULT hr;
  34. if ( fCopy )
  35. {
  36. hr = _strKey.Copy( pszKey );
  37. if ( FAILED( hr ) )
  38. {
  39. return hr;
  40. }
  41. _pszKey = _strKey.QueryStr();
  42. _cchKey = _strKey.QueryCCH();
  43. }
  44. else
  45. {
  46. _pszKey = pszKey;
  47. _cchKey = cchKey;
  48. }
  49. return NO_ERROR;
  50. }
  51. //static
  52. HRESULT
  53. UL_RESPONSE_CACHE_ENTRY::Initialize(
  54. VOID
  55. )
  56. /*++
  57. Description:
  58. UL_RESPONSE_CACHE_ENTRY lookaside initialization
  59. Arguments:
  60. None
  61. Return:
  62. HRESULT
  63. --*/
  64. {
  65. ALLOC_CACHE_CONFIGURATION acConfig;
  66. HRESULT hr;
  67. //
  68. // Initialize allocation lookaside
  69. //
  70. acConfig.nConcurrency = 1;
  71. acConfig.nThreshold = 100;
  72. acConfig.cbSize = sizeof( UL_RESPONSE_CACHE_ENTRY );
  73. DBG_ASSERT( sm_pachUlResponseCache == NULL );
  74. sm_pachUlResponseCache = new ALLOC_CACHE_HANDLER( "UL_RESPONSE_CACHE_ENTRY",
  75. &acConfig );
  76. if ( sm_pachUlResponseCache == NULL )
  77. {
  78. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  79. DBGPRINTF(( DBG_CONTEXT,
  80. "Error initializing sm_pachUlResponseCache. hr = 0x%x\n",
  81. hr ));
  82. return hr;
  83. }
  84. return NO_ERROR;
  85. }
  86. //static
  87. VOID
  88. UL_RESPONSE_CACHE_ENTRY::Terminate(
  89. VOID
  90. )
  91. /*++
  92. Description:
  93. UL_RESPONSE_CACHE_ENTRY lookaside cleanup
  94. Arguments:
  95. None
  96. Return:
  97. None
  98. --*/
  99. {
  100. if ( sm_pachUlResponseCache != NULL )
  101. {
  102. delete sm_pachUlResponseCache;
  103. sm_pachUlResponseCache = NULL;
  104. }
  105. }
  106. UL_RESPONSE_CACHE_ENTRY::~UL_RESPONSE_CACHE_ENTRY()
  107. {
  108. _dwSignature = UL_RESPONSE_CACHE_ENTRY_SIGNATURE_FREE;
  109. DBGPRINTF(( DBG_CONTEXT,
  110. "Invalidating URL %ws\n",
  111. _strInvalidationUrl.QueryStr() ));
  112. UlAtqFlushUlCache( _strInvalidationUrl.QueryStr() );
  113. }
  114. HRESULT
  115. UL_RESPONSE_CACHE_ENTRY::Create(
  116. STRU & strMetadataPath,
  117. STRU & strPhysicalPath,
  118. STRU & strInvalidationUrl
  119. )
  120. /*++
  121. Routine Description:
  122. Initialize a ul response cache entry
  123. Arguments:
  124. strMetadataPath - Metadata path associated with this response
  125. strPhysicalPath - Physical path to dir monitor
  126. strInvalidationUrl - Exact URL used to flush the UL response cache
  127. Return Value:
  128. HRESULT
  129. --*/
  130. {
  131. HRESULT hr = NO_ERROR;
  132. hr = _cacheKey.CreateCacheKey( strMetadataPath.QueryStr(),
  133. strMetadataPath.QueryCCH(),
  134. TRUE );
  135. if ( FAILED( hr ) )
  136. {
  137. return hr;
  138. }
  139. hr = _strPhysicalPath.Copy( strPhysicalPath );
  140. if ( FAILED( hr ) )
  141. {
  142. return hr;
  143. }
  144. hr = _strInvalidationUrl.Copy( strInvalidationUrl );
  145. if ( FAILED( hr ) )
  146. {
  147. return hr;
  148. }
  149. return NO_ERROR;
  150. }
  151. BOOL
  152. UL_RESPONSE_CACHE_ENTRY::QueryIsOkToFlushDirmon(
  153. WCHAR * pszPath,
  154. DWORD cchPath
  155. )
  156. /*++
  157. Description:
  158. Is it OK to flush this entry based on the given file which has changed
  159. Arguments:
  160. pszPath - Path that changed
  161. cchPath - Length of path
  162. Return:
  163. TRUE if we should flush, else FALSE
  164. --*/
  165. {
  166. if ( _wcsnicmp( _strPhysicalPath.QueryStr(),
  167. pszPath,
  168. cchPath ) == 0 )
  169. {
  170. return TRUE;
  171. }
  172. else
  173. {
  174. return FALSE;
  175. }
  176. }
  177. UL_RESPONSE_CACHE::UL_RESPONSE_CACHE()
  178. : _fUlCacheEnabled( TRUE )
  179. {
  180. }
  181. UL_RESPONSE_CACHE::~UL_RESPONSE_CACHE()
  182. {
  183. }
  184. HRESULT
  185. UL_RESPONSE_CACHE::SetupUlCachedResponse(
  186. W3_CONTEXT * pW3Context,
  187. STRU & strFullUrl,
  188. STRU & strPhysicalPath
  189. )
  190. /*++
  191. Routine Description:
  192. Build (if necessary) a cache entry which controls the invalidation of
  193. a UL cached response
  194. Arguments:
  195. pW3Context - Context
  196. strFullUrl - Exact URL used to flush the UL response cache
  197. strPhysicalPath - Physical path to dir monitor
  198. Return Value:
  199. HRESULT (if FAILED, then we should not UL cache the response)
  200. --*/
  201. {
  202. UL_RESPONSE_CACHE_KEY ulKey;
  203. UL_RESPONSE_CACHE_ENTRY * pEntry = NULL;
  204. HRESULT hr;
  205. W3_METADATA * pMetaData;
  206. W3_URL_INFO * pUrlInfo;
  207. if ( pW3Context == NULL )
  208. {
  209. DBG_ASSERT( FALSE );
  210. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  211. }
  212. DBG_ASSERT( pW3Context->QueryUrlContext() != NULL );
  213. pMetaData = pW3Context->QueryUrlContext()->QueryMetaData();
  214. DBG_ASSERT( pMetaData != NULL );
  215. pUrlInfo = pW3Context->QueryUrlContext()->QueryUrlInfo();
  216. DBG_ASSERT( pUrlInfo != NULL );
  217. //
  218. // Setup key to lookup whether we already have this response cached
  219. //
  220. hr = ulKey.CreateCacheKey( pUrlInfo->QueryMetadataPath()->QueryStr(),
  221. pUrlInfo->QueryMetadataPath()->QueryCCH(),
  222. FALSE );
  223. if ( FAILED( hr ) )
  224. {
  225. return hr;
  226. }
  227. //
  228. // Find a response entry
  229. //
  230. hr = FindCacheEntry( &ulKey,
  231. (CACHE_ENTRY**) &pEntry );
  232. if ( SUCCEEDED( hr ) )
  233. {
  234. DBG_ASSERT( pEntry != NULL );
  235. //
  236. // Ok. We already have a UL cached entry. Just release it
  237. // and return success
  238. //
  239. pEntry->DereferenceCacheEntry();
  240. return NO_ERROR;
  241. }
  242. //
  243. // Ok. Try to add an entry
  244. //
  245. pEntry = new UL_RESPONSE_CACHE_ENTRY( this );
  246. if ( pEntry == NULL )
  247. {
  248. return HRESULT_FROM_WIN32( GetLastError() );
  249. }
  250. hr = pEntry->Create( *(pUrlInfo->QueryMetadataPath()),
  251. strPhysicalPath,
  252. strFullUrl );
  253. if ( FAILED( hr ) )
  254. {
  255. pEntry->DereferenceCacheEntry();
  256. return hr;
  257. }
  258. //
  259. // Start monitoring the appropriate directory for changes
  260. //
  261. hr = pEntry->AddDirmonInvalidator( pMetaData->QueryDirmonConfig() );
  262. if ( FAILED( hr ) )
  263. {
  264. pEntry->DereferenceCacheEntry();
  265. return hr;
  266. }
  267. //
  268. // Add the cache entry
  269. //
  270. hr = AddCacheEntry( pEntry );
  271. if ( FAILED( hr ) )
  272. {
  273. pEntry->DereferenceCacheEntry();
  274. return hr;
  275. }
  276. //
  277. // Hash table owns a reference now. Just release and return success
  278. //
  279. pEntry->DereferenceCacheEntry();
  280. return NO_ERROR;
  281. }
  282. BOOL
  283. UL_RESPONSE_CACHE::CheckUlCacheability(
  284. W3_CONTEXT * pW3Context
  285. )
  286. /*++
  287. Routine Description:
  288. Determine whether the response for the given context appears cacheable
  289. in UL.
  290. Arguments:
  291. pW3Context - Context describing request
  292. Return Value:
  293. TRUE if response seems ul cachable
  294. --*/
  295. {
  296. HRESULT hr = NO_ERROR;
  297. W3_METADATA * pMetaData = NULL;
  298. URL_CONTEXT * pUrlContext = NULL;
  299. if ( pW3Context == NULL )
  300. {
  301. DBG_ASSERT( FALSE );
  302. return FALSE;
  303. }
  304. pUrlContext = pW3Context->QueryUrlContext();
  305. if ( pUrlContext == NULL )
  306. {
  307. //
  308. // We have no metadata (must be a fatal error)
  309. //
  310. return FALSE;
  311. }
  312. pMetaData = pUrlContext->QueryMetaData();
  313. DBG_ASSERT( pMetaData != NULL );
  314. //
  315. // If UL cache is disabled, then response is not UL cacheable (duh!)
  316. //
  317. if ( !QueryUlCacheEnabled() )
  318. {
  319. return FALSE;
  320. }
  321. if ( !pW3Context->QueryIsUlCacheable() )
  322. {
  323. return FALSE;
  324. }
  325. //
  326. // Only UL cache 200 responses
  327. //
  328. if ( pW3Context->QueryResponse()->QueryStatusCode() !=
  329. HttpStatusOk.statusCode )
  330. {
  331. return FALSE;
  332. }
  333. //
  334. // Is either dynamic compression enabled? Since dynamic compression
  335. // is done later in W3_RESPONSE object, we need to do check now
  336. //
  337. if ( pMetaData->QueryDoDynamicCompression() )
  338. {
  339. return FALSE;
  340. }
  341. //
  342. // Is this a child request?
  343. //
  344. if ( pW3Context->QueryParentContext() != NULL )
  345. {
  346. return FALSE;
  347. }
  348. //
  349. // Is there a current handler which is UL friendly?
  350. //
  351. if ( pW3Context->QueryHandler() == NULL ||
  352. !pW3Context->QueryHandler()->QueryIsUlCacheable() )
  353. {
  354. return FALSE;
  355. }
  356. //
  357. // Are there filters installed which are not cache aware?
  358. //
  359. if ( !pW3Context->QuerySite()->QueryFilterList()->QueryIsUlFriendly() )
  360. {
  361. return FALSE;
  362. }
  363. //
  364. // Is this request accessible anonymously?
  365. //
  366. if ( !( pMetaData->QueryAuthentication() & MD_AUTH_ANONYMOUS ) )
  367. {
  368. return FALSE;
  369. }
  370. //
  371. // Are we doing custom logging?
  372. //
  373. if ( pW3Context->QueryDoCustomLogging() )
  374. {
  375. return FALSE;
  376. }
  377. //
  378. // Do we have special SSL requirements?
  379. //
  380. if ( pMetaData->QueryAccessPerms() &
  381. ( VROOT_MASK_NEGO_CERT |
  382. VROOT_MASK_NEGO_MANDATORY |
  383. VROOT_MASK_MAP_CERT |
  384. VROOT_MASK_SSL128 ) )
  385. {
  386. return FALSE;
  387. }
  388. //
  389. // Is compression enabled?
  390. //
  391. if ( pMetaData->QueryDoStaticCompression() )
  392. {
  393. return FALSE;
  394. }
  395. //
  396. // If we got to here, then we believe we can use the UL cache
  397. //
  398. return TRUE;
  399. }
  400. HRESULT
  401. UL_RESPONSE_CACHE::Initialize(
  402. VOID
  403. )
  404. /*++
  405. Routine Description:
  406. Initialize the cache managing invalidation of the UL cache
  407. Arguments:
  408. None
  409. Return Value:
  410. HRESULT
  411. --*/
  412. {
  413. HRESULT hr;
  414. DWORD dwData;
  415. DWORD dwType;
  416. DWORD cbData = sizeof( DWORD );
  417. HKEY hKey;
  418. //
  419. // First determine how UL is configured by reading UL registry config
  420. //
  421. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  422. L"System\\CurrentControlSet\\Services\\http\\Parameters",
  423. 0,
  424. KEY_READ,
  425. &hKey ) == ERROR_SUCCESS )
  426. {
  427. DBG_ASSERT( hKey != NULL );
  428. //
  429. // Is the UL cache enabled?
  430. //
  431. if ( RegQueryValueEx( hKey,
  432. L"UriEnableCache",
  433. NULL,
  434. &dwType,
  435. (LPBYTE) &dwData,
  436. &cbData ) == ERROR_SUCCESS &&
  437. dwType == REG_DWORD )
  438. {
  439. _fUlCacheEnabled = !!dwData;
  440. }
  441. RegCloseKey( hKey );
  442. }
  443. //
  444. // Setup cache configuration
  445. //
  446. hr = SetCacheConfiguration( 60 * 1000,
  447. INFINITE,
  448. CACHE_INVALIDATION_METADATA |
  449. CACHE_INVALIDATION_DIRMON_FLUSH,
  450. NULL );
  451. if ( FAILED( hr ) )
  452. {
  453. return hr;
  454. }
  455. return UL_RESPONSE_CACHE_ENTRY::Initialize();
  456. }