605 lines
12 KiB
C++
605 lines
12 KiB
C++
|
/*++
|
||
|
|
||
|
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 & strPhysicalPath,
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
hr = _strPhysicalPath.Copy( strPhysicalPath );
|
||
|
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,
|
||
|
STRU & strPhysicalPath
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
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
|
||
|
strPhysicalPath - Physical path to dir monitor
|
||
|
|
||
|
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 );
|
||
|
if ( pEntry == NULL )
|
||
|
{
|
||
|
return HRESULT_FROM_WIN32( GetLastError() );
|
||
|
}
|
||
|
|
||
|
hr = pEntry->Create( *(pUrlInfo->QueryMetadataPath()),
|
||
|
strPhysicalPath,
|
||
|
strFullUrl );
|
||
|
if ( FAILED( hr ) )
|
||
|
{
|
||
|
pEntry->DereferenceCacheEntry();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// 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 either 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;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Is compression enabled?
|
||
|
//
|
||
|
|
||
|
if ( pMetaData->QueryDoStaticCompression() )
|
||
|
{
|
||
|
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();
|
||
|
}
|