493 lines
15 KiB
C++
493 lines
15 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1996 Microsoft Corporation
|
|||
|
|
|||
|
Module Name :
|
|||
|
httphdr.hxx
|
|||
|
|
|||
|
Abstract:
|
|||
|
This module declares all the variables and functions
|
|||
|
for Dictionary manager.
|
|||
|
It also defines the structure for handling HTTP headers
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Murali R. Krishnan ( MuraliK ) 8-Nov-1996
|
|||
|
|
|||
|
Environment:
|
|||
|
User - Win32
|
|||
|
|
|||
|
Project:
|
|||
|
|
|||
|
Internet Server DLL
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
# ifndef _DICT_HXX_
|
|||
|
# define _DICT_HXX_
|
|||
|
|
|||
|
/************************************************************
|
|||
|
* Include Headers
|
|||
|
************************************************************/
|
|||
|
|
|||
|
# include "buffer.hxx"
|
|||
|
# include "dbgutil.h"
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Format of entries in the ALL_HTTP_FAST_MAP_HEADERS is
|
|||
|
// HfmHeader( enumeration-id, string)
|
|||
|
//
|
|||
|
|
|||
|
# define ALL_HTTP_FAST_MAP_HEADERS() \
|
|||
|
HfmHeader( HM_MET, "method") \
|
|||
|
HfmHeader( HM_URL, "url") \
|
|||
|
HfmHeader( HM_VER, "version") \
|
|||
|
\
|
|||
|
HfmHeader( HM_ACC, "Accept:") \
|
|||
|
HfmHeader( HM_ACL, "Accept-Language:") \
|
|||
|
HfmHeader( HM_CON, "Connection:") \
|
|||
|
HfmHeader( HM_HST, "Host:") \
|
|||
|
HfmHeader( HM_REF, "Referer:") \
|
|||
|
HfmHeader( HM_UAT, "User-Agent:") \
|
|||
|
\
|
|||
|
HfmHeader( HM_PRG, "Pragma:") \
|
|||
|
HfmHeader( HM_COK, "Cookie:") \
|
|||
|
HfmHeader( HM_AUT, "Authorization:") \
|
|||
|
\
|
|||
|
HfmHeader( HM_IMS, "If-Modified-Since:") \
|
|||
|
\
|
|||
|
HfmHeader( HM_UPX, "UA-pixels:") \
|
|||
|
HfmHeader( HM_UCL, "UA-color:") \
|
|||
|
HfmHeader( HM_UOS, "UA-OS:") \
|
|||
|
HfmHeader( HM_CPU, "UA-CPU:") \
|
|||
|
\
|
|||
|
HfmHeader( HM_CLE, "Content-Length:") \
|
|||
|
HfmHeader( HM_CTY, "Content-Type:") \
|
|||
|
\
|
|||
|
HfmHeader( HM_PRA, "Proxy-Authorization:") \
|
|||
|
HfmHeader( HM_PRC, "Proxy-Connection:") \
|
|||
|
\
|
|||
|
HfmHeader( HM_RNG, "Range:") \
|
|||
|
HfmHeader( HM_IFR, "If-Range:") \
|
|||
|
HfmHeader( HM_IFM, "If-Match:") \
|
|||
|
HfmHeader( HM_INM, "If-None-Match:") \
|
|||
|
HfmHeader( HM_UMS, "Unless-Modified-Since:")\
|
|||
|
HfmHeader( HM_IUM, "If-Unmodified-Since:") \
|
|||
|
\
|
|||
|
HfmHeader( HM_TEC, "Transfer-Encoding:") \
|
|||
|
HfmHeader( HM_VIA, "Via:") \
|
|||
|
HfmHeader( HM_FWD, "Forwarded:") \
|
|||
|
HfmHeader( HM_LCK, "Lock-Token:") \
|
|||
|
HfmHeader( HM_TRN, "Translate:") \
|
|||
|
HfmHeader( HM_ISM, "If:") \
|
|||
|
HfmHeader( HM_ACE, "Accept-Encoding:") \
|
|||
|
|
|||
|
|
|||
|
/*------------------------------------------------------------
|
|||
|
* AVG_HTTP_HEADER_LEN
|
|||
|
* o empirically calculated based on the header-len of various
|
|||
|
* headers specified in ALL_HTTP_FAST_MAP_HEADERS
|
|||
|
* If you add a new header, longer than the average value, make
|
|||
|
* sure you update the average as well!!!
|
|||
|
* Include the terminating null-char in your calculation
|
|||
|
------------------------------------------------------------*/
|
|||
|
# define AVG_HTTP_HEADER_LEN (14)
|
|||
|
|
|||
|
|
|||
|
// generate the enumeration IDs
|
|||
|
# define HfmHeader( HfmId, HfmString) HfmId,
|
|||
|
|
|||
|
enum HTTP_FAST_MAP_HEADERS {
|
|||
|
|
|||
|
ALL_HTTP_FAST_MAP_HEADERS()
|
|||
|
|
|||
|
MAX_HTTP_FAST_MAP_HEADERS
|
|||
|
}; // enum HTTP_FAST_MAP_HEADERS
|
|||
|
|
|||
|
# undef HfmHeader
|
|||
|
|
|||
|
|
|||
|
inline BOOL IsValidHfm( IN HTTP_FAST_MAP_HEADERS hfm)
|
|||
|
{
|
|||
|
return ( (HM_MET <= hfm) && ( hfm < MAX_HTTP_FAST_MAP_HEADERS));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// _HTTP_IS_LINEAR_SPACE()
|
|||
|
// Given a character, this function tests if this character is in
|
|||
|
// linear white-space (\t or ' ') character.
|
|||
|
// It optimizes for the case where the character is not a linear white-space
|
|||
|
//
|
|||
|
inline BOOL _HTTP_IS_LINEAR_SPACE( CHAR c)
|
|||
|
{ return ( ((c) <= ' ') && (((c) == ' ') || ((c) == '\t'))); }
|
|||
|
|
|||
|
/************************************************************
|
|||
|
* Type Definitions
|
|||
|
************************************************************/
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Dictionary: provides storage for <name, value> pairs.
|
|||
|
Goals: Insert and lookup has to be fast.
|
|||
|
Amount of memory consumed should be kept as low as possible.
|
|||
|
|
|||
|
Objects:
|
|||
|
DICTIONARY_MAPPER
|
|||
|
- provides a mapping between the string name and ordinal for fast-mapping.
|
|||
|
- one instance per collection of <string, ordinal>s.
|
|||
|
|
|||
|
DICTIONARY
|
|||
|
provides the storage and lookup for a given collection
|
|||
|
Multiple instances of this object can be created, one per input datum.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
class DICTIONARY_MAPPER {
|
|||
|
|
|||
|
public:
|
|||
|
|
|||
|
dllexp
|
|||
|
virtual ~DICTIONARY_MAPPER(VOID) {}
|
|||
|
|
|||
|
dllexp
|
|||
|
virtual BOOL Initialize( VOID) = 0;
|
|||
|
|
|||
|
dllexp virtual
|
|||
|
BOOL FindOrdinal( IN LPCSTR pszName,
|
|||
|
IN INT cchName,
|
|||
|
OUT DWORD * pdwOrdinal) const = 0;
|
|||
|
|
|||
|
dllexp virtual
|
|||
|
LPCSTR FindName( IN DWORD dwOrdinal) const = 0;
|
|||
|
|
|||
|
dllexp virtual
|
|||
|
DWORD NumItems( VOID) const = 0;
|
|||
|
|
|||
|
dllexp virtual
|
|||
|
VOID PrintToBuffer( IN CHAR * pchBuffer,
|
|||
|
IN OUT LPDWORD pcch) const = 0;
|
|||
|
|
|||
|
dllexp virtual VOID Print( VOID) const = 0;
|
|||
|
|
|||
|
}; // class DICTIONARY_MAPPER
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*++
|
|||
|
class HTTP_HEADER_MAPPER
|
|||
|
|
|||
|
o Defines the mapper for mapping the HTTP header names to ordinals.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
class HTTP_HEADER_MAPPER : public DICTIONARY_MAPPER {
|
|||
|
|
|||
|
public:
|
|||
|
|
|||
|
HTTP_HEADER_MAPPER( IN DWORD sigChar)
|
|||
|
: m_nItems ( 0),
|
|||
|
m_nSigChars ( sigChar),
|
|||
|
m_rgOnNameMapper ( NULL),
|
|||
|
DICTIONARY_MAPPER()
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
dllexp virtual ~HTTP_HEADER_MAPPER(VOID);
|
|||
|
|
|||
|
dllexp
|
|||
|
virtual BOOL Initialize( VOID);
|
|||
|
|
|||
|
dllexp virtual
|
|||
|
BOOL FindOrdinal( IN LPCSTR pszName,
|
|||
|
IN INT cchName,
|
|||
|
OUT DWORD * pdwOrdinal) const;
|
|||
|
|
|||
|
dllexp virtual
|
|||
|
LPCSTR FindName( IN DWORD dwOrdinal) const;
|
|||
|
|
|||
|
dllexp virtual
|
|||
|
DWORD NumItems( VOID) const { return ( m_nItems); }
|
|||
|
|
|||
|
dllexp virtual
|
|||
|
VOID PrintToBuffer( IN CHAR * pchBuffer,
|
|||
|
IN OUT LPDWORD pcch) const;
|
|||
|
dllexp virtual VOID Print( VOID) const;
|
|||
|
|
|||
|
DWORD SizeOfNameMapper( VOID) const { return (m_nSigChars * m_nSigChars); }
|
|||
|
VOID SetSigChars( IN DWORD sigChars) { m_nSigChars = sigChars; }
|
|||
|
|
|||
|
private:
|
|||
|
DWORD m_nItems; // # items in the linear space
|
|||
|
DWORD m_nSigChars;
|
|||
|
// same as g_OnFieldNameMapper[] for HTTP headers
|
|||
|
// int m_rgOnNameMapper[ _HTTP_HEADER_SIG_CHARS * _HTTP_HEADER_SIG_CHARS];
|
|||
|
int * m_rgOnNameMapper;
|
|||
|
|
|||
|
}; // class HTTP_HEADER_MAPPER
|
|||
|
|
|||
|
|
|||
|
|
|||
|
# define MAX_HEADERS_PER_CHUNK ( 10)
|
|||
|
|
|||
|
//
|
|||
|
// The following parameter DEFAULT_HTTP_HEADER_LEN is set using empirical data
|
|||
|
// to cover the 80% of requests coming in. This definitely includes the requests
|
|||
|
// used by performance benchmarks.
|
|||
|
// Any revision or change in HTTP or traffic requires that this parameter be
|
|||
|
// tweaked.
|
|||
|
|
|||
|
# define DEFAULT_HTTP_HEADER_LEN ( 1 * 512) // 0.5 KB
|
|||
|
|
|||
|
// Minimum bytes to maintain in the buffer object of HttpHeader Dictionary
|
|||
|
# define HH_MIN (0) // 4 KB
|
|||
|
# define HH_GROW_BY (1 * 1024) // 1 KB
|
|||
|
//Maximum bytes to maintain in the buffer object of the HttpHeader Dictionary
|
|||
|
#define HH_MAX (64 * 1024) //64 KB
|
|||
|
|
|||
|
struct NAME_VALUE_PAIR {
|
|||
|
const CHAR * pchName; // pointer to start of the name
|
|||
|
DWORD cchName; // length of the name
|
|||
|
LPCSTR pchValue; // pointer to value block
|
|||
|
DWORD cchValue; // length of the value block
|
|||
|
|
|||
|
}; // NAME_VALUE_PAIR
|
|||
|
|
|||
|
|
|||
|
|
|||
|
struct HH_ITERATOR {
|
|||
|
PVOID pChunk;
|
|||
|
DWORD dwOrdinal;
|
|||
|
DWORD dwPair;
|
|||
|
|
|||
|
NAME_VALUE_PAIR np;
|
|||
|
}; // struct HH_ITERATOR
|
|||
|
|
|||
|
|
|||
|
|
|||
|
class NAME_VALUE_CHUNK {
|
|||
|
|
|||
|
public:
|
|||
|
NAME_VALUE_CHUNK(VOID)
|
|||
|
{
|
|||
|
Reset();
|
|||
|
}
|
|||
|
|
|||
|
VOID Reset( VOID)
|
|||
|
{
|
|||
|
InitializeListHead( & m_listEntry);
|
|||
|
ZeroMemory( m_rgNVP, sizeof( m_rgNVP));
|
|||
|
m_nPairs = 0;
|
|||
|
}
|
|||
|
|
|||
|
BOOL IsSpaceAvailable( VOID) const
|
|||
|
{ return ( m_nPairs < MAX_HEADERS_PER_CHUNK); }
|
|||
|
|
|||
|
BOOL AddEntry( IN const CHAR * pszHeader, IN DWORD cchHeader,
|
|||
|
IN const CHAR * pszValue, IN DWORD cchValue
|
|||
|
);
|
|||
|
|
|||
|
dllexp NAME_VALUE_PAIR *
|
|||
|
FindEntry( IN const CHAR * pszHeader, IN DWORD cchHeader);
|
|||
|
|
|||
|
dllexp NAME_VALUE_PAIR *
|
|||
|
FindMatchingOrFreeEntry( IN const CHAR * pszHeader,
|
|||
|
IN DWORD cchHeader,
|
|||
|
IN LPBOOL pfFound );
|
|||
|
|
|||
|
dllexp DWORD PrintToBuffer( IN CHAR * pchBuffer,
|
|||
|
IN OUT LPDWORD pcch) const;
|
|||
|
|
|||
|
dllexp BOOL UpdatePointers( IN const CHAR * pchOld,
|
|||
|
IN DWORD cchLen,
|
|||
|
IN const CHAR * pchNew);
|
|||
|
|
|||
|
LIST_ENTRY m_listEntry;
|
|||
|
DWORD m_nPairs;
|
|||
|
DWORD m_dwPadding;
|
|||
|
NAME_VALUE_PAIR m_rgNVP[ MAX_HEADERS_PER_CHUNK];
|
|||
|
|
|||
|
}; // class NAME_VALUE_CHUNK
|
|||
|
|
|||
|
|
|||
|
class HTTP_HEADERS {
|
|||
|
|
|||
|
public:
|
|||
|
|
|||
|
// ----------------------------------------
|
|||
|
// General functions
|
|||
|
// ----------------------------------------
|
|||
|
|
|||
|
dllexp HTTP_HEADERS(VOID);
|
|||
|
dllexp ~HTTP_HEADERS( VOID);
|
|||
|
dllexp VOID Reset( VOID);
|
|||
|
dllexp BOOL ParseInput( IN const CHAR * pchHeaderBlob,
|
|||
|
IN DWORD cchLen,
|
|||
|
OUT DWORD * pcbExtraData
|
|||
|
);
|
|||
|
|
|||
|
dllexp VOID InitIterator( OUT HH_ITERATOR * phi)
|
|||
|
{
|
|||
|
phi->dwOrdinal = 0;
|
|||
|
phi->pChunk = (PVOID)m_ActiveList.Flink;
|
|||
|
phi->dwPair = 0;
|
|||
|
|
|||
|
} // InitIterator()
|
|||
|
|
|||
|
// ----------------------------------------
|
|||
|
// Fast-Map + Chunks Functions
|
|||
|
// ----------------------------------------
|
|||
|
dllexp BOOL StoreHeader(IN const CHAR * pszHeader, IN DWORD cchHeader,
|
|||
|
IN const CHAR * pszValue, IN DWORD cchValue
|
|||
|
);
|
|||
|
|
|||
|
dllexp BOOL StoreHeader(IN const CHAR * pszHeader,
|
|||
|
IN const CHAR * pszValue
|
|||
|
);
|
|||
|
|
|||
|
// Finds the value in both fast-map and non-fast-map chunks
|
|||
|
dllexp CHAR * FindValue( IN LPCSTR pszName,
|
|||
|
OUT LPDWORD pcchValue = NULL);
|
|||
|
|
|||
|
|
|||
|
// Cancel an item from the headers
|
|||
|
dllexp VOID CancelHeader( IN LPCSTR pszName);
|
|||
|
|
|||
|
dllexp BOOL NextPair( IN OUT HH_ITERATOR * phi,
|
|||
|
OUT NAME_VALUE_PAIR ** ppnp
|
|||
|
);
|
|||
|
|
|||
|
// ----------------------------------------
|
|||
|
// Fast Map functions
|
|||
|
// ----------------------------------------
|
|||
|
|
|||
|
// substitute for GetFastMap()->Store()
|
|||
|
dllexp VOID FastMapStore( IN HTTP_FAST_MAP_HEADERS hfm, IN LPCSTR psz)
|
|||
|
{
|
|||
|
DBG_ASSERT( IsValidHfm( hfm));
|
|||
|
m_rgpszHeaders[ hfm] = psz;
|
|||
|
if ( (DWORD ) hfm >= m_iMaxFastMapHeader) {
|
|||
|
m_iMaxFastMapHeader = (DWORD ) hfm + 1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// substitute for GetFastMap()->CheckAndConat()
|
|||
|
dllexp BOOL FastMapStoreWithConcat( IN HTTP_FAST_MAP_HEADERS hfm,
|
|||
|
IN LPCSTR pszValue, IN DWORD cchValue);
|
|||
|
|
|||
|
// substitute for GetFastMap()->Cancel()
|
|||
|
dllexp VOID FastMapCancel( IN HTTP_FAST_MAP_HEADERS hfm)
|
|||
|
{ FastMapStore( hfm, NULL); }
|
|||
|
|
|||
|
// substitute for GetFastMap()->QueryValue( hfm)
|
|||
|
dllexp LPCSTR FastMapQueryValue( IN HTTP_FAST_MAP_HEADERS hfm) const
|
|||
|
{
|
|||
|
DBG_ASSERT( IsValidHfm( hfm));
|
|||
|
return ( m_rgpszHeaders[ hfm]);
|
|||
|
}
|
|||
|
|
|||
|
// substitute for GetFastMap()->QueryStrValue( hfm)
|
|||
|
dllexp LPCSTR FastMapQueryStrValue( IN HTTP_FAST_MAP_HEADERS hfm) const
|
|||
|
{
|
|||
|
DBG_ASSERT( IsValidHfm( hfm));
|
|||
|
return ( (NULL != m_rgpszHeaders[ hfm]) ?
|
|||
|
m_rgpszHeaders[ hfm] : (LPCSTR ) &m_chNull);
|
|||
|
}
|
|||
|
|
|||
|
dllexp DWORD FastMapMaxIndex( VOID) const
|
|||
|
{ return ( m_iMaxFastMapHeader); }
|
|||
|
|
|||
|
// ----------------------------------------
|
|||
|
// Functions on Chunks
|
|||
|
// ----------------------------------------
|
|||
|
|
|||
|
// Finds the <header,value> pair in non-fast-map
|
|||
|
dllexp NAME_VALUE_PAIR *
|
|||
|
FindValueInChunks( IN LPCSTR pszName, IN DWORD cchName);
|
|||
|
|
|||
|
dllexp BOOL
|
|||
|
NextPairInChunks( IN OUT HH_ITERATOR * phi,
|
|||
|
OUT NAME_VALUE_PAIR ** ppnp
|
|||
|
);
|
|||
|
|
|||
|
// ----------------------------------------
|
|||
|
// Diagnostics/Debugging functions
|
|||
|
// ----------------------------------------
|
|||
|
dllexp VOID PrintToBuffer( IN CHAR * pchBuffer,
|
|||
|
IN OUT LPDWORD pcch) const;
|
|||
|
dllexp VOID Print( VOID) const;
|
|||
|
|
|||
|
private:
|
|||
|
DWORD m_iMaxFastMapHeader; // index for the highest filled fast-map header
|
|||
|
LPCSTR m_rgpszHeaders[ MAX_HTTP_FAST_MAP_HEADERS]; // fast map headers
|
|||
|
CHAR m_chNull; // null string
|
|||
|
|
|||
|
CHAR m_rcInlinedHeader[ DEFAULT_HTTP_HEADER_LEN];
|
|||
|
DWORD m_cchHeaders;
|
|||
|
|
|||
|
// Buffer containing the header-chunks
|
|||
|
DWORD m_cchBuffHeaders; // # of bytes in the buffer
|
|||
|
BUFFER m_buffHeaders;
|
|||
|
|
|||
|
// NYI: Consider using singly-linked list
|
|||
|
LIST_ENTRY m_ActiveList; // objects of type NAME_VALUE_CHUNK
|
|||
|
LIST_ENTRY m_FreeList; // objects of type NAME_VALUE_CHUNK
|
|||
|
|
|||
|
|
|||
|
BOOL MakeRoomInBuffer( IN DWORD cchReqd, IN LPCSTR * ppszVal);
|
|||
|
BOOL UpdatePointers( IN const CHAR * pchOld, IN DWORD cchLen,
|
|||
|
IN const CHAR * pchNew);
|
|||
|
|
|||
|
dllexp BOOL ConcatToHolder( IN LPCSTR * ppsz,
|
|||
|
IN LPCSTR pszNew,
|
|||
|
IN DWORD cchNew
|
|||
|
);
|
|||
|
|
|||
|
// Always adds entry in non-fast-map chunks, with concatenation
|
|||
|
dllexp BOOL
|
|||
|
AddEntryToChunks( IN const CHAR * pszHeader, IN DWORD cchHeader,
|
|||
|
IN const CHAR * pszValue, IN DWORD cchValue,
|
|||
|
BOOL fCopyValue = FALSE
|
|||
|
);
|
|||
|
|
|||
|
dllexp VOID
|
|||
|
CancelHeaderInChunks( IN LPCSTR pszName, IN DWORD cchName);
|
|||
|
|
|||
|
BOOL
|
|||
|
ParseHeaderFirstLine( IN const CHAR * pchFirstLine,
|
|||
|
IN CHAR * pchScan,
|
|||
|
IN DWORD cchFirstLine);
|
|||
|
|
|||
|
|
|||
|
public:
|
|||
|
static dllexp BOOL Initialize( VOID);
|
|||
|
static dllexp VOID Cleanup( VOID);
|
|||
|
|
|||
|
|
|||
|
#ifdef _PRIVATE_HTTP_HEADERS_TEST
|
|||
|
static dllexp HTTP_HEADER_MAPPER * QueryHHMapper(void);
|
|||
|
|
|||
|
#endif // _PRIVATE_HTTP_HEADERS_TEST
|
|||
|
|
|||
|
static BOOL
|
|||
|
FindOrdinalForHeader( LPCSTR pszHeader, DWORD cchHeader,
|
|||
|
LPDWORD pdwOrdinal)
|
|||
|
{ return ( sm_hhm.FindOrdinal( pszHeader, cchHeader,
|
|||
|
pdwOrdinal )
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
private:
|
|||
|
dllexp static HTTP_HEADER_MAPPER sm_hhm;
|
|||
|
|
|||
|
}; // class HTTP_HEADERS
|
|||
|
|
|||
|
typedef HTTP_HEADERS * PHHEADERS;
|
|||
|
|
|||
|
# endif // _DICT_HXX_
|
|||
|
|
|||
|
/************************ End of File ***********************/
|