windows-nt/Source/XPSP1/NT/inetsrv/iis/iisrearc/ulrtl/misc.c

1179 lines
27 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998-1999 Microsoft Corporation
Module Name:
misc.c
Abstract:
This module contains the miscellaneous UL routines.
Author:
Keith Moore (keithmo) 10-Jun-1998
Revision History:
--*/
#include "precomp.h"
ULONG HttpChars[256];
//
// Private prototypes.
//
NTSTATUS
UlpRestartDeviceControl(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp,
IN PVOID pContext
);
#define FIXUP_PTR( Type, pUserPtr, pKernelPtr, pOffsetPtr, BufferLength ) \
(Type) ((PUCHAR)(pUserPtr) + DIFF((PUCHAR)(pOffsetPtr) - (PUCHAR)(pKernelPtr)))
#ifdef ALLOC_PRAGMA
#endif // ALLOC_PRAGMA
#if 0
NOT PAGEABLE -- UlULongLongToAscii
#endif
//
// Public functions.
//
/***************************************************************************++
Routine Description:
Converts the given ULONGLLONG to an ASCII representation and stores it
in the given string.
Arguments:
String - Receives the ASCII representation of the ULONGLONG.
Value - Supplies the ULONGLONG to convert.
Return Value:
PSTR - Pointer to the next character in String *after* the converted
ULONGLONG.
--***************************************************************************/
PSTR
UlULongLongToAscii(
IN PSTR String,
IN ULONGLONG Value
)
{
PSTR p1;
PSTR p2;
CHAR ch;
ULONG digit;
//
// Special case 0 to make the rest of the routine simpler.
//
if (Value == 0)
{
*String++ = '0';
}
else
{
//
// Convert the ULONG. Note that this will result in the string
// being backwards in memory.
//
p1 = String;
p2 = String;
while (Value != 0)
{
digit = (ULONG)( Value % 10 );
Value = Value / 10;
*p1++ = '0' + (CHAR)digit;
}
//
// Reverse the string.
//
String = p1;
p1--;
while (p1 > p2)
{
ch = *p1;
*p1 = *p2;
*p2 = ch;
p2++;
p1--;
}
}
*String = '\0';
return String;
} // UlULongLongToAscii
NTSTATUS
_RtlIntegerToUnicode(
IN ULONG Value,
IN ULONG Base OPTIONAL,
IN LONG BufferLength,
OUT PWSTR String
)
{
PWSTR p1;
PWSTR p2;
WCHAR ch;
ULONG digit;
//
// Special case 0 to make the rest of the routine simpler.
//
if (Value == 0)
{
*String++ = L'0';
}
else
{
//
// Convert the ULONG. Note that this will result in the string
// being backwards in memory.
//
p1 = String;
p2 = String;
while (Value != 0)
{
digit = (ULONG)( Value % 10 );
Value = Value / 10;
*p1++ = L'0' + (WCHAR)digit;
}
//
// Reverse the string.
//
String = p1;
p1--;
while (p1 > p2)
{
ch = *p1;
*p1 = *p2;
*p2 = ch;
p2++;
p1--;
}
}
*String = L'\0';
return STATUS_SUCCESS;
} // _RtlIntegerToUnicode
/***************************************************************************++
Routine Description:
Converts an ansi string to an integer. fails if any non-digit characters
appears in the string. fails on negative numbers, and assumes no preceding
spaces.
Arguments:
PUCHAR pString the string to convert
ULONG Base the base, must be 10 or 16
PULONG pValue the return value of the converted integer
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlAnsiToULongLong(
PUCHAR pString,
ULONG Base,
PULONGLONG pValue
)
{
ULONGLONG Value;
ULONGLONG NewValue;
if (Base != 10 && Base != 16)
RETURN(STATUS_INVALID_PARAMETER);
//
// No preceding space, we already skipped it
//
ASSERT(IS_HTTP_LWS(pString[0]) == FALSE);
Value = 0;
while (pString[0] != ANSI_NULL)
{
if (
(Base == 10 && IS_HTTP_DIGIT(pString[0]) == FALSE) ||
(Base == 16 && IS_HTTP_HEX(pString[0]) == FALSE)
)
{
//
// Not valid , bad!
//
RETURN(STATUS_INVALID_PARAMETER);
}
if (Base == 16)
{
if (IS_HTTP_ALPHA(pString[0]))
{
NewValue = 16 * Value + (UPCASE_CHAR(pString[0]) - 'A' + 10);
}
else
{
NewValue = 16 * Value + (pString[0] - '0');
}
}
else
{
NewValue = 10 * Value + (pString[0] - '0');
}
if (NewValue < Value)
{
//
// Very bad... we overflew
//
RETURN(STATUS_SECTION_TOO_BIG);
}
Value = NewValue;
pString += 1;
}
*pValue = Value;
return STATUS_SUCCESS;
} // UlAnsiToULongLong
/***************************************************************************++
Routine Description:
Converts a unicode string to an integer. fails if any non-digit characters
appear in the string. fails on negative numbers, and assumes no preceding
spaces.
Arguments:
PWCHAR pString the string to convert
ULONG Base the base, must be 10 or 16
PULONG pValue the return value of the converted integer
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlUnicodeToULongLong(
PWCHAR pString,
ULONG Base,
PULONGLONG pValue
)
{
ULONGLONG Value;
ULONGLONG NewValue;
if (Base != 10 && Base != 16)
RETURN(STATUS_INVALID_PARAMETER);
//
// No preceding space, we already skipped it
//
ASSERT(pString[0] < 128 && IS_HTTP_LWS(pString[0]) == FALSE);
Value = 0;
while (pString[0] != UNICODE_NULL)
{
if ((Base == 10 &&
(pString[0] >= 128 || IS_HTTP_DIGIT(pString[0]) == FALSE)) ||
(Base == 16 &&
(pString[0] >= 128 || IS_HTTP_HEX(pString[0]) == FALSE)))
{
//
// Not valid , bad!
//
RETURN(STATUS_INVALID_PARAMETER);
}
if (Base == 16)
{
if (IS_HTTP_ALPHA(pString[0]))
{
NewValue = 16 * Value + (pString[0] - L'A' + 10);
}
else
{
NewValue = 16 * Value + (pString[0] - L'0');
}
}
else
{
NewValue = 10 * Value + (pString[0] - L'0');
}
if (NewValue < Value)
{
//
// Very bad... we overflew
//
RETURN(STATUS_INVALID_PARAMETER);
}
Value = NewValue;
pString += 1;
}
*pValue = Value;
return STATUS_SUCCESS;
} // UlUnicodeToULongLong
//
// Private routines.
//
/*++
Routine Description:
Routine to initialize the utilitu code.
Arguments:
Return Value:
--*/
NTSTATUS
InitializeHttpUtil(
VOID
)
{
ULONG i;
// Initialize the HttpChars array appropriately.
for (i = 0; i < 128; i++)
{
HttpChars[i] = HTTP_CHAR;
}
for (i = 'A'; i <= 'Z'; i++)
{
HttpChars[i] |= HTTP_UPCASE;
}
for (i = 'a'; i <= 'z'; i++)
{
HttpChars[i] |= HTTP_LOCASE;
}
for (i = '0'; i <= '9'; i++)
{
HttpChars[i] |= (HTTP_DIGIT | HTTP_HEX);
}
for (i = 0; i <= 31; i++)
{
HttpChars[i] |= HTTP_CTL;
}
HttpChars[127] |= HTTP_CTL;
HttpChars[SP] |= HTTP_LWS;
HttpChars[HT] |= HTTP_LWS;
for (i = 'A'; i <= 'F'; i++)
{
HttpChars[i] |= HTTP_HEX;
}
for (i = 'a'; i <= 'f'; i++)
{
HttpChars[i] |= HTTP_HEX;
}
HttpChars['('] |= HTTP_SEPERATOR;
HttpChars[')'] |= HTTP_SEPERATOR;
HttpChars['<'] |= HTTP_SEPERATOR;
HttpChars['>'] |= HTTP_SEPERATOR;
HttpChars['@'] |= HTTP_SEPERATOR;
HttpChars[','] |= HTTP_SEPERATOR;
HttpChars[';'] |= HTTP_SEPERATOR;
HttpChars[':'] |= HTTP_SEPERATOR;
HttpChars['\\'] |= HTTP_SEPERATOR;
HttpChars['"'] |= HTTP_SEPERATOR;
HttpChars['/'] |= HTTP_SEPERATOR;
HttpChars['['] |= HTTP_SEPERATOR;
HttpChars[']'] |= HTTP_SEPERATOR;
HttpChars['?'] |= HTTP_SEPERATOR;
HttpChars['='] |= HTTP_SEPERATOR;
HttpChars['{'] |= HTTP_SEPERATOR;
HttpChars['}'] |= HTTP_SEPERATOR;
HttpChars[SP] |= HTTP_SEPERATOR;
HttpChars[HT] |= HTTP_SEPERATOR;
//
// URL "reserved" characters (rfc2396)
//
HttpChars[';'] |= URL_LEGAL;
HttpChars['/'] |= URL_LEGAL;
HttpChars['\\'] |= URL_LEGAL;
HttpChars['?'] |= URL_LEGAL;
HttpChars[':'] |= URL_LEGAL;
HttpChars['@'] |= URL_LEGAL;
HttpChars['&'] |= URL_LEGAL;
HttpChars['='] |= URL_LEGAL;
HttpChars['+'] |= URL_LEGAL;
HttpChars['$'] |= URL_LEGAL;
HttpChars[','] |= URL_LEGAL;
//
// URL escape character
//
HttpChars['%'] |= URL_LEGAL;
//
// URL "mark" characters (rfc2396)
//
HttpChars['-'] |= URL_LEGAL;
HttpChars['_'] |= URL_LEGAL;
HttpChars['.'] |= URL_LEGAL;
HttpChars['!'] |= URL_LEGAL;
HttpChars['~'] |= URL_LEGAL;
HttpChars['*'] |= URL_LEGAL;
HttpChars['\''] |= URL_LEGAL;
HttpChars['('] |= URL_LEGAL;
HttpChars[')'] |= URL_LEGAL;
for (i = 0; i < 128; i++)
{
if (!IS_HTTP_SEPERATOR(i) && !IS_HTTP_CTL(i))
{
HttpChars[i] |= HTTP_TOKEN;
}
}
return STATUS_SUCCESS;
}
//
// constants used by the date formatter
//
const PWSTR pDays[] =
{
L"Sun", L"Mon", L"Tue", L"Wed", L"Thu", L"Fri", L"Sat"
};
const PWSTR pMonths[] =
{
L"Jan", L"Feb", L"Mar", L"Apr", L"May", L"Jun", L"Jul",
L"Aug", L"Sep", L"Oct", L"Nov", L"Dec"
};
__inline
VOID
TwoDigitsToUnicode(
PWSTR pBuffer,
ULONG Number
)
{
pBuffer[0] = L'0' + (WCHAR)(Number / 10);
pBuffer[1] = L'0' + (WCHAR)(Number % 10);
}
/***************************************************************************++
Routine Description:
Converts the given system time to string representation containing
GMT Formatted String.
Arguments:
pTime - System time that needs to be converted.
pBuffer - pointer to string which will contain the GMT time on
successful return.
BufferLength - size of pszBuff in bytes
Return Value:
NTSTATUS
History:
MuraliK 3-Jan-1995
paulmcd 4-Mar-1999 copied to ul
--***************************************************************************/
NTSTATUS
TimeFieldsToHttpDate(
IN PTIME_FIELDS pTime,
OUT PWSTR pBuffer,
IN ULONG BufferLength
)
{
NTSTATUS Status;
ASSERT(pBuffer != NULL);
if (BufferLength < (HTTP_DATE_COUNT + 1)*sizeof(WCHAR))
{
return STATUS_BUFFER_TOO_SMALL;
}
// 0 1 2
// 01234567890123456789012345678
// Formats a string like: "Thu, 14 Jul 1994 15:26:05 GMT"
//
//
// write the constants
//
pBuffer[3] = L',';
pBuffer[4] = pBuffer[7] = pBuffer[11] = L' ';
pBuffer[19] = pBuffer[22] = L':';
//
// now the variants
//
//
// 0-based Weekday
//
RtlCopyMemory(&(pBuffer[0]), pDays[pTime->Weekday], 3*sizeof(WCHAR));
TwoDigitsToUnicode(&(pBuffer[5]), pTime->Day);
//
// 1-based Month
//
RtlCopyMemory(&(pBuffer[8]), pMonths[pTime->Month - 1], 3*sizeof(WCHAR)); // 1-based
Status = _RtlIntegerToUnicode(pTime->Year, 10, 5, &(pBuffer[12]));
ASSERT(NT_SUCCESS(Status));
pBuffer[16] = L' ';
TwoDigitsToUnicode(&(pBuffer[17]), pTime->Hour);
TwoDigitsToUnicode(&(pBuffer[20]), pTime->Minute);
TwoDigitsToUnicode(&(pBuffer[23]), pTime->Second);
RtlCopyMemory(&(pBuffer[25]), L" GMT", sizeof(L" GMT"));
return STATUS_SUCCESS;
} // TimeFieldsToHttpDate
ULONG
_MultiByteToWideCharWin9x(
ULONG uCodePage,
ULONG dwFlags,
PCSTR lpMultiByteStr,
int cchMultiByte,
PWSTR lpWideCharStr,
int cchWideChar
)
{
int i;
//
// simply add a 0 upper byte, it's supposed to be ascii
//
for (i = 0; i < cchMultiByte; ++i)
{
if (lpMultiByteStr[i] > 128)
{
lpWideCharStr[i] = (WCHAR)('_'); // (WCHAR)(DefaultChar);
}
else
{
lpWideCharStr[i] = (WCHAR)(lpMultiByteStr[i]);
}
}
return (ULONG)(i);
} // _MultiByteToWideCharWin9x
/******************************************************************************
Routine Description:
Copy an HTTP request to a buffer.
Arguments:
pRequest - Pointer to this request.
pBuffer - Pointer to buffer where we'll copy.
BufferLength - Length of pBuffer.
pEntityBody - Pointer to entity body of request.
EntityBodyLength - Length of entity body.
Return Value:
******************************************************************************/
NTSTATUS
UlpHttpRequestToBufferWin9x(
PUL_INTERNAL_REQUEST pRequest,
PUCHAR pKernelBuffer,
ULONG BufferLength,
PUCHAR pEntityBody,
ULONG EntityBodyLength,
ULONG ulLocalIPAddress,
USHORT ulLocalPort,
ULONG ulRemoteIPAddress,
USHORT ulRemotePort
)
{
PHTTP_REQUEST pHttpRequest;
PHTTP_UNKNOWN_HEADER pUserCurrentUnknownHeader;
PUCHAR pCurrentBufferPtr;
ULONG i;
ULONG BytesCopied;
ULONG HeaderCount = 0;
PVOID pUserBuffer;
PHTTP_NETWORK_ADDRESS_IPV4 pLocalAddress;
PHTTP_NETWORK_ADDRESS_IPV4 pRemoteAddress;
//
// Sanity check.
//
PAGED_CODE();
ASSERT(IS_VALID_HTTP_REQUEST(pRequest));
ASSERT(pKernelBuffer != NULL);
ASSERT(BufferLength > sizeof(HTTP_REQUEST));
// BUGBUG - this is used for the pointer fixups
// don't know what you want to set this to
// MAUROOT - NULL should be ok.
pUserBuffer = NULL;
//
// wipe it clean
//
RtlZeroMemory( pKernelBuffer, sizeof(HTTP_REQUEST) );
//
// Set up our pointers to the HTTP_REQUEST structure, the
// header arrays we're going to fill in, and the pointer to
// where we're going to start filling them in.
//
// CODEWORK: Make this transport independent.
//
pHttpRequest = (PHTTP_REQUEST)pKernelBuffer;
pLocalAddress = (PHTTP_NETWORK_ADDRESS_IPV4)( pHttpRequest + 1 );
pRemoteAddress = pLocalAddress + 1;
pUserCurrentUnknownHeader = (PHTTP_UNKNOWN_HEADER)( pRemoteAddress + 1 );
pCurrentBufferPtr = (PUCHAR)(pUserCurrentUnknownHeader +
pRequest->UnknownHeaderCount);
//
// Now fill in the HTTP request structure.
//
pHttpRequest->ConnectionId = pRequest->ConnectionId;
pHttpRequest->RequestId = pRequest->RequestId;
// BUGBUG - Don't know where you'll come up with this
// pHttpRequest->UrlContext = pRequest->pConfigGroup->UrlContext;
// MAUROOT - NULL should be ok.
pHttpRequest->UrlContext = 0;
pHttpRequest->Version = pRequest->Version;
pHttpRequest->Verb = pRequest->Verb;
pHttpRequest->Reason = pRequest->Reason;
pHttpRequest->Address.RemoteAddressLength = sizeof(HTTP_NETWORK_ADDRESS_IPV4);
pHttpRequest->Address.RemoteAddressType = HTTP_NETWORK_ADDRESS_TYPE_IPV4;
pHttpRequest->Address.pRemoteAddress = FIXUP_PTR(
PVOID,
pUserBuffer,
pKernelBuffer,
pRemoteAddress,
BufferLength
);
pRemoteAddress->IpAddress = SWAP_LONG( ulRemoteIPAddress );
pRemoteAddress->Port = SWAP_SHORT( ulRemotePort );
pHttpRequest->Address.LocalAddressLength = sizeof(HTTP_NETWORK_ADDRESS_IPV4);
pHttpRequest->Address.LocalAddressType = HTTP_NETWORK_ADDRESS_TYPE_IPV4;
pHttpRequest->Address.pLocalAddress = FIXUP_PTR(
PVOID,
pUserBuffer,
pKernelBuffer,
pLocalAddress,
BufferLength
);
pLocalAddress->IpAddress = SWAP_LONG( ulLocalIPAddress );
pLocalAddress->Port = SWAP_SHORT( ulLocalPort );
//
// any raw verb?
//
if (pRequest->Verb == HttpVerbUnknown)
{
//
// Need to copy in the raw verb for the client.
//
ASSERT(pRequest->RawVerbLength <= 0x7fff);
pHttpRequest->UnknownVerbLength = (USHORT)(pRequest->RawVerbLength * sizeof(CHAR));
pHttpRequest->pUnknownVerb = FIXUP_PTR(
PSTR,
pUserBuffer,
pKernelBuffer,
pCurrentBufferPtr,
BufferLength
);
RtlCopyMemory(
pCurrentBufferPtr,
pRequest->pRawVerb,
pRequest->RawVerbLength
);
pCurrentBufferPtr += pRequest->RawVerbLength;
//
// terminate it
//
((PSTR)pCurrentBufferPtr)[0] = ANSI_NULL;
pCurrentBufferPtr += sizeof(CHAR);
}
//
// copy the raw url
//
ASSERT(pRequest->RawUrl.Length <= 0x7fff);
pHttpRequest->RawUrlLength = (USHORT)(pRequest->RawUrl.Length * sizeof(CHAR));
pHttpRequest->pRawUrl = FIXUP_PTR(
PSTR,
pUserBuffer,
pKernelBuffer,
pCurrentBufferPtr,
BufferLength
);
RtlCopyMemory(
pCurrentBufferPtr,
pRequest->RawUrl.pUrl,
pRequest->RawUrl.Length
);
pCurrentBufferPtr += pRequest->RawUrl.Length;
//
// terminate it
//
((PSTR)pCurrentBufferPtr)[0] = ANSI_NULL;
pCurrentBufferPtr += sizeof(CHAR);
//
// and now the cooked url sections
//
//
// make sure they are valid
//
ASSERT(pRequest->CookedUrl.pUrl != NULL);
ASSERT(pRequest->CookedUrl.pHost != NULL);
ASSERT(pRequest->CookedUrl.pAbsPath != NULL);
//
// do the full url
//
ASSERT(pRequest->CookedUrl.Length <= 0xffff);
pHttpRequest->CookedUrl.FullUrlLength = (USHORT)(pRequest->CookedUrl.Length);
pHttpRequest->CookedUrl.pFullUrl = FIXUP_PTR(
PWSTR,
pUserBuffer,
pKernelBuffer,
pCurrentBufferPtr,
BufferLength
);
//
// and the host
//
pHttpRequest->CookedUrl.HostLength = DIFF(pRequest->CookedUrl.pAbsPath - pRequest->CookedUrl.pHost)
* sizeof(WCHAR);
pHttpRequest->CookedUrl.pHost = pHttpRequest->CookedUrl.pFullUrl +
DIFF(pRequest->CookedUrl.pHost - pRequest->CookedUrl.pUrl);
//
// is there a query string?
//
if (pRequest->CookedUrl.pQueryString != NULL)
{
pHttpRequest->CookedUrl.AbsPathLength = DIFF(pRequest->CookedUrl.pQueryString -
pRequest->CookedUrl.pAbsPath) * sizeof(WCHAR);
pHttpRequest->CookedUrl.pAbsPath = pHttpRequest->CookedUrl.pHost +
(pHttpRequest->CookedUrl.HostLength / sizeof(WCHAR));
pHttpRequest->CookedUrl.QueryStringLength = (USHORT)(pRequest->CookedUrl.Length) - (
DIFF(
pRequest->CookedUrl.pQueryString -
pRequest->CookedUrl.pUrl
) * sizeof(WCHAR)
);
pHttpRequest->CookedUrl.pQueryString = pHttpRequest->CookedUrl.pAbsPath +
(pHttpRequest->CookedUrl.AbsPathLength / sizeof(WCHAR));
}
else
{
pHttpRequest->CookedUrl.AbsPathLength = (USHORT)(pRequest->CookedUrl.Length) - (
DIFF(
pRequest->CookedUrl.pAbsPath -
pRequest->CookedUrl.pUrl
) * sizeof(WCHAR)
);
pHttpRequest->CookedUrl.pAbsPath = pHttpRequest->CookedUrl.pHost +
(pHttpRequest->CookedUrl.HostLength / sizeof(WCHAR));
pHttpRequest->CookedUrl.QueryStringLength = 0;
pHttpRequest->CookedUrl.pQueryString = NULL;
}
//
// copy the full url
//
RtlCopyMemory(
pCurrentBufferPtr,
pRequest->CookedUrl.pUrl,
pRequest->CookedUrl.Length
);
pCurrentBufferPtr += pRequest->CookedUrl.Length;
//
// terminate it
//
((PWSTR)pCurrentBufferPtr)[0] = UNICODE_NULL;
pCurrentBufferPtr += sizeof(WCHAR);
//
// no entity body, CODEWORK.
//
if (pRequest->ContentLength > 0 || pRequest->Chunked == 1)
{
pHttpRequest->MoreEntityBodyExists = 1;
}
else
{
pHttpRequest->MoreEntityBodyExists = 0;
}
pHttpRequest->EntityChunkCount = 0;
pHttpRequest->pEntityChunks = NULL;
//
// Copy in the known headers.
//
// Loop through the known header array in the HTTP connection,
// and copy any that we have.
//
for (i = 0; i < HttpHeaderRequestMaximum; i++)
{
if (pRequest->Headers[i].Valid == 1)
{
//
// Have a header here we need to copy in.
//
ASSERT(pRequest->Headers[i].HeaderLength <= 0x7fff);
//
// ok for HeaderLength to be 0 . we will give usermode a pointer
// pointing to a NULL string. RawValueLength will be 0.
//
pHttpRequest->Headers.pKnownHeaders[i].RawValueLength =
(USHORT)(pRequest->Headers[i].HeaderLength * sizeof(CHAR));
pHttpRequest->Headers.pKnownHeaders[i].pRawValue =
FIXUP_PTR(
PSTR,
pUserBuffer,
pKernelBuffer,
pCurrentBufferPtr,
BufferLength
);
RtlCopyMemory(
pCurrentBufferPtr,
pRequest->Headers[i].pHeader,
pRequest->Headers[i].HeaderLength
);
pCurrentBufferPtr += pRequest->Headers[i].HeaderLength;
//
// terminate it
//
((PSTR)pCurrentBufferPtr)[0] = ANSI_NULL;
pCurrentBufferPtr += sizeof(CHAR);
}
else
{
pHttpRequest->Headers.pKnownHeaders[i].RawValueLength = 0;
pHttpRequest->Headers.pKnownHeaders[i].pRawValue = NULL;
}
}
//
// Now loop through the unknown headers, and copy them in.
//
pHttpRequest->Headers.UnknownHeaderCount = pRequest->UnknownHeaderCount;
if (pRequest->UnknownHeaderCount == 0)
{
pHttpRequest->Headers.pUnknownHeaders = NULL;
}
else
{
pHttpRequest->Headers.pUnknownHeaders =
FIXUP_PTR(
PHTTP_UNKNOWN_HEADER,
pUserBuffer,
pKernelBuffer,
pUserCurrentUnknownHeader,
BufferLength
);
}
while (!IsListEmpty(&pRequest->UnknownHeaderList))
{
PUL_HTTP_UNKNOWN_HEADER pUnknownHeader;
PLIST_ENTRY pListEntry;
pListEntry = RemoveHeadList(&pRequest->UnknownHeaderList);
pListEntry->Flink = pListEntry->Blink = NULL;
pUnknownHeader = CONTAINING_RECORD(
pListEntry,
UL_HTTP_UNKNOWN_HEADER,
List
);
HeaderCount++;
ASSERT(HeaderCount <= pRequest->UnknownHeaderCount);
//
// First copy in the header name.
//
pUserCurrentUnknownHeader->NameLength = (USHORT)
pUnknownHeader->HeaderNameLength * sizeof(CHAR);
pUserCurrentUnknownHeader->pName =
FIXUP_PTR(
PSTR,
pUserBuffer,
pKernelBuffer,
pCurrentBufferPtr,
BufferLength
);
RtlCopyMemory(
pCurrentBufferPtr,
pUnknownHeader->pHeaderName,
pUnknownHeader->HeaderNameLength
);
pCurrentBufferPtr += pUnknownHeader->HeaderNameLength;
//
// terminate it
//
((PSTR)pCurrentBufferPtr)[0] = ANSI_NULL;
pCurrentBufferPtr += sizeof(CHAR);
//
// Now copy in the header value.
//
ASSERT(pUnknownHeader->HeaderValue.HeaderLength <= 0x7fff);
if (pUnknownHeader->HeaderValue.HeaderLength == 0)
{
pUserCurrentUnknownHeader->RawValueLength = 0;
pUserCurrentUnknownHeader->pRawValue = NULL;
}
else
{
pUserCurrentUnknownHeader->RawValueLength =
(USHORT)(pUnknownHeader->HeaderValue.HeaderLength * sizeof(CHAR));
pUserCurrentUnknownHeader->pRawValue =
FIXUP_PTR(
PSTR,
pUserBuffer,
pKernelBuffer,
pCurrentBufferPtr,
BufferLength
);
RtlCopyMemory(
pCurrentBufferPtr,
pUnknownHeader->HeaderValue.pHeader,
pUnknownHeader->HeaderValue.HeaderLength
);
pCurrentBufferPtr += pUnknownHeader->HeaderValue.HeaderLength;
//
// terminate it
//
((PSTR)pCurrentBufferPtr)[0] = ANSI_NULL;
pCurrentBufferPtr += sizeof(CHAR);
}
//
// skip to the next header
//
pUserCurrentUnknownHeader++;
//
// Free the unknown header structure now, as well as the pointer
// (if needed).
//
if (pUnknownHeader->HeaderValue.OurBuffer == 1)
{
UL_FREE_POOL(
pUnknownHeader->HeaderValue.pHeader,
UL_KNOWN_HEADER_POOL_TAG
);
pUnknownHeader->HeaderValue.OurBuffer = 0;
}
UL_FREE_POOL( pUnknownHeader, UL_UNKNOWN_HEADER_POOL_TAG );
}
//
// no more unknown headers exist
//
pRequest->UnknownHeaderCount = 0;
//
// Make sure we didn't use too much
//
ASSERT(DIFF(pCurrentBufferPtr - pKernelBuffer) <= BufferLength);
return STATUS_SUCCESS;
}