/*++ Copyright (c) 1999 Microsoft Corporation Module Name : ulcache.cxx Abstract: UL cache entries Author: Bilal Alam (balam) 11-Nov-2000 Environment: Win32 - User Mode Project: ULW3.DLL --*/ #include "precomp.hxx" ALLOC_CACHE_HANDLER * UL_RESPONSE_CACHE_ENTRY::sm_pachUlResponseCache; HRESULT UL_RESPONSE_CACHE_KEY::CreateCacheKey( WCHAR * pszKey, DWORD cchKey, BOOL fCopy ) /*++ Description: Setup a UL response cache key Arguments: pszKey - URL of cache key cchKey - size of URL fCopy - Set to TRUE if we should copy the URL, else we just keep a ref Return: HRESULT --*/ { HRESULT hr; if ( fCopy ) { hr = _strKey.Copy( pszKey ); if ( FAILED( hr ) ) { return hr; } _pszKey = _strKey.QueryStr(); _cchKey = _strKey.QueryCCH(); } else { _pszKey = pszKey; _cchKey = cchKey; } return NO_ERROR; } //static HRESULT UL_RESPONSE_CACHE_ENTRY::Initialize( VOID ) /*++ Description: UL_RESPONSE_CACHE_ENTRY lookaside initialization Arguments: None Return: HRESULT --*/ { ALLOC_CACHE_CONFIGURATION acConfig; HRESULT hr; // // Initialize allocation lookaside // acConfig.nConcurrency = 1; acConfig.nThreshold = 100; acConfig.cbSize = sizeof( UL_RESPONSE_CACHE_ENTRY ); DBG_ASSERT( sm_pachUlResponseCache == NULL ); sm_pachUlResponseCache = new ALLOC_CACHE_HANDLER( "UL_RESPONSE_CACHE_ENTRY", &acConfig ); if ( sm_pachUlResponseCache == NULL ) { hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY ); DBGPRINTF(( DBG_CONTEXT, "Error initializing sm_pachUlResponseCache. hr = 0x%x\n", hr )); return hr; } return NO_ERROR; } //static VOID UL_RESPONSE_CACHE_ENTRY::Terminate( VOID ) /*++ Description: UL_RESPONSE_CACHE_ENTRY lookaside cleanup Arguments: None Return: None --*/ { if ( sm_pachUlResponseCache != NULL ) { delete sm_pachUlResponseCache; sm_pachUlResponseCache = NULL; } } UL_RESPONSE_CACHE_ENTRY::~UL_RESPONSE_CACHE_ENTRY() { _dwSignature = UL_RESPONSE_CACHE_ENTRY_SIGNATURE_FREE; DBGPRINTF(( DBG_CONTEXT, "Invalidating URL %ws\n", _strInvalidationUrl.QueryStr() )); UlAtqFlushUlCache( _strInvalidationUrl.QueryStr() ); } HRESULT UL_RESPONSE_CACHE_ENTRY::Create( STRU & strMetadataPath, STRU * pstrPhysicalPath, STRU & strInvalidationUrl ) /*++ Routine Description: Initialize a ul response cache entry Arguments: strMetadataPath - Metadata path associated with this response strPhysicalPath - Physical path to dir monitor strInvalidationUrl - Exact URL used to flush the UL response cache Return Value: HRESULT --*/ { HRESULT hr = NO_ERROR; hr = _cacheKey.CreateCacheKey( strMetadataPath.QueryStr(), strMetadataPath.QueryCCH(), TRUE ); if ( FAILED( hr ) ) { return hr; } if (pstrPhysicalPath != NULL) { hr = _strPhysicalPath.Copy( *pstrPhysicalPath ); if ( FAILED( hr ) ) { return hr; } } hr = _strInvalidationUrl.Copy( strInvalidationUrl ); if ( FAILED( hr ) ) { return hr; } return NO_ERROR; } BOOL UL_RESPONSE_CACHE_ENTRY::QueryIsOkToFlushDirmon( WCHAR * pszPath, DWORD cchPath ) /*++ Description: Is it OK to flush this entry based on the given file which has changed Arguments: pszPath - Path that changed cchPath - Length of path Return: TRUE if we should flush, else FALSE --*/ { if ( _wcsnicmp( _strPhysicalPath.QueryStr(), pszPath, cchPath ) == 0 ) { return TRUE; } else { return FALSE; } } UL_RESPONSE_CACHE::UL_RESPONSE_CACHE() : _fUlCacheEnabled( TRUE ) { } UL_RESPONSE_CACHE::~UL_RESPONSE_CACHE() { } HRESULT UL_RESPONSE_CACHE::SetupUlCachedResponse( W3_CONTEXT * pW3Context, STRU & strFullUrl, BOOL fAddDirmonInvalidator, STRU * pstrPhysicalPath, DWORD cTTLOverride ) /*++ Routine Description: Build (if necessary) a cache entry which controls the invalidation of a UL cached response Arguments: pW3Context - Context strFullUrl - Exact URL used to flush the UL response cache fAddDirmonInvalidator - Should we use dirmon to flush the response pstrPhysicalPath - Physical path to dir monitor cTTLOverride - Override the default TTL for UL_CACHE_ENTRY and hence for the response in http.sys cache itself Return Value: HRESULT (if FAILED, then we should not UL cache the response) --*/ { UL_RESPONSE_CACHE_KEY ulKey; UL_RESPONSE_CACHE_ENTRY * pEntry = NULL; HRESULT hr; W3_METADATA * pMetaData; W3_URL_INFO * pUrlInfo; if ( pW3Context == NULL ) { DBG_ASSERT( FALSE ); return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } DBG_ASSERT( pW3Context->QueryUrlContext() != NULL ); pMetaData = pW3Context->QueryUrlContext()->QueryMetaData(); DBG_ASSERT( pMetaData != NULL ); pUrlInfo = pW3Context->QueryUrlContext()->QueryUrlInfo(); DBG_ASSERT( pUrlInfo != NULL ); // // Setup key to lookup whether we already have this response cached // hr = ulKey.CreateCacheKey( pUrlInfo->QueryMetadataPath()->QueryStr(), pUrlInfo->QueryMetadataPath()->QueryCCH(), FALSE ); if ( FAILED( hr ) ) { return hr; } // // Find a response entry // hr = FindCacheEntry( &ulKey, (CACHE_ENTRY**) &pEntry ); if ( SUCCEEDED( hr ) ) { DBG_ASSERT( pEntry != NULL ); // // Ok. We already have a UL cached entry. Just release it // and return success // pEntry->DereferenceCacheEntry(); return NO_ERROR; } // // Ok. Try to add an entry // pEntry = new UL_RESPONSE_CACHE_ENTRY( this, cTTLOverride ); if ( pEntry == NULL ) { return HRESULT_FROM_WIN32( GetLastError() ); } hr = pEntry->Create( *(pUrlInfo->QueryMetadataPath()), pstrPhysicalPath, strFullUrl ); if ( FAILED( hr ) ) { pEntry->DereferenceCacheEntry(); return hr; } if (fAddDirmonInvalidator) { // // Start monitoring the appropriate directory for changes // hr = pEntry->AddDirmonInvalidator( pMetaData->QueryDirmonConfig() ); if ( FAILED( hr ) ) { pEntry->DereferenceCacheEntry(); return hr; } } // // Add the cache entry // hr = AddCacheEntry( pEntry ); if ( FAILED( hr ) ) { pEntry->DereferenceCacheEntry(); return hr; } // // Hash table owns a reference now. Just release and return success // pEntry->DereferenceCacheEntry(); return NO_ERROR; } BOOL UL_RESPONSE_CACHE::CheckUlCacheability( W3_CONTEXT * pW3Context ) /*++ Routine Description: Determine whether the response for the given context appears cacheable in UL. Arguments: pW3Context - Context describing request Return Value: TRUE if response seems ul cachable --*/ { HRESULT hr = NO_ERROR; W3_METADATA * pMetaData = NULL; URL_CONTEXT * pUrlContext = NULL; if ( pW3Context == NULL ) { DBG_ASSERT( FALSE ); return FALSE; } pUrlContext = pW3Context->QueryUrlContext(); if ( pUrlContext == NULL ) { // // We have no metadata (must be a fatal error) // return FALSE; } pMetaData = pUrlContext->QueryMetaData(); DBG_ASSERT( pMetaData != NULL ); // // If UL cache is disabled, then response is not UL cacheable (duh!) // if ( !QueryUlCacheEnabled() ) { return FALSE; } if ( !pW3Context->QueryIsUlCacheable() ) { return FALSE; } // // Only UL cache 200 responses // if ( pW3Context->QueryResponse()->QueryStatusCode() != HttpStatusOk.statusCode ) { return FALSE; } // // Is dynamic compression enabled? Since dynamic compression // is done later in W3_RESPONSE object, we need to do check now // if ( pMetaData->QueryDoDynamicCompression() ) { return FALSE; } // // Is this a child request? // if ( pW3Context->QueryParentContext() != NULL ) { return FALSE; } // // Is there a current handler which is UL friendly? // if ( pW3Context->QueryHandler() == NULL || !pW3Context->QueryHandler()->QueryIsUlCacheable() ) { return FALSE; } // // Are there filters installed which are not cache aware? // if ( !pW3Context->QuerySite()->QueryFilterList()->QueryIsUlFriendly() ) { return FALSE; } // // Is this request accessible anonymously? // if ( !( pMetaData->QueryAuthentication() & MD_AUTH_ANONYMOUS ) ) { return FALSE; } // // Are we doing custom logging? // if ( pW3Context->QueryDoCustomLogging() ) { return FALSE; } // // Do we have special SSL requirements? // if ( pMetaData->QueryAccessPerms() & ( VROOT_MASK_NEGO_CERT | VROOT_MASK_NEGO_MANDATORY | VROOT_MASK_MAP_CERT | VROOT_MASK_SSL128 ) ) { return FALSE; } // // If we got to here, then we believe we can use the UL cache // return TRUE; } HRESULT UL_RESPONSE_CACHE::Initialize( VOID ) /*++ Routine Description: Initialize the cache managing invalidation of the UL cache Arguments: None Return Value: HRESULT --*/ { HRESULT hr; DWORD dwData; DWORD dwType; DWORD cbData = sizeof( DWORD ); HKEY hKey; // // First determine how UL is configured by reading UL registry config // if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Services\\http\\Parameters", 0, KEY_READ, &hKey ) == ERROR_SUCCESS ) { DBG_ASSERT( hKey != NULL ); // // Is the UL cache enabled? // if ( RegQueryValueEx( hKey, L"UriEnableCache", NULL, &dwType, (LPBYTE) &dwData, &cbData ) == ERROR_SUCCESS && dwType == REG_DWORD ) { _fUlCacheEnabled = !!dwData; } RegCloseKey( hKey ); } // // Setup cache configuration // hr = SetCacheConfiguration( 60 * 1000, INFINITE, CACHE_INVALIDATION_METADATA | CACHE_INVALIDATION_DIRMON_FLUSH, NULL ); if ( FAILED( hr ) ) { return hr; } return UL_RESPONSE_CACHE_ENTRY::Initialize(); }