339 lines
7.5 KiB
C++
339 lines
7.5 KiB
C++
/*++
|
|
|
|
Copyright (c) 1995-1996 Microsoft Corporation
|
|
|
|
Module Name :
|
|
svmap.h
|
|
|
|
Abstract:
|
|
|
|
|
|
Author:
|
|
|
|
Taylor Weiss ( TaylorW ) 19-Apr-1999
|
|
|
|
Environment:
|
|
|
|
|
|
Project:
|
|
|
|
svmap.lib private\inet\iis\isrtl\svmap
|
|
|
|
Clients:
|
|
|
|
w3svc.dll private\inet\iis\svcs\w3\server
|
|
wam.dll private\inet\iis\svcs\wam\object
|
|
|
|
Functions Exported:
|
|
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#ifndef SVMAP_H
|
|
#define SVMAP_H
|
|
|
|
#include <srvvarid.h>
|
|
|
|
#define SV_DATA_INVALID_OFFSET (~0)
|
|
|
|
// Possibly derive from data dictionary
|
|
class SV_CACHE_MAP
|
|
/*++
|
|
|
|
Class Description:
|
|
|
|
Provides a lookup map for server variable names. Maps names onto
|
|
IDs. Used to cache server variables for out of process applications.
|
|
|
|
The interface for this class is similar to that for the HTTP header
|
|
map.
|
|
|
|
Note: This mapping mechanism is specific to the intended use of this
|
|
class. May want to replace the implementation with an LKR hash.
|
|
The assumption I made was that we would have a lower overhead mapping
|
|
mechanism if it was customized for this purpose.
|
|
|
|
--*/
|
|
{
|
|
public:
|
|
|
|
SV_CACHE_MAP()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create a server variable map.
|
|
|
|
--*/
|
|
{
|
|
// Init the memory for the cache entries - 0xFF is an empty
|
|
// entry
|
|
|
|
::FillMemory( m_rgHashTable, sizeof(m_rgHashTable), ~0 );
|
|
}
|
|
|
|
BOOL Initialize( VOID );
|
|
|
|
BOOL FindOrdinal( IN LPCSTR pszName,
|
|
IN INT cchName,
|
|
OUT DWORD * pdwOrdinal
|
|
) const;
|
|
|
|
LPCSTR FindName( IN DWORD dwOrdinal ) const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return the name of the server variable corresponding to dwOrdinal
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT( dwOrdinal < SVID_COUNT );
|
|
return SV_CACHE_MAP::sm_rgNames[dwOrdinal].name;
|
|
}
|
|
|
|
DWORD NumItems( VOID ) const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return the number of items held in the map.
|
|
|
|
--*/
|
|
{
|
|
return SV_COUNT;
|
|
}
|
|
|
|
DWORD FindLen( IN DWORD dwOrdinal ) const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return the length of the server variable corresponding to dwOrdinal
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT( dwOrdinal < SVID_COUNT );
|
|
return SV_CACHE_MAP::sm_rgNames[dwOrdinal].len;
|
|
}
|
|
|
|
// The Print functions are unsafe and should only be used when
|
|
// debugging and not in regular CHK builds
|
|
VOID PrintToBuffer( IN CHAR * pchBuffer,
|
|
IN OUT LPDWORD pcch
|
|
) const;
|
|
|
|
VOID Print( VOID ) const;
|
|
|
|
private:
|
|
|
|
enum
|
|
{
|
|
SV_COUNT = SVID_COUNT,
|
|
|
|
// Table size based on initial choice of which server variables
|
|
// to cache.
|
|
TABLE_SIZE = 256,
|
|
HASH_MODULUS = 251,
|
|
};
|
|
|
|
// Holds the server variable id.
|
|
struct HASH_TABLE_ENTRY
|
|
/*++
|
|
|
|
Class Description:
|
|
|
|
Since the server variables that are designated as cachable
|
|
are preselected, we can use a simple hash entry structure.
|
|
Each entry can handle four possible values (slots). Since
|
|
the number of server variables is < 128 we use the high bit
|
|
to determine if a slot is empty.
|
|
|
|
The data value is the id of the server variable.
|
|
|
|
--*/
|
|
{
|
|
enum
|
|
{
|
|
MAX_ITEMS = 4,
|
|
ITEM_EMPTY_FLAG = 0x80,
|
|
};
|
|
|
|
BOOL InsertValue( DWORD dwValue )
|
|
{
|
|
DBG_ASSERT( !(dwValue & ITEM_EMPTY_FLAG) );
|
|
|
|
BOOL fReturn = FALSE;
|
|
for( int i = 0; i < MAX_ITEMS; ++i )
|
|
{
|
|
if( items[i] & ITEM_EMPTY_FLAG )
|
|
{
|
|
items[i] = (BYTE)dwValue;
|
|
fReturn = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
return fReturn;
|
|
}
|
|
|
|
BOOL IsSlotEmpty( int item ) const
|
|
{
|
|
DBG_ASSERT( item >= 0 && item < MAX_ITEMS );
|
|
return ( items[item] & ITEM_EMPTY_FLAG );
|
|
}
|
|
|
|
DWORD GetSlotValue( int item ) const
|
|
{
|
|
DBG_ASSERT( item >= 0 && item < MAX_ITEMS );
|
|
return items[item];
|
|
}
|
|
|
|
BYTE items[MAX_ITEMS];
|
|
};
|
|
|
|
// Internal struct used to generate a static table of the
|
|
// server variables that we will cache.
|
|
struct SV_NAME
|
|
{
|
|
LPCSTR name;
|
|
DWORD len;
|
|
};
|
|
|
|
// String hashing routines based on those used by LKR hash.
|
|
|
|
// These are pretty generic and should be customizable given
|
|
// our limited data set. But I wasn't able to come up with
|
|
// anything better.
|
|
|
|
inline DWORD
|
|
HashString( LPCSTR psz ) const
|
|
{
|
|
DWORD dwHash = 0;
|
|
|
|
for ( ; *psz; ++psz)
|
|
{
|
|
dwHash = 37 * dwHash + *psz;
|
|
}
|
|
return dwHash % HASH_MODULUS;
|
|
}
|
|
|
|
inline DWORD
|
|
HashStringWithCount( LPCSTR psz, DWORD *pch ) const
|
|
{
|
|
DWORD dwHash = 0;
|
|
DWORD cch = 0;
|
|
|
|
for ( ; *psz; ++psz, ++cch)
|
|
{
|
|
dwHash = 37 * dwHash + *psz;
|
|
}
|
|
*pch = cch;
|
|
return dwHash % HASH_MODULUS;
|
|
}
|
|
|
|
inline BOOL
|
|
StringMatches(
|
|
IN LPCSTR psz,
|
|
IN DWORD cch,
|
|
IN DWORD dwOrdinal
|
|
) const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compare the given string to the server variable name corresponding
|
|
to dwOrdinal.
|
|
|
|
--*/
|
|
{
|
|
return ( cch == FindLen(dwOrdinal) &&
|
|
strcmp( psz, FindName(dwOrdinal) ) == 0
|
|
);
|
|
}
|
|
|
|
private:
|
|
|
|
// Member data
|
|
|
|
// Our hash table. Maps SV_NAMES to ordinals
|
|
HASH_TABLE_ENTRY m_rgHashTable[TABLE_SIZE];
|
|
|
|
// Static data
|
|
|
|
// Table of the server variables that are cachable
|
|
static SV_NAME sm_rgNames[SV_COUNT];
|
|
};
|
|
|
|
class SV_CACHE_LIST
|
|
/*++
|
|
|
|
Class Description:
|
|
|
|
This actually forms the "cache" of the server variables. We don't
|
|
store any data here only the intent to store data.
|
|
|
|
This class is a list of those server variables that we will retrieve
|
|
and then marshal to the remote application.
|
|
|
|
--*/
|
|
{
|
|
public:
|
|
|
|
DWORD Size( VOID )
|
|
{
|
|
return SVID_COUNT;
|
|
}
|
|
|
|
BOOL GetCacheIt( DWORD item )
|
|
{
|
|
return m_rgItems[item].fCached;
|
|
}
|
|
|
|
VOID SetCacheIt( DWORD item, BOOL fCacheIt = TRUE )
|
|
{
|
|
m_rgItems[item].fCached = fCacheIt;
|
|
}
|
|
|
|
// This is kinda hokey
|
|
|
|
// BUFFER_ITEM and GetBufferItems are use to initialize the
|
|
// array that we will marshal to the remote process. There should
|
|
// be much better way to do this, but I want to avoid any locking
|
|
// issues so keeping around the number of cached items is
|
|
// problematic.
|
|
|
|
struct BUFFER_ITEM
|
|
{
|
|
DWORD svid;
|
|
DWORD dwOffset;
|
|
};
|
|
|
|
VOID
|
|
GetBufferItems
|
|
(
|
|
IN OUT BUFFER_ITEM * pBufferItems,
|
|
IN OUT DWORD * pdwBufferItemCount
|
|
);
|
|
|
|
private:
|
|
|
|
// We are using a single bit to indicate the cached/not-cached
|
|
// status. We want to minimize space usage as this may end up
|
|
// being cached on a per-url basis.
|
|
|
|
struct ITEM
|
|
{
|
|
// Init here or zero the memory in SV_CACHE_LIST ctor
|
|
// It looks like when this is built fre that it does a
|
|
// pretty good job of optimizing it. But if ZeroMemory is
|
|
// linked in locally it might be faster.
|
|
ITEM() : fCached(FALSE) {}
|
|
BOOL fCached : 1;
|
|
};
|
|
|
|
ITEM m_rgItems[SVID_COUNT];
|
|
};
|
|
|
|
|
|
#endif // SVMAP_H
|