945 lines
27 KiB
C++
945 lines
27 KiB
C++
/*++
|
||
|
||
Copyright (c) 1994 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
query.cxx
|
||
|
||
Abstract:
|
||
|
||
This file contains the implementation of the HttpQueryInfoA API.
|
||
|
||
Contents:
|
||
HttpQueryInfoA
|
||
WinHttpQueryHeaders
|
||
HTTP_REQUEST_HANDLE_OBJECT::QueryInfo
|
||
|
||
Author:
|
||
|
||
Keith Moore (keithmo) 16-Nov-1994
|
||
|
||
Revision History:
|
||
|
||
Modified to make HttpQueryInfoA remotable. madana (2/8/95)
|
||
|
||
--*/
|
||
|
||
#include <wininetp.h>
|
||
#include "httpp.h"
|
||
|
||
//
|
||
// private prototypes
|
||
//
|
||
|
||
//
|
||
// private data
|
||
//
|
||
|
||
#define NUM_HEADERS ARRAY_ELEMENTS(GlobalKnownHeaders)
|
||
|
||
//
|
||
// functions
|
||
//
|
||
|
||
|
||
INTERNETAPI
|
||
BOOL
|
||
WINAPI
|
||
HttpQueryInfoA(
|
||
IN HINTERNET hRequest,
|
||
IN DWORD dwInfoLevel,
|
||
IN LPCSTR lpszName OPTIONAL,
|
||
IN OUT LPVOID lpBuffer OPTIONAL,
|
||
IN OUT LPDWORD lpdwBufferLength,
|
||
IN OUT LPDWORD lpdwIndex OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Queries a request or response header from the HTTP request handle
|
||
|
||
Arguments:
|
||
|
||
hRequest - an open HTTP request handle returned by
|
||
HttpOpenRequest()
|
||
|
||
dwInfoLevel - one of the HTTP_QUERY_* values indicating the
|
||
attribute to query. In addition, the following flags
|
||
can be set:
|
||
|
||
HTTP_QUERY_FLAG_REQUEST_HEADERS
|
||
- Causes the request headers to be queried. The
|
||
default is to check the response headers
|
||
|
||
HTTP_QUERY_FLAG_SYSTEMTIME
|
||
- Causes headers that contain date & time
|
||
information to be returned as SYSTEMTIME
|
||
structures
|
||
|
||
HTTP_QUERY_FLAG_NUMBER
|
||
- Causes header value to be returned as a number.
|
||
Useful for when the app knows it is expecting
|
||
a numeric value, e.g. status code
|
||
|
||
lpBuffer - pointer to the buffer to receive the information.
|
||
If dwInfoLevel is HTTP_QUERY_CUSTOM then buffer
|
||
contains the header to query.
|
||
|
||
If NULL then we just return the required buffer length
|
||
to hold the header specified by dwInfoLevel
|
||
|
||
lpdwBufferLength - IN: contains the length (in BYTEs) of lpBuffer
|
||
OUT: size of data written to lpBuffer, or required
|
||
buffer length if ERROR_INSUFFICIENT_BUFFER
|
||
returned
|
||
|
||
lpdwIndex - IN: 0-based header index
|
||
OUT: next index to query, if success returned
|
||
|
||
Return Value:
|
||
|
||
TRUE - The query succeeded. lpBuffer contains the query information, and
|
||
*lpdwBufferLength contains the size (in BYTEs) of the information
|
||
|
||
FALSE - The operation failed. Error status is available by calling
|
||
GetLastError().
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER_API((DBG_API,
|
||
Bool,
|
||
"HttpQueryInfoA",
|
||
"%#x, %s (%#x), %#x [%q], %#x [%d], %#x [%d]",
|
||
hRequest,
|
||
InternetMapHttpOption(dwInfoLevel & HTTP_QUERY_HEADER_MASK),
|
||
dwInfoLevel,
|
||
lpBuffer,
|
||
((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
|
||
? lpBuffer
|
||
: "",
|
||
lpdwBufferLength,
|
||
lpdwBufferLength ? *lpdwBufferLength : 0,
|
||
lpdwIndex,
|
||
lpdwIndex ? *lpdwIndex : 0
|
||
));
|
||
|
||
DWORD defaultIndex = 0;
|
||
DWORD error;
|
||
HINTERNET hRequestMapped = NULL;
|
||
|
||
if (!GlobalDataInitialized) {
|
||
error = ERROR_WINHTTP_NOT_INITIALIZED;
|
||
goto done;
|
||
}
|
||
|
||
//
|
||
// get the thread info
|
||
//
|
||
|
||
LPINTERNET_THREAD_INFO lpThreadInfo;
|
||
|
||
lpThreadInfo = InternetGetThreadInfo();
|
||
if (lpThreadInfo == NULL) {
|
||
error = ERROR_WINHTTP_INTERNAL_ERROR;
|
||
goto done;
|
||
}
|
||
|
||
_InternetIncNestingCount();
|
||
|
||
//
|
||
// map the handle
|
||
//
|
||
|
||
error = MapHandleToAddress(hRequest, (LPVOID *)&hRequestMapped, FALSE);
|
||
if (error != ERROR_SUCCESS) {
|
||
goto quit;
|
||
}
|
||
|
||
|
||
//
|
||
// find path from Internet handle
|
||
//
|
||
|
||
BOOL isLocal;
|
||
BOOL isAsync;
|
||
|
||
error = RIsHandleLocal(hRequestMapped,
|
||
&isLocal,
|
||
&isAsync,
|
||
TypeHttpRequestHandle
|
||
);
|
||
if (error != ERROR_SUCCESS) {
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// validate parameters
|
||
//
|
||
|
||
DWORD queryModifiers;
|
||
DWORD infoLevel;
|
||
|
||
queryModifiers = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
|
||
infoLevel = dwInfoLevel & HTTP_QUERY_HEADER_MASK;
|
||
|
||
if (((infoLevel > HTTP_QUERY_MAX) && (infoLevel != HTTP_QUERY_CUSTOM))
|
||
|| (lpdwBufferLength == NULL)
|
||
|
||
//
|
||
// nip in the bud apps that want SYSTEMTIME AND NUMBER for same header(!)
|
||
//
|
||
|
||
#define EXCLUSIVE_MODIFIERS (HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_FLAG_SYSTEMTIME)
|
||
|
||
|| ((dwInfoLevel & EXCLUSIVE_MODIFIERS) == EXCLUSIVE_MODIFIERS)) {
|
||
|
||
error = ERROR_INVALID_PARAMETER;
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// if the app passed in a NULL lpdwIndex then it is asking for index 0
|
||
//
|
||
|
||
if (!ARGUMENT_PRESENT(lpdwIndex)) {
|
||
lpdwIndex = &defaultIndex;
|
||
}
|
||
|
||
//
|
||
// if the app is asking for one of the special query items - status code,
|
||
// status text, HTTP version, or one of the raw header variants, then make
|
||
// sure the index is 0. These pseudo-header types cannot be enumerated
|
||
//
|
||
|
||
if ((*lpdwIndex != 0)
|
||
&& ((infoLevel == HTTP_QUERY_VERSION)
|
||
|| (infoLevel == HTTP_QUERY_STATUS_CODE)
|
||
|| (infoLevel == HTTP_QUERY_STATUS_TEXT)
|
||
|| (infoLevel == HTTP_QUERY_RAW_HEADERS)
|
||
|| (infoLevel == HTTP_QUERY_RAW_HEADERS_CRLF))) {
|
||
|
||
error = ERROR_HTTP_HEADER_NOT_FOUND;
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// ensure that we can use any flags passed in
|
||
//
|
||
|
||
if (infoLevel == HTTP_QUERY_CUSTOM) {
|
||
|
||
//
|
||
// the app has given us a string to locate. We only accept strings in
|
||
// the following format:
|
||
//
|
||
// <header-to-find>[:][CR][LF]<EOS>
|
||
//
|
||
// The header cannot contain any spaces
|
||
//
|
||
|
||
INET_ASSERT(error == ERROR_SUCCESS);
|
||
|
||
int queryLength = 0;
|
||
int headerLength = 0;
|
||
|
||
for (; lpszName[queryLength] != '\0'; ++queryLength) {
|
||
if ((lpszName[queryLength] == ':')
|
||
|| (lpszName[queryLength] == '\r')
|
||
|| (lpszName[queryLength] == '\n')) {
|
||
break;
|
||
}
|
||
if (iscntrl(lpszName[queryLength])
|
||
|| isspace(lpszName[queryLength])) {
|
||
error = ERROR_INVALID_PARAMETER;
|
||
break;
|
||
}
|
||
}
|
||
} else if ((queryModifiers & ~GlobalKnownHeaders[infoLevel].Flags) != 0) {
|
||
error = ERROR_HTTP_INVALID_QUERY_REQUEST;
|
||
}
|
||
if (error != ERROR_SUCCESS) {
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// if NULL buffer pointer then app wants length of option: set buffer length
|
||
// to zero
|
||
//
|
||
|
||
if (!ARGUMENT_PRESENT(lpBuffer)) {
|
||
*lpdwBufferLength = 0;
|
||
}
|
||
|
||
INET_ASSERT(error == ERROR_SUCCESS);
|
||
|
||
HTTP_REQUEST_HANDLE_OBJECT * pRequest;
|
||
|
||
pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)hRequestMapped;
|
||
if (dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) {
|
||
if (!IS_VALID_HTTP_STATE(pRequest, QUERY_REQUEST, TRUE)) {
|
||
error = ERROR_WINHTTP_INCORRECT_HANDLE_STATE;
|
||
}
|
||
} else {
|
||
if (!IS_VALID_HTTP_STATE(pRequest, QUERY_RESPONSE, TRUE)) {
|
||
error = ERROR_WINHTTP_INCORRECT_HANDLE_STATE;
|
||
}
|
||
}
|
||
if (error == ERROR_SUCCESS) {
|
||
error = pRequest->QueryInfo(dwInfoLevel,
|
||
lpszName,
|
||
lpBuffer,
|
||
lpdwBufferLength,
|
||
lpdwIndex
|
||
);
|
||
}
|
||
|
||
quit:
|
||
|
||
_InternetDecNestingCount(1);
|
||
|
||
done:
|
||
|
||
BOOL success;
|
||
|
||
if (error != ERROR_SUCCESS) {
|
||
|
||
DEBUG_ERROR(HTTP, error);
|
||
|
||
SetLastError(error);
|
||
success = FALSE;
|
||
} else {
|
||
|
||
DEBUG_PRINT_API(API,
|
||
INFO,
|
||
("*lpdwBufferLength = %d\n",
|
||
*lpdwBufferLength
|
||
));
|
||
|
||
DEBUG_DUMP_API(DUMP_API_DATA,
|
||
"Query data:\n",
|
||
lpBuffer,
|
||
*lpdwBufferLength
|
||
);
|
||
|
||
success = TRUE;
|
||
}
|
||
|
||
if (hRequestMapped != NULL) {
|
||
DereferenceObject((LPVOID)hRequestMapped);
|
||
}
|
||
|
||
DEBUG_LEAVE_API(success);
|
||
|
||
return success;
|
||
}
|
||
|
||
|
||
INTERNETAPI
|
||
BOOL
|
||
WINAPI
|
||
WinHttpQueryHeaders(
|
||
IN HINTERNET hRequest,
|
||
IN DWORD dwInfoLevel,
|
||
IN LPCWSTR lpszName OPTIONAL,
|
||
OUT LPVOID lpBuffer OPTIONAL,
|
||
IN OUT LPDWORD lpdwBufferLength,
|
||
IN OUT LPDWORD lpdwIndex OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Queries information from the HTTP request handle.
|
||
|
||
Arguments:
|
||
|
||
hHttpRequest - An open HTTP request handle returned by HttpOpenRequest().
|
||
|
||
dwInfoLevel - One of the HTTP_QUERY_* values indicating the attribute
|
||
to query.
|
||
|
||
lpBuffer - Pointer to the buffer to receive the information.
|
||
|
||
dwBufferLength - On entry, contains the length (in BYTEs) of the data
|
||
buffer. On exit, contains the size (in BYTEs) of the data written
|
||
to lpBuffer.
|
||
|
||
Return Value:
|
||
|
||
TRUE - The query succeeded. lpBuffer contains the query information,
|
||
and lpBufferLength contains the size (in BYTEs) of the information.
|
||
|
||
FALSE - The operation failed. Error status is available by calling
|
||
GetLastError().
|
||
|
||
Comments:
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER_API((DBG_API,
|
||
Bool,
|
||
"WinHttpQueryHeaders",
|
||
"%#x, %s (%#x), %wq, %#x, %#x [%d], %#x [%d]",
|
||
hRequest,
|
||
InternetMapHttpOption(dwInfoLevel & HTTP_QUERY_HEADER_MASK),
|
||
dwInfoLevel,
|
||
lpszName? lpszName : L"<null>",
|
||
lpBuffer,
|
||
lpdwBufferLength,
|
||
lpdwBufferLength ? *lpdwBufferLength : 0,
|
||
lpdwIndex,
|
||
lpdwIndex ? *lpdwIndex : 0
|
||
));
|
||
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
BOOL fResult=FALSE;
|
||
INET_ASSERT(hRequest);
|
||
MEMORYPACKET mpBuffer, mpName;
|
||
|
||
if (!lpdwBufferLength
|
||
|| IsBadWritePtr(lpdwBufferLength, sizeof(*lpdwBufferLength))
|
||
|| (lpBuffer && ProbeWriteBuffer(lpBuffer, *lpdwBufferLength))
|
||
|| (lpdwIndex && IsBadWritePtr(lpdwIndex, sizeof(*lpdwIndex))))
|
||
{
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
|
||
{
|
||
if (!lpszName
|
||
|| IsBadStringPtrW(lpszName, -1))
|
||
{
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
ALLOC_MB(lpszName,0,mpName);
|
||
if (!mpName.psStr)
|
||
{
|
||
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto cleanup;
|
||
}
|
||
UNICODE_TO_ANSI(lpszName,mpName);
|
||
}
|
||
|
||
if (lpBuffer)
|
||
{
|
||
mpBuffer.dwAlloc = mpBuffer.dwSize = *lpdwBufferLength;
|
||
mpBuffer.psStr = (LPSTR)ALLOC_BYTES(mpBuffer.dwAlloc*sizeof(CHAR));
|
||
if (!mpBuffer.psStr)
|
||
{
|
||
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto cleanup;
|
||
}
|
||
}
|
||
|
||
fResult = HttpQueryInfoA(hRequest,dwInfoLevel, mpName.psStr,
|
||
mpBuffer.psStr, &mpBuffer.dwSize, lpdwIndex);
|
||
|
||
if (!((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
|
||
(dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)))
|
||
{
|
||
// This is the default, we've been handed back a string.
|
||
if (fResult)
|
||
{
|
||
*lpdwBufferLength = MultiByteToWideChar(CP_ACP, 0, mpBuffer.psStr, mpBuffer.dwSize + 1,
|
||
NULL, 0);
|
||
*lpdwBufferLength *= sizeof(WCHAR);
|
||
if (*lpdwBufferLength<=mpBuffer.dwAlloc)
|
||
{
|
||
MultiByteToWideChar(CP_ACP, 0, mpBuffer.psStr, mpBuffer.dwSize+1,
|
||
(LPWSTR)lpBuffer, mpBuffer.dwAlloc/sizeof(WCHAR));
|
||
*lpdwBufferLength -= sizeof(WCHAR);
|
||
}
|
||
else
|
||
{
|
||
fResult = FALSE;
|
||
dwErr = ERROR_INSUFFICIENT_BUFFER;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (GetLastError()==ERROR_INSUFFICIENT_BUFFER)
|
||
{
|
||
*lpdwBufferLength = mpBuffer.dwSize*sizeof(WCHAR);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (fResult)
|
||
{
|
||
memcpy(lpBuffer, (LPVOID)mpBuffer.psStr, mpBuffer.dwSize);
|
||
}
|
||
*lpdwBufferLength = mpBuffer.dwSize;
|
||
}
|
||
|
||
cleanup:
|
||
if (dwErr!=ERROR_SUCCESS)
|
||
{
|
||
SetLastError(dwErr);
|
||
DEBUG_ERROR(HTTP, dwErr);
|
||
}
|
||
DEBUG_LEAVE_API(fResult);
|
||
return fResult;
|
||
}
|
||
|
||
//
|
||
// object methods
|
||
//
|
||
|
||
|
||
DWORD
|
||
HTTP_REQUEST_HANDLE_OBJECT::QueryInfo(
|
||
IN DWORD dwInfoLevel,
|
||
IN LPCSTR headerName,
|
||
OUT LPVOID lpBuffer OPTIONAL,
|
||
IN OUT LPDWORD lpdwBufferLength,
|
||
IN OUT LPDWORD lpdwIndex
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Header query method for HTTP_REQUEST_HANDLE_OBJECT class
|
||
|
||
Arguments:
|
||
|
||
dwInfoLevel - level of info (header) to get
|
||
|
||
headerName - name of header with HTTP_QUERY_CUSTOM
|
||
|
||
lpBuffer - pointer to user's buffer
|
||
|
||
lpdwBufferLength - IN: length of user's buffer
|
||
OUT: length of returned information or required buffer
|
||
length if insufficient
|
||
|
||
lpdwIndex - IN: 0-based index of named header to return
|
||
OUT: index of next header if success returned
|
||
|
||
Return Value:
|
||
|
||
DWORD
|
||
Success - ERROR_SUCCESS
|
||
|
||
Failure - ERROR_HTTP_HEADER_NOT_FOUND
|
||
Couldn't find the requested header
|
||
|
||
ERROR_HTTP_INVALID_QUERY_REQUEST
|
||
The caller asked for e.g. the Accept: header to be returned
|
||
as a SYSTEMTIME structure, or for e.g. a request header that
|
||
only exists for response headers (status code, for example)
|
||
|
||
ERROR_INSUFFICIENT_BUFFER
|
||
User's buffer not large enough to hold requested data
|
||
|
||
--*/
|
||
|
||
{
|
||
INET_ASSERT(lpdwBufferLength != NULL);
|
||
INET_ASSERT(lpdwIndex != NULL);
|
||
|
||
DWORD error;
|
||
DWORD headerNameLength;
|
||
DWORD modifiers;
|
||
|
||
modifiers = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
|
||
dwInfoLevel &= HTTP_QUERY_HEADER_MASK;
|
||
|
||
if (dwInfoLevel == HTTP_QUERY_CUSTOM) {
|
||
for (headerNameLength = 0; ; ++headerNameLength) {
|
||
if ((headerName[headerNameLength] == '\0')
|
||
|| (headerName[headerNameLength] == ':')
|
||
|| (headerName[headerNameLength] == '\r')
|
||
|| (headerName[headerNameLength] == '\n')) {
|
||
break;
|
||
}
|
||
}
|
||
} else if (dwInfoLevel == HTTP_QUERY_REQUEST_METHOD) {
|
||
|
||
LPSTR lpszVerb;
|
||
DWORD dwVerbLength;
|
||
|
||
lpszVerb = _RequestHeaders.GetVerb(&dwVerbLength);
|
||
if ((lpszVerb != NULL) && (dwVerbLength != 0)) {
|
||
|
||
//
|
||
// the verb is (usually) space terminated
|
||
//
|
||
|
||
while ((dwVerbLength > 0) && (lpszVerb[dwVerbLength - 1] == ' ')) {
|
||
--dwVerbLength;
|
||
}
|
||
|
||
//
|
||
// *lpdwBufferLength will be 0 if lpBuffer is NULL
|
||
//
|
||
|
||
if (*lpdwBufferLength > dwVerbLength) {
|
||
memcpy(lpBuffer, lpszVerb, dwVerbLength);
|
||
((LPBYTE)lpBuffer)[dwVerbLength] = '\0';
|
||
error = ERROR_SUCCESS;
|
||
} else {
|
||
++dwVerbLength;
|
||
error = ERROR_INSUFFICIENT_BUFFER;
|
||
}
|
||
*lpdwBufferLength = dwVerbLength;
|
||
} else {
|
||
error = ERROR_HTTP_HEADER_NOT_FOUND;
|
||
}
|
||
goto quit;
|
||
} else {
|
||
headerName = GlobalKnownHeaders[dwInfoLevel].Text;
|
||
headerNameLength = GlobalKnownHeaders[dwInfoLevel].Length;
|
||
}
|
||
|
||
if (modifiers & HTTP_QUERY_FLAG_REQUEST_HEADERS) {
|
||
|
||
//
|
||
// we can always query request headers, even if the server is down
|
||
// level
|
||
//
|
||
|
||
switch (dwInfoLevel) {
|
||
case HTTP_QUERY_VERSION:
|
||
case HTTP_QUERY_STATUS_CODE:
|
||
case HTTP_QUERY_STATUS_TEXT:
|
||
|
||
//
|
||
// can't query these sub-header values from the request headers
|
||
//
|
||
|
||
error = ERROR_HTTP_INVALID_QUERY_REQUEST;
|
||
break;
|
||
|
||
case HTTP_QUERY_RAW_HEADERS:
|
||
case HTTP_QUERY_RAW_HEADERS_CRLF:
|
||
error = _RequestHeaders.QueryRawHeaders(
|
||
NULL,
|
||
dwInfoLevel == HTTP_QUERY_RAW_HEADERS_CRLF,
|
||
lpBuffer,
|
||
lpdwBufferLength
|
||
);
|
||
break;
|
||
|
||
case HTTP_QUERY_ECHO_HEADERS:
|
||
case HTTP_QUERY_ECHO_HEADERS_CRLF:
|
||
error = QueryRequestHeadersWithEcho(
|
||
dwInfoLevel == HTTP_QUERY_ECHO_HEADERS_CRLF,
|
||
lpBuffer,
|
||
lpdwBufferLength
|
||
);
|
||
break;
|
||
|
||
case HTTP_QUERY_CUSTOM:
|
||
|
||
if (_RequestHeaders.LockHeaders())
|
||
{
|
||
error = QueryRequestHeader(headerName,
|
||
headerNameLength,
|
||
lpBuffer,
|
||
lpdwBufferLength,
|
||
modifiers,
|
||
lpdwIndex
|
||
);
|
||
|
||
_RequestHeaders.UnlockHeaders();
|
||
}
|
||
else
|
||
{
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
if (_RequestHeaders.LockHeaders())
|
||
{
|
||
error = QueryRequestHeader( dwInfoLevel,
|
||
lpBuffer,
|
||
lpdwBufferLength,
|
||
modifiers,
|
||
lpdwIndex
|
||
);
|
||
|
||
_RequestHeaders.UnlockHeaders();
|
||
}
|
||
else
|
||
{
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
break;
|
||
|
||
}
|
||
} else if (!IsDownLevel()) {
|
||
switch (dwInfoLevel) {
|
||
case HTTP_QUERY_VERSION:
|
||
error = QueryResponseVersion(lpBuffer, lpdwBufferLength);
|
||
break;
|
||
|
||
case HTTP_QUERY_STATUS_CODE:
|
||
error = QueryStatusCode(lpBuffer, lpdwBufferLength, modifiers);
|
||
break;
|
||
|
||
case HTTP_QUERY_STATUS_TEXT:
|
||
error = QueryStatusText(lpBuffer, lpdwBufferLength);
|
||
break;
|
||
|
||
case HTTP_QUERY_RAW_HEADERS:
|
||
case HTTP_QUERY_RAW_HEADERS_CRLF:
|
||
error = _ResponseHeaders.QueryRawHeaders(
|
||
(LPSTR)_ResponseBuffer,
|
||
dwInfoLevel == HTTP_QUERY_RAW_HEADERS_CRLF,
|
||
lpBuffer,
|
||
lpdwBufferLength
|
||
);
|
||
break;
|
||
|
||
case HTTP_QUERY_ECHO_HEADERS:
|
||
case HTTP_QUERY_ECHO_HEADERS_CRLF:
|
||
error = ERROR_HTTP_INVALID_QUERY_REQUEST;
|
||
break;
|
||
|
||
case HTTP_QUERY_CUSTOM:
|
||
|
||
if (_RequestHeaders.LockHeaders())
|
||
{
|
||
error = QueryResponseHeader(
|
||
headerName,
|
||
headerNameLength,
|
||
lpBuffer,
|
||
lpdwBufferLength,
|
||
modifiers,
|
||
lpdwIndex
|
||
);
|
||
|
||
_RequestHeaders.UnlockHeaders();
|
||
}
|
||
else
|
||
{
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
if (_ResponseHeaders.LockHeaders())
|
||
{
|
||
error = QueryResponseHeader(
|
||
dwInfoLevel,
|
||
lpBuffer,
|
||
lpdwBufferLength,
|
||
modifiers,
|
||
lpdwIndex
|
||
);
|
||
|
||
_ResponseHeaders.UnlockHeaders();
|
||
}
|
||
else
|
||
{
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
break;
|
||
}
|
||
} else {
|
||
|
||
//
|
||
// there are no response headers from down-level servers
|
||
//
|
||
|
||
error = ERROR_HTTP_HEADER_NOT_FOUND;
|
||
}
|
||
|
||
quit:
|
||
|
||
return error;
|
||
}
|
||
|
||
|
||
DWORD
|
||
HTTP_REQUEST_HANDLE_OBJECT::QueryRequestHeadersWithEcho(
|
||
IN BOOL bCrlfTerminated,
|
||
OUT LPVOID lpBuffer OPTIONAL,
|
||
IN OUT LPDWORD lpdwBufferLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Header query for request headers with echo headers added if any..
|
||
|
||
Arguments:
|
||
|
||
bCrlfTerminated - should the headers be seperated by CRLF's
|
||
lpBuffer - pointer to user's buffer
|
||
|
||
lpdwBufferLength - IN: length of user's buffer
|
||
OUT: length of returned information or required buffer
|
||
length if insufficient
|
||
|
||
Return Value:
|
||
|
||
DWORD
|
||
Success - ERROR_SUCCESS
|
||
|
||
Failure -
|
||
|
||
ERROR_INSUFFICIENT_BUFFER
|
||
User's buffer not large enough to hold requested data
|
||
|
||
--*/
|
||
{
|
||
INET_ASSERT(lpdwBufferLength != NULL);
|
||
|
||
DWORD error;
|
||
LPSTR lpszEchoHeaderIn = NULL ;
|
||
LPSTR lpszEchoHeaderOut = NULL;
|
||
DWORD cbHeaderIn = 0;
|
||
DWORD cbHeaderOut = 0;
|
||
BOOL bEchoPresent = FALSE;
|
||
|
||
// List of headers to filter out of the Request headers
|
||
|
||
LPSTR rglpFilter [ ] =
|
||
{
|
||
GlobalKnownHeaders[HTTP_QUERY_AUTHORIZATION].Text,
|
||
GlobalKnownHeaders[HTTP_QUERY_CONNECTION].Text,
|
||
GlobalKnownHeaders[HTTP_QUERY_CONTENT_LENGTH].Text,
|
||
GlobalKnownHeaders[HTTP_QUERY_COOKIE].Text,
|
||
GlobalKnownHeaders[HTTP_QUERY_ECHO_REPLY].Text,
|
||
GlobalKnownHeaders[HTTP_QUERY_HOST].Text,
|
||
GlobalKnownHeaders[HTTP_QUERY_IF_MODIFIED_SINCE].Text,
|
||
GlobalKnownHeaders[HTTP_QUERY_IF_MATCH].Text,
|
||
GlobalKnownHeaders[HTTP_QUERY_IF_NONE_MATCH].Text,
|
||
GlobalKnownHeaders[HTTP_QUERY_IF_RANGE].Text,
|
||
GlobalKnownHeaders[HTTP_QUERY_IF_UNMODIFIED_SINCE].Text,
|
||
GlobalKnownHeaders[HTTP_QUERY_PROXY_AUTHORIZATION].Text,
|
||
GlobalKnownHeaders[HTTP_QUERY_PROXY_CONNECTION].Text,
|
||
GlobalKnownHeaders[HTTP_QUERY_RANGE].Text,
|
||
GlobalKnownHeaders[HTTP_QUERY_UNLESS_MODIFIED_SINCE].Text,
|
||
};
|
||
|
||
if (!_ResponseHeaders.LockHeaders())
|
||
{
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto quit;
|
||
}
|
||
|
||
error = FastQueryResponseHeader(HTTP_QUERY_ECHO_REQUEST,
|
||
(LPVOID *)&lpszEchoHeaderIn,
|
||
&cbHeaderIn,
|
||
0);
|
||
|
||
if (error == ERROR_SUCCESS)
|
||
{
|
||
DWORD cbEchoRequest = GlobalKnownHeaders[HTTP_QUERY_ECHO_REQUEST].Length;
|
||
DWORD cbEchoReply = GlobalKnownHeaders[HTTP_QUERY_ECHO_REPLY].Length;
|
||
|
||
bEchoPresent = TRUE;
|
||
|
||
// Add echo-reply: to the begining of the header.
|
||
cbHeaderOut = cbEchoReply + 1 // For echo-reply:
|
||
+ cbHeaderIn // Send back the stuff from the header.
|
||
+ (bCrlfTerminated ? 2 : 1) // 2 for CRLF
|
||
+ 1; // 1 for NULL terminator
|
||
|
||
lpszEchoHeaderOut = (LPSTR) _alloca(cbHeaderOut); // Add 1 for null terminator.
|
||
|
||
if ( lpszEchoHeaderOut == NULL)
|
||
{
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto done;
|
||
}
|
||
|
||
LPSTR lpsz = lpszEchoHeaderOut;
|
||
|
||
memcpy(lpszEchoHeaderOut, GlobalKnownHeaders[HTTP_QUERY_ECHO_REPLY].Text, cbEchoReply);
|
||
lpsz += cbEchoReply;
|
||
|
||
lpsz[0] = ':';
|
||
lpsz++;
|
||
|
||
|
||
memcpy(lpsz, lpszEchoHeaderIn, cbHeaderIn );
|
||
lpsz += cbHeaderIn;
|
||
|
||
|
||
if ( bCrlfTerminated)
|
||
{
|
||
lpsz[0] = '\r';
|
||
lpsz[1] = '\n';
|
||
lpsz += 2;
|
||
}
|
||
else
|
||
{
|
||
lpsz[0] = '\0';
|
||
lpsz++;
|
||
}
|
||
|
||
*lpsz = '\0';
|
||
}
|
||
|
||
DWORD dwBufferLength;
|
||
dwBufferLength = *lpdwBufferLength;
|
||
|
||
|
||
error = _RequestHeaders.QueryFilteredRawHeaders(
|
||
NULL,
|
||
rglpFilter,
|
||
sizeof(rglpFilter)/sizeof(rglpFilter[0]),
|
||
TRUE,
|
||
TRUE,
|
||
bCrlfTerminated,
|
||
lpBuffer,
|
||
lpdwBufferLength
|
||
);
|
||
|
||
if ( !bEchoPresent )
|
||
{
|
||
// Nothing more to do in this case.
|
||
}
|
||
else if ( error == ERROR_SUCCESS )
|
||
{
|
||
DWORD dwBufferReqd = *lpdwBufferLength + cbHeaderOut;
|
||
// Check if we have space to add extra headers.
|
||
if (dwBufferReqd <= dwBufferLength)
|
||
{
|
||
memcpy((LPSTR)lpBuffer + *lpdwBufferLength, lpszEchoHeaderOut, cbHeaderOut);
|
||
*lpdwBufferLength += cbHeaderOut - 1; // -1 to exclude terminating '\0'
|
||
}
|
||
else
|
||
{
|
||
error = ERROR_INSUFFICIENT_BUFFER;
|
||
// There is a NULL termination count included both in cbHeaderOut and *lpdwBufferLength
|
||
// hence the -1.
|
||
*lpdwBufferLength += cbHeaderOut - 1 ;
|
||
}
|
||
}
|
||
else if ( error == ERROR_INSUFFICIENT_BUFFER )
|
||
{
|
||
*lpdwBufferLength += cbHeaderOut - 1 ;
|
||
}
|
||
else
|
||
{
|
||
// For other errors just return the original error from QueryRawHeaders.
|
||
}
|
||
|
||
done:
|
||
_ResponseHeaders.UnlockHeaders();
|
||
|
||
quit:
|
||
return error;
|
||
}
|