Windows-Server-2003/inetcore/urlmon/iapp/cnet.cxx

7555 lines
210 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: cnet.cxx
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 12-04-95 JohannP (Johann Posch) Created
//
//----------------------------------------------------------------------------
#include <iapp.h>
#include <winineti.h> // contains bogus INTERNET_FLAG_NO_UI
#include <shlwapip.h>
CMutexSem g_mxsSession; // single access to InternetOpen
PerfDbgTag(tagCINet, "Urlmon", "Log CINet", DEB_PROT);
PerfDbgTag(tagCINetErr, "Urlmon", "Log CINet Errors", DEB_PROT|DEB_ERROR);
LONG UrlMonInvokeExceptionFilter( DWORD lCode, LPEXCEPTION_POINTERS lpep );
DWORD StrLenMultiByteWithMlang(LPCWSTR, DWORD);
BOOL ConvertUnicodeUrl(LPCWSTR, LPSTR, INT, DWORD, BOOL, BOOL*);
DWORD CountUnicodeToUtf8(LPCWSTR, DWORD, BOOL);
extern BOOL g_bGlobalUTF8Enabled;
#define INTERNET_POLICIES_KEY "SOFTWARE\\Policies\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
typedef UINT (WINAPI *GetSystemWow64DirectoryPtr) (LPTSTR lpBuffer, UINT uSize);
// Need this in GetUserAgentString.
HRESULT CallRegInstall(LPSTR szSection);
HRESULT EnsureSecurityManager ();
class CInetState
{
enum WHAT_STATE
{
INETSTATE_NONE = 0
,INETSTATE_SET = 1
,INETSTATE_HANDLED = 2
};
public:
void SetState(DWORD dwState)
{
DEBUG_ENTER((DBG_APP,
None,
"CInetState::SetState",
"this=%#x, %#x",
this, dwState
));
CLock lck(_mxs);
_dwState = dwState;
_What = INETSTATE_SET;
DEBUG_LEAVE(0);
}
HRESULT HandleState()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CInetState::HandleState",
"this=%#x",
this
));
HRESULT hr = NOERROR;
DWORD dwStateNow;
BOOL fPropagate;
{
CLock lck(_mxs);
dwStateNow = _dwState;
fPropagate = (_What == INETSTATE_SET) ? TRUE : FALSE;
_What = INETSTATE_HANDLED;
}
if (fPropagate)
{
hr = PropagateStateChange(dwStateNow);
}
DEBUG_LEAVE(hr);
return hr;
}
HRESULT PropagateStateChange(DWORD dwState);
CInetState()
{
DEBUG_ENTER((DBG_APP,
None,
"CInetState::CInetState",
"this=%#x",
this
));
_dwState = 0;
_What = INETSTATE_NONE;
DEBUG_LEAVE(0);
}
~CInetState()
{
DEBUG_ENTER((DBG_APP,
None,
"CInetState::~CInetState",
"this=%#x",
this
));
DEBUG_LEAVE(0);
}
private:
CMutexSem _mxs;
DWORD _dwState;
WHAT_STATE _What;
};
//+---------------------------------------------------------------------------
//
// Method: CInetState::PropagateStateChange
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 1-22-1997 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CInetState::PropagateStateChange(DWORD dwWhat)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CInetState::PropagateStateChange",
"this=%#x, %#x",
this, dwWhat
));
PerfDbgLog(tagCINet, this, "+CInetState::PropagateStateChange");
HRESULT hr = NOERROR;
// BUGBUG: IE5 need to implement these!
#if 0
if (dwWhat & INTERNET_STATE_CONNECTED)
{
NotfDeliverNotification(
NOTIFICATIONTYPE_CONNECT_TO_INTERNET // REFNOTIFICATIONTYPE rNotificationType
,CLSID_PROCESS_BROADCAST // REFCLSID rClsidDest
,(DELIVERMODE)0 // DELIVERMODE deliverMode
,0 // DWORD dwReserved
);
}
if (dwWhat & INTERNET_STATE_DISCONNECTED)
{
NotfDeliverNotification(
NOTIFICATIONTYPE_DISCONNECT_FROM_INTERNET // REFNOTIFICATIONTYPE rNotificationType
,CLSID_PROCESS_BROADCAST // REFCLSID rClsidDest
,(DELIVERMODE)0 // DELIVERMODE deliverMode
,0 // DWORD dwReserved
);
}
if (dwWhat & INTERNET_STATE_DISCONNECTED_BY_USER)
{
NotfDeliverNotification(
NOTIFICATIONTYPE_CONFIG_CHANGED // REFNOTIFICATIONTYPE rNotificationType
,CLSID_PROCESS_BROADCAST // REFCLSID rClsidDest
,(DELIVERMODE)0 // DELIVERMODE deliverMode
,0 // DWORD dwReserved
);
}
#ifdef _with_idle_and_busy_
//
// NOTE: wininet will send idle with every state change
// will be fixed by RFirth
if (dwWhat & INTERNET_STATE_IDLE)
{
NotfDeliverNotification(
NOTIFICATIONTYPE_INET_IDLE // REFNOTIFICATIONTYPE rNotificationType
,CLSID_PROCESS_BROADCAST // REFCLSID rClsidDest
,(DELIVERMODE)0 // DELIVERMODE deliverMode
,0 // DWORD dwReserved
);
}
if (dwWhat & INTERNET_STATE_BUSY)
{
NotfDeliverNotification(
NOTIFICATIONTYPE_INET_BUSY // REFNOTIFICATIONTYPE rNotificationType
,CLSID_PROCESS_BROADCAST // REFCLSID rClsidDest
,(DELIVERMODE)0 // DELIVERMODE deliverMode
,0 // DWORD dwReserved
);
}
#endif //_with_idle_and_busy_
#endif // 0
PerfDbgLog1(tagCINet, this, "-CInetState:PropagateStateChange (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//
// REMOVE THIS joHANNP
//
extern LPSTR g_pszUserAgentString;
HINTERNET g_hSession;
CInetState g_cInetState;
char vszLocationTag[] = "Location: ";
static DWORD dwLstError;
typedef struct tagProtocolInfo
{
LPWSTR pwzProtocol;
LPSTR pszProtocol;
DWORD dwId;
CLSID *pClsID;
int protlen;
} ProtocolInfo;
extern IInternetSecurityManager* g_pSecurityManager; // to handle GetSecurityId for cookies fix.
/*
This function is not heavy on error-checking:
The ASSERTS in the code MUST be satisfied for this function to work
NOTE: don't care about OPAQUE urls since they are NOT http by definition.
*/
enum ComparisonState
{
seenZone=1,
seen1Dot,
seen2Dots,
seen3Dots,
domainSame
};
#define MAKELOWER(val) (((val) > 'a') ? (val) : ((val)-'A'+'a'))
BOOL IsKnown2ndSubstring(BYTE* pStart, BYTE* pEnd)
{
static const char *s_pachSpecialDomains[] = {"COM", "EDU", "NET", "ORG", "GOV", "MIL", "INT"};
static const DWORD s_padwSpecialDomains[] = {0x00636f6d, 0x00656475, 0x006e6574, 0x006f7267, 0x00676f76, 0x006d696c, 0x00696e74};
BOOL bKnown = FALSE;
int nLen = (int) (pEnd-pStart+1);
if ((nLen==2) && !StrCmpNI((LPCSTR)pStart, "CO", nLen))
{
bKnown = TRUE;
}
else if (nLen==3)
{
DWORD dwExt, dwByte;
dwByte = *pStart++;
dwExt = MAKELOWER(dwByte);
dwExt <<= 8;
dwByte = *pStart++;
dwExt |= MAKELOWER(dwByte);
dwExt <<= 8;
dwByte = *pStart++;
dwExt |= MAKELOWER(dwByte);
for (int i=0; i<sizeof(s_padwSpecialDomains);)
{
if (dwExt == s_padwSpecialDomains[i++])
{
bKnown = TRUE;
break;
}
}
}
return bKnown;
}
BOOL SecurityIdsMatch(BYTE* pbSecurityId1, DWORD dwLen1, BYTE* pbSecurityId2, DWORD dwLen2)
{
//ASSERT((pbSecurityId1 && pbSecurityId2 && (dwLen1 > 0) && (dwLen2 > 0)));
ComparisonState currState;
BOOL bRetval = FALSE;
//BOOL bRetval = ((dwLen1 == dwLen2) && (0 == memcmp(pbSecurityId1, pbSecurityId2, dwLen1)));
BYTE *pCurr1, *pCurr2;
DWORD dwDomainLen1, dwDomainLen2; //sizes of securityId w/o protocol.
pCurr1 = pbSecurityId1;
while(*pCurr1++ != ':');
dwDomainLen1 = (DWORD)(pCurr1-pbSecurityId1);
pCurr2 = pbSecurityId2;
while(*pCurr2++ != ':');
dwDomainLen2 = (DWORD)(pCurr2-pbSecurityId2);
DEBUG_ENTER((DBG_APP,
Bool,
"SecurityIdsMatch",
"%#x, %d, domainLen=%d %#x, %d, domainLen=%d",
pbSecurityId1, dwLen1, dwDomainLen1, pbSecurityId2, dwLen2, dwDomainLen2
));
BYTE *pBase1, *pBase2;
BYTE bLeftByte, bRightByte;
DWORD cbSubstring1 = 0;
BYTE *pSubstring2Start = NULL;
BYTE *pSubstring2End = NULL;
//pCurr1 is the shorter one
if (dwDomainLen1 < dwDomainLen2)
{
pCurr1 = pbSecurityId1+dwLen1-1-sizeof(DWORD);
pBase1 = pbSecurityId1;
pCurr2 = pbSecurityId2+dwLen2-1-sizeof(DWORD);
pBase2 = pbSecurityId2;
}
else
{
pCurr2 = pbSecurityId1+dwLen1-1-sizeof(DWORD);
pBase2 = pbSecurityId1;
pCurr1 = pbSecurityId2+dwLen2-1-sizeof(DWORD);
pBase1 = pbSecurityId2;
}
/* compare zone dword
if (memcmp(pCurr1, pCurr2, sizeof(DWORD)))
goto End;
*/
/* compare domains */
currState = seenZone;
while ((pCurr1 > pBase1) && (pCurr2 > pBase2))
{
if ((bLeftByte=*pCurr1--) == (bRightByte=*pCurr2--))
{
/* valid assumption? no ':' in domain name */
//ASSERT(((currState==seenZone) && (bLeftByte == ':')))
if ((bLeftByte == '.') && (currState < seen3Dots))
{
currState = (ComparisonState)(currState+1);
switch (currState)
{
case seen1Dot:
pSubstring2End = pCurr1;
break;
case seen2Dots:
pSubstring2Start = pCurr1+2;
break;
}
}
else if (bLeftByte == ':')
{
currState = domainSame;
break;
}
else if (currState == seenZone)
cbSubstring1++;
}
else
break;
}
switch (currState)
{
case seenZone:
/* NOTE: this rules out http:ieinternal and http:foo.ieinternal not to be INCLUDED */
/* The alternative is to risk http:com and http:www.microsoft.com */
goto End;
case seen1Dot:
/* INCLUDE http:microsoft.com and http:www.microsoft.com,
( http:a.micro.com and http:b.micro.com included by seen2Dots )
EXCLUDE http:co.uk and http:www.microsoft.co.uk
and all else
eg. http:amicrosoft.com and http:www.microsoft.com
&
http:microsoft.com and http:amicrosoft.com
*/
if ((bLeftByte != ':') || (bRightByte != '.') || ((cbSubstring1 == 2) && IsKnown2ndSubstring(pCurr1+2, pSubstring2End)))
goto End;
break;
case seen2Dots:
/* INCLUDE http:ood.microsoft.com and http:food.microsoft.com
INCLUDE http:a.co.uk and http:b.a.co.uk
EXCLUDE http:www.microsoft.co.uk and http:www.amicrosoft.co.uk
*/
if ((cbSubstring1 == 2) && IsKnown2ndSubstring(pSubstring2Start, pSubstring2End) && ((bLeftByte != ':') || (bRightByte != '.')))
goto End;
break;
case seen3Dots:
/* INCLUDES all cases including
http:food.microsoft.co.uk and http:drink.microsoft.co.uk */
case domainSame:
/* INCLUDES all equal domain cases of all substring sizes, including intranet sites */
break;
}
/* no longer compare the protocols.
if we get to this point, then the SecurityId's match.
*/
bRetval = TRUE;
End:
DEBUG_LEAVE(bRetval);
return bRetval;
}
BOOL SecurityIdContainsScheme(BYTE* pbSecurityId, DWORD dwLen)
{
BYTE* pCurr = pbSecurityId;
BOOL fRet = TRUE;
while ( (DWORD)(pCurr-pbSecurityId) < dwLen )
{
if (*pCurr++ == ':')
{
goto End;
break;
}
}
fRet = FALSE;
End:
return fRet;
}
//returns S_OK if they match,
// S_FALSE if they don't ( i.e. THIRD PARTY )
STDAPI CompareSecurityIds(BYTE* pbSecurityId1, DWORD dwLen1, BYTE* pbSecurityId2, DWORD dwLen2, DWORD dwReserved)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CompareSecurityIds",
"%#x, %#x, %#x, %#x, %#x",
pbSecurityId1, dwLen1, pbSecurityId2, dwLen2, dwReserved
));
HRESULT hr = E_INVALIDARG;
BOOL fRet;
//parameter validation
if ((dwLen1 <= 0) || (!pbSecurityId1) || (dwLen2 <= 0) || (!pbSecurityId2))
goto End;
if (!SecurityIdContainsScheme(pbSecurityId1, dwLen1) ||
!SecurityIdContainsScheme(pbSecurityId2, dwLen2))
goto End;
fRet = SecurityIdsMatch(pbSecurityId1, dwLen1, pbSecurityId2, dwLen2);
if (fRet == TRUE)
hr = S_OK;
else
hr = S_FALSE;
End:
DEBUG_LEAVE(hr);
return hr;
}
BOOL CINet::IsThirdPartyUrl(LPCWSTR pwszUrl)
{
DEBUG_ENTER((DBG_APP,
Bool,
"CINet::IsThirdPartyUrl",
"this=%#x, %.80wq",
this, pwszUrl
));
BOOL bRetval = TRUE; // be safe or sorry?
HRESULT hr = NOERROR;
BYTE bSID[MAX_SIZE_SECURITY_ID];
DWORD cbSID = MAX_SIZE_SECURITY_ID;
if(!SUCCEEDED(hr = EnsureSecurityManager()))
{
goto End;
}
if (_pbRootSecurityId == NULL)
{
// ASSERT(FALSE);
goto End;
}
else if (_pbRootSecurityId == INVALID_P_ROOT_SECURITY_ID)
{
bRetval = FALSE;
goto End;
}
hr = g_pSecurityManager->GetSecurityId( pwszUrl, bSID, &cbSID, 0 );
if (FAILED(hr))
goto End;
bRetval = !SecurityIdsMatch(bSID, cbSID, _pbRootSecurityId, _cbRootSecurityId);
End:
DEBUG_LEAVE(bRetval);
return bRetval;
}
BOOL CINet::IsThirdPartyUrl(LPCSTR pszUrl)
{
DEBUG_ENTER((DBG_APP,
Bool,
"CINet::IsThirdPartyUrl",
"this=%#x, %.80q",
this, pszUrl
));
WCHAR pwszUrl[MAX_URL_SIZE];
BOOL bRetval = TRUE; // be safe or sorry?
if(MultiByteToWideChar(CP_ACP, 0, pszUrl, -1, pwszUrl, MAX_URL_SIZE))
bRetval = IsThirdPartyUrl(pwszUrl);
DEBUG_LEAVE(bRetval);
return bRetval;
}
//+---------------------------------------------------------------------------
//
// Function: CreateKnownProtocolInstance
//
// Synopsis:
//
// Arguments: [dwProtId] --
// [rclsid] --
// [pUnkOuter] --
// [riid] --
// [ppUnk] --
//
// Returns:
//
// History: 11-01-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CreateKnownProtocolInstance(DWORD dwProtId, REFCLSID rclsid, IUnknown *pUnkOuter, REFIID riid, IUnknown **ppUnk)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CreateKnownProtocolInstance",
"%#x, %#x, %#x, %#x, %#x",
dwProtId, &rclsid, pUnkOuter, &riid, ppUnk
));
PerfDbgLog(tagCINet, NULL, "+CreateKnownProtocolInstance");
HRESULT hr = NOERROR;
CINet *pCINet = NULL;
PProtAssert((ppUnk));
if (!ppUnk || (pUnkOuter && (riid != IID_IUnknown)) )
{
// Note: aggregation only works if asked for IUnknown
PProtAssert((FALSE && "Dude, look up aggregation rules - need to ask for IUnknown"));
hr = E_INVALIDARG;
}
#if 0
else if (riid == IID_IOInetProtocolInfo)
{
PProtAssert((dwProtId != DLD_PROTOCOL_NONE));
COInetProtocolInfo *pProtInfo = new COInetProtocolInfo(dwProtId);
if (pProtInfo)
{
hr = pProtInfo->QueryInterface(IID_IOInetProtocolInfo, (void **)ppUnk);
}
else
{
hr = E_OUTOFMEMORY;
}
}
#endif // 0
else if (dwProtId != DLD_PROTOCOL_NONE)
{
CINet *pCINet = NULL;
switch (dwProtId)
{
case DLD_PROTOCOL_LOCAL :
case DLD_PROTOCOL_FILE :
pCINet = new CINetFile(CLSID_FileProtocol,pUnkOuter);
break;
case DLD_PROTOCOL_HTTP :
pCINet = new CINetHttp(CLSID_HttpProtocol,pUnkOuter);
break;
case DLD_PROTOCOL_FTP :
pCINet = new CINetFtp(CLSID_FtpProtocol,pUnkOuter);
break;
case DLD_PROTOCOL_GOPHER :
pCINet = new CINetGopher(CLSID_GopherProtocol,pUnkOuter);
break;
case DLD_PROTOCOL_HTTPS :
pCINet = new CINetHttpS(CLSID_HttpSProtocol,pUnkOuter);
break;
case DLD_PROTOCOL_STREAM :
pCINet = new CINetStream(CLSID_MkProtocol,pUnkOuter);
break;
default:
PProtAssert((FALSE));
hr = E_FAIL;
}
if (hr == NOERROR)
{
if (pCINet)
{
if (riid == IID_IUnknown)
{
// pCINet has refcount of 1 now
// get the pUnkInner
// pUnkInner does not addref pUnkOuter
if (pUnkOuter && ppUnk)
{
*ppUnk = pCINet->GetIUnkInner(TRUE);
// addref the outer object since releasing pCINet will go cause a release on pUnkOuter
TransAssert((*ppUnk));
}
}
else
{
if (riid == IID_IOInetProtocol)
{
// ok, got the right interface already
*ppUnk = (IOInetProtocol *)pCINet;
}
else
{
hr = pCINet->QueryInterface(riid, (void **)ppUnk);
// remove extra refcount
pCINet->Release();
}
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
}
else
{
//load the protocol by looking up the registry
hr = E_FAIL;
}
PerfDbgLog1(tagCINet, NULL, "-CreateKnownProtocolInstance(hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
ProtocolInfo rgKnownProts[] =
{
{ L"http" , "http" , DLD_PROTOCOL_HTTP , (CLSID *) &CLSID_HttpProtocol , sizeof("http") - 1 }
,{ L"file" , "file" , DLD_PROTOCOL_FILE , (CLSID *) &CLSID_FileProtocol , sizeof("file") - 1 }
,{ L"ftp" , "ftp" , DLD_PROTOCOL_FTP , (CLSID *) &CLSID_FtpProtocol , sizeof("ftp") - 1 }
,{ L"https" , "https" , DLD_PROTOCOL_HTTPS , (CLSID *) &CLSID_HttpSProtocol , sizeof("http") - 1 }
,{ L"mk" , "mk" , DLD_PROTOCOL_STREAM , (CLSID *) &CLSID_MkProtocol , sizeof("mk") - 1 }
,{ L"gopher", "Gopher" , DLD_PROTOCOL_GOPHER , (CLSID *) &CLSID_GopherProtocol, sizeof("gopher") - 1 }
,{ L"local" , "local" , DLD_PROTOCOL_LOCAL , (CLSID *) &CLSID_FileProtocol , sizeof("local") - 1 }
};
typedef struct tagInterErrorToHResult
{
DWORD dwError;
HRESULT hresult;
} InterErrorToHResult;
InterErrorToHResult INetError[] =
{
0 ,NOERROR
,ERROR_INTERNET_OUT_OF_HANDLES ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_TIMEOUT ,INET_E_CONNECTION_TIMEOUT
,ERROR_INTERNET_EXTENDED_ERROR ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_INTERNAL_ERROR ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_INVALID_URL ,INET_E_INVALID_URL
,ERROR_INTERNET_UNRECOGNIZED_SCHEME ,INET_E_UNKNOWN_PROTOCOL
,ERROR_INTERNET_NAME_NOT_RESOLVED ,INET_E_RESOURCE_NOT_FOUND
,ERROR_INTERNET_PROTOCOL_NOT_FOUND ,INET_E_UNKNOWN_PROTOCOL
,ERROR_INTERNET_INVALID_OPTION ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_BAD_OPTION_LENGTH ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_OPTION_NOT_SETTABLE ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_SHUTDOWN ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_INCORRECT_USER_NAME ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_INCORRECT_PASSWORD ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_LOGIN_FAILURE ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_INVALID_OPERATION ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_OPERATION_CANCELLED ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_INCORRECT_HANDLE_TYPE ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_INCORRECT_HANDLE_STATE ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_NOT_PROXY_REQUEST ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_REGISTRY_VALUE_NOT_FOUND ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_BAD_REGISTRY_PARAMETER ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_NO_DIRECT_ACCESS ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_NO_CONTEXT ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_NO_CALLBACK ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_REQUEST_PENDING ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_INCORRECT_FORMAT ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_ITEM_NOT_FOUND ,INET_E_OBJECT_NOT_FOUND
,ERROR_INTERNET_CANNOT_CONNECT ,INET_E_RESOURCE_NOT_FOUND
,ERROR_INTERNET_CONNECTION_ABORTED ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_CONNECTION_RESET ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_FORCE_RETRY ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_INVALID_PROXY_REQUEST ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_NEED_UI ,INET_E_DOWNLOAD_FAILURE
,0 ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_HANDLE_EXISTS ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_SEC_CERT_DATE_INVALID ,INET_E_SECURITY_PROBLEM
,ERROR_INTERNET_SEC_CERT_CN_INVALID ,INET_E_SECURITY_PROBLEM
,ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_HTTPS_TO_HTTP_ON_REDIR ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_MIXED_SECURITY ,INET_E_SECURITY_PROBLEM
,ERROR_INTERNET_CHG_POST_IS_NON_SECURE ,INET_E_SECURITY_PROBLEM
,ERROR_INTERNET_POST_IS_NON_SECURE ,INET_E_SECURITY_PROBLEM
,ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED ,INET_E_SECURITY_PROBLEM
,ERROR_INTERNET_INVALID_CA ,INET_E_SECURITY_PROBLEM
,ERROR_INTERNET_CLIENT_AUTH_NOT_SETUP ,INET_E_SECURITY_PROBLEM
,ERROR_INTERNET_SEC_CERT_REV_FAILED ,INET_E_SECURITY_PROBLEM
,ERROR_INTERNET_SEC_CERT_REVOKED ,INET_E_SECURITY_PROBLEM
,ERROR_INTERNET_FORTEZZA_LOGIN_NEEDED ,INET_E_SECURITY_PROBLEM
,ERROR_INTERNET_ASYNC_THREAD_FAILED ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_REDIRECT_SCHEME_CHANGE ,INET_E_DOWNLOAD_FAILURE
};
// list of non-sequential errors
InterErrorToHResult INetErrorExtended[] =
{
ERROR_FTP_TRANSFER_IN_PROGRESS ,INET_E_DOWNLOAD_FAILURE
,ERROR_FTP_DROPPED ,INET_E_DOWNLOAD_FAILURE
,ERROR_GOPHER_PROTOCOL_ERROR ,INET_E_DOWNLOAD_FAILURE
,ERROR_GOPHER_NOT_FILE ,INET_E_DOWNLOAD_FAILURE
,ERROR_GOPHER_DATA_ERROR ,INET_E_DOWNLOAD_FAILURE
,ERROR_GOPHER_END_OF_DATA ,INET_E_DOWNLOAD_FAILURE
,ERROR_GOPHER_INVALID_LOCATOR ,INET_E_DOWNLOAD_FAILURE
,ERROR_GOPHER_INCORRECT_LOCATOR_TYPE ,INET_E_DOWNLOAD_FAILURE
,ERROR_GOPHER_NOT_GOPHER_PLUS ,INET_E_DOWNLOAD_FAILURE
,ERROR_GOPHER_ATTRIBUTE_NOT_FOUND ,INET_E_DOWNLOAD_FAILURE
,ERROR_GOPHER_UNKNOWN_LOCATOR ,INET_E_DOWNLOAD_FAILURE
,ERROR_HTTP_HEADER_NOT_FOUND ,INET_E_DOWNLOAD_FAILURE
,ERROR_HTTP_DOWNLEVEL_SERVER ,INET_E_DOWNLOAD_FAILURE
,ERROR_HTTP_INVALID_SERVER_RESPONSE ,INET_E_DOWNLOAD_FAILURE
,ERROR_HTTP_INVALID_HEADER ,INET_E_DOWNLOAD_FAILURE
,ERROR_HTTP_INVALID_QUERY_REQUEST ,INET_E_DOWNLOAD_FAILURE
,ERROR_HTTP_HEADER_ALREADY_EXISTS ,INET_E_DOWNLOAD_FAILURE
,ERROR_HTTP_REDIRECT_FAILED ,INET_E_REDIRECT_FAILED
,ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_SECURITY_CHANNEL_ERROR ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_UNABLE_TO_CACHE_FILE ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_TCPIP_NOT_INSTALLED ,INET_E_DOWNLOAD_FAILURE
,ERROR_HTTP_NOT_REDIRECTED ,INET_E_DOWNLOAD_FAILURE
,ERROR_INTERNET_HTTPS_HTTP_SUBMIT_REDIR ,INET_E_DOWNLOAD_FAILURE
};
//+---------------------------------------------------------------------------
//
// Function: IsKnownOInetProtocolClass
//
// Synopsis:
//
// Arguments: [pclsid] --
//
// Returns:
//
// History: 11-01-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD IsKnownOInetProtocolClass(CLSID *pclsid)
{
DEBUG_ENTER((DBG_APP,
Dword,
"IsKnownOInetProtocolClass",
"%#x",
pclsid
));
PProtAssert((pclsid));
DWORD dwRet = DLD_PROTOCOL_NONE;
int i = 0;
int cSize = sizeof(rgKnownProts)/sizeof(ProtocolInfo);
if (pclsid)
{
for (i = 0; i < cSize; ++i)
{
if (*pclsid == *rgKnownProts[i].pClsID)
{
dwRet = rgKnownProts[i].dwId;
i = cSize;
}
}
}
DEBUG_LEAVE(dwRet);
return dwRet;
}
//+---------------------------------------------------------------------------
//
// Function: IsKnownProtocol
//
// Synopsis: looks up if an protocol handler exist for a given url
//
// Arguments: [wzProtocol] --
//
// Returns:
//
// History: 11-01-1996 JohannP (Johann Posch) Created
//
// Notes: used at many place inside urlmon
//
//----------------------------------------------------------------------------
DWORD IsKnownProtocol(LPCWSTR wzProtocol)
{
DEBUG_ENTER((DBG_APP,
Dword,
"IsKnownProtocol",
"%#.80wq",
wzProtocol
));
DWORD dwRet = DLD_PROTOCOL_NONE;
int i = 0;
int cSize = sizeof(rgKnownProts)/sizeof(ProtocolInfo);
for (i = 0; i < cSize; ++i)
{
if (!StrCmpNICW(wzProtocol, rgKnownProts[i].pwzProtocol, rgKnownProts[i].protlen))
{
dwRet = rgKnownProts[i].dwId;
if ((DLD_PROTOCOL_HTTP == dwRet) &&
((wzProtocol[4] == L's') ||
(wzProtocol[4] == L'S')))
{
dwRet = DLD_PROTOCOL_HTTPS;
}
break;
}
}
DEBUG_LEAVE(dwRet);
return dwRet;
}
//+---------------------------------------------------------------------------
//
// Function: GetKnownOInetProtocolClsID
//
// Synopsis:
//
// Arguments: [dwProtoId] --
//
// Returns:
//
// History: 11-01-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
CLSID *GetKnownOInetProtocolClsID(DWORD dwProtoId)
{
DEBUG_ENTER((DBG_APP,
Pointer,
"GetKnownOInetProtocolClsID",
"%#x",
dwProtoId
));
PerfDbgLog1(tagCINet, NULL, "GetKnownOInetProtocolClsID (dwProtoId:%lx)", dwProtoId);
CLSID *pclsid = 0;
int cSize = sizeof(rgKnownProts)/sizeof(ProtocolInfo);
for (int i = 0; i < cSize; ++i)
{
if (dwProtoId == rgKnownProts[i].dwId )
{
pclsid = rgKnownProts[i].pClsID;
i = cSize;
}
}
DEBUG_LEAVE(pclsid);
return pclsid;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::QueryInterface
//
// Synopsis:
//
// Arguments: [riid] --
// [ppvObj] --
//
// Returns:
//
// History: 10-29-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CINet::QueryInterface(REFIID riid, void **ppvObj)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::IUnknown::QueryInterface",
"this=%#x, %#x, %#x",
this, &riid, ppvObj
));
VDATEPTROUT(ppvObj, void *);
VDATETHIS(this);
HRESULT hr = NOERROR;
PerfDbgLog(tagCINet, this, "+CINet::QueryInterface");
if (riid == IID_IOInetPriority)
{
*ppvObj = (IOInetPriority *) this;
AddRef();
}
else
{
hr = _pUnkOuter->QueryInterface(riid, ppvObj);
}
PerfDbgLog1(tagCINet, this, "-CINet::QueryInterface (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: CINet::AddRef
//
// Synopsis:
//
// Arguments: [ULONG] --
//
// Returns:
//
// History: 10-29-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CINet::AddRef(void)
{
DEBUG_ENTER((DBG_APP,
Dword,
"CINet::IUnknown::AddRef",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::AddRef");
LONG lRet = _pUnkOuter->AddRef();
PerfDbgLog1(tagCINet, this, "-CINet::AddRef (cRefs:%ld)", lRet);
DEBUG_LEAVE(lRet);
return lRet;
}
//+---------------------------------------------------------------------------
//
// Function: CINet::Release
//
// Synopsis:
//
// Arguments: [ULONG] --
//
// Returns:
//
// History: 10-29-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CINet::Release(void)
{
DEBUG_ENTER((DBG_APP,
Dword,
"CINet::IUnknown::Release",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::Release");
LONG lRet = _pUnkOuter->Release();
PerfDbgLog1(tagCINet, this, "-CINet::Release (cRefs:%ld)", lRet);
DEBUG_LEAVE(lRet);
return lRet;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::Start
//
// Synopsis:
//
// Arguments: [pwzUrl] --
// [pTrans] --
// [pOIBindInfo] --
// [grfSTI] --
// [dwReserved] --
//
// Returns:
//
// History: 10-29-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CINet::Start(LPCWSTR pwzUrl, IOInetProtocolSink *pTrans, IOInetBindInfo *pOIBindInfo,
DWORD grfSTI, DWORD_PTR dwReserved)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::IInternetProtocolRoot::Start",
"this=%#x, %.200wq, %#x, %#x, %#x, %#x",
this, pwzUrl, pTrans, pOIBindInfo, grfSTI, dwReserved
));
PerfDbgLog(tagCINet, this, "+CINet::Start");
HRESULT hr = NOERROR;
//char szURL[MAX_URL_SIZE];
DWORD dwUrlSize = 0;
DWORD dwMaxUTF8Len = 0;
BOOL fUTF8Enabled = FALSE;
BOOL fUTF8Required = FALSE;
PProtAssert((!_pCTrans && pOIBindInfo && pTrans));
PProtAssert((_pwzUrl == NULL));
if ( !(grfSTI & PI_PARSE_URL))
{
_pCTrans = pTrans;
_pCTrans->AddRef();
_pOIBindInfo = pOIBindInfo;
_pOIBindInfo->AddRef();
_pwzUrl = OLESTRDuplicate((LPWSTR)pwzUrl);
}
_BndInfo.cbSize = sizeof(BINDINFO);
hr = pOIBindInfo->GetBindInfo(&_grfBindF, &_BndInfo);
DEBUG_ENTER((DBG_APP,
Hresult,
"EXTERNAL_CLIENT::GetBindInfo",
"this=%#x, flags=%#x, pBindInfo=%#x",
this, _grfBindF, pOIBindInfo
));
DEBUG_LEAVE(hr);
if( hr != NOERROR )
{
goto End;
}
/************************************************************************
// szURL does not seem to be used, am I missing something?
// szURL is 2K buffer on stack! Let's remove this code at all.
// DanpoZ (98/02/20)
// Do we need to append the extra data to the url?
if (_BndInfo.szExtraInfo)
{
// append extra info at the end of the url
// Make sure we don't overflow the URL
if (CchWzLen(_BndInfo.szExtraInfo) + CchWzLen(pwzUrl) >= MAX_URL_SIZE)
{
hr = E_INVALIDARG;
goto End;
}
W2A(pwzUrl, szURL, MAX_URL_SIZE, _BndInfo.dwCodePage);
// Append the extra data to the url. Note that we have already
// checked for overflow, so we need not worry about it here.
W2A(_BndInfo.szExtraInfo, szURL + CchSzLen(szURL), MAX_URL_SIZE, _BndInfo.dwCodePage);
}
else
{
// Make sure we don't overflow the URL
if (CchWzLen(pwzUrl) + 1 > MAX_URL_SIZE)
{
hr = E_INVALIDARG;
goto End;
}
W2A(pwzUrl, szURL, MAX_URL_SIZE, _BndInfo.dwCodePage);
}
************************************************************************/
// no need to check the length of pwzUrl, this has been done already
if( !_BndInfo.dwCodePage )
_BndInfo.dwCodePage = GetACP();
// utf8 enabled?
fUTF8Enabled = UTF8Enabled();
if( fUTF8Enabled )
{
dwUrlSize = CountUnicodeToUtf8(pwzUrl, wcslen(pwzUrl), TRUE);
DWORD dwMB = StrLenMultiByteWithMlang(pwzUrl, _BndInfo.dwCodePage);
if( dwMB > dwUrlSize )
{
dwUrlSize = dwMB;
}
}
else
{
dwUrlSize = StrLenMultiByteWithMlang(pwzUrl, _BndInfo.dwCodePage);
}
if( !dwUrlSize )
{
hr = E_INVALIDARG;
goto End;
}
if( CUrlInitBasic(dwUrlSize) )
{
//W2A(pwzUrl, _pszBaseURL, dwUrlSize, _BndInfo.dwCodePage);
ConvertUnicodeUrl(
pwzUrl, // (IN) unicode URL
_pszBaseURL, // (OUT) multibyte URL
dwUrlSize, // (IN) multibyte URL length
_BndInfo.dwCodePage, // (IN) codepage
fUTF8Enabled, // (IN) UTF-8 conversion enabled?
&fUTF8Required
);
}
else
{
hr = E_OUTOFMEMORY;
goto End;
}
{
// Init the Embedded Filter
if( _pEmbdFilter )
{
delete _pEmbdFilter;
_pEmbdFilter = NULL;
}
_pEmbdFilter = new CINetEmbdFilter( this, _pCTrans );
if( !_pEmbdFilter )
{
hr = E_OUTOFMEMORY;
goto End;
}
if(!_pEmbdFilter->IsInited())
{
delete _pEmbdFilter;
_pEmbdFilter = NULL;
hr = E_OUTOFMEMORY;
goto End;
}
// For sanity checks later via IsEmbdFilterOk():
_dwEmbdFilter = *(DWORD *)_pEmbdFilter;
}
if (!ParseUrl(fUTF8Required, pwzUrl, _BndInfo.dwCodePage))
{
_hrError = INET_E_INVALID_URL;
hr = MK_E_SYNTAX;
}
else if ( !(grfSTI & PI_PARSE_URL))
{
g_cInetState.HandleState();
PProtAssert((_pCTrans));
if( !(_grfBindF & BINDF_FROMURLMON) && IsEmbdFilterOk() )
{
_pEmbdFilter->ReportProgress(BINDSTATUS_DIRECTBIND, 0);
}
hr = INetAsyncStart();
}
End:
PerfDbgLog1(tagCINet, this, "-CINet::Start (hr:%lx)", hr);
if( hr == E_PENDING )
{
// hack, CTransact will warp E_PENDING with NOERROR and return
// it to client, if we do not have CTrans wrapper (not aggregrated)
// we should return NOERROR.
if( _pUnkOuter == &_Unknown )
{
hr = NOERROR;
}
}
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::Continue
//
// Synopsis:
//
// Arguments: [pStateInfoIn] --
//
// Returns:
//
// History: 10-29-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CINet::Continue(PROTOCOLDATA *pStateInfoIn)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::IInternetProtocolRoot::Continue",
"this=%#x, %#x",
this, pStateInfoIn
));
HRESULT hr = E_FAIL;
if(IsEmbdFilterOk())
hr = _pEmbdFilter->Continue(pStateInfoIn);
DEBUG_LEAVE(hr);
return hr;
}
STDMETHODIMP CINet::MyContinue(PROTOCOLDATA *pStateInfoIn)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::MyContinue",
"this=%#x, %#x",
this, pStateInfoIn
));
PerfDbgLog(tagCINet, this, "+CINet::Continue");
HRESULT hr = NOERROR;
PProtAssert((pStateInfoIn->pData && !pStateInfoIn->cbData));
// check if the inete state changed
g_cInetState.HandleState();
OnINetInternal((DWORD_PTR) pStateInfoIn->pData);
if( !(_grfBindF & BINDF_FROMURLMON) )
{
//
// if the BindInfo is created from heap by CINet
// we need to delete it from here
//
delete pStateInfoIn;
}
PerfDbgLog1(tagCINet, this, "-CINet::Continue (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::Abort
//
// Synopsis:
//
// Arguments: [hrReason] --
// [dwOptions] --
//
// Returns:
//
// History: 10-29-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CINet::Abort(HRESULT hrReason, DWORD dwOptions)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::IInternetProtocolRoot::Abort",
"this=%#x, %#x, %#x",
this, hrReason, dwOptions
));
HRESULT hr = NOERROR;
if( _pEmbdFilter )
{
hr = _pEmbdFilter->Abort(hrReason, dwOptions);
}
DEBUG_LEAVE(hr);
return hr;
}
STDMETHODIMP CINet::MyAbort(HRESULT hrReason, DWORD dwOptions)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::MyAbort",
"this=%#x, %#x, %#x",
this, hrReason, dwOptions
));
PerfDbgLog(tagCINet, this, "+CINet::Abort");
HRESULT hr = NOERROR;
PProtAssert((_pCTrans));
hr = ReportResultAndStop(hrReason);
PerfDbgLog1(tagCINet, this, "-CINet::Abort (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::Terminate
//
// Synopsis:
//
// Arguments: [dwOptions] --
//
// Returns:
//
// History: 10-29-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CINet::Terminate(DWORD dwOptions)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::IInternetProtocolRoot::Terminate",
"this=%#x, %#x",
this, dwOptions
));
// in case we failed on :Start, _pEmbdFilter is
// not in place, however, Terminate might be
// called so we have to call MyTerminate directly
HRESULT hr = NOERROR;
if( _pEmbdFilter )
{
hr = _pEmbdFilter->Terminate(dwOptions);
}
else
{
hr = MyTerminate(dwOptions);
}
DEBUG_LEAVE(hr);
return hr;
}
/*
* This function will only be called into after MyTerminate has been called -
* since only InternetCloseHandle called in MyTerminate should trigger a handle-closing callback.
*
* No synchronization may be required because :
*
* 1. all operations at this point using the handle should have
been done with since the handle has been destroyed ( hence no Reads in progress. )
2. if we find that we need to synchronize access to this, we must correspondinly synchronize
all access to the _pCTrans object from CINet. Hopefully, this is not required because
we should get handleclosing callback from wininet only after we have exited all callbacks.
3. the only other place _pCTrans can be touched from is Reads from above which shouldn't be
happening if this is closed as a result of being aborted or terminated cleanly.
*
The objective of this new function is to let the _pCTrans connection live until wininet is done
with context use - else witness ugly race condition in bug 2270.
ReleaseBindInfo() happening here to get around bug 19809, which again is triggered by IBinding::Abort
situations in stress.
*/
VOID CINet::ReleaseTransAndBindInfo()
{
DEBUG_ENTER((DBG_APP,
None,
"CINet::ReleaseTransAndBindInfo",
"this=%#x, %#x",
this, _pCTrans
));
if (!_fHandlesRecycled)
{
PProtAssert((_pCTrans));
PProtAssert((_dwState == INetState_DONE) || (_dwState == INetState_ERROR));
PProtAssert((_dwIsA == DLD_PROTOCOL_HTTP) || (_dwIsA == DLD_PROTOCOL_HTTPS) || (_dwIsA == DLD_PROTOCOL_FILE) || (_dwIsA == DLD_PROTOCOL_GOPHER));
// Hopefully, this stays an assert.
// scenario where abort is called before/during the OpenRequest/OpenUrl call.
PProtAssert((_HandleStateRequest == HandleState_Closed));
if (_pCTrans)
{
_pCTrans->Release();
_pCTrans = NULL;
}
ReleaseBindInfo(&_BndInfo);
}
DEBUG_LEAVE(0);
}
STDMETHODIMP CINet::MyTerminate(DWORD dwOptions)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::MyTerminate",
"this=%#x, %#x",
this, dwOptions
));
PerfDbgLog(tagCINet, this, "+CINet::Terminate");
HRESULT hr = NOERROR;
BOOL fReleaseBindInfo = FALSE;
//should be called once
PProtAssert((_pCTrans));
if (_pOIBindInfo)
{
_pOIBindInfo->Release();
_pOIBindInfo = NULL;
}
if (_pServiceProvider)
{
_pServiceProvider->Release();
_pServiceProvider = NULL;
}
if (_pCTrans)
{
// release all the handles if unless
// the request was locked
if (!_fLocked && !_hLockHandle)
{
TerminateRequest();
}
// sync block
{
CLock lck(_mxs); // only one thread should be in here
if ((_dwState != INetState_DONE) && (_dwState != INetState_ERROR))
{
_dwState = INetState_DONE;
}
if ( (_dwIsA == DLD_PROTOCOL_FILE)
|| (_dwIsA == DLD_PROTOCOL_LOCAL)
|| (_dwIsA == DLD_PROTOCOL_STREAM)
|| _fHandlesRecycled
|| (_HandleStateServer == HandleState_Aborted))
{
fReleaseBindInfo = TRUE;
_pCTrans->Release();
_pCTrans = NULL;
}
}
}
#if DBG == 1
if ( _BndInfo.stgmedData.tymed != TYMED_NULL )
PerfDbgLog1(tagCINet, this, "--- CINet::Stop ReleaseStgMedium (%lx)", _BndInfo.stgmedData);
#endif
if ( fReleaseBindInfo
|| (_dwIsA == DLD_PROTOCOL_FILE)
|| (_dwIsA == DLD_PROTOCOL_LOCAL)
|| (_dwIsA == DLD_PROTOCOL_STREAM)
|| _fHandlesRecycled
|| (_HandleStateServer == HandleState_Aborted))
{
ReleaseBindInfo(&_BndInfo);
}
PerfDbgLog1(tagCINet, this, "-CINet::Terminate (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::Suspend
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 10-29-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CINet::Suspend()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::IInternetProtocolRoot::Suspend",
"this=%#x",
this
));
HRESULT hr = _pEmbdFilter->Suspend();
DEBUG_LEAVE(hr);
return hr;
}
STDMETHODIMP CINet::MySuspend()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::MySuspend",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::Suspend");
HRESULT hr = E_NOTIMPL;
PerfDbgLog1(tagCINet, this, "-CINet::Suspend (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::Resume
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 10-29-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CINet::Resume()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::IInternetProtocolRoot::Resume",
"this=%#x",
this
));
HRESULT hr = _pEmbdFilter->Resume();
DEBUG_LEAVE(hr);
return hr;
}
STDMETHODIMP CINet::MyResume()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::MyResume",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::Resume");
HRESULT hr = E_NOTIMPL;
PerfDbgLog1(tagCINet, this, "-CINet::Resume (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::SetPriority
//
// Synopsis:
//
// Arguments: [nPriority] --
//
// Returns:
//
// History: 10-29-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CINet::SetPriority(LONG nPriority)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::IInternetPriority::SetPriority",
"this=%#x, %#x",
this, nPriority
));
PerfDbgLog1(tagCINet, this, "+CINet::SetPriority (%ld)", nPriority);
HRESULT hr = S_OK;
_nPriority = nPriority;
PerfDbgLog1(tagCINet, this, "-CINet::SetPriority (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::GetPriority
//
// Synopsis:
//
// Arguments: [pnPriority] --
//
// Returns:
//
// History: 10-29-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CINet::GetPriority(LONG * pnPriority)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::IInternetPriority::GetPriority",
"this=%#x, %#x",
this, pnPriority
));
PerfDbgLog(tagCINet, this, "+CINet::GetPriority");
HRESULT hr = S_OK;
*pnPriority = _nPriority;
PerfDbgLog1(tagCINet, this, "-CINet::GetPriority (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::Read
//
// Synopsis:
//
// Arguments: [ULONG] --
// [ULONG] --
// [pcbRead] --
//
// Returns:
//
// History: 10-29-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CINet::Read(void *pv,ULONG cb,ULONG *pcbRead)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::IInternetProtocol::Read",
"this=%#x, %#x, %#x, %#x",
this, pv, cb, pcbRead
));
HRESULT hr = _pEmbdFilter->Read(pv, cb, pcbRead);
DEBUG_LEAVE(hr);
return hr;
}
STDMETHODIMP CINet::MyRead(void *pv,ULONG cb,ULONG *pcbRead)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::MyRead",
"this=%#x, %#x, %#x, %#x",
this, pv, cb, pcbRead
));
PerfDbgLog(tagCINet, this, "+CINet::Read");
HRESULT hr = NOERROR;
if(GetBindFlags() & BINDF_DIRECT_READ)
{
hr = ReadDirect((BYTE *)pv, cb, pcbRead);
}
else
{
hr = ReadDataHere((BYTE *)pv, cb, pcbRead);
}
PerfDbgLog1(tagCINet, this, "-CINet::Read (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::Seek
//
// Synopsis:
//
// Arguments: [DWORD] --
// [ULARGE_INTEGER] --
// [plibNewPosition] --
//
// Returns:
//
// History: 10-29-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CINet::Seek(LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER *plibNewPosition)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::IInternetProtocol::Seek",
"this=%#x, %#x, %#x, %#x",
this, dlibMove, dwOrigin, plibNewPosition
));
HRESULT hr = _pEmbdFilter->Seek(dlibMove, dwOrigin, plibNewPosition);
DEBUG_LEAVE(hr);
return hr;
}
STDMETHODIMP CINet::MySeek(LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER *plibNewPosition)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::MySeek",
"this=%#x, %#x, %#x, %#x",
this, dlibMove, dwOrigin, plibNewPosition
));
PerfDbgLog(tagCINet, this, "+CINet::Seek");
HRESULT hr;
hr = INetSeek(dlibMove, dwOrigin,plibNewPosition);
PerfDbgLog1(tagCINet, this, "-CINet::Seek (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::LockRequest
//
// Synopsis:
//
// Arguments: [dwOptions] --
//
// Returns:
//
// History: 10-29-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CINet::LockRequest(DWORD dwOptions)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::IInternetProtocol::LockRequest",
"this=%#x, %#x",
this, dwOptions
));
HRESULT hr = _pEmbdFilter->LockRequest(dwOptions);
DEBUG_LEAVE(hr);
return hr;
}
STDMETHODIMP CINet::MyLockRequest(DWORD dwOptions)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::MyLockRequest",
"this=%#x, %#x",
this, dwOptions
));
PerfDbgLog(tagCINet, this, "+CINet::LockRequest");
HRESULT hr = NOERROR;
hr = LockFile(FALSE);
PerfDbgLog1(tagCINet, this, "-CINet::LockRequest (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::UnlockRequest
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 10-29-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CINet::UnlockRequest()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::IInternetProtocol::UnlockRequest",
"this=%#x",
this
));
HRESULT hr = _pEmbdFilter->UnlockRequest();
DEBUG_LEAVE(hr);
return hr;
}
STDMETHODIMP CINet::MyUnlockRequest()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::MyUnlockRequest",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::UnlockRequest");
HRESULT hr = NOERROR;
TerminateRequest();
hr = UnlockFile();
PerfDbgLog1(tagCINet, this, "-CINet::UnlockRequest (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::QueryOption
//
// Synopsis:
//
// Arguments: [dwOption] --
// [pBuffer] --
// [pcbBuf] --
//
// Returns:
//
// History: 4-16-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CINet::QueryOption(DWORD dwOption, LPVOID pBuffer, DWORD *pcbBuf)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::IWininetInfo::QueryOption",
"this=%#x, %#x, %#x, %#x",
this, dwOption, pBuffer, pcbBuf
));
PerfDbgLog1(tagCINet, this, "+CINet::QueryOptions dwOption:%ld", dwOption);
HRESULT hr;
if (!pcbBuf || (*pcbBuf == 0))
{
hr = E_INVALIDARG;
}
else if (!_hRequest)
{
*pcbBuf = 0;
hr = E_FAIL;
}
else if (dwOption == WININETINFO_OPTION_LOCK_HANDLE)
{
if ( *pcbBuf >= sizeof(HANDLE)
&& InternetLockRequestFile(_hRequest, (HANDLE *)pBuffer))
{
*pcbBuf = sizeof(HANDLE);
hr = S_OK;
}
else
{
*pcbBuf = 0;
hr = E_FAIL;
}
}
else
{
if (InternetQueryOption(_hRequest, dwOption, pBuffer, pcbBuf))
{
hr = S_OK;
}
else
{
hr = S_FALSE;
}
}
PerfDbgLog2(tagCINet, this, "-CINet::QueryOptions (hr:%lx,szStr:%s)", hr, pBuffer);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::QueryInfo
//
// Synopsis:
//
// Arguments: [dwOption] --
// [pBuffer] --
// [pcbBuf] --
// [pdwFlag] --
//
// Returns:
//
// History: 4-16-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CINet::QueryInfo(DWORD dwOption, LPVOID pBuffer, DWORD *pcbBuf, DWORD *pdwFlags, DWORD *pdwReserved)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::IWininetHttpInfo::QueryInfo",
"this=%#x, %#x, %#x, %#x, %#x, %#x",
this, dwOption, pBuffer, pcbBuf, pdwFlags, pdwReserved
));
PerfDbgLog1(tagCINet, this, "+CINet::QueryInfo dwOption:%ld", dwOption);
HRESULT hr;
if (!pcbBuf)
{
hr = E_INVALIDARG;
}
else if (!_hRequest)
{
*pcbBuf = 0;
hr = E_FAIL;
}
else
{
if (HttpQueryInfo(_hRequest, dwOption, pBuffer, pcbBuf, pdwFlags))
{
hr = S_OK;
}
else
{
if (pBuffer && (*pcbBuf >= sizeof(HRESULT)) )
{
HRESULT *phr = (HRESULT *)pBuffer;
*phr = HRESULT_FROM_WIN32(GetLastError());
*pcbBuf = sizeof(HRESULT);
}
hr = S_FALSE;
}
}
PerfDbgLog2(tagCINet, this, "-CINet::QueryInfo (hr:%lx,szStr:%s)", hr, XDBG(pBuffer&&!hr?pBuffer:"",""));
DEBUG_LEAVE(hr);
return hr;
}
STDMETHODIMP CINet::Prepare()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::IInternetThreadSwitch::Prepare",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::Prepare");
HRESULT hr = NOERROR;
PerfDbgLog1(tagCINet, this, "-CINet::Prepare (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
STDMETHODIMP CINet::Continue()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::IInternetThreadSwitch::Continue",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::Continue");
HRESULT hr = NOERROR;
_dwThreadID = GetCurrentThreadId();
PerfDbgLog1(tagCINet, this, "-CINet::Continue (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::CINet
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
CINet::CINet(REFCLSID rclsid, IUnknown *pUnkOuter) : _CRefs(), _CRefsHandles(0), _cReadCount(0), _pclsidProtocol(rclsid), _Unknown()
{
DEBUG_ENTER((DBG_APP,
None,
"CINet::CINet",
"this=%#x, %#x, %#x",
this, &rclsid, pUnkOuter
));
PerfDbgLog(tagCINet, this, "+CINet::CINet");
_dwEmbdFilter = NULL;
_pEmbdFilter = NULL;
_dwState = INetState_START;
_dwIsA = DLD_PROTOCOL_NONE;
_fRedirected = FALSE;
_fP2PRedirected = FALSE;
_fLocked = FALSE;
_fFilenameReported = FALSE;
_fHandlesRecycled = FALSE;
_fSendAgain = FALSE;
_fSendRequestAgain = FALSE;
_hLockHandle = NULL;
_hFile = NULL;
_dwThreadID = GetCurrentThreadId();
_fDone = 0;
_hwndAuth = NULL;
_bscf = BSCF_FIRSTDATANOTIFICATION;
_pOIBindInfo = 0;
_pszUserAgentStr = 0;
_nPriority = THREAD_PRIORITY_NORMAL;
_cbSizeLastReportData = 0;
_fForceSwitch = FALSE;
_cbAuthenticate = 0;
_cbProxyAuthenticate = 0;
_fDoSimpleRetry = FALSE;
if (!pUnkOuter)
{
pUnkOuter = &_Unknown;
}
_pUnkOuter = pUnkOuter;
_pWindow = 0;
_hServer = 0;
_hRequest = 0;
PerfDbgLog(tagCINet, this, "-CINet::CINet");
DEBUG_LEAVE(0);
}
CINet::~CINet()
{
DEBUG_ENTER((DBG_APP,
None,
"CINet::~CINet",
"this=%#x",
this
));
delete _pwzUrl;
#if DBG == 1
_pwzUrl = NULL;
#endif
delete _pszUserAgentStr;
// release Embedded Filter
if( _pEmbdFilter )
{
CINetEmbdFilter* pEmbdFilter = _pEmbdFilter;
_pEmbdFilter = NULL;
delete pEmbdFilter;
}
PerfDbgLog(tagCINet, this, "CINet::~CINet");
DEBUG_LEAVE(0);
}
// Helper function for _pEmbdFilter sanity check:
bool CINet::IsEmbdFilterOk()
{
if(_pEmbdFilter && !::IsBadReadPtr(_pEmbdFilter, sizeof(DWORD)) && *(DWORD *)_pEmbdFilter == _dwEmbdFilter)
return true;
// Shouldn't happen, but is happening in rare cases.
// Filter got released because someone likely deleted an incorrect offset.
PProtAssert((FALSE));
PerfDbgLog(tagCINet, this, "+CINet::IsEmbdFilterOk: EmbedFilter missing, recreating.");
if(_pCTrans)
{
CLock lck(_mxs); // only one thread should be in here
// Do the check again just in case we have two threads entering:
if(_pEmbdFilter && !::IsBadReadPtr(_pEmbdFilter, sizeof(DWORD)) && *(DWORD *)_pEmbdFilter == _dwEmbdFilter)
return true;
// Release _pCTrans to compensate for the AddRef in
// the CINetEmbdFilter constructor, since the CINetEmbdFilter destructor would not have been called:
_pCTrans->Release();
// Recreate the filter here if possible:
_pEmbdFilter = new CINetEmbdFilter( this, _pCTrans );
if( !_pEmbdFilter || !_pEmbdFilter->IsInited())
{
// Something failed (deleting NULL is fine):
delete _pEmbdFilter;
goto End;
}
// For sanity checks later via IsEmbdFilterOk():
_dwEmbdFilter = *(DWORD *)_pEmbdFilter;
return true;
}
End:
PerfDbgLog(tagCINetErr, this, "+CINet::IsEmbdFilterOk: Unable to recreate EmbedFilter, possibly out of memory.");
SetINetState(INetState_ERROR);
// Null out and return false:
_pEmbdFilter = NULL;
return false;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::ReportResultAndStop
//
// Synopsis: Post the termination package
//
// Arguments: [hr] --
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::ReportResultAndStop(HRESULT hr, ULONG ulProgress,ULONG ulProgressMax, LPWSTR pwzStr)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::ReportResultAndStop",
"this=%#x, %#x, %#x, %#x, %.80wq",
this, hr, ulProgress, ulProgressMax, pwzStr
));
PerfDbgLog1(tagCINet, this, "+CINet::ReportResultAndStop (hr:%lx)", hr);
HRESULT hrOut = NOERROR;
BOOL fReportResult = FALSE;
BOOL fReportData = FALSE;
{
CLock lck(_mxs); // only one thread should be in here
// set the state to error and report error
// must go in queue since other messages might be ahead
if ((_dwState != INetState_DONE) && (_dwState != INetState_ERROR))
{
_hrINet = hr;
_dwState = (hr != NOERROR) ? INetState_ERROR : INetState_DONE;
if (_dwState == INetState_DONE)
{
if (ulProgress == 0)
{
ulProgress = _cbTotalBytesRead;
ulProgressMax = _cbDataSize;
}
if ( ( (ulProgress != _cbSizeLastReportData ) ||
(!ulProgress && !ulProgressMax) ) &&
( _grfBindF & BINDF_FROMURLMON ) )
{
//
// last notification
// NOTE: we need to report data for empty page
// we might have report this data already,
// so check for the _cbSizeLastReportData
// if they are same, do not report data
// again. (this might give hard time for
// IEFeatuer handler )
//
_bscf |= BSCF_LASTDATANOTIFICATION;
fReportData = TRUE;
}
//
// HACK: for prodegy's ocx
// if we have not send out ReportData(BSCF_LAST...) and
// we are doing BindToStorage but the data has been
// reported, we have to report it again with LAST flag
// tuned on
//
if( !fReportData &&
!(_bscf & BSCF_LASTDATANOTIFICATION ) &&
!(_BndInfo.dwOptions & BINDINFO_OPTIONS_BINDTOOBJECT) )
{
// need to send out last notifiation for whatever
// client depend on it...
_bscf |= BSCF_LASTDATANOTIFICATION;
fReportData = TRUE;
}
}
else if (_dwState == INetState_ERROR)
{
SetINetState(INetState_ERROR);
}
PProtAssert((_pCTrans));
fReportResult = TRUE;
}
}
if (_pCTrans)
{
if (fReportData)
{
_cbSizeLastReportData = ulProgress;
_pEmbdFilter->ReportData(_bscf, ulProgress, ulProgressMax);
}
// teminate might have occured on ReportData
if (fReportResult && _pCTrans)
{
_pEmbdFilter->ReportResult(hr,_dwResult,pwzStr);
}
if( !fReportResult )
{
hrOut = INET_E_RESULT_DISPATCHED;
}
}
PerfDbgLog1(tagCINet, this, "-CINet::ReportResultAndStop (hrOut:%lx)", hrOut);
DEBUG_LEAVE(hrOut);
return hrOut;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::ReportNotification
//
// Synopsis:
//
// Arguments: [NMsg] --
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::ReportNotification(BINDSTATUS NMsg, LPCSTR szStr)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::ReportNotification",
"this=%#x, %#x, %.80q",
this, NMsg, szStr
));
PerfDbgLog1(tagCINet, this, "+CINet::ReportNotification (NMsg:%lx)", NMsg);
HRESULT hr = E_FAIL;
BOOL fReport = FALSE;
LPWSTR pwzStr = 0;
{ // ssync block begin
CLock lck(_mxs); // only one thread should be in here
if ((_dwState != INetState_DONE) && (_dwState != INetState_ERROR))
{
if (szStr)
{
pwzStr = DupA2W((const LPSTR)szStr);
}
if (szStr && !pwzStr)
{
hr = E_OUTOFMEMORY;
}
else
{
fReport = TRUE;
}
}
} // sync block end
if (fReport)
{
if ( _pCTrans && IsEmbdFilterOk() )
{
hr = _pEmbdFilter->ReportProgress((ULONG)NMsg, pwzStr);
}
}
delete pwzStr;
PerfDbgLog(tagCINet, this, "-CINet::ReportNotification");
DEBUG_LEAVE(hr);
return hr;
}
HRESULT CINet::ReportNotificationW(BINDSTATUS NMsg, LPCWSTR wzStr)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::ReportNotificationW",
"this=%#x, %#x, %.80q",
this, NMsg, wzStr
));
PerfDbgLog1(tagCINet, this, "+CINet::ReportNotificationW (NMsg:%lx)", NMsg);
HRESULT hr = E_FAIL;
BOOL fReport = FALSE;
{ // ssync block begin
CLock lck(_mxs); // only one thread should be in here
if ((_dwState != INetState_DONE) && (_dwState != INetState_ERROR))
fReport = TRUE;
} // sync block end
if (fReport)
{
if ( _pCTrans && _pEmbdFilter )
{
hr = _pEmbdFilter->ReportProgress((ULONG)NMsg, wzStr);
}
}
PerfDbgLog(tagCINet, this, "-CINet::ReportNotificationW");
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::SetPending
//
// Synopsis:
//
// Arguments: [hrNew] --
//
// Returns:
//
// History: 3-28-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::SetStatePending(HRESULT hrNew)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::SetStatePending",
"this=%#x, %#x",
this, hrNew
));
CLock lck(_mxs); // only one thread should be in here
HRESULT hr;
PerfDbgLog2(tagCINet, this, "CINet::SetStatePending (hrOld:%lx, hrNew:%lx)", _hrPending, hrNew);
//BUGBUG: turn this assertion on again
PProtAssert(( ( ((_hrPending != E_PENDING) && (hrNew == E_PENDING))
|| ((_hrPending == E_PENDING) && (hrNew != E_PENDING))) ));
hr = _hrPending;
_hrPending = hrNew;
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::GetStatePending
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 4-08-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::GetStatePending()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::GetStatePending",
"this=%#x",
this
));
CLock lck(_mxs); // only one thread should be in here
//PerfDbgLog1(tagCINet, this, "CINet::GetStatePending (hr:%lx)", _hrPending);
DEBUG_LEAVE(_hrPending);
return _hrPending;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::SetByteCountReadyToRead
//
// Synopsis:
//
// Arguments: [cbReadyReadNow] --
//
// Returns:
//
// History: 6-25-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CINet::SetByteCountReadyToRead(LONG cbReadyReadNow)
{
DEBUG_ENTER((DBG_APP,
None,
"CINet::SetByteCountReadyToRead",
"this=%#x, %#x",
this, cbReadyReadNow
));
CLock lck(_mxs); // only one thread should be in here
PerfDbgLog3(tagCINet, this, "CINet::SetByteCountReadyToRead (cbReadReturn:%ld, cbReadyRead:%ld, cbReadyLeft:%ld)",
_cbReadyToRead, cbReadyReadNow, _cbReadyToRead + cbReadyReadNow);
_cbReadyToRead += cbReadyReadNow ;
DEBUG_LEAVE(0);
}
//+---------------------------------------------------------------------------
//
// Method: CINet::GetByteCountReadyToRead
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 6-25-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
ULONG CINet::GetByteCountReadyToRead()
{
DEBUG_ENTER((DBG_APP,
None,
"CINet::GetByteCountReadyToRead",
"this=%#x",
this
));
CLock lck(_mxs); // only one thread should be in here
PerfDbgLog1(tagCINet, this, "CINet::GetByteCountReadyToRead (_cbReadyToRead:%ld)", _cbReadyToRead);
DEBUG_LEAVE(_cbReadyToRead);
return _cbReadyToRead;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::SetINetState
//
// Synopsis:
//
// Arguments: [inState] --
//
// Returns:
//
// History: 2-25-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
INetState CINet::SetINetState(INetState inState)
{
DEBUG_ENTER((DBG_APP,
Dword,
"CINet::SetINetState",
"this=%#x, %#x",
this, inState
));
CLock lck(_mxs); // only one thread should be in here
PerfDbgLog1(tagCINet, this, "+CINet::SetINetState (State:%lx)", inState);
INetState in = _INState;
_INState = inState;
PerfDbgLog1(tagCINet, this, "-CINet::SetINetState (hr:%lx)", in);
DEBUG_LEAVE(in);
return in;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::GetINetState
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 2-25-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
INetState CINet::GetINetState()
{
DEBUG_ENTER((DBG_APP,
Dword,
"CINet::GetINetState",
"this=%#x",
this
));
CLock lck(_mxs); // only one thread should be in here
PerfDbgLog(tagCINet, this, "+CINet::GetINetState");
INetState in = _INState;
PerfDbgLog1(tagCINet, this, "-CINet::GetINetState (hr:%lx)", in);
DEBUG_LEAVE(in);
return in;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::INetAsyncStart
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::INetAsyncStart()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::INetAsyncStart",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::INetAsyncStart");
HRESULT hr = NOERROR;
BOOL fAsyncStart = FALSE;
// guard the object
PrivAddRef();
if (fAsyncStart)
{
// post notification for next step
SetINetState(INetState_START);
TransitState(INetState_START);
}
else
{
hr = INetAsyncOpen();
}
if (_hrError != INET_E_OK)
{
if (hr != S_OK && hr != E_PENDING && hr != INET_E_DONE)
{
PProtAssert(( (hr >= INET_E_ERROR_FIRST && hr <= INET_E_ERROR_LAST)
||(hr == E_OUTOFMEMORY)
||(hr == E_ABORT)
));
ReportResultAndStop(hr);
}
else
{
// he will do inetdone notifications
ReportResultAndStop(NOERROR);
}
}
PrivRelease();
PerfDbgLog1(tagCINet, this, "-CINet::INetAsyncStart (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::OnINetStart
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::OnINetStart()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::OnINetStart",
"this=%#x",
this
));
HRESULT hr;
PerfDbgLog(tagCINet, this, "+CINet::OnINetStart");
// nothing to do - just call
hr = INetAsyncOpen();
PerfDbgLog1(tagCINet, this, "-CINet::OnINetStart (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::INetAsyncOpen
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::INetAsyncOpen()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::INetAsyncOpen",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::INetAsyncOpen");
PProtAssert((GetStatePending() == NOERROR));
DWORD dwFlags = INTERNET_FLAG_ASYNC;
DWORD dwBindF = 0;
HRESULT hr = NOERROR;
if (g_hSession == NULL)
{
// Only 1 thread should be in here, this is to protect
// two global variables g_hSession and g_pszUserAgentString
{
CLock lck(g_mxsSession);
if( g_hSession == NULL )
{
SetINetState(INetState_OPEN_REQUEST);
PerfDbgLog1(tagCINet, this, "___ INetAysncOpen calling InternetOpen %ld", GetTickCount());
SetStatePending(E_PENDING);
g_hSession = InternetOpen(
GetUserAgentString()
, INTERNET_OPEN_TYPE_PRECONFIG
, NULL
, NULL
, dwFlags);
PerfDbgLog1(tagCINet, this, "___ INetAysncOpen done InternetOpen %ld", GetTickCount());
if (g_hSession == NULL)
{
dwLstError = GetLastError();
if (dwLstError == ERROR_IO_PENDING)
{
hr = E_PENDING;
}
else
{
SetStatePending(NOERROR);
hr = _hrError = INET_E_NO_SESSION;
SetBindResult(dwLstError, hr);
}
}
else
{
if (g_pszUserAgentString)
{
// Open was successful, so we don't need the replacement
// User Agent string anymore.
delete g_pszUserAgentString;
g_pszUserAgentString = NULL;
}
SetStatePending(NOERROR);
InternetSetStatusCallbackA(g_hSession, CINetCallback);
hr = INetAsyncConnect();
}
}
else
{
hr = INetAsyncConnect();
}
} // single access block
}
else
{
hr = INetAsyncConnect();
}
PerfDbgLog1(tagCINet, this, "-CINet::INetAsyncOpen (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::OnINetAsyncOpen
//
// Synopsis:
//
// Arguments: [dwResult] --
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::OnINetAsyncOpen(DWORD_PTR dwResult)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::OnINetAsyncOpen",
"this=%#x, %#x",
this, dwResult
));
PerfDbgLog(tagCINet, this, "+CINet::OnINetAsyncOpen");
HRESULT hr = NOERROR;
PProtAssert((GetStatePending() == E_PENDING));
// set state to normal - no pending transaction
SetStatePending(NOERROR);
if (dwResult)
{
// set the handle and the callback
g_hSession = (HINTERNET) dwResult;
InternetSetStatusCallbackA(g_hSession, CINetCallback);
}
// notification for next request
TransitState(INetState_OPEN_REQUEST);
PerfDbgLog1(tagCINet, this, "-CINet::OnINetAsyncOpen (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::INetAsyncConnect
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::INetAsyncConnect()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::INetAsyncConnect",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::INetAsyncConnect");
PProtAssert((GetStatePending() == NOERROR));
HRESULT hr = NOERROR;
BOOL fRestarted;
DWORD dwBindF = 0;
DWORD dwService = INTERNET_SERVICE_HTTP;
// get the open flags
dwBindF = GetBindFlags();
if (dwBindF & BINDF_GETNEWESTVERSION)
{
_dwOpenFlags |= INTERNET_FLAG_RELOAD;
PerfDbgLog1(tagCINet, this, "***CINet::****RELOAD***** %lx", dwBindF);
}
else
{
PerfDbgLog1(tagCINet, this, "---CINet::----NO-RELOAD %lx --", dwBindF);
}
if (dwBindF & BINDF_NOWRITECACHE)
{
_dwOpenFlags |= INTERNET_FLAG_DONT_CACHE ;
}
if (dwBindF & BINDF_NEEDFILE)
{
PerfDbgLog(tagCINet, this, "CINet::INetAsyncConnect: turn on: INTERNET_FLAG_NEED_FILE");
_dwOpenFlags |= INTERNET_FLAG_NEED_FILE;
}
if (dwBindF & (BINDF_NO_UI | BINDF_SILENTOPERATION))
{
_dwOpenFlags |= INTERNET_FLAG_NO_UI;
}
// BUGBUG OFFLINE, RELOAD, RESYNCHRONIZE and HYPERLINK are mutually
// exclusive. But inside wininet there is priority, so
// the priority is OFFLINE, RELOAD, RESYNCHRONIZE, HYPERLINK in that order
if (dwBindF & BINDF_RESYNCHRONIZE)
{
// caller asking to do if-modified-since
_dwOpenFlags |= INTERNET_FLAG_RESYNCHRONIZE;
}
if (dwBindF & BINDF_HYPERLINK)
{
// caller says this is a hyperlink access
_dwOpenFlags |= INTERNET_FLAG_HYPERLINK;
}
if (dwBindF & BINDF_FORMS_SUBMIT)
{
// caller says this is a forms submit.
_dwOpenFlags |= INTERNET_FLAG_FORMS_SUBMIT;
}
if (dwBindF & BINDF_OFFLINEOPERATION )
{
_dwOpenFlags |= INTERNET_FLAG_OFFLINE;
}
// connect flags
if (dwBindF & BINDF_OFFLINEOPERATION )
{
_dwConnectFlags |= INTERNET_FLAG_OFFLINE;
}
if (dwBindF & BINDF_PRAGMA_NO_CACHE )
{
_dwOpenFlags |= INTERNET_FLAG_PRAGMA_NOCACHE;
}
if( dwBindF & BINDF_GETFROMCACHE_IF_NET_FAIL)
{
_dwOpenFlags |= INTERNET_FLAG_CACHE_IF_NET_FAIL;
}
if( dwBindF & BINDF_FWD_BACK )
{
_dwOpenFlags |= INTERNET_FLAG_FWD_BACK;
}
// additional wininet flags are passed with bindinfo
if( _BndInfo.dwOptions == BINDINFO_OPTIONS_WININETFLAG )
{
_dwOpenFlags |= _BndInfo.dwOptionsFlags;
}
SetINetState(INetState_CONNECT_REQUEST);
PrivAddRef(TRUE);
_HandleStateServer = HandleState_Pending;
SetStatePending(E_PENDING);
HINTERNET hServerTmp = InternetConnect(
g_hSession, // hInternetSession
GetServerName(), // lpszServerName
_ipPort, // nServerPort
(_pszUserName[0])?_pszUserName:NULL, // lpszUserName
(_pszPassword[0])?_pszPassword:NULL, // lpszPassword
dwService, // INTERNET_SERVICE_HTTP
_dwConnectFlags, // dwFlags
(DWORD_PTR) this
);
//
// Note: do not remove this state setting here!
// there is a timing window - needs to
// be fixed in wininet/urlmon!!!
SetINetState(INetState_CONNECT_REQUEST);
if ( hServerTmp == 0)
{
dwLstError = GetLastError();
if (dwLstError == ERROR_IO_PENDING)
{
// wait async for the handle
hr = E_PENDING;
}
else
{
PrivRelease(TRUE);
SetStatePending(NOERROR);
hr = _hrError = INET_E_CANNOT_CONNECT;
SetBindResult(dwLstError, hr);
}
}
else
{
_hServer = hServerTmp;
SetStatePending(NOERROR);
// wininet holds on to CINet - Release called on the callback on close handle
_HandleStateServer = HandleState_Initialized;
PerfDbgLog1(tagCINet, this, "=== CINet::INetAsyncConnect (hServer:%lx)", _hServer);
PProtAssert((_hServer));
hr = INetAsyncOpenRequest();
}
PerfDbgLog1(tagCINet, this, "-CINet::INetAsyncConnect (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::OnINetConnect
//
// Synopsis:
//
// Arguments: [dwResult] --
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::OnINetConnect(DWORD_PTR dwResult)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::OnINetConnect",
"this=%#x, %#x",
this, dwResult
));
PerfDbgLog(tagCINet, this, "+CINet::OnINetConnect");
HRESULT hr = NOERROR;
PProtAssert((GetStatePending() == E_PENDING));
// set state to normal - no pending transaction
SetStatePending(NOERROR);
TransAssert((_hServer == 0));
if (dwResult)
{
CLock lck(_mxs); // only one thread should be in here
if (_HandleStateServer == HandleState_Pending)
{
TransAssert((_hServer == 0));
// set the server handle
_HandleStateServer = HandleState_Initialized;
_hServer = (HANDLE)dwResult;
}
// wininet holds on to CINet - Release called on the callback on close handle
PerfDbgLog1(tagCINet, this, "=== CINet::OnINetConnect (hServer:%lx)", _hServer);
}
if (_hServer)
{
TransitState(INetState_CONNECT_REQUEST);
}
else
{
PProtAssert((_HandleStateServer == HandleState_Aborted));
PrivRelease(TRUE);
}
PerfDbgLog1(tagCINet, this, "-CINet::OnINetConnect (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::INetAsyncOpenRequest
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::INetAsyncOpenRequest()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::INetAsyncOpenRequest",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::INetAsyncOpenRequest");
HRESULT hr = E_FAIL;
PerfDbgLog1(tagCINet, this, "-CINet::INetAsyncOpenRequest (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::OnINetOpenRequest
//
// Synopsis:
//
// Arguments: [dwResult] --
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::OnINetOpenRequest(DWORD_PTR dwResult)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::OnINetOpenRequest",
"this=%#x, %#x",
this, dwResult
));
PerfDbgLog1(tagCINet, this, "+CINet::OnINetOpenRequest (dwResult:%lx)", dwResult);
HRESULT hr = NOERROR;
PProtAssert((GetStatePending() == E_PENDING));
// set state to normal - no pending transaction
SetStatePending(NOERROR);
TransAssert((_hRequest == 0));
if (dwResult)
{
CLock lck(_mxs); // only one thread should be in here
if (_HandleStateRequest == HandleState_Pending)
{
// set the request handle
_HandleStateRequest = HandleState_Initialized;
_hRequest = (HANDLE)dwResult;
PProtAssert((_hServer != _hRequest));
}
}
if (_hRequest)
{
if (_fUTF8hack)
{
DWORD dwSendUTF8 = 1;
InternetSetOption(_hRequest, INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY, &dwSendUTF8, sizeof(DWORD));
}
hr = INetAsyncSendRequest();
}
else
{
PProtAssert((_HandleStateRequest == HandleState_Aborted));
PrivRelease(TRUE);
}
PerfDbgLog1(tagCINet, this, "-CINet::OnINetOpenRequest (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::INetAsyncSendRequest
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::INetAsyncSendRequest()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::INetAsyncSendRequest",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::INetAsyncSendRequest");
HRESULT hr = E_FAIL;
PerfDbgLog1(tagCINet, this, "-CINet::INetAsyncSendRequest (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::OnINetSendRequest
//
// Synopsis:
//
// Arguments: [dwResult] --
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::OnINetSendRequest( DWORD dwResult)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::OnINetSendRequest",
"this=%#x, %#x",
this, dwResult
));
PerfDbgLog(tagCINet, this, "+CINet::OnINetSendRequest");
HRESULT hr = NOERROR;
PProtAssert((GetStatePending() == E_PENDING));
// set state to normal - no pending transaction
SetStatePending(NOERROR);
_dwSendRequestResult = dwResult;
_lpvExtraSendRequestResult = NULL;
if( dwResult == ERROR_INTERNET_FORCE_RETRY )
{
PerfDbgLog(tagCINet, this, " --dwResult = FORCE_RETRY! ");
_fSendRequestAgain = TRUE;
}
if (OperationOnAparmentThread(INetState_SEND_REQUEST))
{
// query for content-encoding header, if we find one,
// we will have to force TransitState to do thread switching
// since the compression filter can not be loaded on worker
// thread
char szEncType[SZMIMESIZE_MAX] = "";
DWORD cbLen = sizeof(szEncType);
if( _hRequest &&
HttpQueryInfo(_hRequest, HTTP_QUERY_CONTENT_ENCODING,
szEncType, &cbLen, NULL) )
{
if( cbLen && szEncType[0] )
_fForceSwitch = TRUE;
}
// if sec problem shows up on UI thread, we need to
// force switch
switch(_dwSendRequestResult)
{
case ERROR_INTERNET_SEC_CERT_DATE_INVALID :
case ERROR_INTERNET_SEC_CERT_CN_INVALID :
case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR :
case ERROR_INTERNET_HTTPS_TO_HTTP_ON_REDIR :
case ERROR_INTERNET_HTTPS_HTTP_SUBMIT_REDIR :
case ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION :
case ERROR_INTERNET_INVALID_CA :
case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED :
case ERROR_INTERNET_FORTEZZA_LOGIN_NEEDED :
case ERROR_INTERNET_FORCE_RETRY :
case ERROR_INTERNET_SEC_CERT_ERRORS :
case ERROR_INTERNET_SEC_CERT_REV_FAILED :
case ERROR_INTERNET_SEC_CERT_REVOKED :
_fForceSwitch = TRUE;
}
TransitState(INetState_SEND_REQUEST);
}
else if (!IsUpLoad())
{
hr = INetQueryInfo();
}
else
{
if( _fSendRequestAgain )
{
_fCompleted = FALSE;
_fSendAgain = TRUE;
_fSendRequestAgain = FALSE;
hr = INetAsyncSendRequest();
}
}
PerfDbgLog1(tagCINet, this, "-CINet::OnINetSendRequest (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::OnINetSuspendSendRequest
//
// Synopsis: called on a wininet callback to indicate the suspentition
// of request processing until UI is displayed to the user.
//
// Arguments: [dwResult] -- error code to generate dialog for
// [lpvExtraResult] -- extra void pointer used pass dialog specific data
//
// Returns:
//
// History: 5-24-98 ArthurBi (Arthur Bierer) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::OnINetSuspendSendRequest(DWORD dwResult, LPVOID lpvExtraResult)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::OnINetSuspendSendRequest",
"this=%#x, %#x, %#x",
this, dwResult, lpvExtraResult
));
PerfDbgLog(tagCINet, this, "+CINet::OnINetSuspendSendRequest");
HRESULT hr = NOERROR;
PProtAssert((GetStatePending() == E_PENDING));
// set state to normal - no pending transaction
SetStatePending(NOERROR);
_dwSendRequestResult = dwResult;
_lpvExtraSendRequestResult = lpvExtraResult;
//if (OperationOnAparmentThread(INetState_SEND_REQUEST))
// even though we're not doing auth, we need to do UI
_hrINet = INET_E_AUTHENTICATION_REQUIRED;
TransitState(INetState_DISPLAY_UI, TRUE);
PerfDbgLog1(tagCINet, this, "-CINet::OnINetSuspendSendRequest (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::INetStateChange
//
// Synopsis: called on the apartment thread
//
// Arguments: (none)
//
// Returns:
//
// History: 1-22-1997 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::INetStateChange()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::INetStateChange",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::INetStateChange");
HRESULT hr = NOERROR;
g_cInetState.HandleState();
PerfDbgLog1(tagCINet, this, "-CINet::INetStateChange (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::OnINetStateChange
//
// Synopsis: called on the wininet worker thread whenever the
// wininet state changes
//
// Arguments: [dwResult] --
//
// Returns:
//
// History: 1-22-1997 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::OnINetStateChange( DWORD dwResult)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::OnINetStateChange",
"this=%#x, %#x",
this, dwResult
));
PerfDbgLog(tagCINet, this, "+CINet::OnINetStateChange");
HRESULT hr = NOERROR;
// set the new state and ping the apartment thread
g_cInetState.SetState(dwResult);
TransitState(INetState_INETSTATE_CHANGE);
PerfDbgLog1(tagCINet, this, "-CINet::OnINetStateChange (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::INetQueryInfo
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::INetQueryInfo()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::INetQueryInfo",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::INetQueryInfo");
HRESULT hr = NOERROR;
// Here we check if we need to do redirection, or
// whether authentication is needed etc.
if (!IsUpLoad())
{
hr = QueryInfoOnResponse();
}
if (hr == NOERROR)
{
// read more data from wininet
hr = INetRead();
}
else if (hr == S_FALSE)
{
// S_FALSE means successful redirecting occured
hr = NOERROR;
}
if (_hrError != INET_E_OK)
{
// we need to terminate here
ReportResultAndStop(hr);
}
PerfDbgLog1(tagCINet, this, "-CINet::INetQueryInfo (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::OnINetRead
//
// Synopsis:
//
// Arguments: [dwResult] --
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::OnINetRead(DWORD_PTR dwResult)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::OnINetRead",
"this=%#x, %#x",
this, dwResult
));
PerfDbgLog(tagCINet, this, "+CINet::OnINetRead");
HRESULT hr = NOERROR;
PProtAssert((GetStatePending() == E_PENDING));
// set state to normal - no pending transaction
SetStatePending(NOERROR);
if (OperationOnAparmentThread(INetState_SEND_REQUEST))
{
TransitState(INetState_READ);
}
else
{
hr = INetRead();
}
PerfDbgLog1(tagCINet, this, "-CINet::OnINetRead (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::INetRead
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::INetRead()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::INetRead",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::INetRead");
HRESULT hr = NOERROR;
if (IsUpLoad())
{
hr = INetWrite();
}
else if(GetBindFlags() & BINDF_DIRECT_READ)
{
hr = INetReadDirect();
}
else
{
// this is the no-copy case
// read data to users buffer
hr = INetDataAvailable();
}
if (_hrError != INET_E_OK)
{
// we need to terminate here
ReportResultAndStop((_hrError == INET_E_DONE) ? NOERROR : _hrError);
}
PerfDbgLog1(tagCINet, this, "-CINet::INetRead (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::INetwrite
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::INetWrite()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::INetWrite",
"this=%#x",
this
));
HRESULT hr = E_FAIL;
TransAssert((FALSE && "HAS TO BE OVERWRITTEN"));
DEBUG_LEAVE(hr);
return hr;
}
#define COOKIES_BLOCKED_STRING "CookiesBlocked"
BINDSTATUS BindStatusFromCookieAction(DWORD dwCookieAction)
{
BINDSTATUS nMsg;
switch(dwCookieAction)
{
case COOKIE_STATE_PROMPT:
nMsg = BINDSTATUS_COOKIE_STATE_PROMPT;
break;
case COOKIE_STATE_ACCEPT:
nMsg = BINDSTATUS_COOKIE_STATE_ACCEPT;
break;
case COOKIE_STATE_REJECT:
nMsg = BINDSTATUS_COOKIE_STATE_REJECT;
break;
case COOKIE_STATE_LEASH:
nMsg = BINDSTATUS_COOKIE_STATE_LEASH;
break;
case COOKIE_STATE_DOWNGRADE:
nMsg = BINDSTATUS_COOKIE_STATE_DOWNGRADE;
break;
default:
nMsg = BINDSTATUS_COOKIE_STATE_UNKNOWN;
break;
}
return nMsg;
}
HRESULT CINet::OnCookieNotification(DWORD dwStatus, IN LPVOID pvInfo)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::OnCookieNotification",
"this=%#x, %#x, %#x",
this, dwStatus, pvInfo
));
HRESULT hr = ERROR_SUCCESS;
BINDSTATUS nMsg;
DWORD dwBlock = 0;
switch (dwStatus)
{
case INTERNET_STATUS_P3P_HEADER:
{
TransAssert(pvInfo && "pvInfo should be a pointer to the P3P header");
hr = ReportNotification(BINDSTATUS_P3P_HEADER, (LPSTR)pvInfo);
break;
}
case INTERNET_STATUS_P3P_POLICYREF:
{
TransAssert(pvInfo && "pvInfo should be pointer to policy-ref URL");
if (char *pszPolicyRef = (char*) pvInfo)
hr = ReportNotification(BINDSTATUS_POLICY_HREF, (LPSTR)pszPolicyRef);
break;
}
case INTERNET_STATUS_COOKIE_HISTORY:
{
InternetCookieHistory *pPastActions = (InternetCookieHistory*) pvInfo;
if (!pPastActions)
break;
if (pPastActions->fAccepted)
ReportNotification(BINDSTATUS_COOKIE_STATE_ACCEPT, NULL);
if (pPastActions->fLeashed)
ReportNotification(BINDSTATUS_COOKIE_STATE_LEASH, NULL);
if (pPastActions->fDowngraded)
ReportNotification(BINDSTATUS_COOKIE_STATE_DOWNGRADE, NULL);
if (pPastActions->fRejected)
ReportNotification(BINDSTATUS_COOKIE_STATE_REJECT, NULL);
break;
}
case INTERNET_STATUS_COOKIE_SENT:
{
OutgoingCookieState* pOutgoing = (OutgoingCookieState *)pvInfo;
TransAssert(pOutgoing && "pvInfo should be OutgoingCookieState*");
if (pOutgoing->cSent)
{
hr = ReportNotification(BINDSTATUS_COOKIE_SENT, pOutgoing->pszLocation);
}
if (pOutgoing->cSuppressed)
{
hr = ReportNotification(BINDSTATUS_COOKIE_SUPPRESSED, pOutgoing->pszLocation);
}
break;
}
case INTERNET_STATUS_COOKIE_RECEIVED:
{
IncomingCookieState* pIncoming = (IncomingCookieState *)pvInfo;
TransAssert(pIncoming && "pvInfo should be OutgoingCookieState*");
if (pIncoming->cAccepted)
hr = ReportNotification(BINDSTATUS_COOKIE_STATE_ACCEPT, pIncoming->pszLocation);
if (SUCCEEDED(hr) && pIncoming->cLeashed)
hr = ReportNotification(BINDSTATUS_COOKIE_STATE_LEASH, pIncoming->pszLocation);
if (SUCCEEDED(hr) && pIncoming->cDowngraded)
hr = ReportNotification(BINDSTATUS_COOKIE_STATE_DOWNGRADE, pIncoming->pszLocation);
if (SUCCEEDED(hr) && pIncoming->cBlocked)
hr = ReportNotification(BINDSTATUS_COOKIE_STATE_REJECT, pIncoming->pszLocation);
break;
}
default:
TransAssert(FALSE);
break;
}
DEBUG_LEAVE(hr);
return hr;
}
#define HRESULT_FROM_WININET(pv) HRESULT_FROM_WIN32( (((LPINTERNET_ASYNC_RESULT) (pv) )->dwError) )
//+---------------------------------------------------------------------------
//
// Method: CINet::CINetCallback
//
// Synopsis:
//
// Arguments: [hInternet] --
// [dwContext] --
// [dwStatus] --
// [pvInfo] --
// [dwStatusLen] --
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
VOID CALLBACK CINet::CINetCallback(IN HINTERNET hInternet, IN DWORD_PTR dwContext,
IN DWORD dwStatus, IN LPVOID pvInfo, IN DWORD dwStatusLen)
{
DEBUG_ENTER((DBG_APP,
None,
"CINet::CINetCallback",
"%#x, %#x, %#x, %#x, %#x",
hInternet, dwContext, dwStatus, pvInfo, dwStatusLen
));
// If this is a request, then we know the cookie type
CINet *pCINet = (CINet *) dwContext;
HRESULT hrError = INET_E_OK;
//
// handle callback without a context
if (!dwContext)
{
switch (dwStatus)
{
default:
//PProtAssert((FALSE));
break;
case INTERNET_STATUS_STATE_CHANGE :
{
DWORD dwState = *(DWORD *) pvInfo;
g_cInetState.SetState(dwState);
}
break;
} // end switch
}
else
{
PerfDbgLog2(tagCINet, pCINet, "+CINet::CINetCallback Status:%ld, State:%ld",
dwStatus, pCINet->_INState);
DWORD_PTR dwAsyncResult;
// from here the original thread needs to be told of various things
// such as errors, operation done etc.
PProtAssert((pCINet));
// guard this call - request might be aborted
//pCINet->AddRef();
DWORD dwFault;
#ifdef INET_CALLBACK_EXCEPTION
_try
#endif // INET_CALLBACK_EXCEPTION
{
switch (dwStatus)
{
// the net connection state changed
case INTERNET_STATUS_STATE_CHANGE :
{
DWORD dwState = *(DWORD *) pvInfo;
pCINet->OnINetStateChange(dwState);
}
break;
// callback to put up UI
case INTERNET_STATUS_USER_INPUT_REQUIRED:
{
// guard this call - request might be aborted
pCINet->PrivAddRef();
PProtAssert(pCINet->_INState == INetState_SEND_REQUEST);
//PProtAssert(!((LPINTERNET_ASYNC_RESULT)pvInfo)->dwResult);
LPVOID lpvSendRequestResultData = (LPVOID) ((LPINTERNET_ASYNC_RESULT)pvInfo)->dwResult;
DWORD dwSendRequestResult = ((LPINTERNET_ASYNC_RESULT) (pvInfo) )->dwError;
// handle the error here in particular pass on info for zone crossing
pCINet->OnINetSuspendSendRequest(dwSendRequestResult, lpvSendRequestResultData);
// unguard - release
pCINet->PrivRelease();
}
break;
// request completed
case INTERNET_STATUS_REQUEST_COMPLETE:
{
// guard this call - request might be aborted
pCINet->PrivAddRef();
if (pCINet->_INState != INetState_ERROR)
{
PProtAssert((pCINet->GetStatePending() == E_PENDING));
}
switch (pCINet->_INState)
{
case INetState_OPEN_REQUEST:
// the internet session handle is supposed to be returned
dwAsyncResult = ((LPINTERNET_ASYNC_RESULT)pvInfo)->dwResult;
if (dwAsyncResult)
{
// got the internet session handle back
pCINet->OnINetAsyncOpen(dwAsyncResult);
}
else
{
hrError = pCINet->SetBindResult(((LPINTERNET_ASYNC_RESULT) (pvInfo))->dwError, INET_E_NO_SESSION);
}
break;
case INetState_CONNECT_REQUEST:
// the server handle is supposed to be returned
dwAsyncResult = ((LPINTERNET_ASYNC_RESULT)pvInfo)->dwResult;
if (dwAsyncResult)
{
pCINet->OnINetConnect(dwAsyncResult);
}
else
{
hrError = pCINet->SetBindResult(((LPINTERNET_ASYNC_RESULT) (pvInfo))->dwError,INET_E_CANNOT_CONNECT);
}
break;
case INetState_PROTOPEN_REQUEST:
// the request handle is suppost to be returned
dwAsyncResult = ((LPINTERNET_ASYNC_RESULT)pvInfo)->dwResult;
if (dwAsyncResult)
{
pCINet->OnINetOpenRequest(dwAsyncResult);
}
else
{
hrError = pCINet->SetBindResult(((LPINTERNET_ASYNC_RESULT) (pvInfo))->dwError,INET_E_OBJECT_NOT_FOUND);
}
break;
case INetState_SEND_REQUEST:
{
// SendRequest returns a BOOL
dwAsyncResult = ((LPINTERNET_ASYNC_RESULT)pvInfo)->dwResult;
if (dwAsyncResult)
{
// pass on 0 and look up the status code with HttpQueryInfo
pCINet->OnINetSendRequest(0);
}
else
{
DWORD dwSendRequestResult = ((LPINTERNET_ASYNC_RESULT) (pvInfo) )->dwError;
// handle the error here in particular pass on info for zone crossing
if (dwSendRequestResult)
{
// handle the sendrequest result
// zone crossing
switch (dwSendRequestResult)
{
case ERROR_INTERNET_SEC_CERT_DATE_INVALID :
case ERROR_INTERNET_SEC_CERT_CN_INVALID :
case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR :
case ERROR_INTERNET_HTTPS_TO_HTTP_ON_REDIR :
case ERROR_INTERNET_HTTPS_HTTP_SUBMIT_REDIR :
case ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION :
case ERROR_INTERNET_INVALID_CA :
case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED :
case ERROR_INTERNET_FORTEZZA_LOGIN_NEEDED :
case ERROR_INTERNET_FORCE_RETRY :
case ERROR_INTERNET_SEC_CERT_ERRORS :
case ERROR_INTERNET_SEC_CERT_REV_FAILED :
case ERROR_INTERNET_SEC_CERT_REVOKED :
case ERROR_INTERNET_LOGIN_FAILURE_DISPLAY_ENTITY_BODY:
pCINet->OnINetSendRequest(dwSendRequestResult);
break;
default:
hrError = pCINet->SetBindResult(((LPINTERNET_ASYNC_RESULT) (pvInfo))->dwError);
break;
}
}
else
{
hrError = pCINet->SetBindResult(((LPINTERNET_ASYNC_RESULT) (pvInfo))->dwError);
}
}
}
break;
case INetState_READ:
// InternetRead returns TRUE of FALSE
dwAsyncResult = ((LPINTERNET_ASYNC_RESULT)pvInfo)->dwResult;
if (dwAsyncResult)
{
pCINet->OnINetRead(dwAsyncResult);
}
else
{
hrError = pCINet->SetBindResult(((LPINTERNET_ASYNC_RESULT) (pvInfo))->dwError);
}
break;
case INetState_DATA_AVAILABLE:
{
DWORD_PTR dwResult = ((LPINTERNET_ASYNC_RESULT)(pvInfo))->dwResult;
if (dwResult)
{
DWORD dwBytes = ((LPINTERNET_ASYNC_RESULT) (pvInfo) )->dwError;
pCINet->OnINetDataAvailable(dwBytes);
}
else
{
hrError = pCINet->SetBindResult(((LPINTERNET_ASYNC_RESULT) (pvInfo))->dwError);
}
}
break;
case INetState_READ_DIRECT:
{
pCINet->OnINetReadDirect(0);
}
break;
case INetState_DATA_AVAILABLE_DIRECT:
{
PProtAssert((FALSE));
}
break;
default:
break;
}
// unguard - release
pCINet->PrivRelease();
}
break;
case INTERNET_STATUS_RESOLVING_NAME :
{
// get server name or proxy as string
//pCINet->ReportNotification(Notify_FindingServer, (LPSTR) pvInfo);
pCINet->ReportNotification(BINDSTATUS_FINDINGRESOURCE, (LPSTR) pvInfo);
}
break;
case INTERNET_STATUS_DETECTING_PROXY :
{
// indicate that auto-proxy detection is in progress
pCINet->ReportNotification(BINDSTATUS_PROXYDETECTING, (LPSTR) NULL);
}
break;
case INTERNET_STATUS_CONNECTING_TO_SERVER :
{
// get ip address as string
//pCINet->ReportNotification(Notify_Connecting, (LPSTR) pvInfo);
pCINet->ReportNotification(BINDSTATUS_CONNECTING, (LPSTR) pvInfo);
}
break;
case INTERNET_STATUS_SENDING_REQUEST :
{
// no data passed back
//pCINet->ReportNotification(Notify_SendingRequest);
pCINet->ReportNotification(BINDSTATUS_SENDINGREQUEST);
}
break;
case INTERNET_STATUS_REDIRECT :
{
PerfDbgLog1(tagCINet, pCINet, "+CINet::CINetCallback Redirected by WinINet (szRedirectUrl:%s)", (LPSTR) pvInfo);
// pvinfo contains the new url
pCINet->OnRedirect((LPSTR) pvInfo);
}
break;
case INTERNET_STATUS_HANDLE_CLOSING :
{
if ((*(LPHINTERNET)pvInfo) == pCINet->_hServer)
{
hrError = INET_E_OK;
PerfDbgLog1(tagCINet, pCINet, "=== CINet::CINetCallback (Close Service Handle:%lx)", (*(LPHINTERNET) pvInfo));
PProtAssert((pCINet->_HandleStateServer == HandleState_Closed));
// this is the connect handle - call Release
pCINet->_hServer = 0;
pCINet->PrivRelease(TRUE);
}
else if ((*(LPHINTERNET)pvInfo) == pCINet->_hRequest)
{
hrError = INET_E_OK;
PerfDbgLog1(tagCINet, pCINet, "=== CINet::CINetCallback (Close Request Handle:%lx)", (*(LPHINTERNET) pvInfo));
PProtAssert(( pCINet->_HandleStateRequest == HandleState_Closed));
// this is the connect handle - call Release
pCINet->_hRequest = 0;
pCINet->ReleaseTransAndBindInfo();
pCINet->PrivRelease(TRUE);
}
}
break;
case INTERNET_STATUS_COOKIE_SENT:
case INTERNET_STATUS_COOKIE_RECEIVED:
case INTERNET_STATUS_COOKIE_HISTORY:
case INTERNET_STATUS_PRIVACY_IMPACTED:
case INTERNET_STATUS_P3P_HEADER:
case INTERNET_STATUS_P3P_POLICYREF:
{
pCINet->OnCookieNotification(dwStatus, pvInfo);
}
break;
case INTERNET_STATUS_HANDLE_CREATED :
case INTERNET_STATUS_NAME_RESOLVED :
case INTERNET_STATUS_CONNECTED_TO_SERVER :
case INTERNET_STATUS_REQUEST_SENT :
case INTERNET_STATUS_RECEIVING_RESPONSE :
case INTERNET_STATUS_RESPONSE_RECEIVED :
case INTERNET_STATUS_CTL_RESPONSE_RECEIVED :
case INTERNET_STATUS_PREFETCH :
case INTERNET_STATUS_CLOSING_CONNECTION :
case INTERNET_STATUS_CONNECTION_CLOSED :
default:
{
//handle other status here
}
} // end switch
if (hrError != INET_E_OK)
{
PerfDbgLog2(tagCINet, pCINet, "=== CINet::CINetCallback _hrINet:%lx, ERROR: %lx",
pCINet->_hrINet, hrError);
// we need to terminate here
pCINet->ReportResultAndStop(pCINet->_hrINet);
}
// unguard - release
//pCINet->Release();
}
#ifdef INET_CALLBACK_EXCEPTION
_except(UrlMonInvokeExceptionFilter(GetExceptionCode(), GetExceptionInformation()))
{
dwFault = GetExceptionCode();
#if DBG == 1
//
// UrlMon catches exceptions when the client generates them. This is so we can
// cleanup properly, and allow urlmon to continue.
//
if ( dwFault == STATUS_ACCESS_VIOLATION
|| dwFault == 0xC0000194 /*STATUS_POSSIBLE_DEADLOCK*/
|| dwFault == 0xC00000AA /*STATUS_INSTRUCTION_MISALIGNMENT*/
|| dwFault == 0x80000002 /*STATUS_DATATYPE_MISALIGNMENT*/ )
{
WCHAR iidName[256];
iidName[0] = 0;
char achProgname[256];
achProgname[0] = 0;
GetModuleFileNameA(NULL,achProgname,sizeof(achProgname));
DbgLog2(tagCINetErr, NULL,
"NotificationMgr has caught a fault 0x%08x on behalf of application %s",
dwFault, achProgname);
//TransAssert((!"The application has faulted processing. Check the kernel debugger for useful output.URLMon can continue but you probably want to stop and debug the application."));
}
#endif
}
#ifdef unix
__endexcept
#endif /* unix */
#endif INET_CALLBACK_EXCEPTION
}
PerfDbgLog1(tagCINet, pCINet, "-CINet::CINetCallback (hrError:%lx)", hrError);
DEBUG_LEAVE(0);
}
//+---------------------------------------------------------------------------
//
// Method: CINet::TransitState
//
// Synopsis:
//
// Arguments: [dwState] --
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CINet::TransitState(DWORD dwState, BOOL fAsync)
{
DEBUG_ENTER((DBG_APP,
None,
"CINet::TransitState",
"this=%#x, %#x, %B",
this, dwState, fAsync
));
PerfDbgLog(tagCINet, this, "+CINet::TransitState");
if ((_dwState != INetState_DONE) && (_dwState != INetState_ERROR))
{
BINDSTATUS NMsg = (BINDSTATUS) ((fAsync) ? BINDSTATUS_INTERNALASYNC : BINDSTATUS_INTERNAL);
DWORD dwFlags = 0;
if ( NMsg == BINDSTATUS_INTERNALASYNC
|| NMsg == BINDSTATUS_ERROR
|| NMsg == BINDSTATUS_INTERNALASYNC)
{
dwFlags |= PI_FORCE_ASYNC;
}
if ( (dwState == INetState_AUTHENTICATE)
|| (dwState == INetState_DISPLAY_UI)
|| (_fForceSwitch))
{
dwFlags |= PD_FORCE_SWITCH;
}
if( _grfBindF & BINDF_FROMURLMON )
{
CStateInfo CSI = CStateInfo(NMsg, dwFlags, (LPVOID)(ULongToPtr((ULONG)dwState)));
if( _pCTrans )
{
_pCTrans->Switch(&CSI);
}
}
else
{
CStateInfo* pCSI = new CStateInfo(NMsg, dwFlags, (LPVOID)(ULongToPtr((ULONG)dwState)));
if( !pCSI )
{
ReportResultAndStop(E_OUTOFMEMORY);
}
else
{
if( dwFlags & PD_FORCE_SWITCH || _fForceSwitch )
{
if( _pCTrans )
{
_pCTrans->Switch(pCSI);
}
}
else
{
Continue(pCSI);
}
}
}
}
PerfDbgLog(tagCINet, this, "-CINet::TransitState");
DEBUG_LEAVE(0);
}
//+---------------------------------------------------------------------------
//
// Method: CINet::OnINetInternal
//
// Synopsis:
//
// Arguments: [dwState] --
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CINet::OnINetInternal(DWORD_PTR dwState)
{
DEBUG_ENTER((DBG_APP,
None,
"CINet::OnINetInternal",
"this=%#x, %#x",
this, dwState
));
PerfDbgLog(tagCINet, this, "+CINet::OnINetInternal");
HRESULT hr = NOERROR;
if ((_dwState != INetState_DONE) && (_dwState != INetState_ERROR))
{
switch (dwState)
{
case INetState_START :
// is requested
hr = INetAsyncOpen();
break;
case INetState_OPEN_REQUEST :
hr = INetAsyncConnect();
break;
case INetState_CONNECT_REQUEST :
hr = INetAsyncOpenRequest();
break;
case INetState_PROTOPEN_REQUEST:
hr = INetAsyncSendRequest();
break;
case INetState_SEND_REQUEST :
if( _fSendRequestAgain )
{
_fCompleted = FALSE;
_fSendAgain = TRUE;
_fSendRequestAgain = FALSE;
hr = INetAsyncSendRequest();
}
else
{
hr = INetQueryInfo();
}
break;
case INetState_DISPLAY_UI :
hr = INetDisplayUI();
break;
case INetState_AUTHENTICATE :
hr = INetAuthenticate();
break;
case INetState_READ :
hr = INetRead();
break;
case INetState_READ_DIRECT :
hr = INetReadDirect();
break;
case INetState_DATA_AVAILABLE :
hr = INetReportAvailableData();
break;
case INetState_INETSTATE_CHANGE:
hr = INetStateChange();
break;
case INetState_DONE :
break;
default:
break;
}
}
/*
else
{
PProtAssert((FALSE && "Unknown state"));
}
*/
if ((hr != NOERROR) && (hr != E_PENDING))
{
ReportResultAndStop(hr);
}
PerfDbgLog(tagCINet, this, "-CINet::OnINetInternal");
DEBUG_LEAVE(0);
}
//+---------------------------------------------------------------------------
//
// Method: CINet::TerminateRequest
//
// Synopsis: Close the server and request handle - wininet will make a
// callback on each handle closed
//
// Arguments: (none)
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CINet::TerminateRequest()
{
DEBUG_ENTER((DBG_APP,
None,
"CINet::TerminateRequest",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::TerminateRequest");
CLock lck(_mxs); // only one thread should be in here
if ((_HandleStateRequest == HandleState_Initialized))
{
PProtAssert((_hRequest));
_HandleStateRequest = HandleState_Closed;
InternetCloseHandle(_hRequest);
//_hRequest = 0;
}
else if ((_HandleStateRequest == HandleState_Pending))
{
_HandleStateRequest = HandleState_Aborted;
}
if (_HandleStateServer == HandleState_Initialized)
{
PerfDbgLog1(tagCINet, this, "=== CINet::TerminateRequest InternetCloseHandle (hServer:%lx)", _hServer);
_HandleStateServer = HandleState_Closed;
if (_hServer)
{
// the handle can be NULL
// in case we got aborted during the
// pending open request
InternetCloseHandle(_hServer);
}
}
else if ((_HandleStateServer == HandleState_Pending))
{
_HandleStateServer = HandleState_Aborted;
}
PerfDbgLog(tagCINet, this, "-CINet::TerminateRequest");
DEBUG_LEAVE(0);
}
//+---------------------------------------------------------------------------
//
// Method: CINet::FindTagInHeader
//
// Synopsis:
//
// Arguments: [lpszBuffer] --
// [lpszTag] --
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
LPSTR CINet::FindTagInHeader(LPCSTR lpszBuffer, LPCSTR lpszTag)
{
DEBUG_ENTER((DBG_APP,
String,
"CINet::FindTagInHeader",
"this=%#x, %.80q, %.80q",
this, lpszBuffer, lpszTag
));
PerfDbgLog(tagCINet, this, "+CINet::FindTagInHeader");
LPCSTR p;
int i, cbTagLen;
cbTagLen = strlen(lpszTag);
for (p = lpszBuffer; i = strlen(p); p += (i + 1))
{
if (!StrCmpNI(p, lpszTag, cbTagLen))
{
DEBUG_LEAVE((LPSTR)p);
return (LPSTR)p;
}
}
PerfDbgLog(tagCINet, this, "-CINet::FindTagInHeader");
DEBUG_LEAVE(NULL);
return NULL;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::INetDataAvailable
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 2-23-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::INetDataAvailable()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::INetDataAvailable",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::INetDataAvailable");
HRESULT hr = NOERROR;
BOOL fRet = FALSE;
PProtAssert((GetStatePending() == NOERROR));
SetINetState(INetState_DATA_AVAILABLE);
if (!_fFilenameReported)
{
char szFilename[MAX_PATH];
HRESULT hr1 = GetUrlCacheFilename(szFilename, MAX_PATH);
if (hr1 == NOERROR && szFilename[0] != '\0' )
{
ReportNotification(BINDSTATUS_CACHEFILENAMEAVAILABLE, (LPSTR) szFilename);
_fFilenameReported = TRUE;
}
}
// check if all data were read of the current buffer
SetStatePending(E_PENDING);
fRet = InternetQueryDataAvailable(_hRequest, &_cbReadReturn, 0, 0);
if (fRet == FALSE)
{
dwLstError = GetLastError();
if (dwLstError == ERROR_IO_PENDING)
{
hr = E_PENDING;
}
else
{
SetStatePending(NOERROR);
hr = _hrError = INET_E_DATA_NOT_AVAILABLE;
}
}
else
{
SetByteCountReadyToRead(_cbReadReturn);
SetStatePending(NOERROR);
if (_cbReadReturn == 0)
{
// done
_fDone = 1;
}
hr = INetReportAvailableData();
}
PerfDbgLog1(tagCINet, this, "-CINet::INetDataAvailable (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::OnINetDataAvailable
//
// Synopsis:
//
// Arguments: [dwResult] --
//
// Returns:
//
// History: 2-23-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::OnINetDataAvailable( DWORD dwResult)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::OnINetDataAvailable",
"this=%#x, %#x",
this, dwResult
));
PerfDbgLog1(tagCINet, this, "+CINet::OnINetDataAvailable (dwAvailable:%ld)", dwResult);
HRESULT hr = NOERROR;
PProtAssert((GetStatePending() == E_PENDING));
SetByteCountReadyToRead(dwResult);
if (dwResult == 0)
{
// done
_fDone = 1;
}
// set state to normal - no pending transaction
SetStatePending(NOERROR);
// notification for next request
TransitState(INetState_DATA_AVAILABLE);
PerfDbgLog1(tagCINet, this, "-CINet::OnINetDataAvailable (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::INetReportAvailableData
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 2-23-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::INetReportAvailableData()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::INetReportAvailableData",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::INetReportAvailableData");
HRESULT hr = NOERROR;
DWORD dwError;
ULONG cbBytesAvailable = 0;
//BUGBUG: we hit this assertion sometimes.
//PProtAssert((GetStatePending() == NOERROR));
_hrError = INET_E_OK;
if ((GetStatePending() == E_PENDING))
{
// nothing to do - data for this notfication
// already received
}
else if ((cbBytesAvailable = GetByteCountReadyToRead()) != 0)
{
if ( _fDone
|| ( _cbTotalBytesRead
&& _cbDataSize
&& (_cbTotalBytesRead == _cbDataSize)))
{
_hrError = INET_E_DONE;
}
else
{
if(_cbDataSize && (_cbDataSize < (cbBytesAvailable + _cbTotalBytesRead)))
{
_cbDataSize = cbBytesAvailable + _cbTotalBytesRead;
}
if (_bscf & BSCF_DATAFULLYAVAILABLE)
{
_bscf |= BSCF_LASTDATANOTIFICATION;
_bscf &= ~BSCF_FIRSTDATANOTIFICATION;
}
// BUG-WORK pCTrans migh be gone by now
_cbSizeLastReportData = cbBytesAvailable + _cbTotalBytesRead;
hr = _pEmbdFilter->ReportData(_bscf, cbBytesAvailable + _cbTotalBytesRead, _cbDataSize);
if (_bscf & BSCF_FIRSTDATANOTIFICATION)
{
_bscf &= ~BSCF_FIRSTDATANOTIFICATION;
_bscf |= BSCF_INTERMEDIATEDATANOTIFICATION;
}
}
}
else if ( _fDone
|| ( _cbTotalBytesRead
&& _cbDataSize
&& (_cbTotalBytesRead == _cbDataSize)))
{
if (_cbDataSize == 0)
{
_cbDataSize = _cbTotalBytesRead;
}
PerfDbgLog2(tagCINet, this, "=== CINet::INetReportAvailableData DONE! (cbTotalBytesRead:%ld, cbDataSize:%ld)", _cbTotalBytesRead, _cbDataSize);
// now we should have all data
PProtAssert(( ( ( _cbDataSize == 0)
|| ((_cbDataSize != 0) && (_cbTotalBytesRead == _cbDataSize)))
&& "Did not get all data!!"));
_hrError = INET_E_DONE;
}
if (_hrError != INET_E_OK)
{
_bscf |= BSCF_LASTDATANOTIFICATION;
if (_pCTrans )
{
_cbSizeLastReportData = _cbTotalBytesRead;
hr = _pEmbdFilter->ReportData(_bscf, _cbTotalBytesRead, _cbDataSize);
}
hr = NOERROR;
}
PerfDbgLog2(tagCINet, this, "-CINet::INetReportAvailableData (_hrError:%lx, hr:%lx)", _hrError, hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::ReadDataHere
//
// Synopsis:
//
// Arguments: [pBuffer] --
// [cbBytes] --
// [pcbBytes] --
//
// Returns:
//
// History: 2-13-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::ReadDataHere(BYTE *pBuffer, DWORD cbBytes, DWORD *pcbBytes)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::ReadDataHere",
"this=%#x, pBuffer, cbBytes, pcbBytes",
this, pBuffer, cbBytes, pcbBytes
));
PerfDbgLog(tagCINet, this, "+CINet::ReadDataHere");
HRESULT hr = NOERROR;
DWORD dwError;
*pcbBytes = 0;
ULONG cbReadReturn = 0;
ULONG dwReturned = 0;
ULONG dwReturnedTotal = 0;
ULONG dwBytesLeft = cbBytes;
//BUGBUG: turn this assertion on again
//PProtAssert((GetStatePending() == NOERROR));
if (_hrError == INET_E_DONE)
{
// means end of file
hr = S_FALSE;
}
else if (GetStatePending() != NOERROR)
{
hr = E_PENDING;
}
else
{
_hrError = INET_E_OK;
do
{
if ((cbReadReturn = GetByteCountReadyToRead()) == 0)
{
BOOL fRet;
PerfDbgLog(tagCINet, this, "CINet::ReadDataHere -> InternetQueryDataAvailable");
PProtAssert((GetStatePending() == NOERROR));
SetStatePending(E_PENDING);
fRet = InternetQueryDataAvailable(_hRequest, &_cbReadReturn,0 ,0);
if (fRet == FALSE)
{
dwLstError = GetLastError();
if (dwLstError == ERROR_IO_PENDING)
{
hr = E_PENDING;
}
else
{
SetStatePending(NOERROR);
hr = _hrError = INET_E_DATA_NOT_AVAILABLE;
}
}
else
{
SetByteCountReadyToRead(_cbReadReturn);
SetStatePending(NOERROR);
if (_cbReadReturn == 0)
{
// download completed - no more data available
hr = _hrError = INET_E_DONE;
}
}
PerfDbgLog2(tagCINet, this, "CINet::ReadDataHere == InternetQueryDataAvailable (fRet:%d, _cbReadReturn:%ld)", fRet, _cbReadReturn);
}
// in case of noerror read the bits
if ((hr == NOERROR) && (_hrError == INET_E_OK))
{
cbReadReturn = GetByteCountReadyToRead();
PProtAssert((GetStatePending() == NOERROR));
// get the read buffer from the trans data object
PProtAssert(((pBuffer != NULL) && (cbBytes > 0)));
PProtAssert((cbReadReturn > 0));
dwBytesLeft = cbBytes - dwReturnedTotal;
if (dwBytesLeft > cbReadReturn)
{
dwBytesLeft = cbReadReturn;
}
PProtAssert(( dwBytesLeft <= (cbBytes - dwReturnedTotal) ));
dwReturned = 0;
PerfDbgLog1(tagCINet, this, "CINet::ReadDataHere -> InternetReadFile (dwBytesLeft:%ld)", dwBytesLeft);
if (!InternetReadFile(_hRequest, pBuffer + dwReturnedTotal, dwBytesLeft, &dwReturned))
{
dwError = GetLastError();
if (dwError != ERROR_IO_PENDING)
{
hr = _hrError = INET_E_DOWNLOAD_FAILURE;
DbgLog3(tagCINetErr, this, "CINet::ReadDataHere failed: (dwError:%lx, hr:%lx, hrError:%lx)",
dwError, hr, _hrError);
}
else
{
// Note: BIG ERROR - we need to shut down now
// wininet is using the client buffer and the client is not
// aware that the buffer is used during the pending time
//
DbgLog(tagCINetErr, this, "CINet::ReadDataHere - InternetReadFile returned E_PENDING!!!");
PProtAssert((FALSE && "CINet::ReadDataHere - InternetReadFile returned E_PENDING!!!"));
hr = _hrError = INET_E_DOWNLOAD_FAILURE;
}
PerfDbgLog1(tagCINet, this, "CINet::ReadDataHere == InternetReadFile (dwError:%lx)", dwError);
}
else
{
PerfDbgLog3(tagCINet, this, "CINet::ReadDataHere == InternetReadFile ==> (cbBytes:%ld, dwReturned:%ld,_cbReadReturn:%ld)",
cbBytes, dwReturned,_cbReadReturn);
PProtAssert(( (cbBytes + dwReturnedTotal) >= dwReturned ));
if (dwReturned == 0)
{
hr = _hrError = INET_E_DONE;
}
else
{
hr = NOERROR;
}
dwReturnedTotal += dwReturned;
cbReadReturn -= dwReturned;
SetByteCountReadyToRead(-(LONG)dwReturned);
_cbTotalBytesRead += dwReturned;
}
} // read case - bits available
PerfDbgLog4(tagCINet, this, "CINet::ReadDataHere ooo InternetReadFile ==>(cbBytes:%ld, dwReturned:%ld,cbReadReturn:%ld,dwReturnedTotal:%ld)",
cbBytes, dwReturned,cbReadReturn,dwReturnedTotal);
} while ((hr == NOERROR) && (dwReturnedTotal < cbBytes));
PProtAssert((dwReturnedTotal <= cbBytes));
*pcbBytes = dwReturnedTotal;
if (hr == INET_E_DONE)
{
hr = (dwReturnedTotal) ? S_OK : S_FALSE;
}
}
// Note: stop the download in case of DONE or ERROR!
if (_hrError != INET_E_OK)
{
ReportResultAndStop((hr == S_FALSE) ? NOERROR : hr, _cbTotalBytesRead, _cbDataSize);
}
PerfDbgLog4(tagCINet, this, "-CINet::ReadDataHere (_hrError:%lx, [hr:%lx,cbBytesAsked:%ld,cbBytesReturned:%ld])",
_hrError, hr, cbBytes, *pcbBytes);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::OperationOnAparmentThread
//
// Synopsis:
//
// Arguments: [dwState] --
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL CINet::OperationOnAparmentThread(DWORD dwState)
{
DEBUG_ENTER((DBG_APP,
Bool,
"CINet::OperationOnAparmentThread",
"this=%#x, %#x",
this, dwState
));
PerfDbgLog(tagCINet, this, "+CINet::OperationOnAparmentThread");
BOOL fRet = FALSE;
switch (dwState)
{
case INetState_OPEN_REQUEST:
break;
case INetState_CONNECT_REQUEST:
break;
case INetState_PROTOPEN_REQUEST:
break;
case INetState_SEND_REQUEST:
break;
case INetState_READ:
case INetState_READ_DIRECT:
fRet = TRUE;
break;
default:
fRet = TRUE;
break;
}
//return fRet;
PerfDbgLog(tagCINet, this, "-CINet::OperationOnAparmentThread");
DEBUG_LEAVE(TRUE);
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::OperationOnAparmentThread
//
// Synopsis:
//
// Returns:
//
// History: 10-27-98 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL CINet::UTF8Enabled()
{
DEBUG_ENTER((DBG_APP,
Bool,
"CINet::UTF8Enabled",
"this=%#x",
this
));
BOOL bRet = FALSE;
// do not enable utf8 on file or ftp protocol
if( _dwIsA == DLD_PROTOCOL_FILE ||
_dwIsA == DLD_PROTOCOL_FTP )
{
goto exit;
}
// default to per-machine utf-8 setting
bRet = g_bGlobalUTF8Enabled;
// per-binding flag
if( _BndInfo.dwOptions & BINDINFO_OPTIONS_ENABLE_UTF8)
{
bRet = TRUE;
}
if( _BndInfo.dwOptions & BINDINFO_OPTIONS_DISABLE_UTF8)
{
bRet = FALSE;
}
if( _BndInfo.dwOptions & BINDINFO_OPTIONS_USE_IE_ENCODING)
{
DWORD dwIE;
DWORD dwOutLen = sizeof(DWORD);
HRESULT hr = UrlMkGetSessionOption(
URLMON_OPTION_URL_ENCODING,
&dwIE,
sizeof(DWORD),
&dwOutLen,
NULL );
if( hr == NOERROR )
{
if( dwIE == URL_ENCODING_ENABLE_UTF8 )
{
bRet = TRUE;
}
else if( dwIE == URL_ENCODING_DISABLE_UTF8 )
{
bRet = FALSE;
}
}
}
exit:
DEBUG_LEAVE(bRet);
return bRet;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::QueryInfoOnResponse
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::QueryInfoOnResponse()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::QueryInfoOnResponse",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::QueryInfoOnResponse");
HRESULT hr = NOERROR;
DWORD dwFlags;
DWORD cbLen = sizeof(dwFlags);
// See if it is from the cache
if (InternetQueryOption(_hRequest, INTERNET_OPTION_REQUEST_FLAGS, &dwFlags, &cbLen))
{
if (dwFlags & INTERNET_REQFLAG_FROM_CACHE)
{
_dwCacheFlags |= INTERNET_REQFLAG_FROM_CACHE;
// set flag that data are from cache
_bscf |= BSCF_DATAFULLYAVAILABLE;
}
}
hr = QueryStatusOnResponse();
if (hr == NOERROR)
{
hr = QueryHeaderOnResponse();
}
if (_hrError != INET_E_OK)
{
SetINetState(INetState_DONE);
}
PerfDbgLog1(tagCINet, this, "-CINet::QueryInfoOnResponse (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::QueryStatusOnResponse
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::QueryStatusOnResponse()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::QueryStatusOnResponse",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::QueryStatusOnResponse");
PProtAssert((FALSE));
PerfDbgLog1(tagCINet, this, "-CINet::QueryStatusOnResponse hr:%lx", E_FAIL);
DEBUG_LEAVE(E_FAIL);
return E_FAIL;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::QueryStatusOnResponseDefault
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::QueryStatusOnResponseDefault(DWORD dwStat)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::QueryStatusOnResponseDefault",
"this=%#x, %#x",
this, dwStat
));
PerfDbgLog(tagCINet, this, "+CINet::QueryStatusOnResponseDefault");
PProtAssert((FALSE));
PerfDbgLog1(tagCINet, this, "-CINet::QueryStatusOnResponseDefault hr:%lx", E_FAIL);
DEBUG_LEAVE(E_FAIL);
return E_FAIL;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::QueryHeaderOnResponse
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::QueryHeaderOnResponse()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::QueryHeaderOnResponse",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::QueryHeaderOnResponse");
PProtAssert((FALSE));
PerfDbgLog1(tagCINet, this, "-CINet::QueryHeaderOnResponse hr:%lx", E_FAIL);
DEBUG_LEAVE(E_FAIL);
return E_FAIL;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::RedirectRequest
//
// Synopsis:
//
// Arguments: [lpszBuffer] --
// [pdwBuffSize] --
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::RedirectRequest(LPSTR lpszBuffer, DWORD *pdwBuffSize, DWORD dwStatus)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::RedirectRequest",
"this=%#x, %#x, %#x, %d",
this, lpszBuffer, pdwBuffSize, dwStatus
));
PerfDbgLog(tagCINet, this, "+CINet::RedirectRequest");
PProtAssert((FALSE));
PerfDbgLog1(tagCINet, this, "-CINet::RedirectRequest(fRet:%ld)", FALSE);
DEBUG_LEAVE(E_FAIL);
return E_FAIL;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::AuthenticationRequest
//
// Synopsis:
//
// Arguments: [lpszBuffer] --
// [pdwBuffSize] --
//
// Returns:
//
// History: 2-06-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::AuthenticationRequest()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::AuthenticationRequest",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::AuthenticationRequest");
HRESULT hr = NOERROR;
DWORD dwError;
LPWSTR pwzUsername = NULL;
LPWSTR pwzPassword = NULL;
DWORD dwBindF = GetBindFlags();
PerfDbgLog2(tagCINet, this, "<1> _cbProxyAuthenticate:%d _cbAuthenticate:%d",
_cbProxyAuthenticate, _cbAuthenticate);
if (_fProxyAuth ? (_cbProxyAuthenticate >= AUTHENTICATE_MAX):(_cbAuthenticate >= AUTHENTICATE_MAX))
{
// NOTE: set the error to noerror and
// continue reading data and show the 401 contained
_hrINet = hr = NOERROR;
}
else
{
if (_hwndAuth == NULL)
{
IAuthenticate *pPInfo;
DbgLog(tagCINetErr, this, "+CINet::AuthenticationRequest: QS for IAuthenticate");
hr = QueryService(IID_IAuthenticate, (void **)&pPInfo);
if (hr == NOERROR)
{
PProtAssert((pPInfo));
hr = pPInfo->Authenticate(&_hwndAuth, &pwzUsername, &pwzPassword);
pPInfo->Release();
}
}
if (hr == NOERROR)
{
_hrINet = hr = E_ACCESSDENIED;
if (pwzUsername && pwzPassword)
{
// set the username and password
// and retry sendrequest
LPSTR pszUsername = DupW2A(pwzUsername);
LPSTR pszPassword = DupW2A(pwzPassword);
if (pszUsername)
{
InternetSetOption(_hRequest, INTERNET_OPTION_USERNAME, pszUsername, strlen(pszUsername)+1);
delete pszUsername;
}
if (pszPassword)
{
InternetSetOption(_hRequest, INTERNET_OPTION_PASSWORD, pszPassword, strlen(pszPassword)+1);
delete pszPassword;
}
// if we got username & pwd, only try once
_fProxyAuth ? _cbProxyAuthenticate = AUTHENTICATE_MAX :
_cbAuthenticate = AUTHENTICATE_MAX;
_hrINet = hr = RPC_E_RETRY;
PerfDbgLog2(tagCINet, this, "<2> _cbProxyAuthenticate:%d _cbAuthenticate:%d",
_cbProxyAuthenticate, _cbAuthenticate);
}
if ( (_hwndAuth || (_hwndAuth == (HWND)-1) )
&& (_pCAuthData == NULL)
&& (hr != RPC_E_RETRY) )
{
PProtAssert((_pCAuthData == NULL));
_pCAuthData = new CAuthData(this);
}
if ( (_hwndAuth || (_hwndAuth == (HWND)-1) )
&& _pCAuthData
&& (hr != RPC_E_RETRY) )
{
BOOL fRetry = FALSE;
BOOL fDeleteAuthData = TRUE;
DWORD dwFlags = ( FLAGS_ERROR_UI_FILTER_FOR_ERRORS | FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS
| FLAGS_ERROR_UI_FLAGS_GENERATE_DATA | FLAGS_ERROR_UI_SERIALIZE_DIALOGS);
if ((dwBindF & BINDF_NO_UI) || (dwBindF & BINDF_SILENTOPERATION))
{
dwFlags |= FLAGS_ERROR_UI_FLAGS_NO_UI;
}
if (_hwndAuth == (HWND)-1)
{
_hwndAuth = 0;
}
do
{
_fProxyAuth ? _cbProxyAuthenticate++ : _cbAuthenticate++;
PerfDbgLog2(tagCINet, this, "<3> _cbProxyAuthenticate:%d _cbAuthenticate:%d",
_cbProxyAuthenticate, _cbAuthenticate);
dwError = InternetErrorDlg(_hwndAuth,_hRequest,ERROR_SUCCESS,dwFlags,(LPVOID *)&_pCAuthData);
switch (dwError)
{
case ERROR_CANCELLED :
// wininet should never return cancelled here
PProtAssert((FALSE));
case ERROR_SUCCESS :
// NOTE: succes and cancel means display the content according to ArthurBi
// continue reading data and show the 401 contained
_hrINet = hr = NOERROR;
break;
case ERROR_INTERNET_FORCE_RETRY :
_hrINet = hr = RPC_E_RETRY;
break;
case ERROR_INTERNET_DIALOG_PENDING :
// a dialog is up on another thread
// start wating on the callback
SetINetState(INetState_AUTHENTICATE);
SetStatePending(E_PENDING);
_fProxyAuth ? _cbProxyAuthenticate-- : _cbAuthenticate--;
PerfDbgLog2(tagCINet, this, "<4> _cbProxyAuthenticate:%d _cbAuthenticate:%d",
_cbProxyAuthenticate, _cbAuthenticate);
fDeleteAuthData = FALSE;
_hrINet = hr = E_PENDING;
break;
case ERROR_INTERNET_RETRY_DIALOG:
_fProxyAuth ? _cbProxyAuthenticate-- : _cbAuthenticate--;
PerfDbgLog2(tagCINet, this, "<5> _cbProxyAuthenticate:%d _cbAuthenticate:%d",
_cbProxyAuthenticate, _cbAuthenticate);
fRetry = TRUE;
break;
default:
_hrINet = hr = E_ACCESSDENIED;
break;
}
} while (fRetry);
if (fDeleteAuthData)
{
delete _pCAuthData;
_pCAuthData = NULL;
}
}
}
else
{
_hrINet = hr = E_ACCESSDENIED;
}
if (hr == RPC_E_RETRY)
{
_hrINet = NOERROR;
_fCompleted = FALSE;
_fSendAgain = TRUE;
if (IsA() == DLD_PROTOCOL_FTP || IsA() == DLD_PROTOCOL_GOPHER)
{
// Retry InternetOpenUrl using the updated auth info.
_fDoSimpleRetry = TRUE;
hr = INetAsyncOpenRequest();
}
else
{
hr = INetAsyncSendRequest();
}
}
else if (hr == E_PENDING)
{
// do nothing and wait for async completion
}
else if ( (hr != HRESULT_FROM_WIN32(ERROR_CANCELLED))
&& (hr != NOERROR))
{
// set the error to access denied
_hrINet = hr = E_ACCESSDENIED;
}
}
if (pwzUsername)
{
delete pwzUsername;
}
if (pwzPassword)
{
delete pwzPassword;
}
PerfDbgLog1(tagCINet, this, "-CINet::AuthenticationRequest(hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::GetUrlCacheFilename
//
// Synopsis:
//
// Arguments: [szFilename] --
// [dwSize] --
//
// Returns:
//
// History: 2-28-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::GetUrlCacheFilename(LPSTR szFilename, DWORD dwSize)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::GetUrlCacheFilename",
"this=%#x, %#x, %#x",
this, szFilename, dwSize
));
PerfDbgLog(tagCINet, this, "+CINet::GetUrlCacheFilename");
HRESULT hr = NOERROR;
BOOL fRet = FALSE;
DWORD dwSizeLocal = dwSize;
DWORD dwError = 0;
if (dwSize)
{
szFilename[0] = '\0';
}
if ( !(GetBindFlags() & BINDF_NOWRITECACHE)
|| (GetBindFlags() & BINDF_NEEDFILE))
{
fRet = InternetQueryOption(_hRequest, INTERNET_OPTION_DATAFILE_NAME, szFilename, &dwSizeLocal);
if (!fRet && (GetBindFlags() & BINDF_NEEDFILE))
{
dwError = GetLastError();
hr = INET_E_DATA_NOT_AVAILABLE;
SetBindResult(dwError, hr);
if (dwSize)
{
szFilename[0] = '\0';
}
}
}
PerfDbgLog3(tagCINet, this, "-CINet::GetUrlCacheFilename (hr:%lx,fRet%d; szFilename:%s)", hr, fRet, szFilename);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::LockFile
//
// Synopsis:
//
// Arguments: [szFilename] --
// [dwSize] --
//
// Returns:
//
// History: 8-13-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::LockFile(BOOL fRetrieve)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::LockFile",
"this=%#x, %B",
this, fRetrieve
));
PerfDbgLog(tagCINet, this, "+CINet::LockFile");
HRESULT hr = NOERROR;
BOOL fRet = FALSE;
if (fRetrieve)
{
DWORD dwCacheEntryInfoBufferSize = MAX_URL_SIZE + MAX_PATH + sizeof(INTERNET_CACHE_ENTRY_INFO) + 2;
INTERNET_CACHE_ENTRY_INFO *pCacheEntryInfo = (INTERNET_CACHE_ENTRY_INFO *)new CHAR [dwCacheEntryInfoBufferSize];
DWORD dwError = 0;
if ( (_fLocked == FALSE)
&& (pCacheEntryInfo != NULL)
&& (RetrieveUrlCacheEntryFileA( _pszFullURL, pCacheEntryInfo, &dwCacheEntryInfoBufferSize, 0)))
{
_fLocked = TRUE;
}
if (pCacheEntryInfo != NULL)
{
delete pCacheEntryInfo;
}
}
else if ((_hLockHandle == NULL) && _hRequest)
{
if (InternetLockRequestFile(_hRequest, &_hLockHandle))
{
PProtAssert((_hLockHandle));
}
}
PerfDbgLog2(tagCINet, this, "-CINet::LockFile (hr:%lx,fRet%d)", hr, fRet);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::UnlockFile
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 8-13-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::UnlockFile()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::UnlockFile",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "IN CINet::UnlockFile");
HRESULT hr = NOERROR;
if (_fLocked)
{
UnlockUrlCacheEntryFileA(_pszFullURL, 0);
_fLocked = FALSE;
}
else if (_hLockHandle)
{
if (InternetUnlockRequestFile(_hLockHandle))
{
_hLockHandle = NULL;
}
}
PerfDbgLog1(tagCINet, this, "-CINet::UnlockFile (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::HResultFromInternetError
//
// Synopsis: maps the dwStatus ERROR_INTERNET_XXX do an hresult
//
// Arguments: [dwStatus] --
//
// Returns:
//
// History: 3-22-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::HResultFromInternetError(DWORD dwStatus)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::HResultFromInternetError",
"this=%#x, %#x",
this, dwStatus
));
PerfDbgLog(tagCINet, this, "+CINet::HResultFromInternetError");
// dwResult is out of our know table
HRESULT hr = INET_E_DOWNLOAD_FAILURE;
ULONG ulIndex = dwStatus - INTERNET_ERROR_BASE;
PProtAssert((ulIndex > 0));
BOOL fTable1 = (ulIndex > 0 && ulIndex < sizeof(INetError)/sizeof(InterErrorToHResult));
DWORD dwTable2Size = sizeof(INetErrorExtended)/sizeof(InterErrorToHResult);
BOOL fTable2 = FALSE;
if (!fTable1)
{
fTable2 = (dwStatus <= INetErrorExtended[dwTable2Size].dwError);
}
if (fTable1)
{
// sequential table
hr = INetError[ulIndex].hresult;
}
else if (fTable2)
{
// walk the table
for (DWORD i = 0; i < dwTable2Size; i++)
{
if (INetErrorExtended[i].dwError == dwStatus)
{
hr = INetErrorExtended[i].hresult;
break;
}
}
}
PerfDbgLog1(tagCINet, this, "-CINet::HResultFromInternetError (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: SetBindResult
//
// Synopsis:
//
// Arguments: [dwResult] --
//
// Returns:
//
// History: 5-10-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::SetBindResult(DWORD dwResult, HRESULT hrSuggested)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::SetBindResult",
"this=%#x, %#x, %#x",
this, dwResult, hrSuggested
));
PerfDbgLog2(tagCINet, this, "+CINet::SetBindResult(dwResult:%ld, hrSuggested:%lx)", dwResult, hrSuggested);
HRESULT hr = NOERROR;
PProtAssert((_pszResult == NULL));
_pszResult = NULL;
_dwResult = dwResult;
// only find hresult in the mapping table
// if no erro was suggested
if (hrSuggested == NOERROR)
{
hr = _hrINet = HResultFromInternetError(_dwResult);
}
else
{
hr = _hrINet = hrSuggested;
}
PerfDbgLog3(tagCINet, this, "-CINet::SetBindResult (dwResult:%ld, _hrINet:%lx, hr:%lx)", dwResult, _hrINet, hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::GetBindResult
//
// Synopsis: returns the protocol specific error
//
// Arguments: [pclsidProtocol] --
// [pdwResult] --
// [DWORD] --
// [pdwReserved] --
//
// Returns:
//
// History: 4-16-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::GetBindResult(CLSID *pclsidProtocol, DWORD *pdwResult, LPWSTR *pszResult, DWORD *pdwReserved)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::GetBindResult",
"this=%#x, %#x, %#x, %#x, %#x",
this, pclsidProtocol, pdwResult, pszResult, pdwReserved
));
PerfDbgLog(tagCINet, this, "+CINet::GetBindResult");
HRESULT hr = NOERROR;
PProtAssert((pclsidProtocol && pdwResult && pszResult));
*pclsidProtocol = _pclsidProtocol;
*pdwResult = _dwResult;
if (_pszResult)
{
// the client is supposted to free the string
*pszResult = new WCHAR [strlen(_pszResult) + 1];
if (*pszResult)
{
A2W(_pszResult, *pszResult, strlen(_pszResult));
}
}
else
{
*pszResult = NULL;
}
PerfDbgLog2(tagCINet, this, "-CINet::GetBindResult (dwResult:%lx, szStr:%ws)", _dwResult, pszResult);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::OnRedirected
//
// Synopsis: Called on wininet worker thread when wininet does a redirect.
// Sends notification to apartment thread.
//
// Arguments: [szNewUrl] --
//
// Returns:
//
// History: 4-17-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::OnRedirect(LPSTR szNewUrl)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::OnRedirect",
"this=%#x, %.80q",
this, szNewUrl
));
PerfDbgLog1(tagCINet, this, "+CINet::OnRedirect (szNewUrl:%s)",szNewUrl);
HRESULT hr = NOERROR;
PProtAssert((szNewUrl && "WinINet reports redirect with redirect URL"));
if (szNewUrl)
{
_fRedirected = TRUE;
ReportNotification(BINDSTATUS_REDIRECTING, szNewUrl);
}
LONG lThirdParty;
if (IsThirdPartyUrl(szNewUrl))
{
lThirdParty = 1;
//MessageBoxA( 0, szNewUrl, "redirect: THIRDPARTY!", 0 );
InternetSetOption(_hRequest, INTERNET_OPTION_COOKIES_3RD_PARTY, &lThirdParty, sizeof(LONG));
}
else
{
lThirdParty = 0;
//MessageBoxA( 0, szNewUrl, "redirect: NOT THIRDPARTY!", 0 );
InternetSetOption(_hRequest, INTERNET_OPTION_COOKIES_3RD_PARTY, &lThirdParty, sizeof(LONG));
}
PerfDbgLog1(tagCINet, this, "-CINet::OnRedirect(hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: AppendToString
//
// Synopsis: Fast append of src to dest, reallocing of dest if necessary.
//
//
// Arguments: [IN/OUT] pszDest
// [IN/OUT] pcbDest
// [IN/OUT] pcbAlloced
// [IN] szSrc
// [IN] cbSrc
//
// Returns: TRUE/FALSE
//
// History: 6-2-97 Adriaan Canter (AdriaanC) Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL AppendToString(LPSTR* pszDest, LPDWORD pcbDest,
LPDWORD pcbAlloced, LPSTR szSrc, DWORD cbSrc)
{
DEBUG_ENTER((DBG_APP,
Bool,
"AppendToString",
"%#x, %#x, %#x, %.80q, %#x",
pszDest, pcbDest, pcbAlloced, szSrc, cbSrc
));
DWORD cbNew = *pcbDest + cbSrc;
if (cbNew > *pcbAlloced)
{
DWORD cbNewAlloc = *pcbAlloced + (cbSrc < MAX_PATH ? MAX_PATH : cbSrc);
LPSTR szNew = (LPSTR) new CHAR[cbNewAlloc];
if (!szNew)
{
DEBUG_LEAVE(FALSE);
return FALSE;
}
memcpy(szNew, *pszDest, *pcbDest);
delete [] *pszDest;
*pszDest = szNew;
*pcbAlloced = cbNewAlloc;
}
memcpy(*pszDest + *pcbDest, szSrc, cbSrc);
*pcbDest = cbNew;
DEBUG_LEAVE(TRUE);
return TRUE;
}
#ifdef unix
#include <sys/utsname.h>
#endif /* unix */
//+---------------------------------------------------------------------------
//
// Function: GetUserAgentString
//
// Synopsis: Gets the user agent string from the registry. If entry is
// the default string is returned.
//
// Arguments: (none)
//
// Returns: Allocated user agent string.
//
// History: 5-13-96 JohannP (Johann Posch) Created
// 6-02-97 AdriaanC (Adriaan Canter) Mods for mult reg entries.
//
// 6-25-97 AdriaanC (Adriaan Canter) Further mods described below.
//
// 12-18-98 Adriaanc (Adriaan Canter) - Versioned base values for
// IE5 and added a versioned IE5 location for token values
// which will get read in addition to common (IE4) location.
//
// Notes: User Agent string madness: We now generate the User Agent string
// from diverse entries in the registry. We first scan HKCU for base
// keys, falling back to HKLM if not found, or finally, defaults.
// For Pre and Post platform we now pickup all entries in both HKCU
// and HKLM. Finally, for back compatibility we enumerate a list of
// tokens (such as MSN 2.0, MSN 2.1, etc) from UA Tokens in the HKLM
// registry under Internet Settings, and if any of these tokens are
// found in the *old* HKCU location User Agent String we insert them
// into the pre platform portion of the generated user agent string.
// This was specifically done for MSN which has been fixing up the old
// registry location and depends on these tokens being found in the
// User Agent string.
//
//----------------------------------------------------------------------------
LPCSTR GetUserAgentString()
{
DEBUG_ENTER((DBG_APP,
String,
"GetUserAgentString",
NULL
));
// Reg keys.
#define INTERNET_SETTINGS_KEY_SZ "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
#define USER_AGENT_KEY_SZ "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\User Agent"
#define USER_AGENT_KEY5_SZ "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\5.0\\User Agent"
#define USER_AGENT_SZ "User Agent"
#define PRE_PLATFORM_KEY_SZ "Pre Platform"
#define POST_PLATFORM_KEY_SZ "Post Platform"
#define UA_TOKENS_KEY_SZ "UA Tokens"
// Base UA key strings.
#define UA_KEY_SZ NULL
#define COMPATIBLE_KEY_SZ "Compatible"
#define VERSION_KEY_SZ "Version"
#define PLATFORM_KEY_SZ "Platform"
// Base UA value strings.
#define UA_VAL_SZ "Mozilla/4.0"
#define COMPATIBLE_VAL_SZ "compatible"
#define VERSION_VAL_SZ "MSIE 6.0"
// Their lengths.
#define UA_VAL_LEN (sizeof(UA_VAL_SZ) - 1)
#define COMPATIBLE_VAL_LEN (sizeof(COMPATIBLE_VAL_SZ) - 1)
#define VERSION_VAL_LEN (sizeof(VERSION_VAL_SZ) - 1)
// If we encounter a failure in constructing the string, send this.
#ifdef _WIN64
#define DEFAULT_UA_STRING UA_VAL_SZ" ("COMPATIBLE_VAL_SZ"; "VERSION_VAL_SZ"; Win64)"
#else
#define DEFAULT_UA_STRING UA_VAL_SZ" ("COMPATIBLE_VAL_SZ"; "VERSION_VAL_SZ")"
#endif
// Used for backing up user agent string.
#define IE4_UA_BACKUP_FLAG "IE5_UA_Backup_Flag"
#define BACKUP_USER_AGENT_SZ "BackupUserAgent"
#define COMPAT_MODE_TOKEN "compat"
#define NUM_UA_KEYS 4
BOOL bSuccess = TRUE;
INT i, nBaseKeys;
DWORD dwIndex, dwType, cbBuf, cbUA, cbTotal;
LPSTR szUA, szBuf, pszWinVer;
OSVERSIONINFO osVersionInfo;
// Reg handles.
HKEY hHKCU_ISKey;
HKEY hHKCU_UAKey;
HKEY hHKLM_UAKey;
HKEY hHKCU_UA5Key;
HKEY hHKLM_UA5Key;
HKEY hPreKey;
HKEY hPostKey;
HKEY hTokensKey;
// Set all regkeys to invalid handle.
hHKCU_ISKey = hHKLM_UAKey = hHKCU_UAKey = hHKLM_UA5Key = hHKCU_UA5Key
= hPreKey = hPostKey = hTokensKey = (HKEY) INVALID_HANDLE_VALUE;
// The UA keys are iterated in loops below; Keep an array
// of pointers to the HKLMUA, HKCUUA, HKLMUA5 and HKCUUA5 locations
// to use as alias in the loop. NOTE!! - Do not change the ordering.
HKEY *phUAKeyArray[NUM_UA_KEYS];
phUAKeyArray[0] = &hHKLM_UAKey;
phUAKeyArray[1] = &hHKCU_UAKey;
phUAKeyArray[2] = &hHKLM_UA5Key;
phUAKeyArray[3] = &hHKCU_UA5Key;
// Platform strings.
LPSTR szWin32 = "Win32";
LPSTR szWin95 = "Windows 95";
LPSTR szWin98 = "Windows 98";
LPSTR szMillennium = "Windows 98; Win 9x 4.90";
LPSTR szWinNT = "Windows NT";
//for WinNT appended with version numbers
//Note: Limitation on total# of digits in Major+Minor versions=8.
//length = sizeof("Windows NT"+" "+majorverstring+"."+minorverstring
//Additional allowance is made for Win64 token.
#define WINNT_VERSION_STRING_MAX_LEN 32
char szWinNTVer[WINNT_VERSION_STRING_MAX_LEN];
#ifdef unix
CHAR szUnixPlatformName[SYS_NMLN*4+3+1]; // 4 substrings,3 spaces, 1 NULL
#endif /* unix */
// Arrays of base keys, values and lengths.
LPSTR szBaseKeys[] = {UA_KEY_SZ, COMPATIBLE_KEY_SZ, VERSION_KEY_SZ};
LPSTR szBaseValues[] = {UA_VAL_SZ, COMPATIBLE_VAL_SZ, VERSION_VAL_SZ};
DWORD cbBaseValues[] = {UA_VAL_LEN, COMPATIBLE_VAL_LEN, VERSION_VAL_LEN};
nBaseKeys = sizeof(szBaseKeys) / sizeof(LPSTR);
cbUA = 0;
cbTotal = cbBuf = MAX_PATH;
szBuf = szUA = 0;
// User agent string already exists.
if (g_pszUserAgentString != NULL)
{
szUA = g_pszUserAgentString;
goto End;
}
// Max size for any one field from registry is MAX_PATH.
szUA = new CHAR[MAX_PATH];
szBuf = new CHAR[MAX_PATH];
if (!szUA || !szBuf)
{
bSuccess = FALSE;
goto End;
}
// Open all 4 User Agent reg keys (HKLMUA, HKCUUA, HKLMUA5, HKCUUA5).
if (RegOpenKeyEx(HKEY_CURRENT_USER, USER_AGENT_KEY_SZ, 0, KEY_QUERY_VALUE, &hHKCU_UAKey) != ERROR_SUCCESS)
hHKCU_UAKey = (HKEY)INVALID_HANDLE_VALUE;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, USER_AGENT_KEY_SZ, 0, KEY_QUERY_VALUE, &hHKLM_UAKey) != ERROR_SUCCESS)
hHKLM_UAKey = (HKEY)INVALID_HANDLE_VALUE;
if (RegOpenKeyEx(HKEY_CURRENT_USER, USER_AGENT_KEY5_SZ, 0, KEY_QUERY_VALUE, &hHKCU_UA5Key) != ERROR_SUCCESS)
hHKCU_UA5Key = (HKEY)INVALID_HANDLE_VALUE;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, USER_AGENT_KEY5_SZ, 0, KEY_QUERY_VALUE, &hHKLM_UA5Key) != ERROR_SUCCESS)
hHKLM_UA5Key = (HKEY)INVALID_HANDLE_VALUE;
// Get user agent, compatible and version strings from IE 5.0 location.
// IE6 and on must revise this location.
for (i = 0; i < nBaseKeys; i++)
{
if ((hHKCU_UA5Key != INVALID_HANDLE_VALUE) && RegQueryValueEx(hHKCU_UA5Key, szBaseKeys[i],
NULL, &dwType, (LPBYTE) szBuf, &(cbBuf = MAX_PATH)) == ERROR_SUCCESS
&& cbBuf > 1)
{
// Got from HKCU registry.
if (!(bSuccess = AppendToString(&szUA, &cbUA,
&cbTotal, szBuf, cbBuf - 1)))
goto End;
}
else if ((hHKLM_UA5Key != INVALID_HANDLE_VALUE) && RegQueryValueEx(hHKLM_UA5Key, szBaseKeys[i],
NULL, &dwType, (LPBYTE) szBuf, &(cbBuf = MAX_PATH)) == ERROR_SUCCESS
&& cbBuf > 1)
{
// Got from HKLM registry.
if (!(bSuccess = AppendToString(&szUA, &cbUA,
&cbTotal, szBuf, cbBuf - 1)))
goto End;
}
else
{
// Got from defaults.
if (!(bSuccess = AppendToString(&szUA, &cbUA, &cbTotal,
szBaseValues[i], cbBaseValues[i])))
goto End;
}
// Formating.
if (!(bSuccess = AppendToString(&szUA, &cbUA,
&cbTotal, (i == 0 ? " (" : "; "), 2)))
goto End;
}
// Leave the four UA keys open; Proceed to open HKLM tokens key to scan
// to scan and open Internet Settings HKCU key to read legacy UA string.
// Tokens to scan for from the old registry location to include
// in the user agent string: These are enumerated from UA Tokens,
// scanned for in the old location and added to the pre platform.
if (hHKLM_UAKey != INVALID_HANDLE_VALUE)
RegOpenKeyEx(hHKLM_UAKey, UA_TOKENS_KEY_SZ, 0, KEY_QUERY_VALUE, &hTokensKey);
if (hTokensKey != INVALID_HANDLE_VALUE)
{
CHAR szOldUserAgentString[MAX_PATH];
// Read in the old user agent string from HKCU
RegOpenKeyEx(HKEY_CURRENT_USER, INTERNET_SETTINGS_KEY_SZ, 0, KEY_QUERY_VALUE, &hHKCU_ISKey);
if ((hHKCU_ISKey != INVALID_HANDLE_VALUE) && RegQueryValueEx(hHKCU_ISKey, USER_AGENT_SZ,
NULL, &dwType, (LPBYTE) szOldUserAgentString, &(cbBuf = MAX_PATH)) == ERROR_SUCCESS
&& cbBuf > 1)
{
// Close the HKCU Internet Settings key.
RegCloseKey(hHKCU_ISKey);
hHKCU_ISKey = (HKEY) INVALID_HANDLE_VALUE;
// Got old user agent string from HKCU registry. Enumerate the values in UA Tokens
// and see if any exist in the old string and if so, add them to the current string.
dwIndex = 0;
#ifndef unix
while (RegEnumValue(hTokensKey, dwIndex++, szBuf, &(cbBuf = MAX_PATH - 4), /* sizeof(' ' + "; ") */
NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
{
// eg; find a token enumerated from UA Tokens
// Mozilla/4.0 (compatible; MSIE 4.0b2; MSN2.5; Windows NT)
// ^
// szBuf
if (cbBuf)
{
// Fix up token to include leading
// space and trailing semi-colon before strstr.
CHAR szToken[MAX_PATH];
szToken[0] = ' ';
memcpy(szToken+1, szBuf, cbBuf);
memcpy(szToken + 1 + cbBuf, "; ", sizeof("; "));
// Found a match - insert this token into user agent string.
if (strstr(szOldUserAgentString, szToken))
{
if (!(bSuccess = AppendToString(&szUA, &cbUA, &cbTotal, szBuf, cbBuf)))
goto End;
if (!(bSuccess = AppendToString(&szUA, &cbUA, &cbTotal, "; ", 2)))
goto End;
}
}
}
#endif /* !unix */
}
RegCloseKey(hTokensKey);
hTokensKey = (HKEY) INVALID_HANDLE_VALUE;
}
// Pre platform strings - get from HKCUUA, HKLMUA,
// HKLMUA5 and HKCUUA5 locations. These are additive;
// order is not important.
for (i = 0; i < NUM_UA_KEYS; i++)
{
if (*(phUAKeyArray[i]) == INVALID_HANDLE_VALUE)
continue;
RegOpenKeyEx(*(phUAKeyArray[i]),
PRE_PLATFORM_KEY_SZ, 0, KEY_QUERY_VALUE, &hPreKey);
if (hPreKey != INVALID_HANDLE_VALUE)
{
dwIndex = 0;
while (RegEnumValue(hPreKey, dwIndex++, szBuf, &(cbBuf = MAX_PATH),
NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
{
if (cbBuf)
{
// Got from registry and non null.
if (!(bSuccess = AppendToString(&szUA, &cbUA, &cbTotal, szBuf, cbBuf)))
goto End;
if (!(bSuccess = AppendToString(&szUA, &cbUA, &cbTotal, "; ", 2)))
goto End;
}
cbBuf = MAX_PATH;
}
// Close pre platform key; User agent keys still open.
RegCloseKey(hPreKey);
hPreKey = (HKEY) INVALID_HANDLE_VALUE;
}
}
// Platform string. This is read from the IE 5.0 location only. IE6 and later
// must revise this. If no platform value read from registry, get from OS.
if (hHKCU_UA5Key != INVALID_HANDLE_VALUE && RegQueryValueEx(hHKCU_UA5Key, PLATFORM_KEY_SZ,
NULL, &dwType, (LPBYTE) szBuf, &(cbBuf = MAX_PATH)) == ERROR_SUCCESS)
{
// Got from HKCU.
if (!(bSuccess = AppendToString(&szUA, &cbUA, &cbTotal, szBuf, cbBuf -1)))
goto End;
}
else if (hHKLM_UA5Key != INVALID_HANDLE_VALUE && RegQueryValueEx(hHKLM_UA5Key, PLATFORM_KEY_SZ,
NULL, &dwType, (LPBYTE) szBuf, &(cbBuf = MAX_PATH)) == ERROR_SUCCESS)
{
// Got from HKLM
if (!(bSuccess = AppendToString(&szUA, &cbUA, &cbTotal, szBuf, cbBuf -1)))
goto End;
}
else
{
// Couldn't get User Agent value from registry.
// Set the default value.
osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (GetVersionEx(&osVersionInfo))
{
#ifndef unix
// Platform ID is either Win95 or WinNT.
if(VER_PLATFORM_WIN32_NT == osVersionInfo.dwPlatformId)
{
Assert(osVersionInfo.dwMajorVersion < 10000 &&
osVersionInfo.dwMinorVersion < 10000);
/* Check for WIN64, adding another token if necessary */
LPSTR szWin64Token = "; Win64";
LPSTR szWow64Token = "; WOW64";
SYSTEM_INFO SysInfo;
GetSystemInfo(&SysInfo);
bool fWin64 = ((SysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) ||
(SysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64));
bool fWow64 = FALSE;
// There is no easy way to determine whether a 32-bit app is running on a 32-bit OS
// or Wow64. The recommended approach (Q275217) to determine this is to see if
// GetSystemWow64DirectoryA is implemented in kernel32.dll and to see if the function
// succeeds. If it succeeds, then we're running on a 64-bit processor.
if (!fWin64 && SysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
{
char directoryPath[MAX_PATH];
HMODULE hModule;
GetSystemWow64DirectoryPtr func;
hModule = GetModuleHandle("kernel32.dll");
func = (GetSystemWow64DirectoryPtr) GetProcAddress(hModule, "GetSystemWow64DirectoryA");
if (func && func(directoryPath, sizeof(directoryPath)))
{
fWow64 = TRUE;
}
}
LPSTR sz64Str = NULL;
if( fWin64)
sz64Str = szWin64Token;
else if( fWow64)
sz64Str = szWow64Token;
else
sz64Str = "";
memset(szWinNTVer, 0, WINNT_VERSION_STRING_MAX_LEN);
wsprintfA(szWinNTVer,
"%s %u.%u%s",
szWinNT,
osVersionInfo.dwMajorVersion,
osVersionInfo.dwMinorVersion,
sz64Str);
pszWinVer = szWinNTVer;
}
else
{
if(osVersionInfo.dwMinorVersion >= 10)
{
if(osVersionInfo.dwMinorVersion >= 90)
{
// Millennium
pszWinVer = szMillennium;
}
else
{
// Win98
pszWinVer = szWin98;
}
}
else
{
// Win95
pszWinVer = szWin95;
}
}
#else
struct utsname uName;
if(uname(&uName) > -1)
{
strcpy(szUnixPlatformName,uName.sysname);
strcat(szUnixPlatformName," ");
strcat(szUnixPlatformName,uName.release);
strcat(szUnixPlatformName," ");
strcat(szUnixPlatformName,uName.machine);
strcat(szUnixPlatformName,"; X11");
pszWinVer = &szUnixPlatformName[0];
}
else
pszWinVer = "Generic Unix";
#endif /* unix */
}
else
{
// GetVersionEx failed! - set Platform to Win32.
pszWinVer = szWin32;
}
if (!(bSuccess = AppendToString(&szUA, &cbUA, &cbTotal,
pszWinVer, strlen(pszWinVer))))
goto End;
}
// Post platform strings - get from HKCUUA, HKLMUA,
// HKLMUA5 and HKCUUA5 locations. These are additive;
// order is not important. Special case the IE4
// compat token. IE6 and later must do this also.
for (i = 0; i < NUM_UA_KEYS; i++)
{
if (*(phUAKeyArray[i]) == INVALID_HANDLE_VALUE)
continue;
RegOpenKeyEx(*(phUAKeyArray[i]),
POST_PLATFORM_KEY_SZ, 0, KEY_QUERY_VALUE, &hPostKey);
if (hPostKey != INVALID_HANDLE_VALUE)
{
dwIndex = 0;
while (RegEnumValue(hPostKey, dwIndex++, szBuf, &(cbBuf = MAX_PATH),
NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
{
// We need to special case the IE4 compat mode token in the
// first two keys in phUAKeyArray[];
if (cbBuf && ((i > 1) || strcmp(szBuf, COMPAT_MODE_TOKEN)))
{
// Got from registry and non null.
if (!(bSuccess = AppendToString(&szUA, &cbUA, &cbTotal, "; ", 2)))
goto End;
if (!(bSuccess = AppendToString(&szUA, &cbUA, &cbTotal, szBuf, cbBuf)))
goto End;
}
cbBuf = MAX_PATH;
}
// Close post platform key; User agent keys still open.
RegCloseKey(hPostKey);
hPostKey = (HKEY) INVALID_HANDLE_VALUE;
}
}
// Terminate with ")\0"
if (!(bSuccess = AppendToString(&szUA, &cbUA, &cbTotal, ")", 2)))
goto End;
for (i = 0; i < NUM_UA_KEYS; i++)
{
if (*(phUAKeyArray[i]) != INVALID_HANDLE_VALUE)
{
RegCloseKey(*(phUAKeyArray[i]));
*(phUAKeyArray[i]) = (HKEY) INVALID_HANDLE_VALUE;
}
}
// Finally, write out the generated user agent string in the old location.
if (bSuccess)
{
// Remember the computed user agent string for later.
g_pszUserAgentString = szUA;
}
End:
// Cleanup.
delete [] szBuf;
if (!bSuccess)
{
delete [] szUA;
DEBUG_LEAVE(DEFAULT_UA_STRING);
return DEFAULT_UA_STRING;
}
DEBUG_LEAVE(szUA);
return szUA;
}
//+---------------------------------------------------------------------------
//
// Method: ObtainUserAgentString
//
// Synopsis:
//
// Returns:
//
// History: 08-07-1997 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDAPI ObtainUserAgentString(DWORD dwOption, LPSTR pszUAOut, DWORD *cbSize )
{
DEBUG_ENTER_API((DBG_API,
Hresult,
"ObtainUserAgentString",
"%#x, %#x, %#x",
dwOption, pszUAOut, cbSize
));
// since GetUserAgentString may change some global variable,
// this API needs to add a global mutex to protect them
CLock lck(g_mxsSession);
HRESULT hr = NOERROR;
if( pszUAOut && cbSize )
{
LPSTR pcszUA = (LPSTR)GetUserAgentString();
DWORD cbLen = strlen(pcszUA);
if( *cbSize <= cbLen )
{
hr = E_OUTOFMEMORY;
}
else
{
strcpy(pszUAOut, pcszUA);
}
*cbSize = cbLen + 1;
}
else
{
hr = E_INVALIDARG;
}
DEBUG_LEAVE_API(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::InternetAuthNotifyCallback
//
// Synopsis:
//
// Arguments: [dwContext] --
// [dwAction] --
// [lpReserved] --
//
// Returns:
//
// History: 10-10-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD CALLBACK CINet::InternetAuthNotifyCallback(DWORD_PTR dwContext, DWORD dwAction, LPVOID lpReserved)
{
DEBUG_ENTER((DBG_APP,
Dword,
"CINet::InternetAuthNotifyCallback",
"%#x, %#x, %#x",
dwContext, dwAction, lpReserved
));
// If this is a request, then we know the cookie type
CINet *pCINet = (CINet *) dwContext;
PerfDbgLog2(tagCINet, pCINet, "+CINet::InternetAuthNotifyCallback Action:%ld, State:%ld",
dwAction, pCINet->_INState);
PProtAssert((lpReserved == NULL));
DWORD dwRes = ERROR_SUCCESS;
switch (dwAction)
{
case ERROR_SUCCESS :
// should never be returned here
PProtAssert((FALSE));
case ERROR_CANCELLED :
// NOTE: succes and cancel means display the content according to ArthurBi
// continue reading data and show the 401 contained
pCINet->_hrINet = NOERROR;
// Why do we inc the count here??
pCINet->_fProxyAuth ? pCINet->_cbProxyAuthenticate++ : pCINet->_cbAuthenticate++;
break;
case ERROR_INTERNET_RETRY_DIALOG:
pCINet->_hrINet = INET_E_AUTHENTICATION_REQUIRED;
break;
case ERROR_INTERNET_FORCE_RETRY :
pCINet->_hrINet = RPC_E_RETRY;
pCINet->_fProxyAuth ? pCINet->_cbProxyAuthenticate++ : pCINet->_cbAuthenticate++;
break;
default:
pCINet->_hrINet = E_ACCESSDENIED;
break;
}
pCINet->OnINetAuthenticate(dwAction);
PerfDbgLog2(tagCINet, pCINet, "-CINet::InternetAuthNotifyCallback (pCINet->_hrINet:%lx, dwResult:%lx)", pCINet->_hrINet,dwRes);
DEBUG_LEAVE(dwRes);
return dwRes;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::OnINetAuthenticate
//
// Synopsis:
//
// Arguments: [dwResult] --
//
// Returns:
//
// History: 10-10-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::OnINetAuthenticate(DWORD dwResult)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::OnINetAuthenticate",
"this=%#x, %#x",
this, dwResult
));
PerfDbgLog(tagCINet, this, "+CINet::OnINetAuthenticate");
HRESULT hr = NOERROR;
PProtAssert((GetStatePending() == E_PENDING));
// set state to normal - no pending transaction
SetStatePending(NOERROR);
PProtAssert((_INState == INetState_AUTHENTICATE));
if (dwResult)
{
TransitState(INetState_AUTHENTICATE, TRUE);
}
PerfDbgLog1(tagCINet, this, "-CINet::OnINetAuthenticate (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::INetAuthenticate
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 10-10-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::INetAuthenticate()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::INetAuthenticate",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::INetAuthenticate");
PProtAssert((GetStatePending() == NOERROR));
HRESULT hr = NOERROR;
DWORD dwOperation;
PProtAssert((GetStatePending() == NOERROR));
if (_hrINet == INET_E_AUTHENTICATION_REQUIRED)
{
// bring up the internet errro dialog
hr = AuthenticationRequest();
if ((hr != NOERROR) && (hr != E_PENDING))
{
_hrError = INET_E_AUTHENTICATION_REQUIRED;
}
else
{
_hrError = INET_E_OK;
}
}
if (hr == NOERROR)
{
if (_hrINet == RPC_E_RETRY)
{
// retry the send/request
_hrINet = NOERROR;
_fCompleted = FALSE;
_fSendAgain = TRUE;
hr = INetAsyncSendRequest();
}
else if (_hrINet == NOERROR)
{
hr = QueryStatusOnResponseDefault(0);
if( hr == NOERROR )
{
hr = QueryHeaderOnResponse();
if (hr == NOERROR)
{
// read more data from wininet
hr = INetRead();
}
}
}
else
{
// this will report the hresult return from the dialog
hr = _hrINet;
}
}
PerfDbgLog1(tagCINet, this, "-CINet::INetAuthenticate (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::INetResumeAsyncRequest
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 1-27-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::INetResumeAsyncRequest(DWORD dwResultCode)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::INetResumeAsyncRequest",
"this=%#x, %#x",
this, dwResultCode
));
PerfDbgLog(tagCINet, this, "+CINet::INetResumeAsyncRequest");
HRESULT hr = NOERROR;
BOOL fRestarted;
BOOL fRet;
PProtAssert((GetStatePending() == NOERROR));
SetINetState(INetState_SEND_REQUEST);
{
SetStatePending(E_PENDING);
fRet = ResumeSuspendedDownload(_hRequest,
dwResultCode
);
if (fRet == FALSE)
{
dwLstError = GetLastError();
if (dwLstError == ERROR_IO_PENDING)
{
// wait async for the handle
hr = E_PENDING;
}
else
{
SetStatePending(NOERROR);
hr = _hrError = INET_E_DOWNLOAD_FAILURE;
SetBindResult(dwLstError,hr);
PerfDbgLog3(tagCINet, this, "CINet::INetResumeAsyncRequest (fRet:%d, _hrError:%lx, LstError:%ld)", fRet, _hrError, dwLstError);
}
}
else
{
SetStatePending(NOERROR);
}
}
if (_hrError != INET_E_OK)
{
// we need to terminate here
ReportResultAndStop(hr);
}
PerfDbgLog1(tagCINet, this, "-CINet::INetResumeAsyncRequest (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::INetDisplayUI
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 10-10-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::INetDisplayUI()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::INetDisplayUI",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::INetDisplayUI");
PProtAssert((GetStatePending() == NOERROR));
HRESULT hr = NOERROR;
DWORD dwOperation;
DWORD dwResultCode = ERROR_SUCCESS;
PProtAssert((GetStatePending() == NOERROR));
DWORD dwBindF = GetBindFlags();
if (_hrINet == INET_E_AUTHENTICATION_REQUIRED)
{
HWND hwnd = 0;
hr = NOERROR;
// Get a window handle. QueryService on IWindowForBindingUI
// to get a window object first if necessary.
if (_pWindow == NULL)
{
hr = QueryService(IID_IWindowForBindingUI, (void **) &_pWindow);
}
// If we don't already have a window handle, get one from the interface.
if (!hwnd && _pWindow)
{
hr = _pWindow->GetWindow(IID_IHttpSecurity, &hwnd);
PProtAssert(( (hr == S_FALSE) && (hwnd == NULL)
|| (hr == S_OK) && (hwnd != NULL)));
}
if (hwnd && (hr == S_OK))
{
DWORD dwFlags = FLAGS_ERROR_UI_SERIALIZE_DIALOGS;
if ((dwBindF & BINDF_NO_UI) || (dwBindF & BINDF_SILENTOPERATION))
{
dwFlags |= FLAGS_ERROR_UI_FLAGS_NO_UI;
}
dwResultCode =
InternetErrorDlg( hwnd, _hRequest, _dwSendRequestResult, dwFlags, &_lpvExtraSendRequestResult);
if ( dwResultCode == ERROR_CANCELLED || dwResultCode == ERROR_SUCCESS )
{
// hack-hack alert, if _lpvExtraSendRequestResult non-null we change behavior
if ( !(dwResultCode == ERROR_SUCCESS && _lpvExtraSendRequestResult != NULL) )
{
dwResultCode = ERROR_INTERNET_OPERATION_CANCELLED;
}
}
_hrINet = RPC_E_RETRY;
hr = NOERROR;
}
else if (_dwSendRequestResult == ERROR_HTTP_COOKIE_NEEDS_CONFIRMATION ||
_dwSendRequestResult == ERROR_HTTP_COOKIE_NEEDS_CONFIRMATION_EX)
{
//fix to prevent heap trashing in wininet.b#86959
dwResultCode = ERROR_HTTP_COOKIE_DECLINED;
_hrINet = RPC_E_RETRY;
hr = NOERROR;
}
if ((hr != NOERROR) && (hr != E_PENDING))
{
_hrError = INET_E_AUTHENTICATION_REQUIRED;
}
else
{
_hrError = INET_E_OK;
}
}
if (hr == NOERROR)
{
if (_hrINet == RPC_E_RETRY)
{
// retry the send/request
_hrINet = NOERROR;
// hack-arama around to allow CD-ROM dialog to still work
if ( _dwSendRequestResult == ERROR_INTERNET_INSERT_CDROM )
{
hr = INetAsyncSendRequest();
}
else
{
hr = INetResumeAsyncRequest(dwResultCode);
}
}
else
{
// this will report the hresult return from the dialog
hr = _hrINet;
}
}
PerfDbgLog1(tagCINet, this, "-CINet::INetDisplayUI (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::INetSeek
//
// Synopsis:
//
// Arguments: [DWORD] --
// [ULARGE_INTEGER] --
// [plibNewPosition] --
//
// Returns:
//
// History: 10-29-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::INetSeek(LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER *plibNewPosition)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::INetSeek",
"this=%#x, %#x, %#x, %#x",
this, dlibMove, dwOrigin, plibNewPosition
));
PerfDbgLog(tagCINet, this, "+CINet::INetSeek");
HRESULT hr = E_FAIL;
// each protocol has to overwrite this method if
// seek is supported
DWORD dwResult = InternetSetFilePointer(
_hRequest
,dlibMove.LowPart
,0
,dwOrigin
,0
);
PerfDbgLog1(tagCINet, this, "-CINet::INetSeek (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::IsUpLoad
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 4-28-1997 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL CINet::IsUpLoad()
{
DEBUG_ENTER((DBG_APP,
Bool,
"CINet::IsUpLoad",
"this=%#x",
this
));
BINDINFO *pBndInfo = GetBindInfo();
BOOL fRet = ( (pBndInfo->dwBindVerb != BINDVERB_GET)
&& (pBndInfo->stgmedData.tymed == TYMED_ISTREAM)
&& !_fCompleted
&& !_fRedirected);
DEBUG_LEAVE(fRet);
return fRet;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::CPrivUnknown::QueryInterface
//
// Synopsis:
//
// Arguments: [riid] --
// [ppvObj] --
//
// Returns:
//
// History: 10-29-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CINet::CPrivUnknown::QueryInterface(REFIID riid, void **ppvObj)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::CPrivUnknown::IUnknown::QueryInterface",
"this=%#x, %#x, %#x",
this, &riid, ppvObj
));
VDATEPTROUT(ppvObj, void *);
VDATETHIS(this);
HRESULT hr = NOERROR;
PerfDbgLog(tagCINet, this, "+CINet::CPrivUnknown::QueryInterface");
CINet *pCINet = GETPPARENT(this, CINet, _Unknown);
*ppvObj = NULL;
if ((riid == IID_IUnknown) || (riid == IID_IOInetProtocol) || (riid == IID_IOInetProtocolRoot) )
{
*ppvObj = (IOInetProtocol *) pCINet;
pCINet->AddRef();
}
else if ( ( IsEqualIID(riid, IID_IWinInetInfo)||
IsEqualIID(riid, IID_IWinInetHttpInfo) ) &&
( !IsEqualIID(CLSID_FileProtocol, pCINet->_pclsidProtocol) ) )
{
*ppvObj = (void FAR *) (IWinInetHttpInfo *)pCINet;
pCINet->AddRef();
}
else if (riid == IID_IOInetThreadSwitch)
{
*ppvObj = (IOInetThreadSwitch *)pCINet;
pCINet->AddRef();
}
else
{
hr = E_NOINTERFACE;
}
PerfDbgLog1(tagCINet, this, "-CINet::CPrivUnknown::QueryInterface (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: CINet::CPrivUnknown::AddRef
//
// Synopsis:
//
// Arguments: [ULONG] --
//
// Returns:
//
// History: 10-29-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CINet::CPrivUnknown::AddRef(void)
{
DEBUG_ENTER((DBG_APP,
Dword,
"CINet::CPrivUnknown::IUnknown::AddRef",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::CPrivUnknown::AddRef");
LONG lRet = ++_CRefs;
PerfDbgLog1(tagCINet, this, "-CINet::CPrivUnknown::AddRef (cRefs:%ld)", lRet);
DEBUG_LEAVE(lRet);
return lRet;
}
//+---------------------------------------------------------------------------
//
// Function: CINet::Release
//
// Synopsis:
//
// Arguments: [ULONG] --
//
// Returns:
//
// History: 10-29-1996 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CINet::CPrivUnknown::Release(void)
{
DEBUG_ENTER((DBG_APP,
Dword,
"CINet::CPrivUnknown::IUnknown::Release",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::CPrivUnknown::Release");
CINet *pCINet = GETPPARENT(this, CINet, _Unknown);
LONG lRet = --_CRefs;
if (lRet == 0)
{
delete pCINet;
}
PerfDbgLog1(tagCINet, this, "-CINet::CPrivUnknown::Release (cRefs:%ld)", lRet);
DEBUG_LEAVE(lRet);
return lRet;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::OnINetReadDirect
//
// Synopsis:
//
// Arguments: [dwResult] --
//
// Returns:
//
// History: 4-28-1997 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::OnINetReadDirect(DWORD dwResult)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::OnINetReadDirect",
"this=%#x, %#x",
this, dwResult
));
PerfDbgLog(tagCINet, this, "+CINet::OnINetReadDirect");
HRESULT hr = NOERROR;
PProtAssert((GetStatePending() == E_PENDING));
// set state to normal - no pending transaction
SetStatePending(NOERROR);
if (OperationOnAparmentThread(INetState_SEND_REQUEST))
{
TransitState(INetState_READ_DIRECT);
}
else
{
hr = INetReadDirect();
}
PerfDbgLog1(tagCINet, this, "-CINet::OnINetReadDirect (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::INetReadDirect
//
// Synopsis:
//
// Arguments: (none)
//
// Returns:
//
// History: 4-28-1997 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::INetReadDirect()
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::INetReadDirect",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::INetReadDirect");
HRESULT hr = NOERROR;
DWORD dwError;
ULONG cbBytesAvailable = 1;
ULONG cbBytesReport = 0;
SetINetState(INetState_READ_DIRECT);
//BUGBUG: we hit this assertion sometimes.
//PProtAssert((GetStatePending() == NOERROR));
_hrError = INET_E_OK;
if (!_fFilenameReported)
{
char szFilename[MAX_PATH];
HRESULT hr1 = GetUrlCacheFilename(szFilename, MAX_PATH);
if (hr1 == NOERROR && szFilename[0] != '\0')
{
ReportNotification(BINDSTATUS_CACHEFILENAMEAVAILABLE, (LPSTR) szFilename);
_fFilenameReported = TRUE;
}
}
if ((GetStatePending() == E_PENDING))
{
// nothing to do - data for this notfication
// already received
DbgLog(tagCINetErr, this, "CINet::INetReadDirect E_PENIDNG");
}
else
{
if ( _fDone
|| ( _cbTotalBytesRead
&& _cbDataSize
&& (_cbTotalBytesRead == _cbDataSize)))
{
_hrError = INET_E_DONE;
_pEmbdFilter->ReportData(_bscf, cbBytesAvailable, _cbDataSize);
ReportResultAndStop(NOERROR, _cbTotalBytesRead, _cbDataSize);
hr = NOERROR;
}
else
{
if (_bscf & BSCF_DATAFULLYAVAILABLE)
{
_bscf |= BSCF_LASTDATANOTIFICATION;
_bscf &= ~BSCF_FIRSTDATANOTIFICATION;
cbBytesReport = cbBytesAvailable + _cbTotalBytesRead;
if (IsEmbdFilterOk() )
{
_pEmbdFilter->ReportData(_bscf, cbBytesReport, _cbDataSize);
}
ReportResultAndStop(NOERROR, cbBytesReport, _cbDataSize);
}
else
{
_bscf |= BSCF_AVAILABLEDATASIZEUNKNOWN;
cbBytesReport = cbBytesAvailable + _cbTotalBytesRead;
if (_pCTrans && IsEmbdFilterOk() )
{
_cbSizeLastReportData = cbBytesReport;
hr = _pEmbdFilter->ReportData(_bscf, cbBytesReport, _cbDataSize);
}
}
if (_bscf & BSCF_FIRSTDATANOTIFICATION)
{
_bscf &= ~BSCF_FIRSTDATANOTIFICATION;
_bscf |= BSCF_INTERMEDIATEDATANOTIFICATION;
}
}
}
PerfDbgLog2(tagCINet, this, "-CINet::INetReadDirect (_hrError:%lx, hr:%lx)", _hrError, hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::ReadDirect
//
// Synopsis:
//
// Arguments: [pBuffer] --
// [cbBytes] --
// [pcbBytes] --
//
// Returns:
//
// History: 4-28-1997 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CINet::ReadDirect(BYTE *pBuffer, DWORD cbBytes, DWORD *pcbBytes)
{
DEBUG_ENTER((DBG_APP,
Hresult,
"CINet::ReadDirect",
"this=%#x, %#x, %#x, %#x",
this, pBuffer, cbBytes, pcbBytes
));
PerfDbgLog(tagCINet, this, "+CINet::ReadDirect");
HRESULT hr = NOERROR;
DWORD dwError;
*pcbBytes = 0;
ULONG dwReturned = 0;
//BUGBUG: turn this assertion on again
//PProtAssert((GetStatePending() == NOERROR));
if (_hrError == INET_E_DONE)
{
// means end of file
hr = S_FALSE;
}
else if (GetStatePending() != NOERROR)
{
hr = E_PENDING;
}
else
{
_hrError = INET_E_OK;
PProtAssert(((pBuffer != NULL) && (cbBytes > 0)));
//PerfDbgLog1(tagCINet, this, "CINet::ReadDirect -> InternetReadFile (dwBytesLeft:%ld)", dwBytesLeft);
LPINTERNET_BUFFERSA pIB = &_inetBufferSend;
pIB->dwStructSize = sizeof (INTERNET_BUFFERSA);
pIB->Next = 0;
pIB->lpcszHeader = 0;
pIB->dwHeadersLength = 0;
pIB->dwHeadersTotal = 0;
pIB->lpvBuffer = pBuffer;
pIB->dwBufferLength = cbBytes;
pIB->dwBufferTotal = 0;
pIB->dwOffsetLow = 0;
pIB->dwOffsetHigh = 0;
dwReturned = 0;
PProtAssert((GetStatePending() == NOERROR));
SetStatePending(E_PENDING);
if (!InternetReadFileExA(
_hRequest //IN HINTERNET hFile,
,pIB // OUT LPINTERNET_BUFFERSA lpBuffersOut,
,IRF_NO_WAIT // IN DWORD dwFlags,
,0 // IN DWORD dwContext
))
{
//
// async completion
//
dwError = GetLastError();
if (dwError != ERROR_IO_PENDING)
{
hr = _hrError = INET_E_DOWNLOAD_FAILURE;
DbgLog3(tagCINetErr, this, "CINet::ReadDirect failed: (dwError:%lx, hr:%lx, hrError:%lx)",
dwError, hr, _hrError);
}
else
{
hr = E_PENDING;
}
}
else
{
//
// sync completion
//
SetStatePending(NOERROR);
//
dwReturned = pIB->dwBufferLength;
_cbTotalBytesRead += dwReturned;
*pcbBytes = dwReturned;
PerfDbgLog3(tagCINet, this, "CINet::ReadDirect == InternetReadFileEx ==> (cbBytes:%ld, dwReturned:%ld,_cbTotalBytesRead:%ld)",
cbBytes, dwReturned,_cbTotalBytesRead);
if (dwReturned == 0)
{
// eof
hr = _hrError = INET_E_DONE;
//TransDebugOut((DEB_TRACE, "%p _IN CINetStream::INetSeek\n", this));
PProtAssert(( ( (_cbDataSize && (_cbDataSize == _cbTotalBytesRead))
|| (!_cbDataSize)) && "WinInet returned incorrent amount of data!!" ));
}
else
{
hr = NOERROR;
}
} // read case - bits available
*pcbBytes = dwReturned;
if (hr == INET_E_DONE)
{
hr = (dwReturned) ? S_OK : S_FALSE;
}
}
// Note: stop the download in case of DONE or ERROR!
if (_hrError != INET_E_OK)
{
ReportResultAndStop((hr == S_FALSE) ? NOERROR : hr);
}
PerfDbgLog4(tagCINet, this, "-CINet::ReadDirect (_hrError:%lx, [hr:%lx,cbBytesAsked:%ld,cbBytesReturned:%ld])",
_hrError, hr, cbBytes, *pcbBytes);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CINet::GetUserAgentString
//
// Synopsis:
//
// Arguments: [pBuffer] --
// [cbBytes] --
// [pcbBytes] --
//
// Returns:
//
// History: 4-28-1997 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
LPSTR CINet::GetUserAgentString()
{
DEBUG_ENTER((DBG_APP,
String,
"CINet::GetUserAgentString",
"this=%#x",
this
));
PerfDbgLog(tagCINet, this, "+CINet::GetUserAgentString");
HRESULT hr = NOERROR;
ULONG ulCount = 0;
LPWSTR pwzStr = 0;
LPSTR pszStr = 0;
hr = _pOIBindInfo->GetBindString(BINDSTRING_USER_AGENT, (LPWSTR *)&pwzStr, 1, &ulCount);
if ((hr == NOERROR) && ulCount)
{
PProtAssert((pwzStr));
delete _pszUserAgentStr;
pszStr = _pszUserAgentStr = DupW2A(pwzStr);
}
else
{
pszStr = (LPSTR)::GetUserAgentString();
}
PerfDbgLog1(tagCINet, this, "-CINet::GetUserAgentString (pszStr:%s)", pszStr);
DEBUG_LEAVE(pszStr);
return pszStr;
}
BOOL GlobalUTF8Enabled()
{
DEBUG_ENTER((DBG_APP,
Bool,
"GlobalUTF8Enabled",
NULL
));
// read the IE5 B2 global reg key
DWORD dwErr = ERROR_SUCCESS;
BOOL fRet = FALSE;
HKEY hKeyClient;
DWORD dwUTF8 = 0;
DWORD dwSize = sizeof(DWORD);
DWORD dwType;
dwErr = RegOpenKeyEx(
HKEY_CURRENT_USER,
INTERNET_POLICIES_KEY,
0,
KEY_QUERY_VALUE,
&hKeyClient
);
if( dwErr == ERROR_SUCCESS )
{
dwErr = RegQueryValueEx(
hKeyClient,
"EnableUTF8",
0,
&dwType,
(LPBYTE)&dwUTF8,
&dwSize
);
if( dwErr == ERROR_SUCCESS && dwUTF8 )
{
fRet = TRUE;
}
RegCloseKey(hKeyClient);
}
DEBUG_LEAVE(fRet);
return fRet;
}
// Enabled by adding a DWORD value "MBCSServername" with non=zero value under POLICY key
BOOL GlobalUTF8hackEnabled()
{
DEBUG_ENTER((DBG_APP,
Bool,
"GlobalUTF8hackEnabled",
NULL
));
DWORD dwErr = ERROR_SUCCESS;
BOOL fRet = TRUE;
HKEY hKeyClient;
DWORD dwUTF8 = 0;
DWORD dwSize = sizeof(DWORD);
DWORD dwType;
dwErr = RegOpenKeyEx(
HKEY_CURRENT_USER,
INTERNET_POLICIES_KEY,
0,
KEY_QUERY_VALUE,
&hKeyClient
);
if( dwErr == ERROR_SUCCESS )
{
dwErr = RegQueryValueEx(
hKeyClient,
"MBCSServername",
0,
&dwType,
(LPBYTE)&dwUTF8,
&dwSize
);
if( dwErr == ERROR_SUCCESS && !dwUTF8 )
{
fRet = FALSE;
}
RegCloseKey(hKeyClient);
}
DEBUG_LEAVE(fRet);
return fRet;
}