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.
 
 
 
 
 
 

1723 lines
41 KiB

/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
hinet.cxx
Abstract:
contains methods for INTERNET_HANDLE_BASE class
Contents:
HANDLE_OBJECT::HANDLE_OBJECT()
HANDLE_OBJECT::HANDLE_OBJECT()
HANDLE_OBJECT::Reference()
HANDLE_OBJECT::Dereference()
HANDLE_OBJECT::IsValid()
INTERNET_HANDLE_BASE::INTERNET_HANDLE_BASE(LPCSTR, ...)
INTERNET_HANDLE_BASE::INTERNET_HANDLE_BASE(INTERNET_HANDLE_BASE*)
INTERNET_HANDLE_BASE::~INTERNET_HANDLE_BASE()
INTERNET_HANDLE_BASE::SetAbortHandle(ICSocket)
INTERNET_HANDLE_BASE::ResetAbortHandle()
INTERNET_HANDLE_BASE::AbortSocket()
INTERNET_HANDLE_BASE::SetProxyInfo()
INTERNET_HANDLE_BASE::GetProxyInfo(LPVOID, LPDWORD)
INTERNET_HANDLE_BASE::GetProxyInfo(INTERNET_SCHEME, LPINTERNET_SCHEME, LPSTR *, LPDWORD, LPINTERNET_PORT)
Author:
Madan Appiah (madana) 16-Nov-1994
Environment:
User Mode - Win32
Revision History:
Sophia Chung (sophiac) 14-Feb-1995 (added FTP and Archie class impl.)
(code adopted from madana)
--*/
#include <wininetp.h>
#include <perfdiag.hxx>
//
// private manifests
//
#define PROXY_REGISTRY_STRING_LENGTH (4 K)
//
// methods
//
HANDLE_OBJECT::HANDLE_OBJECT(
IN HANDLE_OBJECT * Parent
)
/*++
Routine Description:
HANDLE_OBJECT constructor
Arguments:
Parent - pointer to parent HANDLE_OBJECT
Return Value:
None.
--*/
{
DEBUG_ENTER((DBG_OBJECTS,
None,
"HANDLE_OBJECT",
"%#x",
this
));
//InitializeListHead(&_List);
_Parent = Parent;
if (_Parent)
_Parent->Reference();
_Status = AllocateHandle(this, &_Handle);
_ObjectType = TypeGenericHandle;
_ReferenceCount = 1;
_Invalid = FALSE;
_Error = ERROR_SUCCESS;
_Signature = OBJECT_SIGNATURE;
_Context = NULL;
if (!InsertAtTailOfSerializedList(&GlobalObjectList, &_List))
_Status = ERROR_NOT_ENOUGH_MEMORY;
//
// if AllocateHandle() failed then we cannot create this handle object.
// Invalidate it ready for the destructor
//
if (_Status != ERROR_SUCCESS) {
_Invalid = TRUE;
_ReferenceCount = 0;
}
DEBUG_PRINT(OBJECTS,
INFO,
("handle %#x created; address %#x; %d objects\n",
_Handle,
this,
ElementsOnSerializedList(&GlobalObjectList)
));
DEBUG_LEAVE(0);
}
HANDLE_OBJECT::~HANDLE_OBJECT(VOID)
/*++
Routine Description:
HANDLE_OBJECT destructor. Virtual function
Arguments:
None.
Return Value:
None.
--*/
{
DEBUG_ENTER((DBG_OBJECTS,
None,
"~HANDLE_OBJECT",
"%#x",
this
));
//
// remove this object from global object list
//
if (LockSerializedList(&GlobalObjectList))
{
// should always succeed since we already have the lock
RemoveFromSerializedList(&GlobalObjectList, &_List);
UnlockSerializedList(&GlobalObjectList);
}
INET_DEBUG_ASSERT((_List.Flink == NULL) && (_List.Blink == NULL));
//
// inform the app that this handle is completely closed
//
LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();
HINTERNET hCurrent = _InternetGetObjectHandle(lpThreadInfo);
HINTERNET hCurrentMapped = _InternetGetMappedObjectHandle(lpThreadInfo);
_InternetSetObjectHandle(lpThreadInfo, _Handle, (HINTERNET)this);
HINTERNET hTemp = _Handle;
InternetIndicateStatus(WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING,
(LPVOID)&hTemp,
sizeof(hTemp)
);
_InternetSetObjectHandle(lpThreadInfo, hCurrent, hCurrentMapped);
if (_Parent != NULL)
_Parent->Dereference();
//
// now we can free up the API handle value
//
if (_Handle != NULL) {
_Status = FreeHandle(_Handle);
INET_ASSERT(_Status == ERROR_SUCCESS);
}
//
// set the signature to a value that indicates the handle has been
// destroyed (not useful in debug builds)
//
_Signature = DESTROYED_OBJECT_SIGNATURE;
INET_ASSERT((_ReferenceCount == 0) && _Invalid);
DEBUG_PRINT(OBJECTS,
INFO,
("handle %#x destroyed; type %s; address %#x; %d objects\n",
_Handle,
InternetMapHandleType(_ObjectType),
this,
ElementsOnSerializedList(&GlobalObjectList)
));
DEBUG_LEAVE(0);
}
DWORD
HANDLE_OBJECT::Reference(
VOID
)
/*++
Routine Description:
Increases the reference count on the HANDLE_OBJECT
Arguments:
None.
Return Value:
DWORD
Success - ERROR_SUCCESS
Failure - ERROR_INVALID_HANDLE
Handle has already been invalidated
ERROR_ACCESS_DENIED
Handle object is being destroyed, cannot use it
--*/
{
DEBUG_ENTER((DBG_OBJECTS,
Dword,
"HANDLE_OBJECT::Reference",
"{%#x}",
_Handle
));
DWORD error;
if (_Invalid) {
DEBUG_PRINT(OBJECTS,
INFO,
("handle object %#x [%#x] is invalid\n",
_Handle,
this
));
error = ERROR_INVALID_HANDLE;
} else {
error = ERROR_SUCCESS;
}
//
// even if the handle has been invalidated (i.e. closed), we allow it
// to continue to be referenced. The caller should return the fact
// that the handle has been invalidated, but may require information
// from the object in order to do so (e.g. in async thread)
//
do
{
LONG lRefCountBeforeIncrement = _ReferenceCount;
//
// refcount is > 0 means that the object's destructor has not been called yet
//
if (lRefCountBeforeIncrement > 0)
{
//
// try to increment the refcount using compare-exchange
//
#ifndef _WIN64
LONG lRefCountCurrent = (LONG)SHInterlockedCompareExchange((LPVOID*)&_ReferenceCount,
(LPVOID)(lRefCountBeforeIncrement + 1),
(LPVOID)lRefCountBeforeIncrement);
#else
//
// can't use SHInterlockedCompareExchange on win64 because the values are really LONG's (32-bits) but they
// are treated as pointers (64-bits) because SHInterlockedCompareExchange should really be called
// SHInterlockedCompareExchangePointer (sigh...).
//
LONG lRefCountCurrent = InterlockedCompareExchange(&_ReferenceCount,
lRefCountBeforeIncrement + 1,
lRefCountBeforeIncrement);
#endif
if (lRefCountCurrent == lRefCountBeforeIncrement)
{
//
// since SHInterlockedCompareExchange returns the value in _ReferenceCount
// before the exchange, we know the exchange sucessfully took place (i.e. we
// sucessfully incremented the refrence count of the object by one)
//
INET_ASSERT(lRefCountCurrent > 0);
break;
}
}
else
{
//
// the refcount dropped to zero before we could increment it,
// so the object is being destroyed.
//
error = ERROR_ACCESS_DENIED;
break;
}
} while (TRUE);
DEBUG_PRINT(REFCOUNT,
INFO,
("handle object %#x [%#x] ReferenceCount = %d\n",
_Handle,
this,
_ReferenceCount
));
DEBUG_LEAVE(error);
return error;
}
BOOL
HANDLE_OBJECT::Dereference(
VOID
)
/*++
Routine Description:
Reduces the reference count on the HANDLE_OBJECT, and if it goes to zero,
the object is deleted
Arguments:
None.
Return Value:
BOOL
TRUE - this object was deleted
FALSE - this object is still valid
--*/
{
DEBUG_ENTER((DBG_OBJECTS,
Bool,
"HANDLE_OBJECT::Dereference",
"{%#x}",
_Handle
));
//
// by the time we get here, the reference count should not be 0. There
// should be 1 call to Dereference() for each call to Reference()
//
INET_ASSERT(_ReferenceCount != 0);
BOOL deleted = FALSE;
if (InterlockedDecrement(&_ReferenceCount) == 0)
{
deleted = TRUE;
}
if (deleted)
{
//
// if we are calling the destructor, the handle had better be invalid!
//
INET_ASSERT(_Invalid);
//
// this handle has now been closed. If there is no activity on it
// then it will be destroyed
//
DEBUG_PRINT(REFCOUNT,
INFO,
("handle object %#x [%#x] ReferenceCount = %d\n",
_Handle,
this,
_ReferenceCount
));
delete this;
} else {
DEBUG_PRINT(REFCOUNT,
INFO,
("handle object %#x [%#x] ReferenceCount = %d\n",
_Handle,
this,
_ReferenceCount
));
}
DEBUG_LEAVE(deleted);
return deleted;
}
DWORD
HANDLE_OBJECT::IsValid(
IN HINTERNET_HANDLE_TYPE ExpectedHandleType
)
/*++
Routine Description:
Checks a HANDLE_OBJECT for validity
Arguments:
ExpectedHandleType - type of object we are testing for. Can be
TypeWildHandle which matches any valid handle
Return Value:
DWORD
Success - ERROR_SUCCESS
Failure - ERROR_INVALID_HANDLE
The handle object is invalid
ERROR_WINHTTP_INCORRECT_HANDLE_TYPE
The handle object is valid, but not the type we want
--*/
{
DWORD error;
BOOL IsOkHandle = TRUE;
//
// test handle object within try..except in case we are given a bad address
//
__try {
if (_Signature == OBJECT_SIGNATURE) {
error = ERROR_SUCCESS;
//
// check handle type if we are asked to do so.
//
if (ExpectedHandleType != TypeWildHandle) {
if (ExpectedHandleType != this->GetHandleType()) {
error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
}
}
} else {
error = ERROR_INVALID_HANDLE;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
error = ERROR_INVALID_HANDLE;
}
ENDEXCEPT
return error;
}
INTERNET_HANDLE_BASE::INTERNET_HANDLE_BASE(
LPCSTR UserAgent,
DWORD AccessMethod,
LPSTR ProxyServerList,
LPSTR ProxyBypassList,
DWORD Flags
) : HANDLE_OBJECT(NULL)
/*++
Routine Description:
Creates the handle object for InternetOpen()
Arguments:
UserAgent - name of agent (user-agent string for HTTP)
AccessMethod - DIRECT, PROXY or PRECONFIG
ProxyServerList - one or more proxy servers. The string has the form:
[<scheme>=][<scheme>"://"]<server>[":"<port>][";"*]
ProxyBypassList - zero or more addresses which if matched will result in
requests NOT going via the proxy (only if PROXY access).
The string has the form:
bp_entry ::= [<scheme>"://"]<server>[":"<port>]
bp_macro ::= "<local>"
bp_list ::= [<> | bp_entry bp_macro][";"*]
Flags - various open flags:
WINHTTP_FLAG_ASYNC - not support in WinHttpX
Return Value:
None.
--*/
{
DEBUG_ENTER((DBG_OBJECTS,
None,
"INTERNET_HANDLE_BASE::INTERNET_HANDLE_BASE",
NULL
));
//
// if the HANDLE_OBJECT constructor failed then bail out now
//
if (_Status != ERROR_SUCCESS) {
DEBUG_PRINT(OBJECTS,
ERROR,
("early-exit: _Status = %d\n",
_Status
));
DEBUG_LEAVE(0);
return;
}
_PPContext = 0;
_ThreadToken = 0;
_IsCopy = FALSE;
_UserAgent = (LPSTR)UserAgent;
_ProxyInfo = NULL;
_dwInternetOpenFlags = Flags;
_WinsockLoaded = FALSE;
_Context = NULL;
_MaxConnectionsPerServer = WINHTTP_CONNS_PER_SERVER_UNLIMITED;
_MaxConnectionsPer1_0Server = WINHTTP_CONNS_PER_SERVER_UNLIMITED;
//
// set _Async based on the WINHTTP_FLAG_ASYNC supplied to InternetOpen()
//
_dwCodePage = CP_UTF8;
_Async = (Flags & WINHTTP_FLAG_ASYNC) ? TRUE : FALSE;
//
// no data available yet
//
SetAvailableDataLength(0);
//
// not yet end of file
//
ResetEndOfFile();
//
// no status callback by default
//
_StatusCallback = NULL;
_StatusCallbackType = FALSE;
_dwStatusCallbackFlags = 0;
SetObjectType(TypeInternetHandle);
_ProxyInfoResourceLock.Initialize();
_Status = SetProxyInfo(AccessMethod, ProxyServerList, ProxyBypassList);
//
// if _pICSocket is not NULL then this is the socket that this object handle
// is currently working on. We close it to cancel the operation
//
_pICSocket = NULL;
if (::OpenThreadToken(
GetCurrentThread(),
TOKEN_READ | TOKEN_IMPERSONATE,
FALSE,
&_ThreadToken
) == FALSE)
{
_ThreadToken = 0;
}
//
// load winsock now.
//
if (_Status == ERROR_SUCCESS) {
_Status = LoadWinsock();
_WinsockLoaded = (_Status == ERROR_SUCCESS);
if ( _Status == ERROR_SUCCESS )
{
LONG lOpenHandleCnt;
LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();
if ( lpThreadInfo )
{
lOpenHandleCnt = InterlockedIncrement((LPLONG)&GlobalInternetOpenHandleCount);
if ( lOpenHandleCnt == 0 )
{
DWORD fAlreadyInInit = (DWORD) InterlockedExchange((LPLONG) &GlobalAutoProxyInInit, TRUE);
INET_ASSERT (! fAlreadyInInit );
g_pGlobalProxyInfo->ReleaseQueuedRefresh();
InterlockedExchange((LPLONG)&GlobalAutoProxyInInit, FALSE);
}
}
}
}
DEBUG_LEAVE(0);
}
INTERNET_HANDLE_BASE::INTERNET_HANDLE_BASE(
INTERNET_HANDLE_BASE *INetObj
) : HANDLE_OBJECT((HANDLE_OBJECT*)INetObj)
/*++
Routine Description:
Constructor for derived handle object. We are creating this handle as part
of an INTERNET_CONNECT_HANDLE_OBJECT
Arguments:
INetObj - pointer to INTERNET_HANDLE_BASE to copy
Return Value:
None.
--*/
{
DEBUG_ENTER((DBG_OBJECTS,
None,
"INTERNET_HANDLE_BASE::INTERNET_HANDLE_BASE",
"{IsCopy}"
));
_PPContext = INetObj->_PPContext;
_ThreadToken = INetObj->_ThreadToken;
_IsCopy = TRUE;
//
// copy user agent string
//
//
// BUGBUG - compiler generated copy constructor (no new string)
//
_UserAgent = INetObj->_UserAgent;
//
// do not inherit the proxy info - code must go to parent handle
//
_ProxyInfo = NULL;
_dwInternetOpenFlags = INetObj->_dwInternetOpenFlags;
//
// creating this handle didn't load winsock
//
_WinsockLoaded = FALSE;
//
// inherit the context, async flag and status callback from
// the parent object handle
//
_Context = INetObj->_Context;
_MaxConnectionsPerServer = INetObj->_MaxConnectionsPerServer;
_MaxConnectionsPer1_0Server = INetObj->_MaxConnectionsPer1_0Server;
_dwCodePage = INetObj->_dwCodePage;
_Async = INetObj->_Async;
//
// inherit callback function
//
SetAvailableDataLength(0);
ResetEndOfFile();
_StatusCallback = INetObj->_StatusCallback;
_StatusCallbackType = INetObj->_StatusCallbackType;
_dwStatusCallbackFlags = INetObj->_dwStatusCallbackFlags;
//
// no socket operation to abort yet
//
_pICSocket = NULL;
//
// BUGBUG - this overwrites status set above?
//
_Status = INetObj->_Status;
DEBUG_LEAVE(0);
}
INTERNET_HANDLE_BASE::~INTERNET_HANDLE_BASE(
VOID
)
/*++
Routine Description:
INTERNET_HANDLE_BASE destructor
Arguments:
None.
Return Value:
None.
--*/
{
DEBUG_ENTER((DBG_OBJECTS,
None,
"INTERNET_HANDLE_BASE::~INTERNET_HANDLE_BASE",
""
));
if (_ProxyInfo && !IsProxyGlobal() && (_ProxyInfo != PROXY_INFO_DIRECT))
{
DEBUG_PRINT(OBJECTS,
INFO,
("Free-ing ProxyInfo\n"
));
delete _ProxyInfo;
_ProxyInfo = NULL;
}
//
// if this handle is not a copy (i.e., it is a Session handle), then delete
// the Passport context
//
if (!IsCopy()) {
DEBUG_PRINT(OBJECTS,
INFO,
("Not a Copy...\n"
));
if (_PPContext)
{
::PP_FreeContext(_PPContext);
}
//
// don't unload winsock. There really is no need to unload separately
// from process detach and if we do unload, we first have to terminate
// async support. Dynaloading and unloading winsock is vestigial
//
//if (_WinsockLoaded) {
// UnloadWinsock();
//}
if (_ThreadToken)
{
::CloseHandle(_ThreadToken);
_ThreadToken = NULL;
}
}
DEBUG_LEAVE(0);
}
DWORD
INTERNET_HANDLE_BASE::ExchangeStatusCallback(
LPWINHTTP_STATUS_CALLBACK lpStatusCallback,
BOOL fType,
DWORD dwFlags
)
{
DWORD error;
WINHTTP_STATUS_CALLBACK callback;
// exchange new and current callbacks
callback = _StatusCallback;
_StatusCallback = *lpStatusCallback;
*lpStatusCallback = callback;
_StatusCallbackType = fType;
_dwStatusCallbackFlags = dwFlags;
error = ERROR_SUCCESS;
return error;
}
VOID
INTERNET_HANDLE_BASE::SetAbortHandle(
IN ICSocket * Socket
)
/*++
Routine Description:
Associates with this request handle the ICSocket object currently being used
for network I/O
Arguments:
Socket - pointer to ICSocket
Return Value:
None.
--*/
{
DEBUG_ENTER((DBG_OBJECTS | DBG_SOCKETS,
None,
"INTERNET_HANDLE_BASE::SetAbortHandle",
"{%#x} %#x [sock=%#x ref=%d]",
GetPseudoHandle(),
Socket,
Socket ? Socket->GetSocket() : 0,
Socket ? Socket->ReferenceCount() : 0
));
INET_ASSERT(Socket != NULL);
//
// first off, increase the socket reference count to stop any other threads
// killing it whilst we are performing the socket operation. The only way
// another thread can dereference the socket is by calling our AbortSocket()
// method
//
Socket->Reference();
//
// now associate the socket object with this handle object. We should not
// have a current association
//
ICSocket * pSocket;
pSocket = (ICSocket *) InterlockedExchangePointer((PVOID*)&_pICSocket, Socket);
//
// because ConnectSocket() can call this method multiple times without
// intervening calls to ResetAbortHandle(), pSocket can legitimately be
// non-NULL at this point
//
//INET_ASSERT(pSocket == NULL);
//
// if the handle was invalidated on another thread before we got
// chance to set the socket to close, then abort the request now
//
//
// BUGBUG - screws up normal FTP close handle processing - we
// have to communicate with the server in order to
// drop the connection
//
//if (IsInvalidated()) {
// AbortSocket();
//}
DEBUG_LEAVE(0);
}
VOID
INTERNET_HANDLE_BASE::ResetAbortHandle(
VOID
)
/*++
Routine Description:
Disassociates this request handle and the ICSocket object when the network
operation has completed
Arguments:
None.
Return Value:
None.
--*/
{
DEBUG_ENTER((DBG_OBJECTS | DBG_SOCKETS,
None,
"INTERNET_HANDLE_BASE::ResetAbortHandle",
"{%#x}",
GetPseudoHandle()
));
//
// there really should be a ICSocket associated with this object, otherwise
// our handle close/invalidation logic is broken
//
//
// however, we can call ResetAbortHandle() from paths where we completed
// early, not having called SetAbortHandle()
//
//INET_ASSERT(pSocket != NULL);
//
// so if there was a ICSocket associated with this object then remove the
// reference added in SetAbortHandle()
//
ICSocket * pICSocket;
pICSocket = (ICSocket *)InterlockedExchangePointer((PVOID*)&_pICSocket, NULL);
if (pICSocket != NULL) {
DEBUG_PRINT(SOCKETS,
INFO,
("socket=%#x ref=%d\n",
pICSocket->GetSocket(),
pICSocket->ReferenceCount()
));
pICSocket->Dereference();
}
DEBUG_LEAVE(0);
}
VOID
INTERNET_HANDLE_BASE::AbortSocket(
VOID
)
/*++
Routine Description:
If there is a ICSocket associated with this handle object then abort it. This
forces the current network operation aborted and the request to complete
with ERROR_WINHTTP_OPERATION_CANCELLED
Arguments:
None.
Return Value:
None.
--*/
{
DEBUG_ENTER((DBG_OBJECTS | DBG_SOCKETS,
None,
"INTERNET_HANDLE_BASE::AbortSocket",
"{%#x, %#x [sock=%#x, ref=%d]}",
GetPseudoHandle(),
(_pICSocket != NULL)
? (LPVOID)_pICSocket
: (LPVOID)_pICSocket,
_pICSocket
? _pICSocket->GetSocket()
: (_pICSocket
? _pICSocket->GetSocket()
: 0),
_pICSocket
? _pICSocket->ReferenceCount()
: (_pICSocket
? _pICSocket->ReferenceCount()
: 0)
));
//
// get the associated ICSocket. It may have already been removed by a call
// to ResetAbortHandle()
//
//
// if there is an associated ICSocket then abort it (close the socket handle)
// which will complete the current network I/O (if active) with an error.
// Once the ICSocket is aborted, we reduce the reference count that was added
// in SetAbortHandle(). This may cause the ICSocket to be deleted
//
LPVOID pAddr;
pAddr = (LPVOID)InterlockedExchangePointer((PVOID*)&_pICSocket, NULL);
if (pAddr != NULL) {
ICSocket * pSocket = (ICSocket *)pAddr;
//dprintf(">>>>>>>> %#x AbortSocket %#x [%#x]\n", GetCurrentThreadId(), pSocket, pSocket->GetSocket());
pSocket->Abort();
pSocket->Dereference();
}
DEBUG_LEAVE(0);
}
DWORD
INTERNET_HANDLE_BASE::Refresh()
/*++
Routine Description:
Refreshes the proxy info on an InternetOpen() HINTERNET based on the parameters
Assumes: 1. The parameters have already been validated in the API that calls
this method (i.e. InternetOpen(), InternetSetOption())
Return Value:
DWORD
Success - ERROR_SUCCESS
--*/
{
DWORD error;
//
// Reload the proxy info from registry into the GlobalProxyInfo object,
// unless it was changed in-process to something else.
//
if (!g_pGlobalProxyInfo->IsModifiedInProcess()) {
return LoadProxySettings();
} else {
//
// not using global proxy or it has been set to something other
// than the registry contents. Just return success
//
return ERROR_SUCCESS;
}
}
DWORD
INTERNET_HANDLE_BASE::SetProxyInfo(
IN DWORD dwAccessType,
IN LPCSTR lpszProxy OPTIONAL,
IN LPCSTR lpszProxyBypass OPTIONAL
)
/*++
Routine Description:
Sets the proxy info on an InternetOpen() HINTERNET based on the parameters
Assumes: 1. The parameters have already been validated in the API that calls
this method (i.e. InternetOpen(), InternetSetOption())
Arguments:
dwAccessType - type of proxy access required
lpszProxy - pointer to proxy server list
lpszProxyBypass - pointer to proxy bypass list
Return Value:
DWORD
Success - ERROR_SUCCESS
Failure - ERROR_INVALID_PARAMETER
The lpszProxy or lpszProxyBypass list was bad
ERROR_NOT_ENOUGH_MEMORY
Failed to create an object or allocate space for a list,
etc.
--*/
{
DEBUG_ENTER((DBG_INET,
Dword,
"INTERNET_HANDLE_BASE::SetProxyInfo",
"%s (%d), %#x (%q), %#x (%q)",
InternetMapOpenType(dwAccessType),
dwAccessType,
lpszProxy,
lpszProxy,
lpszProxyBypass,
lpszProxyBypass
));
//
// Session and HTTP Request objects can have proxy information
//
INET_ASSERT((GetHandleType()==TypeInternetHandle) || (GetHandleType()==TypeHttpRequestHandle));
/*
We are setting the proxy information for an InternetOpen() handle. Based on
the current and new settings we do the following (Note: the handle is
initialized to DIRECT operation):
current access
+---------------------------------------------------------------
new | DIRECT | PROXY | PRECONFIG
access | | |
+-----------+--------------------+--------------------+---------------------
| DIRECT | No action | Delete proxy info | Remove reference to
| | | | global proxy info
+-----------+--------------------+--------------------+---------------------
| PROXY | Set new proxy info | Delete proxy info. | Remove reference to
| | | Set new proxy info | global proxy info.
| | | | Set new proxy info
+-----------+--------------------+--------------------+---------------------
| PRECONFIG | Set proxy info to | Delete proxy info. | No action
| | global proxy info | Set proxy info to |
| | | global proxy info |
+-----------+--------------------+--------------------+---------------------
*/
DWORD error = ERROR_SUCCESS;
PROXY_INFO * proxyInfo = NULL;
//
// acquire proxy info for exclusive access
//
if (!AcquireProxyInfo(TRUE))
{
error = ERROR_NOT_ENOUGH_MEMORY;
goto quit;
}
if (IsProxy()) {
//
// delete private proxy info, or unlink from global proxy info
//
SafeDeleteProxyInfo();
}
//
// Map Various Proxy types to their internal counterparts,
// note that I've ordered them in what I think is their
// use frequency (how often each one is most likely to get hit).
//
switch (dwAccessType)
{
#ifndef WININET_SERVER_CORE
// In WinHttpX, INTERNET_OPEN_TYPE_PRECONFIG is equivalent
// to INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY.
case INTERNET_OPEN_TYPE_PRECONFIG:
proxyInfo = g_pGlobalProxyInfo;
break;
#endif
case INTERNET_OPEN_TYPE_DIRECT:
proxyInfo = PROXY_INFO_DIRECT;
break;
case INTERNET_OPEN_TYPE_PROXY:
{
INET_ASSERT(!IsProxy());
INTERNET_HANDLE_OBJECT * pSession;
if (IsCopy())
{
pSession = GetRootHandle(this);
}
else
{
pSession = static_cast<INTERNET_HANDLE_OBJECT *>(this);
INET_ASSERT(pSession->IsValid(TypeInternetHandle) == ERROR_SUCCESS);
}
proxyInfo = New PROXY_INFO;
if (proxyInfo != NULL) {
proxyInfo->InitializeProxySettings();
proxyInfo->SetSessionObject(pSession);
error = proxyInfo->GetError();
if (error == ERROR_SUCCESS &&
lpszProxy )
{
INTERNET_PROXY_INFO_EX info;
memset(&info, 0, sizeof(info));
info.dwStructSize = sizeof(info);
info.dwFlags = (PROXY_TYPE_DIRECT | PROXY_TYPE_PROXY);
info.lpszProxy = lpszProxy;
info.lpszProxyBypass = lpszProxyBypass;
error = proxyInfo->SetProxySettings(&info, TRUE /*modified*/);
}
if (error != ERROR_SUCCESS) {
delete proxyInfo;
proxyInfo = NULL;
}
} else {
error = ERROR_NOT_ENOUGH_MEMORY;
}
break;
}
case INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY:
{
// Refresh global proxy info.
Refresh();
proxyInfo = New PROXY_INFO_GLOBAL_WRAPPER;
if (proxyInfo == NULL)
error = ERROR_NOT_ENOUGH_MEMORY;
else
proxyInfo->SetSessionObject(static_cast<INTERNET_HANDLE_OBJECT *>(this));
break;
}
default:
proxyInfo = NULL;
break;
}
SetProxyInfo(proxyInfo);
ReleaseProxyInfo();
quit:
DEBUG_LEAVE(error);
return error;
}
DWORD
INTERNET_HANDLE_BASE::GetProxyStringInfo(
OUT LPVOID lpBuffer,
IN OUT LPDWORD lpdwBufferLength
)
/*++
Routine Description:
Returns the current proxy information for this INTERNET_HANDLE_BASE
Arguments:
lpBuffer - pointer to buffer where WINHTTP_PROXY_INFOA will be
written, and any proxy strings (if sufficient space)
lpdwBufferLength - IN: number of bytes in lpBuffer
OUT: number of bytes returned in lpBuffer
Return Value:
DWORD
Success - ERROR_SUCCESS
Failure - ERROR_INSUFFICIENT_BUFFER
lpBuffer doesn't have enough space to hold the proxy
information. *lpdwBufferLength has the required size
--*/
{
DEBUG_ENTER((DBG_INET,
Dword,
"INTERNET_HANDLE_BASE::GetProxyStringInfo",
"%#x, %#x [%d]",
lpBuffer,
lpdwBufferLength,
lpdwBufferLength ? *lpdwBufferLength : 0
));
INET_ASSERT(!IsCopy());
AcquireProxyInfo(FALSE);
DWORD error;
if (IsProxy()) {
error = _ProxyInfo->GetProxyStringInfo(lpBuffer, lpdwBufferLength);
} else {
if (*lpdwBufferLength >= sizeof(WINHTTP_PROXY_INFOA)) {
WINHTTP_PROXY_INFOA * lpInfo = (WINHTTP_PROXY_INFOA *)lpBuffer;
lpInfo->dwAccessType = INTERNET_OPEN_TYPE_DIRECT;
lpInfo->lpszProxy = NULL;
lpInfo->lpszProxyBypass = NULL;
error = ERROR_SUCCESS;
} else {
error = ERROR_INSUFFICIENT_BUFFER;
}
*lpdwBufferLength = sizeof(WINHTTP_PROXY_INFOA);
}
ReleaseProxyInfo();
DEBUG_LEAVE(error);
return error;
}
DWORD
INTERNET_HANDLE_BASE::GetProxyInfo(
IN AUTO_PROXY_ASYNC_MSG **ppQueryForProxyInfo
)
/*++
Routine Description:
Returns all proxy information based on a protocol scheme
Arguments:
tProtocol - protocol to get proxy info for
lptScheme - returned scheme
lplpszHostName - returned proxy name
lpdwHostNameLength - returned length of proxy name
lpHostPort - returned proxy port
Return Value:
BOOL
Success - TRUE
Failure - FALSE
--*/
{
DEBUG_ENTER((DBG_INET,
Dword,
"INTERNET_HANDLE_BASE::GetProxyInfo",
"%#x",
ppQueryForProxyInfo
));
INET_ASSERT((GetHandleType() == TypeInternetHandle) ||
(GetHandleType() == TypeHttpRequestHandle));
DWORD error;
BOOL rc;
AcquireProxyInfo(FALSE);
if ( _ProxyInfo && _ProxyInfo != PROXY_INFO_DIRECT )
{
error = _ProxyInfo->QueryProxySettings(ppQueryForProxyInfo);
}
else
{
error = ERROR_SUCCESS;
(*ppQueryForProxyInfo)->SetUseProxy(FALSE);
}
ReleaseProxyInfo();
DEBUG_LEAVE(error);
return error;
}
BOOL
INTERNET_HANDLE_BASE::RedoSendRequest(
IN OUT LPDWORD lpdwError,
IN DWORD dwSecureStatus,
IN AUTO_PROXY_ASYNC_MSG *pQueryForProxyInfo,
IN CServerInfo *pOriginServer,
IN CServerInfo *pProxyServer
)
{
INET_ASSERT(!IsCopy());
BOOL rc;
AcquireProxyInfo(FALSE);
if ( _ProxyInfo )
{
rc = _ProxyInfo->RedoSendRequest(
lpdwError,
dwSecureStatus,
pQueryForProxyInfo,
pOriginServer,
pProxyServer
);
}
else
{
rc = FALSE;
}
ReleaseProxyInfo();
return rc;
}
INTERNET_HANDLE_OBJECT::INTERNET_HANDLE_OBJECT
(LPCSTR ua, DWORD access, LPSTR proxy, LPSTR bypass, DWORD flags)
: INTERNET_HANDLE_BASE (ua, access, proxy, bypass, flags)
{
DEBUG_ENTER((DBG_OBJECTS,
None,
"INTERNET_HANDLE_OBJECT::INTERNET_HANDLE_OBJECT",
NULL
));
InterlockedIncrement(&g_cSessionCount);
if (g_pAsyncCount)
{
if (flags & WINHTTP_FLAG_ASYNC)
{
g_pAsyncCount->AddRef();
}
}
else
{
RIP(FALSE);
}
InitializeSerializedList(&_ServerInfoList);
//
// WinHttpX supports session cookies. Each session has it's own
// cookie jar, instead of a shared global cookie jar as in WinInet.
//
_CookieJar = NULL;
_pOptionalParams = NULL;
_pResolverCache = New CResolverCache(&_Status);
if (!_pResolverCache)
{
_Status = ERROR_NOT_ENOUGH_MEMORY;
}
if (_Status == ERROR_SUCCESS)
{
_CookieJar = CreateCookieJar();
if (_CookieJar == NULL)
_Status = ERROR_NOT_ENOUGH_MEMORY;
}
_fUseSessionCertCache = FALSE;
_SessionCertCache.Initialize();
DEBUG_LEAVE(0);
};
INTERNET_HANDLE_OBJECT::~INTERNET_HANDLE_OBJECT ( )
{
DEBUG_ENTER((DBG_OBJECTS,
None,
"INTERNET_HANDLE_OBJECT::~INTERNET_HANDLE_OBJECT",
NULL
));
PurgeServerInfoList(TRUE);
TerminateSerializedList(&_ServerInfoList);
if (_pResolverCache)
{
_pResolverCache->EmptyHandlesList();
delete _pResolverCache;
}
delete _pOptionalParams;
_pOptionalParams = NULL;
// Delete Cookie Jar
CloseCookieJar(_CookieJar);
_CookieJar = NULL;
_SessionCertCache.Terminate();
if (g_pAsyncCount)
{
g_pAsyncCount->Release();
}
else
{
RIP(FALSE);
}
DEBUG_LEAVE(0);
}
//
// This function walks up to the InternetOpen handle from either
// a connect handle (child) or a request handle (grandchild).
// We only go one or two hops rather than recurse.
//
INTERNET_HANDLE_OBJECT* GetRootHandle (HANDLE_OBJECT* pHandle)
{
pHandle = (HANDLE_OBJECT*) pHandle->GetParent();
INET_ASSERT (pHandle);
if (pHandle->GetHandleType() == TypeInternetHandle)
return (INTERNET_HANDLE_OBJECT*) pHandle;
pHandle = (HANDLE_OBJECT*) pHandle->GetParent();
INET_ASSERT (pHandle);
INET_ASSERT (pHandle->GetHandleType() == TypeInternetHandle);
return (INTERNET_HANDLE_OBJECT*) pHandle;
}
/*
* When called from API functions,
* caller should SetLastError() in case of failure
*/
BOOL
INTERNET_HANDLE_OBJECT::SetTimeout(
IN DWORD dwTimeoutOption,
IN DWORD dwTimeoutValue
)
{
BOOL bRetval = TRUE;
if (!_pOptionalParams)
{
_pOptionalParams = New OPTIONAL_SESSION_PARAMS();
if (!_pOptionalParams)
{
bRetval = FALSE;
goto quit;
}
}
switch (dwTimeoutOption)
{
case WINHTTP_OPTION_RESOLVE_TIMEOUT:
_pOptionalParams->dwResolveTimeout = dwTimeoutValue;
break;
case WINHTTP_OPTION_CONNECT_TIMEOUT:
_pOptionalParams->dwConnectTimeout = dwTimeoutValue;
break;
case WINHTTP_OPTION_CONNECT_RETRIES:
_pOptionalParams->dwConnectRetries = dwTimeoutValue;
break;
case WINHTTP_OPTION_SEND_TIMEOUT:
_pOptionalParams->dwSendTimeout = dwTimeoutValue;
break;
case WINHTTP_OPTION_RECEIVE_TIMEOUT:
_pOptionalParams->dwReceiveTimeout = dwTimeoutValue;
break;
default:
bRetval = FALSE;
}
quit:
return bRetval;
}
/*
* When called from API functions,
* caller should SetLastError() in case of failure
*/
BOOL
INTERNET_HANDLE_OBJECT::SetTimeouts(
IN DWORD dwResolveTimeout,
IN DWORD dwConnectTimeout,
IN DWORD dwSendTimeout,
IN DWORD dwReceiveTimeout
)
{
BOOL bRetval = TRUE;
if (!_pOptionalParams)
{
_pOptionalParams = New OPTIONAL_SESSION_PARAMS();
if (!_pOptionalParams)
{
bRetval = FALSE;
goto quit;
}
}
_pOptionalParams->dwResolveTimeout = dwResolveTimeout;
_pOptionalParams->dwConnectTimeout = dwConnectTimeout;
_pOptionalParams->dwSendTimeout = dwSendTimeout;
_pOptionalParams->dwReceiveTimeout = dwReceiveTimeout;
quit:
return bRetval;
}
/*
* When called from API functions,
* caller should SetLastError() in case of failure
*/
BOOL
INTERNET_HANDLE_OBJECT::GetTimeout(
IN DWORD dwTimeoutOption,
OUT DWORD* pdwTimeoutValue
)
{
BOOL bRetval = TRUE;
if (!_pOptionalParams)
{
bRetval = FALSE;
goto quit;
}
switch (dwTimeoutOption)
{
case WINHTTP_OPTION_RESOLVE_TIMEOUT:
*pdwTimeoutValue = _pOptionalParams->dwResolveTimeout;
break;
case WINHTTP_OPTION_CONNECT_TIMEOUT:
*pdwTimeoutValue = _pOptionalParams->dwConnectTimeout;
break;
case WINHTTP_OPTION_CONNECT_RETRIES:
*pdwTimeoutValue = _pOptionalParams->dwConnectRetries;
break;
case WINHTTP_OPTION_SEND_TIMEOUT:
*pdwTimeoutValue = _pOptionalParams->dwSendTimeout;
break;
case WINHTTP_OPTION_RECEIVE_TIMEOUT:
*pdwTimeoutValue = _pOptionalParams->dwReceiveTimeout;
break;
default:
bRetval = FALSE;
break;
}
quit:
return bRetval;
}