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.
273 lines
8.7 KiB
273 lines
8.7 KiB
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// INSTDATA.CPP
|
|
//
|
|
// HTTP instance data cache implementation.
|
|
//
|
|
//
|
|
// Copyright 1997 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
|
|
#include "_davprs.h"
|
|
|
|
#include <buffer.h>
|
|
#include "instdata.h"
|
|
|
|
// ========================================================================
|
|
//
|
|
// class CInstData
|
|
//
|
|
|
|
// ------------------------------------------------------------------------
|
|
//
|
|
// CInstData::CInstData()
|
|
//
|
|
// Constructor. Init all variables. Make a copy of the name string
|
|
// for us to keep.
|
|
//
|
|
// NOTE: This object must be constructed while we are REVERTED.
|
|
//
|
|
CInstData::CInstData( LPCWSTR pwszName )
|
|
{
|
|
// Make copy of wide instance name
|
|
//
|
|
m_wszVRoot = WszDupWsz(pwszName);
|
|
|
|
// Parse out and store service instance, otherwise
|
|
// sometimes referred as the server ID.
|
|
//
|
|
m_lServerID = LInstFromVroot( m_wszVRoot );
|
|
|
|
// Create our objects. Please read the notes about the
|
|
// relative costs and reasons behind creating these objects
|
|
// now rather than on demand. Don't create anything here that
|
|
// can be created on demand unless at least one of the
|
|
// following is true:
|
|
//
|
|
// 1. The object is lightweight and cheap to create.
|
|
// Example: an empty cache.
|
|
//
|
|
// 2. The object is used in the processing of a vast
|
|
// majority of HTTP requests.
|
|
// Example: any object used on every GET request.
|
|
//
|
|
|
|
}
|
|
|
|
// ========================================================================
|
|
//
|
|
// class CInstDataCache
|
|
//
|
|
|
|
// ------------------------------------------------------------------------
|
|
//
|
|
// CInstDataCache::GetInstData()
|
|
//
|
|
// Fetch a row from the cache.
|
|
//
|
|
CInstData& CInstDataCache::GetInstData( const IEcb& ecb )
|
|
{
|
|
auto_ref_ptr<CInstData> pinst;
|
|
CStackBuffer<WCHAR> pwszMetaPath;
|
|
UINT cchMetaPath;
|
|
CStackBuffer<WCHAR> pwszVRoot;
|
|
UINT cchVRoot;
|
|
LPCWSTR pwszRootName;
|
|
UINT cchRootName;
|
|
|
|
// Build up a unique string from the vroot and instance:
|
|
// lm/w3svc/<site id>/root/<vroot name>
|
|
//
|
|
|
|
// Get the virtual root from the ecb (/<vroot name>).
|
|
//
|
|
cchRootName = ecb.CchGetVirtualRootW( &pwszRootName );
|
|
|
|
// pwszRootName should still be NULL-terminated. Check it, 'cause
|
|
// we're going to put the next string after there, and we don't want
|
|
// to get them mixed...
|
|
//
|
|
Assert( pwszRootName );
|
|
Assert( L'\0' == pwszRootName[cchRootName] );
|
|
|
|
// Ask IIS for the metabase prefix (lm/w3svc/<site id>) for the
|
|
// virtual server (site) we're on...
|
|
//
|
|
cchMetaPath = pwszMetaPath.celems();
|
|
if (!ecb.FGetServerVariable( "INSTANCE_META_PATH",
|
|
pwszMetaPath.get(),
|
|
reinterpret_cast<DWORD *>(&cchMetaPath) ))
|
|
{
|
|
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
|
|
{
|
|
DebugTrace( "CInstDataCache::GetInstData() - FGetServerVariable() failed"
|
|
" to get INSTANCE_META_PATH\n" );
|
|
throw CLastErrorException();
|
|
}
|
|
|
|
if (NULL == pwszMetaPath.resize(cchMetaPath * sizeof(WCHAR)))
|
|
{
|
|
SetLastError(E_OUTOFMEMORY);
|
|
|
|
DebugTrace( "CInstDataCache::GetInstData() - failed to allocate memory\n" );
|
|
throw CLastErrorException();
|
|
}
|
|
|
|
if (!ecb.FGetServerVariable( "INSTANCE_META_PATH",
|
|
pwszMetaPath.get(),
|
|
reinterpret_cast<DWORD *>(&cchMetaPath) ))
|
|
{
|
|
DebugTrace( "CInstDataCache::GetInstData() - FGetServerVariable() failed"
|
|
" to get INSTANCE_META_PATH\n" );
|
|
throw CLastErrorException();
|
|
}
|
|
}
|
|
|
|
// The function returning server variable returns total number of characters
|
|
// written to the output buffer, so it will include '\0' termination. Let us make
|
|
// sure that the return is what is expected.
|
|
//
|
|
Assert(0 == cchMetaPath ||
|
|
L'\0' == pwszMetaPath[cchMetaPath - 1]);
|
|
|
|
// Adjust the cchMetaPath to reflect the actual character count
|
|
//
|
|
if (0 != cchMetaPath)
|
|
{
|
|
cchMetaPath--;
|
|
}
|
|
|
|
// Check that the root name is either NULL (zero-length string)
|
|
// or has its own separator.
|
|
//
|
|
// NOTE: This is conditional because IF we are installed at the ROOT
|
|
// (on w3svc/1 or w3svc/1/root) and you throw a method against
|
|
// a file that doesn't live under a registered K2 vroot
|
|
// (like /default.asp) -- we DO get called, but the mi.cchMatchingURL
|
|
// comes back as 0, so pwszRootName is a zero-len string.
|
|
// (In IIS terms, you are not really hitting a virtual root,
|
|
// so your vroot is "".)
|
|
// I'm making this assert CONDITIONAL until we figure out more about
|
|
// how we'll handle this particular install case.
|
|
//$REVIEW: The installed-at-the-root case needs to be examined more
|
|
//$REVIEW: becuase we DON'T always build the same instance string
|
|
//$REVIEW: in that case -- we'll still get vroot strings when the URI
|
|
//$REVIEW: hits a resource under a REGISTERED vroot, and so we'll
|
|
//$REVIEW: build different strings for the different vroots, even though
|
|
//$REVIEW: we are running from a single, global install of DAV.
|
|
//$REVIEW: The name might need to be treated as a starting point for a lookup.
|
|
// NTBug #168188: On OPTIONS, "*" is a valid URI. Need to handle this
|
|
// special case without asserting.
|
|
//
|
|
AssertSz( (L'*' == pwszRootName[0] && 1 == cchRootName) ||
|
|
(0 == cchRootName) ||
|
|
(L'/' == pwszRootName[0]),
|
|
"(Non-zero) VRoot name doesn't have expected slash delimiter. Instance name string may be malformed!" );
|
|
|
|
// NTBug # 168188: Special case for OPTIONS * -- map us to the root
|
|
// instdata name of "/w3svc/#/root" (don't want an instdata named
|
|
// "/w3svc/#/root*" that noone else can ever use!).
|
|
//
|
|
cchVRoot = pwszVRoot.celems();
|
|
if (cchVRoot < cchMetaPath + gc_cch_Root + cchRootName + 1)
|
|
{
|
|
cchVRoot = cchMetaPath + gc_cch_Root + cchRootName;
|
|
if (NULL == pwszVRoot.resize(CbSizeWsz(cchVRoot)))
|
|
{
|
|
SetLastError(E_OUTOFMEMORY);
|
|
|
|
DebugTrace( "CInstDataCache::GetInstData() - failed to allocate memory\n" );
|
|
throw CLastErrorException();
|
|
}
|
|
}
|
|
|
|
// Copy first 2 portions: 'lm/w3svc/<site id>' and '/root'
|
|
//
|
|
memcpy(pwszVRoot.get(), pwszMetaPath.get(), cchMetaPath * sizeof(WCHAR));
|
|
memcpy(pwszVRoot.get() + cchMetaPath, gc_wsz_Root, gc_cch_Root * sizeof(WCHAR));
|
|
|
|
// Copy remaining 3-rd portion: '/<vroot name>' and terminate the string.
|
|
// NTBug # 168188: Special case for OPTIONS * -- map us to the root
|
|
// instdata name of "/w3svc/#/root" (don't want an instdata named
|
|
// "/w3svc/#/root*" that noone else can ever use!).
|
|
//
|
|
if (L'*' == pwszRootName[0] && 1 == cchRootName)
|
|
{
|
|
(pwszVRoot.get())[cchMetaPath + gc_cch_Root] = L'\0';
|
|
}
|
|
else
|
|
{
|
|
memcpy(pwszVRoot.get() + cchMetaPath + gc_cch_Root, pwszRootName, cchRootName * sizeof(WCHAR));
|
|
(pwszVRoot.get())[cchMetaPath + gc_cch_Root + cchRootName] = L'\0';
|
|
}
|
|
|
|
// Slam the string to lower-case so that all variations on the vroot
|
|
// name will match. (IIS doesn't allow vroots with the same name --
|
|
// and "VRoot" and "vroot" count as the same!)
|
|
//
|
|
_wcslwr( pwszVRoot.get() );
|
|
|
|
// Demand load the instance data for this vroot
|
|
//
|
|
{
|
|
CRCWsz crcwszVRoot( pwszVRoot.get() );
|
|
|
|
while ( !Instance().m_cache.FFetch( crcwszVRoot, &pinst ) )
|
|
{
|
|
CInitGate ig( L"DAV/CInstDataCache::GetInstData/", pwszVRoot.get() );
|
|
|
|
if ( ig.FInit() )
|
|
{
|
|
// Setup instance data from the system security context,
|
|
// not the client's security context.
|
|
//
|
|
safe_revert sr(ecb.HitUser());
|
|
|
|
pinst = new CInstData(pwszVRoot.get());
|
|
|
|
// Since we are going to use this crcsz as a key in a cache,
|
|
// need to make sure that it's built on a name string that
|
|
// WON'T EVER MOVE (go away, get realloc'd). The stack-based one
|
|
// above just isn't good enough. SO, build a new little CRC-dude
|
|
// on the UNMOVABLE name data in the inst object.
|
|
// (And check that this new crc matches the old one!)
|
|
//
|
|
CRCWsz crcwszAdd( pinst->GetNameW() );
|
|
AssertSz( crcwszVRoot.isequal(crcwszAdd),
|
|
"Two CRC's from the same string don't match!" );
|
|
|
|
Instance().m_cache.Add( crcwszAdd, pinst );
|
|
|
|
// Log the fact that we've got a new instance pluged in.
|
|
// Message DAVPRS_VROOT_ATTACH takes two parameters:
|
|
// the signature of the impl and the vroot.
|
|
//
|
|
//$ RAID:NT:283650: Logging each attach causes a large
|
|
// number of events to be registered. We really should
|
|
// only Log one-time-startup/failure events.
|
|
//
|
|
#undef LOG_STARTUP_EVENT
|
|
#ifdef LOG_STARTUP_EVENT
|
|
{
|
|
LPCWSTR pwszStrings[2];
|
|
|
|
pwszStrings[0] = gc_wszSignature;
|
|
pwszStrings[1] = pwszVRoot.get();
|
|
LogEventW(DAVPRS_VROOT_ATTACH,
|
|
EVENTLOG_INFORMATION_TYPE,
|
|
2,
|
|
pwszStrings,
|
|
0,
|
|
NULL );
|
|
}
|
|
#endif // LOG_STARTUP_EVENT
|
|
//
|
|
//$ RAID:X5:283650: end.
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return *pinst;
|
|
}
|