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.

606 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 * pstrPhysicalPath,
  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. if (pstrPhysicalPath != NULL)
  140. {
  141. hr = _strPhysicalPath.Copy( *pstrPhysicalPath );
  142. if ( FAILED( hr ) )
  143. {
  144. return hr;
  145. }
  146. }
  147. hr = _strInvalidationUrl.Copy( strInvalidationUrl );
  148. if ( FAILED( hr ) )
  149. {
  150. return hr;
  151. }
  152. return NO_ERROR;
  153. }
  154. BOOL
  155. UL_RESPONSE_CACHE_ENTRY::QueryIsOkToFlushDirmon(
  156. WCHAR * pszPath,
  157. DWORD cchPath
  158. )
  159. /*++
  160. Description:
  161. Is it OK to flush this entry based on the given file which has changed
  162. Arguments:
  163. pszPath - Path that changed
  164. cchPath - Length of path
  165. Return:
  166. TRUE if we should flush, else FALSE
  167. --*/
  168. {
  169. if ( _wcsnicmp( _strPhysicalPath.QueryStr(),
  170. pszPath,
  171. cchPath ) == 0 )
  172. {
  173. return TRUE;
  174. }
  175. else
  176. {
  177. return FALSE;
  178. }
  179. }
  180. UL_RESPONSE_CACHE::UL_RESPONSE_CACHE()
  181. : _fUlCacheEnabled( TRUE )
  182. {
  183. }
  184. UL_RESPONSE_CACHE::~UL_RESPONSE_CACHE()
  185. {
  186. }
  187. HRESULT
  188. UL_RESPONSE_CACHE::SetupUlCachedResponse(
  189. W3_CONTEXT * pW3Context,
  190. STRU & strFullUrl,
  191. BOOL fAddDirmonInvalidator,
  192. STRU * pstrPhysicalPath,
  193. DWORD cTTLOverride
  194. )
  195. /*++
  196. Routine Description:
  197. Build (if necessary) a cache entry which controls the invalidation of
  198. a UL cached response
  199. Arguments:
  200. pW3Context - Context
  201. strFullUrl - Exact URL used to flush the UL response cache
  202. fAddDirmonInvalidator - Should we use dirmon to flush the response
  203. pstrPhysicalPath - Physical path to dir monitor
  204. cTTLOverride - Override the default TTL for UL_CACHE_ENTRY and hence for
  205. the response in http.sys cache itself
  206. Return Value:
  207. HRESULT (if FAILED, then we should not UL cache the response)
  208. --*/
  209. {
  210. UL_RESPONSE_CACHE_KEY ulKey;
  211. UL_RESPONSE_CACHE_ENTRY * pEntry = NULL;
  212. HRESULT hr;
  213. W3_METADATA * pMetaData;
  214. W3_URL_INFO * pUrlInfo;
  215. if ( pW3Context == NULL )
  216. {
  217. DBG_ASSERT( FALSE );
  218. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  219. }
  220. DBG_ASSERT( pW3Context->QueryUrlContext() != NULL );
  221. pMetaData = pW3Context->QueryUrlContext()->QueryMetaData();
  222. DBG_ASSERT( pMetaData != NULL );
  223. pUrlInfo = pW3Context->QueryUrlContext()->QueryUrlInfo();
  224. DBG_ASSERT( pUrlInfo != NULL );
  225. //
  226. // Setup key to lookup whether we already have this response cached
  227. //
  228. hr = ulKey.CreateCacheKey( pUrlInfo->QueryMetadataPath()->QueryStr(),
  229. pUrlInfo->QueryMetadataPath()->QueryCCH(),
  230. FALSE );
  231. if ( FAILED( hr ) )
  232. {
  233. return hr;
  234. }
  235. //
  236. // Find a response entry
  237. //
  238. hr = FindCacheEntry( &ulKey,
  239. (CACHE_ENTRY**) &pEntry );
  240. if ( SUCCEEDED( hr ) )
  241. {
  242. DBG_ASSERT( pEntry != NULL );
  243. //
  244. // Ok. We already have a UL cached entry. Just release it
  245. // and return success
  246. //
  247. pEntry->DereferenceCacheEntry();
  248. return NO_ERROR;
  249. }
  250. //
  251. // Ok. Try to add an entry
  252. //
  253. pEntry = new UL_RESPONSE_CACHE_ENTRY( this, cTTLOverride );
  254. if ( pEntry == NULL )
  255. {
  256. return HRESULT_FROM_WIN32( GetLastError() );
  257. }
  258. hr = pEntry->Create( *(pUrlInfo->QueryMetadataPath()),
  259. pstrPhysicalPath,
  260. strFullUrl );
  261. if ( FAILED( hr ) )
  262. {
  263. pEntry->DereferenceCacheEntry();
  264. return hr;
  265. }
  266. if (fAddDirmonInvalidator)
  267. {
  268. //
  269. // Start monitoring the appropriate directory for changes
  270. //
  271. hr = pEntry->AddDirmonInvalidator( pMetaData->QueryDirmonConfig() );
  272. if ( FAILED( hr ) )
  273. {
  274. pEntry->DereferenceCacheEntry();
  275. return hr;
  276. }
  277. }
  278. //
  279. // Add the cache entry
  280. //
  281. hr = AddCacheEntry( pEntry );
  282. if ( FAILED( hr ) )
  283. {
  284. pEntry->DereferenceCacheEntry();
  285. return hr;
  286. }
  287. //
  288. // Hash table owns a reference now. Just release and return success
  289. //
  290. pEntry->DereferenceCacheEntry();
  291. return NO_ERROR;
  292. }
  293. BOOL
  294. UL_RESPONSE_CACHE::CheckUlCacheability(
  295. W3_CONTEXT * pW3Context
  296. )
  297. /*++
  298. Routine Description:
  299. Determine whether the response for the given context appears cacheable
  300. in UL.
  301. Arguments:
  302. pW3Context - Context describing request
  303. Return Value:
  304. TRUE if response seems ul cachable
  305. --*/
  306. {
  307. HRESULT hr = NO_ERROR;
  308. W3_METADATA * pMetaData = NULL;
  309. URL_CONTEXT * pUrlContext = NULL;
  310. if ( pW3Context == NULL )
  311. {
  312. DBG_ASSERT( FALSE );
  313. return FALSE;
  314. }
  315. pUrlContext = pW3Context->QueryUrlContext();
  316. if ( pUrlContext == NULL )
  317. {
  318. //
  319. // We have no metadata (must be a fatal error)
  320. //
  321. return FALSE;
  322. }
  323. pMetaData = pUrlContext->QueryMetaData();
  324. DBG_ASSERT( pMetaData != NULL );
  325. //
  326. // If UL cache is disabled, then response is not UL cacheable (duh!)
  327. //
  328. if ( !QueryUlCacheEnabled() )
  329. {
  330. return FALSE;
  331. }
  332. if ( !pW3Context->QueryIsUlCacheable() )
  333. {
  334. return FALSE;
  335. }
  336. //
  337. // Only UL cache 200 responses
  338. //
  339. if ( pW3Context->QueryResponse()->QueryStatusCode() !=
  340. HttpStatusOk.statusCode )
  341. {
  342. return FALSE;
  343. }
  344. //
  345. // Is dynamic compression enabled? Since dynamic compression
  346. // is done later in W3_RESPONSE object, we need to do check now
  347. //
  348. if ( pMetaData->QueryDoDynamicCompression() )
  349. {
  350. return FALSE;
  351. }
  352. //
  353. // Is this a child request?
  354. //
  355. if ( pW3Context->QueryParentContext() != NULL )
  356. {
  357. return FALSE;
  358. }
  359. //
  360. // Is there a current handler which is UL friendly?
  361. //
  362. if ( pW3Context->QueryHandler() == NULL ||
  363. !pW3Context->QueryHandler()->QueryIsUlCacheable() )
  364. {
  365. return FALSE;
  366. }
  367. //
  368. // Are there filters installed which are not cache aware?
  369. //
  370. if ( !pW3Context->QuerySite()->QueryFilterList()->QueryIsUlFriendly() )
  371. {
  372. return FALSE;
  373. }
  374. //
  375. // Is this request accessible anonymously?
  376. //
  377. if ( !( pMetaData->QueryAuthentication() & MD_AUTH_ANONYMOUS ) )
  378. {
  379. return FALSE;
  380. }
  381. //
  382. // Are we doing custom logging?
  383. //
  384. if ( pW3Context->QueryDoCustomLogging() )
  385. {
  386. return FALSE;
  387. }
  388. //
  389. // Do we have special SSL requirements?
  390. //
  391. if ( pMetaData->QueryAccessPerms() &
  392. ( VROOT_MASK_NEGO_CERT |
  393. VROOT_MASK_NEGO_MANDATORY |
  394. VROOT_MASK_MAP_CERT |
  395. VROOT_MASK_SSL128 ) )
  396. {
  397. return FALSE;
  398. }
  399. //
  400. // If we got to here, then we believe we can use the UL cache
  401. //
  402. return TRUE;
  403. }
  404. HRESULT
  405. UL_RESPONSE_CACHE::Initialize(
  406. VOID
  407. )
  408. /*++
  409. Routine Description:
  410. Initialize the cache managing invalidation of the UL cache
  411. Arguments:
  412. None
  413. Return Value:
  414. HRESULT
  415. --*/
  416. {
  417. HRESULT hr;
  418. DWORD dwData;
  419. DWORD dwType;
  420. DWORD cbData = sizeof( DWORD );
  421. HKEY hKey;
  422. //
  423. // First determine how UL is configured by reading UL registry config
  424. //
  425. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  426. L"System\\CurrentControlSet\\Services\\http\\Parameters",
  427. 0,
  428. KEY_READ,
  429. &hKey ) == ERROR_SUCCESS )
  430. {
  431. DBG_ASSERT( hKey != NULL );
  432. //
  433. // Is the UL cache enabled?
  434. //
  435. if ( RegQueryValueEx( hKey,
  436. L"UriEnableCache",
  437. NULL,
  438. &dwType,
  439. (LPBYTE) &dwData,
  440. &cbData ) == ERROR_SUCCESS &&
  441. dwType == REG_DWORD )
  442. {
  443. _fUlCacheEnabled = !!dwData;
  444. }
  445. RegCloseKey( hKey );
  446. }
  447. //
  448. // Setup cache configuration
  449. //
  450. hr = SetCacheConfiguration( 60 * 1000,
  451. INFINITE,
  452. CACHE_INVALIDATION_METADATA |
  453. CACHE_INVALIDATION_DIRMON_FLUSH,
  454. NULL );
  455. if ( FAILED( hr ) )
  456. {
  457. return hr;
  458. }
  459. return UL_RESPONSE_CACHE_ENTRY::Initialize();
  460. }