Leaked source code of windows server 2003
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.
 
 
 
 
 
 

550 lines
12 KiB

#include <syncobj.hxx>
#define INITIAL_HEADERS_COUNT 16
#define HEADERS_INCREMENT 4
#define INVALID_HEADER_INDEX 0xff
#define INVALID_HEADER_SLOT 0xFFFFFFFF
//
// STRESS_BUG_DEBUG - used to catch a specific stress fault,
// where we have a corrupted crit sec.
//
#define CLEAR_DEBUG_CRIT(x)
#define IS_DEBUG_CRIT_OK(x)
typedef enum {
HTTP_METHOD_TYPE_UNKNOWN = -1,
HTTP_METHOD_TYPE_FIRST = 0,
HTTP_METHOD_TYPE_GET= HTTP_METHOD_TYPE_FIRST,
HTTP_METHOD_TYPE_HEAD,
HTTP_METHOD_TYPE_POST,
HTTP_METHOD_TYPE_PUT,
HTTP_METHOD_TYPE_PROPFIND,
HTTP_METHOD_TYPE_PROPPATCH,
HTTP_METHOD_TYPE_LOCK,
HTTP_METHOD_TYPE_UNLOCK,
HTTP_METHOD_TYPE_COPY,
HTTP_METHOD_TYPE_MOVE,
HTTP_METHOD_TYPE_MKCOL,
HTTP_METHOD_TYPE_CONNECT,
HTTP_METHOD_TYPE_DELETE,
HTTP_METHOD_TYPE_LINK,
HTTP_METHOD_TYPE_UNLINK,
HTTP_METHOD_TYPE_BMOVE,
HTTP_METHOD_TYPE_BCOPY,
HTTP_METHOD_TYPE_BPROPFIND,
HTTP_METHOD_TYPE_BPROPPATCH,
HTTP_METHOD_TYPE_BDELETE,
HTTP_METHOD_TYPE_SUBSCRIBE,
HTTP_METHOD_TYPE_UNSUBSCRIBE,
HTTP_METHOD_TYPE_NOTIFY,
HTTP_METHOD_TYPE_POLL,
HTTP_METHOD_TYPE_CHECKIN,
HTTP_METHOD_TYPE_CHECKOUT,
HTTP_METHOD_TYPE_INVOKE,
HTTP_METHOD_TYPE_SEARCH,
HTTP_METHOD_TYPE_PIN,
HTTP_METHOD_TYPE_MPOST,
HTTP_METHOD_TYPE_LAST = HTTP_METHOD_TYPE_MPOST
} HTTP_METHOD_TYPE;
//
// HTTP_HEADERS - array of pointers to general HTTP header strings. Headers are
// stored without line termination. _HeadersLength maintains the cumulative
// amount of buffer space required to store all the headers. Accounts for the
// missing line termination sequence
//
#define HTTP_HEADER_SIGNATURE 0x64616548 // "Head"
class HTTP_HEADERS {
public:
//
// _bKnownHeaders - array of bytes which index into lpHeaders
// the 0 column is an error catcher, so all indexes need to be biased by 1 (++'ed)
//
BYTE _bKnownHeaders[HTTP_QUERY_MAX+2];
private:
#if INET_DEBUG
DWORD _Signature;
#endif
//
// _lpHeaders - (growable) array of pointers to headers added by app
//
HEADER_STRING * _lpHeaders;
//
// _TotalSlots - number of pointers in (i.e. size of) _lpHeaders
//
DWORD _TotalSlots;
//
// _NextOpenSlot - offset where the next array is open for allocation
//
DWORD _NextOpenSlot;
//
// _FreeSlots - number of available headers in _lpHeaders
//
DWORD _FreeSlots;
//
// _HeadersLength - the amount of buffer space required to store the headers.
// For each header, includes +2 for the line termination that must be added
// when the header buffer is generated, or when the headers are queried
//
DWORD _HeadersLength;
//
// _IsRequestHeaders - TRUE if this HTTP_HEADERS object describes the
// request headers
//
BOOL _IsRequestHeaders;
//
// _lpszVerb etc. - in the case of request headers, we maintain these
// pointers and corresponding lengths to make modifying the request line
// easier in the case of a redirect
//
// N.B. The pointers are just offsets into the request line AND MUST NOT BE
// FREED
//
LPSTR _lpszVerb;
DWORD _dwVerbLength;
LPSTR _lpszObjectName;
DWORD _dwObjectNameLength;
LPSTR _lpszVersion;
DWORD _dwVersionLength;
DWORD _RequestVersionMajor;
DWORD _RequestVersionMinor;
//
// _Error - status code if error
//
DWORD _Error;
//
// _CritSec - acquire this when accessing header structure - stops multiple
// threads clashing while modifying headers
//
// Question: why do we allow multi-threaded access to headers on same request?
//
CCritSec _CritSec;
//
// private methods
//
DWORD
AllocateHeaders(
IN DWORD dwNumberOfHeaders
);
public:
HTTP_HEADERS() {
#if INET_DEBUG
_Signature = HTTP_HEADER_SIGNATURE;
#endif
CLEAR_DEBUG_CRIT(_szCritSecBefore);
CLEAR_DEBUG_CRIT(_szCritSecAfter);
_CritSec.Init();
Initialize();
}
~HTTP_HEADERS() {
DEBUG_ENTER((DBG_OBJECTS,
None,
"~HTTP_HEADERS",
"%#x",
this
));
#if INET_DEBUG
INET_ASSERT(_Signature == HTTP_HEADER_SIGNATURE);
#endif
FreeHeaders();
DEBUG_LEAVE(0);
}
VOID Initialize(VOID) {
_lpHeaders = NULL;
_TotalSlots = 0;
_FreeSlots = 0;
_HeadersLength = 0;
_lpszVerb = NULL;
_dwVerbLength = 0;
_lpszObjectName = NULL;
_dwObjectNameLength = 0;
_lpszVersion = NULL;
_dwVersionLength = 0;
_RequestVersionMajor = 0;
_RequestVersionMinor = 0;
_NextOpenSlot = 0;
memset((void *) _bKnownHeaders, INVALID_HEADER_SLOT, ARRAY_ELEMENTS(_bKnownHeaders));
_Error = AllocateHeaders(INITIAL_HEADERS_COUNT);
}
BOOL IsHeaderPresent(DWORD dwQueryIndex) const {
return (_bKnownHeaders[dwQueryIndex] != INVALID_HEADER_INDEX) ? TRUE : FALSE ;
}
BOOL LockHeaders(VOID) {
return _CritSec.Lock();
}
VOID UnlockHeaders(VOID) {
_CritSec.Unlock();
}
VOID
FreeHeaders(
VOID
);
DWORD
CopyHeaders(
IN OUT LPSTR * lpBuffer,
IN LPSTR lpszObjectName,
IN DWORD dwObjectNameLength
);
#ifdef COMPRESSED_HEADERS
VOID
CopyCompressedHeaders(
IN OUT LPSTR * lpBuffer
);
#endif //COMPRESSED_HEADERS
HEADER_STRING *
FASTCALL
FindFreeSlot(
DWORD* piSlot
);
HEADER_STRING *
GetSlot(
DWORD iSlot
)
{
return &_lpHeaders[iSlot];
}
LPSTR GetHeaderPointer (LPBYTE pbBase, DWORD iSlot)
{
INET_ASSERT (iSlot < _TotalSlots);
return _lpHeaders[iSlot].StringAddress((LPSTR) pbBase);
}
VOID
ShrinkHeader(
LPBYTE pbBase,
DWORD iSlot,
DWORD dwOldQueryIndex,
DWORD dwNewQueryIndex,
DWORD cbNewSize
);
DWORD
inline
FastFind(
IN DWORD dwQueryIndex,
IN DWORD dwIndex
);
DWORD
inline
FastNukeFind(
IN DWORD dwQueryIndex,
IN DWORD dwIndex,
OUT BYTE **lplpbPrevIndex
);
DWORD
inline
SlowFind(
IN LPSTR lpBase,
IN LPCSTR lpszHeaderName,
IN DWORD dwHeaderNameLength,
IN DWORD dwIndex,
IN DWORD dwHash,
OUT DWORD *lpdwQueryIndex,
OUT BYTE **lplpbPrevIndex
);
BYTE
inline
FastAdd(
IN DWORD dwQueryIndex,
IN DWORD dwSlot
);
BOOL
inline
HeaderMatch(
IN DWORD dwHash,
IN LPSTR lpszHeaderName,
IN DWORD dwHeaderNameLength,
OUT DWORD *lpdwQueryIndex
);
VOID
RemoveAllByIndex(
IN DWORD dwQueryIndex
);
VOID RemoveHeader(IN DWORD dwIndex, IN DWORD dwQueryIndex, IN BYTE *pbPrevByte) {
INET_ASSERT(dwIndex < _TotalSlots);
INET_ASSERT(dwIndex != 0);
// INET_ASSERT(_HeadersLength > 2);
INET_ASSERT(_lpHeaders[dwIndex].StringLength() > 2);
INET_ASSERT(_FreeSlots <= _TotalSlots);
//
// remove the length of the header + 2 for CR-LF from the total headers
// length
//
if (_HeadersLength) {
_HeadersLength -= _lpHeaders[dwIndex].StringLength()
+ (sizeof("\r\n") - 1)
;
}
//
// Update the cached known headers, if this is one.
//
if ( dwQueryIndex < INVALID_HEADER_INDEX )
{
*pbPrevByte = (BYTE) _lpHeaders[dwIndex].GetNextKnownIndex();
}
//
// set the header string to NULL. Frees the header buffer
//
_lpHeaders[dwIndex] = (LPSTR)NULL;
//
// we have freed a slot in the headers array
//
if ( _FreeSlots == 0 )
{
_NextOpenSlot = dwIndex;
}
++_FreeSlots;
INET_ASSERT(_FreeSlots <= _TotalSlots);
}
DWORD GetSlotsInUse (void) {
return _TotalSlots - _FreeSlots;
}
DWORD HeadersLength(VOID) const {
return _HeadersLength;
}
DWORD ObjectNameLength(VOID) const {
return _dwObjectNameLength;
}
LPSTR ObjectName(VOID) const {
return _lpszObjectName;
}
DWORD
AddHeader(
IN LPSTR lpszHeaderName,
IN DWORD dwHeaderNameLength,
IN LPSTR lpszHeaderValue,
IN DWORD dwHeaderValueLength,
IN DWORD dwIndex,
IN DWORD dwFlags
);
DWORD
AddHeader(
IN DWORD dwQueryIndex,
IN LPSTR lpszHeaderValue,
IN DWORD dwHeaderValueLength,
IN DWORD dwIndex,
IN DWORD dwFlags
);
DWORD
ReplaceHeader(
IN LPSTR lpszHeaderName,
IN DWORD dwHeaderNameLength,
IN LPSTR lpszHeaderValue,
IN DWORD dwHeaderValueLength,
IN DWORD dwIndex,
IN DWORD dwFlags
);
DWORD
ReplaceHeader(
IN DWORD dwQueryIndex,
IN LPSTR lpszHeaderValue,
IN DWORD dwHeaderValueLength,
IN DWORD dwIndex,
IN DWORD dwFlags
);
DWORD
FindHeader(
IN LPSTR lpBase,
IN LPCSTR lpszHeaderName,
IN DWORD dwHeaderNameLength,
IN DWORD dwModifiers,
OUT LPVOID lpBuffer,
IN OUT LPDWORD lpdwBufferLength,
IN OUT LPDWORD lpdwIndex
);
DWORD
FindHeader(
IN LPSTR lpBase,
IN DWORD dwQueryIndex,
IN DWORD dwModifiers,
OUT LPVOID lpBuffer,
IN OUT LPDWORD lpdwBufferLength,
IN OUT LPDWORD lpdwIndex
);
DWORD
FastFindHeader(
IN LPSTR lpBase,
IN DWORD dwQueryIndex,
OUT LPVOID *lplpBuffer,
IN OUT LPDWORD lpdwBufferLength,
IN OUT DWORD dwIndex
);
DWORD
QueryRawHeaders(
IN LPSTR lpBase,
IN BOOL bCrLfTerminated,
IN LPVOID lpBuffer,
IN OUT LPDWORD lpdwBufferLength
);
DWORD
QueryFilteredRawHeaders(
IN LPSTR lpBase,
IN LPSTR *lplpFilterList,
IN DWORD cListElements,
IN BOOL fExclude,
IN BOOL fSkipVerb,
IN BOOL bCrLfTerminated,
IN LPVOID lpBuffer,
IN OUT LPDWORD lpdwBufferLength
);
DWORD
AddRequest(
IN LPSTR lpszVerb,
IN LPSTR lpszObjectName,
IN LPSTR lpszVersion
);
DWORD
ModifyRequest(
IN HTTP_METHOD_TYPE tMethod,
IN LPSTR lpszObjectName,
IN DWORD dwObjectNameLength,
IN LPSTR lpszVersion OPTIONAL,
IN DWORD dwVersionLength
);
HEADER_STRING * GetFirstHeader(VOID) const {
INET_ASSERT(_lpHeaders != NULL);
return _lpHeaders;
}
HEADER_STRING * GetEmptyHeader(VOID) const {
for (DWORD i = 0; i < _TotalSlots; ++i) {
if (_lpHeaders[i].HaveString() && _lpHeaders[i].StringLength() == 0) {
return &_lpHeaders[i];
}
}
return NULL;
}
VOID SetIsRequestHeaders(BOOL bRequestHeaders) {
_IsRequestHeaders = bRequestHeaders;
}
DWORD GetError(VOID) const {
return _Error;
}
LPSTR GetVerb(LPDWORD lpdwVerbLength) const {
*lpdwVerbLength = _dwVerbLength;
return _lpszVerb;
}
//VOID SetRequestVersion(DWORD dwMajor, DWORD dwMinor) {
// _RequestVersionMajor = dwMajor;
// _RequestVersionMinor = dwMinor;
//}
VOID
SetRequestVersion(
VOID
);
DWORD MajorVersion(VOID) const {
return _RequestVersionMajor;
}
DWORD MinorVersion(VOID) const {
return _RequestVersionMinor;
}
};