/*++ 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 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 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 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 ***********************/