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
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;
|
|
}
|
|
};
|
|
|
|
|