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.
 
 
 
 
 
 

2247 lines
66 KiB

/*++
Copyright (c) 1994-98 Microsoft Corporation
Module Name:
options.cxx
Abstract:
Contains the Internet*Option APIs
Contents:
InternetQueryOptionA
InternetSetOptionA
WinHttpQueryOption
WinHttpSetOption
(FValidCacheHandleType)
Author:
Richard L Firth (rfirth) 02-Mar-1995
Environment:
Win32 user-mode DLL
Revision History:
02-Mar-1995 rfirth
Created
07-Mar-1995 madana
07-Jul-1998 Forked by akabir
--*/
#include <wininetp.h>
#include <perfdiag.hxx>
#include "msident.h"
//
// private macros
//
//
// IS_PER_THREAD_OPTION - options applicable to the thread (HINTERNET is NULL).
// Subset of IS_VALID_OPTION()
//
#define IS_PER_THREAD_OPTION(option) (( \
((option) == WINHTTP_OPTION_EXTENDED_ERROR) \
|| ((option) == WINHTTP_OPTION_PER_CONNECTION_OPTION) \
) ? TRUE : FALSE)
//
// IS_PER_PROCESS_OPTION - options applicable to the process (HINTERNET is NULL).
// Subset of IS_VALID_OPTION()
//
#define IS_PER_PROCESS_OPTION(option) \
(( ((option) == WINHTTP_OPTION_GET_DEBUG_INFO) \
|| ((option) == WINHTTP_OPTION_SET_DEBUG_INFO) \
|| ((option) == WINHTTP_OPTION_GET_HANDLE_COUNT) \
|| ((option) == WINHTTP_OPTION_PROXY) \
|| ((option) == WINHTTP_OPTION_VERSION) \
|| ((option) == WINHTTP_OPTION_HTTP_VERSION) \
|| ((option) == WINHTTP_OPTION_DIGEST_AUTH_UNLOAD) \
|| ((option) == WINHTTP_OPTION_PER_CONNECTION_OPTION) \
|| ((option) == WINHTTP_OPTION_WORKER_THREAD_COUNT) \
) ? TRUE : FALSE)
//
// IS_DEBUG_OPTION - the set of debug-specific options
//
#define IS_DEBUG_OPTION(option) \
(( ((option) >= INTERNET_FIRST_DEBUG_OPTION) \
&& ((option) <= INTERNET_LAST_DEBUG_OPTION) \
) ? TRUE : FALSE)
//
// IS_VALID_OPTION - the set of known option values, for a HINTERNET, thread, or
// process. In the retail version, debug options are invalid
//
#if INET_DEBUG
#define IS_VALID_OPTION(option) \
(((((option) >= WINHTTP_FIRST_OPTION) \
&& ((option) <= WINHTTP_LAST_OPTION_INTERNAL)) \
|| IS_DEBUG_OPTION(option) \
) ? TRUE : FALSE)
#else
#define IS_VALID_OPTION(option) \
(((((option) >= WINHTTP_FIRST_OPTION) \
&& ((option) <= WINHTTP_LAST_OPTION_INTERNAL)) \
) ? TRUE : FALSE)
#endif // INET_DEBUG
//
// private prototypes
//
PRIVATE
BOOL
FValidCacheHandleType(
HINTERNET_HANDLE_TYPE hType
);
PRIVATE
VOID
InitIPCOList(LPINTERNET_PER_CONN_OPTION_LISTW plistW, LPINTERNET_PER_CONN_OPTION_LISTA plistA)
{
plistA->dwSize = sizeof(INTERNET_PER_CONN_OPTION_LISTA);
plistA->dwOptionCount = plistW->dwOptionCount;
if (plistW->pszConnection && *plistW->pszConnection)
{
SHUnicodeToAnsi(plistW->pszConnection, plistA->pszConnection, RAS_MaxEntryName + 1);
}
else
{
plistA->pszConnection = NULL;
}
}
//
// functions
//
INTERNETAPI
BOOL
WINAPI
InternetQueryOptionA(
IN HINTERNET hInternet OPTIONAL,
IN DWORD dwOption,
OUT LPVOID lpBuffer OPTIONAL,
IN OUT LPDWORD lpdwBufferLength
)
/*++
Routine Description:
Returns information about various handle-specific variables
Arguments:
hInternet - handle of object for which information will be
returned
dwOption - the handle-specific WINHTTP_OPTION to query
lpBuffer - pointer to a buffer which will receive results
lpdwBufferLength - IN: number of bytes available in lpBuffer
OUT: number of bytes returned in lpBuffer
Return Value:
BOOL
Success - TRUE
Failure - FALSE. Call GetLastError() for more info:
ERROR_INVALID_HANDLE
hInternet does not identify a valid Internet handle
object
ERROR_WINHTTP_INTERNAL_ERROR
Shouldn't see this?
ERROR_INVALID_PARAMETER
One of the parameters was bad
ERROR_INSUFFICIENT_BUFFER
lpBuffer is not large enough to hold the requested
information; *lpdwBufferLength contains the number of
bytes needed
ERROR_WINHTTP_INCORRECT_HANDLE_TYPE
The handle is the wrong type for the requested option
ERROR_WINHTTP_INVALID_OPTION
The option is unrecognized
--*/
{
DEBUG_ENTER_API((DBG_API,
Bool,
"InternetQueryOptionA",
"%#x, %s (%d), %#x, %#x [%d]",
hInternet,
InternetMapOption(dwOption),
dwOption,
lpBuffer,
lpdwBufferLength,
lpdwBufferLength
? (!IsBadReadPtr(lpdwBufferLength, sizeof(DWORD))
? *lpdwBufferLength
: 0)
: 0
));
DWORD error;
BOOL success;
HINTERNET_HANDLE_TYPE handleType;
LPINTERNET_THREAD_INFO lpThreadInfo;
DWORD requiredSize = 0;
LPVOID lpSource;
DWORD dwValue;
DWORD_PTR dwPtrValue;
HANDLE hValue;
HINTERNET hObjectMapped = NULL;
BOOL isString = FALSE;
INTERNET_DIAGNOSTIC_SOCKET_INFO socketInfo;
if (!GlobalDataInitialized) {
error = GlobalDataInitialize();
if (error != ERROR_SUCCESS) {
goto done;
}
}
lpThreadInfo = InternetGetThreadInfo();
if (lpThreadInfo == NULL) {
error = ERROR_WINHTTP_INTERNAL_ERROR;
goto done;
}
//
// validate parameters
//
INET_ASSERT(lpdwBufferLength);
if (!ARGUMENT_PRESENT(lpBuffer)) {
*lpdwBufferLength = 0;
}
//
// validate the handle and get its type
//
HINTERNET hOriginal;
hOriginal = hInternet;
if (ARGUMENT_PRESENT(hInternet)) {
//
// map the handle
//
error = MapHandleToAddress(hInternet, (LPVOID *)&hObjectMapped, FALSE);
if (error == ERROR_SUCCESS) {
hInternet = hObjectMapped;
error = RGetHandleType(hInternet, &handleType);
}
} else if (IS_PER_THREAD_OPTION(dwOption)) {
//
// this option updates the per-thread information block, so this is a
// good point at which to get it
//
if (lpThreadInfo != NULL) {
error = ERROR_SUCCESS;
} else {
DEBUG_PRINT(INET,
ERROR,
("InternetGetThreadInfo() returns NULL\n"
));
//
// we never expect this - ERROR_WINHTTP_SPANISH_INQUISITION
//
INET_ASSERT(FALSE);
error = ERROR_WINHTTP_INTERNAL_ERROR;
}
} else if (IS_PER_PROCESS_OPTION(dwOption)) {
error = ERROR_SUCCESS;
} else {
//
// catch any invalid options for the NULL handle. If the option is valid
// then it is incorrect for this handle type, otherwise its an invalid
// option, period
//
error = IS_VALID_OPTION(dwOption)
? ERROR_WINHTTP_INCORRECT_HANDLE_TYPE
: ERROR_WINHTTP_INVALID_OPTION
;
}
//
// if the option and handle combination is valid then query the option value
//
if (error != ERROR_SUCCESS) {
goto quit;
}
HTTP_REQUEST_HANDLE_OBJECT* pReq;
switch (handleType)
{
case TypeHttpRequestHandle:
pReq = (HTTP_REQUEST_HANDLE_OBJECT*) hInternet;
break;
case TypeInternetHandle:
pReq = NULL;
break;
default:
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
goto quit;
}
// New fast path for request handle options.
if (dwOption > WINHTTP_OPTION_MASK)
{
dwOption &= WINHTTP_OPTION_MASK;
if (dwOption > MAX_INTERNET_STRING_OPTION)
error = ERROR_INVALID_PARAMETER;
else if (!pReq)
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
else
{
lpSource = pReq->GetProp (dwOption);
isString = TRUE;
error = ERROR_SUCCESS;
}
goto quit;
}
switch (dwOption) {
case WINHTTP_OPTION_CALLBACK:
requiredSize = sizeof(WINHTTP_STATUS_CALLBACK);
if (hInternet != NULL) {
error = RGetStatusCallback(hInternet,
(LPWINHTTP_STATUS_CALLBACK)&dwValue
);
lpSource = (LPVOID)&dwValue;
} else {
error = ERROR_INVALID_HANDLE;
}
break;
case WINHTTP_OPTION_RESOLVE_TIMEOUT:
case WINHTTP_OPTION_CONNECT_TIMEOUT:
case WINHTTP_OPTION_CONNECT_RETRIES:
case WINHTTP_OPTION_SEND_TIMEOUT:
case WINHTTP_OPTION_RECEIVE_TIMEOUT:
requiredSize = sizeof(DWORD);
//
// remember hInternet in the INTERNET_THREAD_INFO then call
// GetTimeoutValue(). If hInternet refers to a valid Internet
// object handle, then the relevant timeout value will be
// returned from that, else we will return the global value
// corresponding to the requested option
//
InternetSetObjectHandle(hOriginal, hInternet);
dwValue = GetTimeoutValue(dwOption);
lpSource = (LPVOID)&dwValue;
break;
case WINHTTP_OPTION_HANDLE_TYPE:
requiredSize = sizeof(dwValue);
switch (handleType)
{
case TypeInternetHandle:
dwValue = WINHTTP_HANDLE_TYPE_SESSION;
break;
case TypeHttpConnectHandle:
dwValue = WINHTTP_HANDLE_TYPE_CONNECT;
break;
case TypeHttpRequestHandle:
dwValue = WINHTTP_HANDLE_TYPE_REQUEST;
break;
default:
error = ERROR_WINHTTP_INTERNAL_ERROR;
break;
}
lpSource = (LPVOID)&dwValue;
break;
case WINHTTP_OPTION_CONTEXT_VALUE:
requiredSize = sizeof(DWORD_PTR);
error = RGetContext(hInternet, &dwPtrValue);
lpSource = (LPVOID)&dwPtrValue;
break;
case WINHTTP_OPTION_READ_BUFFER_SIZE:
case WINHTTP_OPTION_WRITE_BUFFER_SIZE:
if (pReq)
{
requiredSize = sizeof(DWORD);
error = ERROR_SUCCESS;
dwValue = pReq->GetBufferSize(dwOption);
lpSource = (LPVOID)&dwValue;
}
else
{
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
break;
case WINHTTP_OPTION_PARENT_HANDLE:
hInternet = ((HANDLE_OBJECT *)hInternet)->GetParent();
if (hInternet != NULL) {
hInternet = ((HANDLE_OBJECT *)hInternet)->GetPseudoHandle();
}
requiredSize = sizeof(hInternet);
lpSource = (LPVOID)&hInternet;
break;
case WINHTTP_OPTION_EXTENDED_ERROR:
requiredSize = sizeof(lpThreadInfo->dwMappedErrorCode);
lpSource = (LPVOID)&lpThreadInfo->dwMappedErrorCode;
break;
case WINHTTP_OPTION_SECURITY_FLAGS:
if (handleType != TypeHttpRequestHandle)
{
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
else
{
HTTP_REQUEST_HANDLE_OBJECT *lphHttpRqst;
requiredSize = sizeof(dwValue);
dwValue = 0;
lpSource = (LPVOID)&dwValue;
lphHttpRqst = (HTTP_REQUEST_HANDLE_OBJECT *) hInternet;
dwValue = lphHttpRqst->GetSecureFlags();
DEBUG_PRINT(INET,
INFO,
("SECURITY_FLAGS: %X\n",
dwValue
));
error = ERROR_SUCCESS;
}
break;
case WINHTTP_OPTION_URL:
//
// return the URL associated with the request handle. This may be
// different from the original URL due to redirections
//
if (pReq)
{
//
// only these handle types (retrieved object handles) can have
// associated URLs
//
lpSource = pReq->GetURL();
isString = TRUE;
INET_ASSERT(error == ERROR_SUCCESS);
}
else
{
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
break;
case WINHTTP_OPTION_SECURITY_CONNECTION_INFO:
//
// Caller is expected to pass in an INTERNET_SECURITY_CONNECTION_INFO structure.
if (handleType != TypeHttpRequestHandle) {
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
} else if (*lpdwBufferLength < (DWORD)sizeof(INTERNET_SECURITY_CONNECTION_INFO)) {
requiredSize = sizeof(INTERNET_SECURITY_CONNECTION_INFO);
*lpdwBufferLength = requiredSize;
error = ERROR_INSUFFICIENT_BUFFER;
} else {
HTTP_REQUEST_HANDLE_OBJECT *lphHttpRqst;
LPINTERNET_SECURITY_CONNECTION_INFO lpSecConnInfo;
INTERNET_SECURITY_INFO ciInfo;
lphHttpRqst = (HTTP_REQUEST_HANDLE_OBJECT *)hInternet;
lpSecConnInfo = (LPINTERNET_SECURITY_CONNECTION_INFO)lpBuffer;
requiredSize = sizeof(INTERNET_SECURITY_CONNECTION_INFO);
if ((error = lphHttpRqst->GetSecurityInfo(&ciInfo)) == ERROR_SUCCESS) {
// Set up that data members in the structure passed in.
lpSecConnInfo->fSecure = TRUE;
lpSecConnInfo->dwProtocol = ciInfo.dwProtocol;
lpSecConnInfo->aiCipher = ciInfo.aiCipher;
lpSecConnInfo->dwCipherStrength = ciInfo.dwCipherStrength;
lpSecConnInfo->aiHash = ciInfo.aiHash;
lpSecConnInfo->dwHashStrength = ciInfo.dwHashStrength;
lpSecConnInfo->aiExch = ciInfo.aiExch;
lpSecConnInfo->dwExchStrength = ciInfo.dwExchStrength;
if (ciInfo.pCertificate)
{
WRAP_REVERT_USER_VOID(CertFreeCertificateContext, (ciInfo.pCertificate));
}
} else if (error == ERROR_WINHTTP_INTERNAL_ERROR) {
// This implies we are not secure.
error = ERROR_SUCCESS;
lpSecConnInfo->fSecure = FALSE;
}
lpSecConnInfo->dwSize = requiredSize;
*lpdwBufferLength = requiredSize;
}
goto quit;
case WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT:
//
// Allocates memory that caller is expected to free.
//
if (handleType != TypeHttpRequestHandle) {
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
} else {
LPTSTR szResult = NULL;
DWORD cchNeedLen = 0;
HTTP_REQUEST_HANDLE_OBJECT *lphHttpRqst;
INTERNET_SECURITY_INFO cInfo;
lphHttpRqst = (HTTP_REQUEST_HANDLE_OBJECT *) hInternet;
requiredSize = sizeof(INTERNET_CERTIFICATE_INFO);
if (ERROR_SUCCESS == lphHttpRqst->GetSecurityInfo(&cInfo))
{
error = ConvertSecurityInfoIntoCertInfoStruct(&cInfo, (LPINTERNET_CERTIFICATE_INFO)lpBuffer, lpdwBufferLength);
if(cInfo.pCertificate)
{
WRAP_REVERT_USER_VOID(CertFreeCertificateContext, (cInfo.pCertificate));
}
goto quit;
}
else
{
error = ERROR_INVALID_OPERATION;
}
}
break;
case WINHTTP_OPTION_SERVER_CERT_CONTEXT:
if (handleType != TypeHttpRequestHandle)
{
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
else
{
HTTP_REQUEST_HANDLE_OBJECT *lphHttpRqst;
INTERNET_SECURITY_INFO cInfo;
lphHttpRqst = (HTTP_REQUEST_HANDLE_OBJECT *) hInternet;
requiredSize = sizeof(PCERT_CONTEXT);
if (lpBuffer)
{
if (ERROR_SUCCESS == lphHttpRqst->GetSecurityInfo(&cInfo))
{
// GetSecurityInfo calls CertDuplicateCertificateContext, so
// the client app should call CertFreeCertificateContext when
// finished in order to maintain the proper ref count.
*((PCCERT_CONTEXT *) lpBuffer) = cInfo.pCertificate;
}
else
{
error = ERROR_INVALID_OPERATION;
}
}
}
case WINHTTP_OPTION_SECURITY_KEY_BITNESS:
if (handleType != TypeHttpRequestHandle)
{
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
else
{
HTTP_REQUEST_HANDLE_OBJECT *lphHttpRqst;
INTERNET_SECURITY_INFO secInfo;
requiredSize = sizeof(dwValue);
dwValue = 0;
lpSource = (LPVOID)&dwValue;
lphHttpRqst = (HTTP_REQUEST_HANDLE_OBJECT *) hInternet;
if (ERROR_SUCCESS != lphHttpRqst->GetSecurityInfo(&secInfo)) {
error = ERROR_INVALID_OPERATION;
} else {
dwValue = secInfo.dwCipherStrength;
WRAP_REVERT_USER_VOID(CertFreeCertificateContext,
(secInfo.pCertificate));
INET_ASSERT (error == ERROR_SUCCESS);
DEBUG_PRINT(INET,
INFO,
("SECURITY_KEY_BITNESS: %X\n",
dwValue
));
}
}
break;
case WINHTTP_OPTION_PROXY:
if (!ARGUMENT_PRESENT(hInternet)) {
error = g_pGlobalProxyInfo->GetProxyStringInfo(lpBuffer, lpdwBufferLength);
requiredSize = *lpdwBufferLength;
goto quit;
} else if ((handleType == TypeInternetHandle) || (handleType == TypeHttpRequestHandle)) {
//
// GetProxyInfo() will return the data, or calculate the buffer
// length required
//
error = ((INTERNET_HANDLE_BASE *)hInternet)->GetProxyStringInfo(
lpBuffer,
lpdwBufferLength
);
requiredSize = *lpdwBufferLength;
goto quit;
} else {
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
break;
case WINHTTP_OPTION_VERSION:
requiredSize = sizeof(InternetVersionInfo);
lpSource = (LPVOID)&InternetVersionInfo;
break;
case WINHTTP_OPTION_USER_AGENT:
if (handleType == TypeInternetHandle) {
lpSource = ((INTERNET_HANDLE_OBJECT *)hInternet)->GetUserAgent();
isString = TRUE;
} else {
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
break;
case WINHTTP_OPTION_REQUEST_PRIORITY:
if (handleType == TypeHttpRequestHandle) {
requiredSize = sizeof(dwValue);
dwValue = ((HTTP_REQUEST_HANDLE_OBJECT *)hInternet)->GetPriority();
lpSource = (LPVOID)&dwValue;
} else {
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
break;
case WINHTTP_OPTION_HTTP_VERSION:
requiredSize = sizeof(HttpVersionInfo);
lpSource = (LPVOID)&HttpVersionInfo;
break;
case WINHTTP_OPTION_DIAGNOSTIC_SOCKET_INFO:
//
// internal option
//
if (pReq) {
requiredSize = sizeof(socketInfo);
lpSource = (LPVOID)&socketInfo;
socketInfo.Socket = pReq->GetSocket();
socketInfo.SourcePort = pReq->GetSourcePort();
socketInfo.DestPort = pReq->GetDestPort();
socketInfo.Flags = (pReq->FromKeepAlivePool()
? IDSI_FLAG_KEEP_ALIVE : 0)
| (pReq->IsSecure()
? IDSI_FLAG_SECURE : 0)
| (pReq->IsRequestUsingProxy()
? IDSI_FLAG_PROXY : 0)
| (pReq->IsTunnel()
? IDSI_FLAG_TUNNEL : 0);
} else {
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
break;
case WINHTTP_OPTION_MAX_CONNS_PER_SERVER:
case WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER:
if (hInternet)
{
if (handleType == TypeInternetHandle)
{
requiredSize = sizeof(dwValue);
dwValue = 0;
lpSource = (LPVOID)&dwValue;
dwValue = ((INTERNET_HANDLE_OBJECT *)hInternet)->GetMaxConnectionsPerServer(dwOption);
}
else
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
else
error = ERROR_INVALID_OPERATION;
break;
case WINHTTP_OPTION_PER_CONNECTION_OPTION:
{
if (handleType != TypeInternetHandle) {
hInternet = NULL;
}
error = QueryPerConnOptions(hInternet,
FALSE,
(LPINTERNET_PER_CONN_OPTION_LIST)lpBuffer);
requiredSize = *lpdwBufferLength;
goto quit;
}
case WINHTTP_OPTION_WORKER_THREAD_COUNT:
requiredSize = sizeof(DWORD);
dwValue = g_cNumIOCPThreads;
lpSource = (LPVOID)&dwValue;
break;
#if INET_DEBUG
case WINHTTP_OPTION_GET_DEBUG_INFO:
error = InternetGetDebugInfo((LPINTERNET_DEBUG_INFO)lpBuffer,
lpdwBufferLength
);
//
// everything updated, so quit without going through common buffer
// processing
//
goto quit;
break;
case WINHTTP_OPTION_GET_HANDLE_COUNT:
requiredSize = sizeof(DWORD);
dwValue = InternetHandleCount();
lpSource = (LPVOID)&dwValue;
break;
#endif // INET_DEBUG
default:
requiredSize = 0;
error = ERROR_INVALID_PARAMETER;
break;
}
//
// if we have a buffer and enough space, then copy the data
//
if (error == ERROR_SUCCESS) {
//
// if we are returning a string, calculate the amount of space
// required to hold it
//
if (isString) {
if (lpSource != NULL) {
requiredSize = lstrlen((LPCSTR)lpSource) + 1;
} else {
//
// option string is NULL: return an empty string
//
lpSource = "";
requiredSize = 1;
}
}
INET_ASSERT(lpSource != NULL);
if ((*lpdwBufferLength >= requiredSize)
&& ARGUMENT_PRESENT(lpBuffer)) {
memcpy(lpBuffer, lpSource, requiredSize);
if (isString) {
//
// string copied successfully. Returned length is string
// length, not buffer length, i.e. drop 1 for '\0'
//
--requiredSize;
}
} else {
error = ERROR_INSUFFICIENT_BUFFER;
}
}
quit:
//
// return the amount the app needs to supply, or the amount of data in the
// buffer, depending on success/failure status
//
*lpdwBufferLength = requiredSize;
if (hObjectMapped != NULL) {
DereferenceObject((LPVOID)hObjectMapped);
}
done:
if (error == ERROR_SUCCESS) {
success = TRUE;
IF_DEBUG(API) {
if (isString) {
DEBUG_PRINT_API(API,
INFO,
("returning %q (%d chars)\n",
lpBuffer,
requiredSize
));
} else {
DEBUG_DUMP_API(API,
"option data:\n",
lpBuffer,
requiredSize
);
}
}
} else {
DEBUG_ERROR(API, error);
IF_DEBUG(API) {
if (error == ERROR_INSUFFICIENT_BUFFER) {
DEBUG_PRINT_API(API,
INFO,
("*lpdwBufferLength (%#x)= %d\n",
lpdwBufferLength,
*lpdwBufferLength
));
}
}
SetLastError(error);
success = FALSE;
}
DEBUG_LEAVE_API(success);
return success;
}
INTERNETAPI
BOOL
WINAPI
WinHttpQueryOption(
IN HINTERNET hInternet OPTIONAL,
IN DWORD dwOption,
OUT LPVOID lpBuffer OPTIONAL,
IN OUT LPDWORD lpdwBufferLength
)
/*++
Routine Description:
description-of-function.
Arguments:
hInternet -
dwOption -
lpBuffer -
lpdwBufferLength -
Return Value:
BOOL
--*/
{
DEBUG_ENTER_API((DBG_API,
Bool,
"WinHttpQueryOption",
"%#x, %s (%d), %#x, %#x [%d]",
hInternet,
InternetMapOption(dwOption),
dwOption,
lpBuffer,
lpdwBufferLength,
lpdwBufferLength
? (!IsBadReadPtr(lpdwBufferLength, sizeof(DWORD))
? *lpdwBufferLength
: 0)
: 0
));
DWORD dwErr = ERROR_SUCCESS;
BOOL fResult = FALSE;
MEMORYPACKET mpBuffer;
if (!lpdwBufferLength
|| IsBadWritePtr(lpdwBufferLength, sizeof(*lpdwBufferLength))
|| (lpBuffer && *lpdwBufferLength && IsBadWritePtr(lpBuffer, *lpdwBufferLength)) )
{
dwErr = ERROR_INVALID_PARAMETER;
goto cleanup;
}
switch (dwOption)
{
case WINHTTP_OPTION_USERNAME:
case WINHTTP_OPTION_PASSWORD:
case WINHTTP_OPTION_URL:
case WINHTTP_OPTION_USER_AGENT:
case WINHTTP_OPTION_PROXY_USERNAME:
case WINHTTP_OPTION_PROXY_PASSWORD:
if (lpBuffer)
{
mpBuffer.dwAlloc = mpBuffer.dwSize = *lpdwBufferLength;
mpBuffer.psStr = (LPSTR)ALLOC_BYTES(mpBuffer.dwAlloc*sizeof(CHAR));
if (!mpBuffer.psStr)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
break;
}
}
fResult = InternetQueryOptionA(hInternet,
dwOption,
(LPVOID)mpBuffer.psStr,
&mpBuffer.dwSize
);
if (fResult)
{
*lpdwBufferLength = sizeof(WCHAR) *
MultiByteToWideChar(CP_ACP, 0, mpBuffer.psStr, mpBuffer.dwSize + 1, NULL, 0);
if (*lpdwBufferLength <= mpBuffer.dwAlloc && lpBuffer)
{
MultiByteToWideChar(CP_ACP, 0, mpBuffer.psStr, mpBuffer.dwSize+1,
(LPWSTR)lpBuffer, *lpdwBufferLength);
(*lpdwBufferLength)-=sizeof(WCHAR);
}
else
{
fResult = FALSE;
dwErr = ERROR_INSUFFICIENT_BUFFER;
}
}
else
{
if (GetLastError()==ERROR_INSUFFICIENT_BUFFER)
{
*lpdwBufferLength = mpBuffer.dwSize*sizeof(WCHAR);
}
}
break;
case WINHTTP_OPTION_PER_CONNECTION_OPTION:
{
if (!lpBuffer)
{
dwErr = ERROR_INVALID_PARAMETER;
break;
}
INTERNET_PER_CONN_OPTION_LISTA listA;
LPINTERNET_PER_CONN_OPTION_LISTW plistW = (LPINTERNET_PER_CONN_OPTION_LISTW)lpBuffer;
CHAR szEntryA[RAS_MaxEntryName + 1];
listA.pszConnection = szEntryA;
InitIPCOList(plistW, &listA);
listA.pOptions = (LPINTERNET_PER_CONN_OPTIONA)_alloca(sizeof(INTERNET_PER_CONN_OPTIONA)*listA.dwOptionCount);
for (DWORD i=0; i<listA.dwOptionCount; i++)
{
listA.pOptions[i].dwOption = plistW->pOptions[i].dwOption;
listA.pOptions[i].Value.pszValue = NULL;
plistW->pOptions[i].Value.pszValue = NULL;
}
fResult = InternetQueryOptionA(hInternet,
dwOption,
(PVOID)&listA,
lpdwBufferLength);
// Now, convert from ansi to unicode
if (fResult)
{
for (DWORD i=0; i<listA.dwOptionCount; i++)
{
switch (listA.pOptions[i].dwOption)
{
case INTERNET_PER_CONN_FLAGS:
case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
plistW->pOptions[i].Value.dwValue = listA.pOptions[i].Value.dwValue;
break;
case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
plistW->pOptions[i].Value.ftValue = listA.pOptions[i].Value.ftValue;
break;
case INTERNET_PER_CONN_PROXY_SERVER:
case INTERNET_PER_CONN_PROXY_BYPASS:
case INTERNET_PER_CONN_AUTOCONFIG_URL:
case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
if (listA.pOptions[i].Value.pszValue && *listA.pOptions[i].Value.pszValue)
{
DWORD cc = MultiByteToWideChar(CP_ACP,
0,
listA.pOptions[i].Value.pszValue,
-1,
NULL,
0);
plistW->pOptions[i].Value.pszValue = (PWSTR)GlobalAlloc(GPTR, cc*sizeof(WCHAR));
if (!plistW->pOptions[i].Value.pszValue)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
goto iopco_cleanup;
}
MultiByteToWideChar(CP_ACP,
0,
listA.pOptions[i].Value.pszValue,
-1,
plistW->pOptions[i].Value.pszValue,
cc);
}
break;
default:
INET_ASSERT(FALSE);
dwErr = ERROR_INVALID_PARAMETER;
goto iopco_cleanup;
break;
}
}
}
else
{
plistW->dwOptionError = listA.dwOptionError;
}
iopco_cleanup:
// Free all the allocated buffers
for (i=0; i<listA.dwOptionCount; i++)
{
switch (listA.pOptions[i].dwOption)
{
case INTERNET_PER_CONN_PROXY_SERVER:
case INTERNET_PER_CONN_PROXY_BYPASS:
case INTERNET_PER_CONN_AUTOCONFIG_URL:
case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
// These should have been converted from ansi to unicode
// and can be freed now
if (listA.pOptions[i].Value.pszValue)
{
GlobalFree(listA.pOptions[i].Value.pszValue);
}
// No point in passing back buffers in the event of an error
// condition
if (dwErr && plistW->pOptions[i].Value.pszValue)
{
GlobalFree(plistW->pOptions[i].Value.pszValue);
}
break;
default:
// No need to do anything
break;
}
}
}
break;
case WINHTTP_OPTION_PROXY:
{
WINHTTP_PROXY_INFOW * pInfo = (WINHTTP_PROXY_INFOW *) lpBuffer;
union
{
WINHTTP_PROXY_INFOA InfoA;
char Buffer[1024];
};
char * pBuffer;
DWORD dwBufferLen = sizeof(Buffer);
bool fFreeBuffer = false;
if (IsBadWritePtr(pInfo, sizeof(WINHTTP_PROXY_INFOW)) ||
(*lpdwBufferLength < sizeof(WINHTTP_PROXY_INFOW)))
{
dwErr = ERROR_INVALID_PARAMETER;
break;
}
fResult = InternetQueryOptionA(hInternet, WINHTTP_OPTION_PROXY,
(void *) &Buffer,
&dwBufferLen);
if (!fResult && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
{
pBuffer = New char[dwBufferLen];
if (pBuffer)
{
fFreeBuffer = true;
fResult = InternetQueryOptionA(hInternet, WINHTTP_OPTION_PROXY,
(void *) pBuffer,
&dwBufferLen);
}
else
dwErr = ERROR_NOT_ENOUGH_MEMORY;
}
if (fResult)
{
pInfo->dwAccessType = InfoA.dwAccessType;
dwErr = AsciiToWideChar_UsingGlobalAlloc(InfoA.lpszProxy,
&(pInfo->lpszProxy));
if (dwErr == ERROR_SUCCESS)
{
dwErr = AsciiToWideChar_UsingGlobalAlloc(InfoA.lpszProxyBypass,
&(pInfo->lpszProxyBypass));
if ((dwErr != ERROR_SUCCESS) && (pInfo->lpszProxy != NULL))
{
GlobalFree(pInfo->lpszProxy);
pInfo->lpszProxy = NULL;
}
}
fResult = (dwErr == ERROR_SUCCESS);
}
if (fFreeBuffer)
{
delete [] pBuffer;
}
}
break;
default:
fResult = InternetQueryOptionA(hInternet,
dwOption,
lpBuffer,
lpdwBufferLength
);
}
cleanup:
if (dwErr!=ERROR_SUCCESS)
{
SetLastError(dwErr);
DEBUG_ERROR(INET, dwErr);
}
DEBUG_LEAVE_API(fResult);
return fResult;
}
INTERNETAPI
BOOL
WINAPI
InternetSetOptionA(
IN HINTERNET hInternet OPTIONAL,
IN DWORD dwOption,
IN LPVOID lpBuffer,
IN DWORD dwBufferLength
)
/*++
Routine Description:
Sets a handle-specific variable, or a per-thread variable
Arguments:
hInternet - handle of object for which information will be set,
or NULL if the option defines a per-thread variable
dwOption - the handle-specific WINHTTP_OPTION to set
lpBuffer - pointer to a buffer containing value to set
dwBufferLength - size of lpBuffer
Return Value:
BOOL
Success - TRUE
Failure - FALSE. Call GetLastError() for more info:
ERROR_INVALID_HANDLE
hInternet does not identify a valid Internet handle
object
ERROR_WINHTTP_INTERNAL_ERROR
Shouldn't see this?
ERROR_INVALID_PARAMETER
One of the parameters was bad
ERROR_WINHTTP_INVALID_OPTION
The requested option cannot be set
ERROR_WINHTTP_OPTION_NOT_SETTABLE
Can't set this option, only query it
ERROR_INSUFFICIENT_BUFFER
The dwBufferLength parameter is incorrect for the
expected type of the option
--*/
{
DEBUG_ENTER_API((DBG_API,
Bool,
"InternetSetOptionA",
"%#x, %s (%d), %#x [%#x], %d",
hInternet,
InternetMapOption(dwOption),
dwOption,
lpBuffer,
lpBuffer
? (!IsBadReadPtr(lpBuffer, sizeof(DWORD))
? *(LPDWORD)lpBuffer
: 0)
: 0,
dwBufferLength
));
DWORD error;
BOOL success = TRUE;
HINTERNET_HANDLE_TYPE handleType;
LPINTERNET_THREAD_INFO lpThreadInfo;
DWORD requiredSize;
HINTERNET hObjectMapped = NULL;
INET_ASSERT(dwBufferLength != 0);
if (!GlobalDataInitialized) {
error = GlobalDataInitialize();
if (error != ERROR_SUCCESS) {
goto done;
}
}
//
// validate the handle and get its type
//
if (ARGUMENT_PRESENT(hInternet)) {
//
// map the handle
//
error = MapHandleToAddress(hInternet, (LPVOID *)&hObjectMapped, FALSE);
if (error == ERROR_SUCCESS) {
hInternet = hObjectMapped;
error = RGetHandleType(hInternet, &handleType);
}
} else if (IS_PER_THREAD_OPTION(dwOption)) {
//
// this option updates the per-thread information block, so this is a
// good point at which to get it
//
lpThreadInfo = InternetGetThreadInfo();
if (lpThreadInfo != NULL) {
error = ERROR_SUCCESS;
} else {
DEBUG_PRINT(INET,
ERROR,
("InternetGetThreadInfo() returns NULL\n"
));
//
// we never expect this - ERROR_WINHTTP_SPANISH_INQUISITION
//
INET_ASSERT(FALSE);
error = ERROR_WINHTTP_INTERNAL_ERROR;
}
} else if (IS_PER_PROCESS_OPTION(dwOption)) {
error = ERROR_SUCCESS;
} else {
//
// catch any invalid options for the NULL handle. If the option is valid
// then it is incorrect for this handle type, otherwise its an invalid
// option, period
//
error = IS_VALID_OPTION(dwOption)
? ERROR_WINHTTP_INCORRECT_HANDLE_TYPE
: ERROR_WINHTTP_INVALID_OPTION
;
}
if (error != ERROR_SUCCESS) {
goto quit;
}
HTTP_REQUEST_HANDLE_OBJECT *pReq;
switch (handleType)
{
case TypeHttpRequestHandle:
pReq = (HTTP_REQUEST_HANDLE_OBJECT*) hInternet;
break;
case TypeInternetHandle:
pReq = NULL;
break;
default:
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
goto quit;
}
// New fast path for request handle options.
if (dwOption > WINHTTP_OPTION_MASK)
{
dwOption &= WINHTTP_OPTION_MASK;
if (dwOption > MAX_INTERNET_STRING_OPTION)
error = ERROR_INVALID_PARAMETER;
else if (!pReq)
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
else if (pReq->SetProp (dwOption, (LPSTR) lpBuffer))
error = ERROR_SUCCESS;
else
error = ERROR_WINHTTP_INTERNAL_ERROR;
goto quit;
}
//
// if the option and handle combination is valid then set the option value
//
switch (dwOption) {
case WINHTTP_OPTION_CALLBACK:
case WINHTTP_OPTION_HANDLE_TYPE:
// these options cannot be set by this function
error = ERROR_WINHTTP_OPTION_NOT_SETTABLE;
break;
case WINHTTP_OPTION_RESOLVE_TIMEOUT:
case WINHTTP_OPTION_CONNECT_TIMEOUT:
case WINHTTP_OPTION_CONNECT_RETRIES:
case WINHTTP_OPTION_SEND_TIMEOUT:
case WINHTTP_OPTION_RECEIVE_TIMEOUT:
requiredSize = sizeof(DWORD);
if (dwBufferLength != requiredSize)
{
error = ERROR_INSUFFICIENT_BUFFER;
break;
}
// For WinHttp, these options are per-handle, not per-process.
if (hInternet == NULL)
{
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
break;
}
// we have a non-NULL context handle: the app wants to set specific
// protocol timeouts
switch (handleType)
{
case TypeInternetHandle:
//only error possible is in allocing memory for OPTIONAL_PARAMS struct
if (! ((INTERNET_HANDLE_OBJECT*)hObjectMapped)->SetTimeout(dwOption, *(LPDWORD)lpBuffer) )
{
error = ERROR_NOT_ENOUGH_MEMORY;
}
break;
case TypeHttpRequestHandle:
// no errors possible here
((HTTP_REQUEST_HANDLE_OBJECT*)hObjectMapped)->SetTimeout(dwOption, *(LPDWORD)lpBuffer);
break;
default:
// any other handle type (?) cannot have timeouts set for it
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
break;
}
break;
case WINHTTP_OPTION_CONTEXT_VALUE:
//
// BUGBUG - can't change context if async operation is pending
//
if (dwBufferLength == sizeof(LPVOID)) {
error = RSetContext(hInternet, *((DWORD_PTR *) lpBuffer));
} else {
error = ERROR_INSUFFICIENT_BUFFER;
}
break;
case WINHTTP_OPTION_READ_BUFFER_SIZE:
case WINHTTP_OPTION_WRITE_BUFFER_SIZE:
if (pReq)
{
if (dwBufferLength == sizeof(DWORD))
{
DWORD bufferSize;
bufferSize = *(LPDWORD)lpBuffer;
if (bufferSize > 0)
{
pReq->SetBufferSize(dwOption, bufferSize);
error = ERROR_SUCCESS;
}
else // the read/write buffer size cannot be set to 0
{
error = ERROR_INVALID_PARAMETER;
}
}
else
{
error = ERROR_INSUFFICIENT_BUFFER;
}
}
else
{
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
break;
case WINHTTP_OPTION_CLIENT_CERT_CONTEXT:
if (handleType != TypeHttpRequestHandle)
{
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
else if (dwBufferLength < sizeof(CERT_CONTEXT))
{
error = ERROR_INSUFFICIENT_BUFFER;
}
else
{
HTTP_REQUEST_HANDLE_OBJECT *pRequest =
(HTTP_REQUEST_HANDLE_OBJECT *) hInternet;
CERT_CONTEXT_ARRAY* pArray = pRequest->GetCertContextArray();
if (!pArray)
error = ERROR_WINHTTP_NOT_INITIALIZED;
else
{
pArray->Reset();
pArray->AddCertContext((PCCERT_CONTEXT) lpBuffer);
pArray->SelectCertContext(0);
error = ERROR_SUCCESS;
}
}
break;
case WINHTTP_OPTION_SECURITY_FLAGS:
if (handleType != TypeHttpRequestHandle)
{
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
else if (dwBufferLength < sizeof(DWORD))
{
error = ERROR_INSUFFICIENT_BUFFER;
}
else
{
HTTP_REQUEST_HANDLE_OBJECT *lphHttpRqst;
lphHttpRqst = (HTTP_REQUEST_HANDLE_OBJECT *) hInternet;
lphHttpRqst->SetSecureFlags(*(LPDWORD)lpBuffer);
error = ERROR_SUCCESS;
}
break;
case WINHTTP_OPTION_PROXY:
if ((handleType == TypeInternetHandle) || (handleType == TypeHttpRequestHandle))
{
WINHTTP_PROXY_INFOA * lpInfo = (WINHTTP_PROXY_INFOA *) lpBuffer;
//
// validate parameters
//
if (dwBufferLength != sizeof(*lpInfo))
{
error = ERROR_INSUFFICIENT_BUFFER;
}
else if (!((lpInfo->dwAccessType == WINHTTP_ACCESS_TYPE_NO_PROXY)
|| (lpInfo->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY))
|| ((lpInfo->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
&& ((lpInfo->lpszProxy == NULL) || (*lpInfo->lpszProxy == '\0'))))
{
error = ERROR_INVALID_PARAMETER;
}
else
{
error = ((INTERNET_HANDLE_BASE *)hInternet)->SetProxyInfo(
lpInfo->dwAccessType,
lpInfo->lpszProxy,
lpInfo->lpszProxyBypass
);
}
}
else
{
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
break;
case WINHTTP_OPTION_USER_AGENT:
if (*(LPSTR)lpBuffer == '\0') {
error = ERROR_INSUFFICIENT_BUFFER;
} else {
if ((handleType == TypeInternetHandle) || (handleType == TypeHttpRequestHandle))
{
((INTERNET_HANDLE_BASE *)hInternet)->SetUserAgent((LPSTR)lpBuffer);
} else {
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
}
break;
case WINHTTP_OPTION_DIGEST_AUTH_UNLOAD:
if (DIGEST_CTX::g_pFuncTbl)
{
DIGEST_CTX::Logoff();
DIGEST_CTX::g_pFuncTbl = NULL;
}
break;
case WINHTTP_OPTION_REQUEST_PRIORITY:
if (handleType == TypeHttpRequestHandle) {
if (dwBufferLength == sizeof(LONG)) {
((HTTP_REQUEST_HANDLE_OBJECT *)hInternet)->
SetPriority(*(LPLONG)lpBuffer);
} else {
error = ERROR_INSUFFICIENT_BUFFER;
}
} else {
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
break;
case WINHTTP_OPTION_HTTP_VERSION:
if (dwBufferLength == sizeof(HTTP_VERSION_INFO)) {
HttpVersionInfo = *(LPHTTP_VERSION_INFO)lpBuffer;
} else {
error = ERROR_INSUFFICIENT_BUFFER;
}
break;
case WINHTTP_OPTION_DISABLE_FEATURE:
if (handleType != TypeHttpRequestHandle)
{
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
else if (dwBufferLength < sizeof(DWORD))
{
error = ERROR_INVALID_PARAMETER;
}
else
{
HTTP_REQUEST_HANDLE_OBJECT *pRequest =
(HTTP_REQUEST_HANDLE_OBJECT *) hInternet;
DWORD dwDisable = *((LPDWORD) lpBuffer);
if (dwDisable & WINHTTP_DISABLE_KEEP_ALIVE)
{
DWORD dwFlags = pRequest->GetOpenFlags();
dwFlags &= ~INTERNET_FLAG_KEEP_CONNECTION;
pRequest->SetOpenFlags (dwFlags);
}
if (dwDisable & WINHTTP_DISABLE_REDIRECTS)
{
DWORD dwFlags = pRequest->GetOpenFlags();
dwFlags |= INTERNET_FLAG_NO_AUTO_REDIRECT;
pRequest->SetOpenFlags (dwFlags);
}
if (dwDisable & WINHTTP_DISABLE_COOKIES)
{
DWORD dwFlags = pRequest->GetOpenFlags();
dwFlags |= INTERNET_FLAG_NO_COOKIES;
pRequest->SetOpenFlags (dwFlags);
}
if (dwDisable & WINHTTP_DISABLE_AUTHENTICATION)
{
DWORD dwFlags = pRequest->GetOpenFlags();
dwFlags |= INTERNET_FLAG_NO_AUTH;
pRequest->SetOpenFlags (dwFlags);
}
error = ERROR_SUCCESS;
}
break;
case WINHTTP_OPTION_ENABLE_FEATURE:
if (handleType != TypeHttpRequestHandle)
{
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
else if (dwBufferLength < sizeof(DWORD))
{
error = ERROR_INVALID_PARAMETER;
}
else
{
HTTP_REQUEST_HANDLE_OBJECT *pRequest =
(HTTP_REQUEST_HANDLE_OBJECT *) hInternet;
DWORD dwDisable = *((LPDWORD) lpBuffer);
pRequest->SetEnableFlags(*((LPDWORD) lpBuffer));
error = ERROR_SUCCESS;
}
break;
case WINHTTP_OPTION_CODEPAGE:
if ((hInternet == NULL) || (handleType == TypeHttpRequestHandle))
{
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
else
{
if (dwBufferLength == sizeof(DWORD))
{
((INTERNET_HANDLE_BASE *)hInternet)->SetCodePage(*(LPDWORD)lpBuffer);
}
else
{
error = ERROR_INSUFFICIENT_BUFFER;
}
}
break;
case WINHTTP_OPTION_MAX_CONNS_PER_SERVER:
case WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER:
if (handleType == TypeInternetHandle)
{
if (dwBufferLength == sizeof(DWORD))
{
((INTERNET_HANDLE_OBJECT *)hInternet)->SetMaxConnectionsPerServer(dwOption, *(DWORD *)lpBuffer);
}
else
error = ERROR_INSUFFICIENT_BUFFER;
}
else
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
break;
case WINHTTP_OPTION_PER_CONNECTION_OPTION:
{
if (handleType != TypeInternetHandle) {
hInternet = NULL;
}
error = SetPerConnOptions(hInternet,
FALSE,
(LPINTERNET_PER_CONN_OPTION_LIST)lpBuffer);
break;
}
case WINHTTP_OPTION_AUTOLOGON_POLICY:
if (handleType != TypeHttpRequestHandle)
{
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
else if (dwBufferLength < sizeof(DWORD))
{
error = ERROR_INSUFFICIENT_BUFFER;
}
else
{
HTTP_REQUEST_HANDLE_OBJECT *lphHttpRqst;
lphHttpRqst = (HTTP_REQUEST_HANDLE_OBJECT *) hInternet;
lphHttpRqst->SetSecurityLevel(*(LPDWORD)lpBuffer);
error = ERROR_SUCCESS;
}
break;
case WINHTTP_OPTION_WORKER_THREAD_COUNT:
if (dwBufferLength < sizeof(DWORD))
{
error = ERROR_INSUFFICIENT_BUFFER;
}
else
{
if (!g_cNumIOCPThreads)
{
g_cNumIOCPThreads = *(LPDWORD)lpBuffer;
error = ERROR_SUCCESS;
}
else
{
error = ERROR_WINHTTP_OPTION_NOT_SETTABLE;
}
}
break;
#if INET_DEBUG
case WINHTTP_OPTION_SET_DEBUG_INFO:
error = InternetSetDebugInfo((LPINTERNET_DEBUG_INFO)lpBuffer,
dwBufferLength
);
break;
#endif // INET_DEBUG
default:
//
// this option is not recognized
//
error = ERROR_WINHTTP_INVALID_OPTION;
}
quit:
if (hObjectMapped != NULL) {
DereferenceObject((LPVOID)hObjectMapped);
}
done:
if (error != ERROR_SUCCESS) {
DEBUG_ERROR(API, error);
SetLastError(error);
success = FALSE;
}
DEBUG_LEAVE_API(success);
return success;
}
#define CHECK_MODIFY_TIMEOUT(nTimeout) \
{ \
if (nTimeout <= 0) \
{ \
if (nTimeout == 0) \
{ \
nTimeout = (int)INFINITE; \
} \
else if (nTimeout < -1) \
{ \
dwError = ERROR_INVALID_PARAMETER; \
goto quit; \
} \
} \
}
INTERNETAPI
BOOL
WINAPI
WinHttpSetTimeouts(
IN HINTERNET hInternet, // Session/Request handle.
IN int nResolveTimeout,
IN int nConnectTimeout,
IN int nSendTimeout,
IN int nReceiveTimeout
)
{
DEBUG_ENTER_API((DBG_API,
Bool,
"WinHttpSetTimeouts",
"%#x, %d, %d, %d, %d",
hInternet,
nResolveTimeout,
nConnectTimeout,
nSendTimeout,
nReceiveTimeout
));
DWORD dwError = ERROR_SUCCESS;
BOOL bRetval = FALSE;
HINTERNET_HANDLE_TYPE handleType;
HINTERNET hObjectMapped = NULL;
if (!hInternet)
{
dwError = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
goto quit;
}
CHECK_MODIFY_TIMEOUT(nResolveTimeout);
CHECK_MODIFY_TIMEOUT(nConnectTimeout);
CHECK_MODIFY_TIMEOUT(nSendTimeout);
CHECK_MODIFY_TIMEOUT(nReceiveTimeout);
dwError = MapHandleToAddress(hInternet, (LPVOID *)&hObjectMapped, FALSE);
if (dwError != ERROR_SUCCESS)
{
goto quit;
}
dwError = RGetHandleType(hObjectMapped, &handleType);
if (dwError != ERROR_SUCCESS)
{
goto quit;
}
switch(handleType)
{
case TypeInternetHandle:
//only error possible is in allocing memory for OPTIONAL_PARAMS struct
bRetval = ((INTERNET_HANDLE_OBJECT*)hObjectMapped)->SetTimeouts(
nResolveTimeout, nConnectTimeout, nSendTimeout, nReceiveTimeout);
if (!bRetval)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
goto quit;
}
break;
case TypeHttpRequestHandle:
// no errors possible here
bRetval = ((HTTP_REQUEST_HANDLE_OBJECT*)hObjectMapped)->SetTimeouts(
nResolveTimeout, nConnectTimeout, nSendTimeout, nReceiveTimeout);
INET_ASSERT(bRetval);
break;
default:
// any other handle type cannot have timeouts set for it
dwError = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
break;
}
quit:
if (hObjectMapped)
{
DereferenceObject((LPVOID)hObjectMapped);
}
if (dwError != ERROR_SUCCESS)
{
::SetLastError(dwError);
INET_ASSERT(!bRetval);
}
DEBUG_LEAVE_API(bRetval);
return bRetval;
}
INTERNETAPI
BOOL
WINAPI
WinHttpSetOption(
IN HINTERNET hInternet OPTIONAL,
IN DWORD dwOption,
IN LPVOID lpBuffer,
IN DWORD dwBufferLength
)
/*++
Routine Description:
description-of-function.
Arguments:
hInternet -
dwOption -
lpBuffer -
dwBufferLength -
Return Value:
BOOL
--*/
{
DEBUG_ENTER_API((DBG_API,
Bool,
"WinHttpSetOption",
"%#x, %s (%d), %#x [%#x], %d",
hInternet,
InternetMapOption(dwOption),
dwOption,
lpBuffer,
lpBuffer
? (!IsBadReadPtr(lpBuffer, sizeof(DWORD))
? *(LPDWORD)lpBuffer
: 0)
: 0,
dwBufferLength
));
DWORD dwErr = ERROR_SUCCESS;
MEMORYPACKET mpBuffer;
BOOL fResult = FALSE;
//
// validate parameters
//
if ((dwBufferLength == 0) || IsBadReadPtr(lpBuffer, dwBufferLength))
{
switch (dwOption)
{
//
// these options don't require a buffer - don't fail request because
// no buffer supplied
//
case WINHTTP_OPTION_DIGEST_AUTH_UNLOAD:
if (dwBufferLength == 0)
break;
break;
default:
dwErr = ERROR_INVALID_PARAMETER;
goto cleanup;
}
}
switch (dwOption)
{
case WINHTTP_OPTION_USERNAME:
case WINHTTP_OPTION_PASSWORD:
case WINHTTP_OPTION_URL:
case WINHTTP_OPTION_USER_AGENT:
case WINHTTP_OPTION_PROXY_USERNAME:
case WINHTTP_OPTION_PROXY_PASSWORD:
ALLOC_MB((LPWSTR)lpBuffer, dwBufferLength, mpBuffer);
if (!mpBuffer.psStr)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
goto cleanup;
}
UNICODE_TO_ANSI((LPWSTR)lpBuffer, mpBuffer);
fResult = InternetSetOptionA(hInternet,
dwOption,
mpBuffer.psStr,
mpBuffer.dwSize
);
break;
case WINHTTP_OPTION_PER_CONNECTION_OPTION:
{
if (!lpBuffer)
{
dwErr = ERROR_INVALID_PARAMETER;
goto cleanup;
}
INTERNET_PER_CONN_OPTION_LISTA listA;
LPINTERNET_PER_CONN_OPTION_LISTW plistW = (LPINTERNET_PER_CONN_OPTION_LISTW)lpBuffer;
CHAR szEntryA[RAS_MaxEntryName + 1];
listA.pszConnection = szEntryA;
InitIPCOList(plistW, &listA);
listA.pOptions = (LPINTERNET_PER_CONN_OPTIONA)_alloca(sizeof(INTERNET_PER_CONN_OPTIONA)*listA.dwOptionCount);
for (DWORD i=0; i<listA.dwOptionCount; i++)
{
listA.pOptions[i].dwOption = plistW->pOptions[i].dwOption;
switch (listA.pOptions[i].dwOption)
{
case INTERNET_PER_CONN_FLAGS:
case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
listA.pOptions[i].Value.dwValue = plistW->pOptions[i].Value.dwValue;
break;
case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
listA.pOptions[i].Value.ftValue = plistW->pOptions[i].Value.ftValue;
break;
case INTERNET_PER_CONN_PROXY_SERVER:
case INTERNET_PER_CONN_PROXY_BYPASS:
case INTERNET_PER_CONN_AUTOCONFIG_URL:
case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
if (plistW->pOptions[i].Value.pszValue && *plistW->pOptions[i].Value.pszValue)
{
// ** WARNING ** NO UTF8 ENCODING HERE
DWORD cb = WideCharToMultiByte(CP_ACP,
0,
plistW->pOptions[i].Value.pszValue,
-1,
0,
0,
NULL,
NULL);
listA.pOptions[i].Value.pszValue = (PSTR)_alloca(cb);
WideCharToMultiByte(CP_ACP,
0,
plistW->pOptions[i].Value.pszValue,
-1,
listA.pOptions[i].Value.pszValue,
cb,
NULL,
NULL);
}
else
{
listA.pOptions[i].Value.pszValue = NULL;
}
break;
default:
dwErr = ERROR_INVALID_PARAMETER;
goto cleanup;
break;
}
}
fResult = InternetSetOptionA(hInternet,
dwOption,
(PVOID)&listA,
dwBufferLength);
plistW->dwOptionError = listA.dwOptionError;
}
break;
case WINHTTP_OPTION_PROXY:
{
WINHTTP_PROXY_INFOW * pInfo = (WINHTTP_PROXY_INFOW *) lpBuffer;
WINHTTP_PROXY_INFOA InfoA;
if (IsBadReadPtr(pInfo, sizeof(WINHTTP_PROXY_INFOW)) || (dwBufferLength < sizeof(WINHTTP_PROXY_INFOW)))
{
dwErr = ERROR_INVALID_PARAMETER;
break;
}
InfoA.dwAccessType = pInfo->dwAccessType;
dwErr = WideCharToAscii(pInfo->lpszProxy, &InfoA.lpszProxy);
if (dwErr == ERROR_SUCCESS)
{
dwErr = WideCharToAscii(pInfo->lpszProxyBypass, &InfoA.lpszProxyBypass);
if (dwErr == ERROR_SUCCESS)
{
fResult = InternetSetOptionA(hInternet, WINHTTP_OPTION_PROXY, &InfoA, sizeof(InfoA));
if (InfoA.lpszProxyBypass)
{
delete [] InfoA.lpszProxyBypass;
}
}
if (InfoA.lpszProxy)
{
delete [] InfoA.lpszProxy;
}
}
}
break;
default:
fResult = InternetSetOptionA(hInternet,
dwOption,
lpBuffer,
dwBufferLength
);
}
cleanup:
if (dwErr!=ERROR_SUCCESS)
{
SetLastError(dwErr);
DEBUG_ERROR(INET, dwErr);
}
DEBUG_LEAVE_API(fResult);
return fResult;
}
PRIVATE
BOOL
FValidCacheHandleType(
HINTERNET_HANDLE_TYPE hType
)
{
return ((hType != TypeInternetHandle) &&
(hType != TypeHttpConnectHandle));
}
#ifdef ENABLE_DEBUG
#define CASE_OF(constant) case constant: return # constant
LPSTR
InternetMapOption(
IN DWORD Option
)
/*++
Routine Description:
Convert WINHTTP_OPTION_ value to symbolic name
Arguments:
Option - to map
Return Value:
LPSTR - pointer to symbolic name, or "?" if unknown
--*/
{
switch (Option) {
CASE_OF(WINHTTP_OPTION_CALLBACK);
CASE_OF(WINHTTP_OPTION_RESOLVE_TIMEOUT);
CASE_OF(WINHTTP_OPTION_CONNECT_TIMEOUT);
CASE_OF(WINHTTP_OPTION_CONNECT_RETRIES);
CASE_OF(WINHTTP_OPTION_SEND_TIMEOUT);
CASE_OF(WINHTTP_OPTION_RECEIVE_TIMEOUT);
CASE_OF(WINHTTP_OPTION_HANDLE_TYPE);
CASE_OF(WINHTTP_OPTION_READ_BUFFER_SIZE);
CASE_OF(WINHTTP_OPTION_WRITE_BUFFER_SIZE);
CASE_OF(WINHTTP_OPTION_PARENT_HANDLE);
CASE_OF(WINHTTP_OPTION_EXTENDED_ERROR);
CASE_OF(WINHTTP_OPTION_USERNAME);
CASE_OF(WINHTTP_OPTION_PASSWORD);
CASE_OF(WINHTTP_OPTION_SECURITY_FLAGS);
CASE_OF(WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT);
CASE_OF(WINHTTP_OPTION_URL);
CASE_OF(WINHTTP_OPTION_SECURITY_KEY_BITNESS);
CASE_OF(WINHTTP_OPTION_PROXY);
CASE_OF(WINHTTP_OPTION_VERSION);
CASE_OF(WINHTTP_OPTION_USER_AGENT);
CASE_OF(WINHTTP_OPTION_PROXY_USERNAME);
CASE_OF(WINHTTP_OPTION_PROXY_PASSWORD);
CASE_OF(WINHTTP_OPTION_CONTEXT_VALUE);
CASE_OF(WINHTTP_OPTION_CLIENT_CERT_CONTEXT);
CASE_OF(WINHTTP_OPTION_REQUEST_PRIORITY);
CASE_OF(WINHTTP_OPTION_HTTP_VERSION);
CASE_OF(WINHTTP_OPTION_SECURITY_CONNECTION_INFO);
CASE_OF(WINHTTP_OPTION_DIAGNOSTIC_SOCKET_INFO);
CASE_OF(WINHTTP_OPTION_SERVER_CERT_CONTEXT);
}
return "?";
}
#endif // ENABLE_DEBUG