You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
692 lines
23 KiB
692 lines
23 KiB
/******************************************************************************
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
Connectivity
|
|
|
|
Abstract:
|
|
This file contains the implementation of the MPC::Connectitivy classes,
|
|
that are capable to check the real state of the connection with the internet.
|
|
|
|
Revision History:
|
|
Davide Massarenti (Dmassare) 10/19/2000
|
|
created
|
|
|
|
******************************************************************************/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include <process.h>
|
|
#include <wininet.h>
|
|
#include <Iphlpapi.h>
|
|
#include <Winsock2.h>
|
|
#include <inetreg.h>
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// This structure is defined in WinINET.h in terms of TCHAR, but it's wrong, it should be CHAR...
|
|
//
|
|
|
|
typedef struct {
|
|
|
|
//
|
|
// dwAccessType - INTERNET_OPEN_TYPE_DIRECT, INTERNET_OPEN_TYPE_PROXY, or
|
|
// INTERNET_OPEN_TYPE_PRECONFIG (set only)
|
|
//
|
|
|
|
DWORD dwAccessType;
|
|
|
|
//
|
|
// lpszProxy - proxy server list
|
|
//
|
|
|
|
LPCSTR lpszProxy;
|
|
|
|
//
|
|
// lpszProxyBypass - proxy bypass list
|
|
//
|
|
|
|
LPCSTR lpszProxyBypass;
|
|
} INTERNET_PROXY_INFOA;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static const WCHAR c_szIESettings [] = TSZWININETPATH;
|
|
static const WCHAR c_szIESettings_Proxy [] = REGSTR_VAL_PROXYSERVER;
|
|
static const WCHAR c_szIESettings_ProxyBypass[] = REGSTR_VAL_PROXYOVERRIDE;
|
|
|
|
static const WCHAR c_szIEConnections [] = TSZWININETPATH L"\\Connections";
|
|
static const WCHAR c_szIEConnections_Settings[] = L"DefaultConnectionSettings";
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static HRESULT local_GetDWORD( /*[in/out]*/ BYTE*& pBuf ,
|
|
/*[in/out]*/ DWORD& dwSize ,
|
|
/*[out ]*/ DWORD& dwValue )
|
|
{
|
|
if(dwSize < sizeof(DWORD)) return E_FAIL;
|
|
|
|
::CopyMemory( &dwValue, pBuf, sizeof(DWORD) );
|
|
|
|
dwSize -= sizeof(DWORD);
|
|
pBuf += sizeof(DWORD);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT local_GetSTRING( /*[in/out]*/ BYTE*& pBuf ,
|
|
/*[in/out]*/ DWORD& dwSize ,
|
|
/*[out ]*/ MPC::string& strValue )
|
|
{
|
|
DWORD dwLen;
|
|
HRESULT hr;
|
|
|
|
if(FAILED(hr = local_GetDWORD( pBuf, dwSize, dwLen ))) return hr;
|
|
|
|
if(dwSize < dwLen) return E_FAIL;
|
|
|
|
strValue.append( (char*)pBuf, (char*)&pBuf[dwLen] );
|
|
|
|
dwSize -= dwLen;
|
|
pBuf += dwLen;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT local_GetProxyData( /*[in ]*/ BYTE* pBuf ,
|
|
/*[in ]*/ DWORD dwSize ,
|
|
/*[out]*/ DWORD& dwCurrentSettingsVersion ,
|
|
/*[out]*/ DWORD& dwFlags ,
|
|
/*[out]*/ DWORD& dwAccessType ,
|
|
/*[out]*/ MPC::string& strProxy ,
|
|
/*[out]*/ MPC::string& strProxyBypass )
|
|
{
|
|
__MPC_FUNC_ENTRY( COMMONID, "MPC::Connectitivy::Proxy GetProxyData" );
|
|
|
|
|
|
HRESULT hr;
|
|
DWORD dwStructSize;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, local_GetDWORD( pBuf, dwSize, dwStructSize )); //if(dwStructSize != 0x3C) __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, local_GetDWORD( pBuf, dwSize, dwCurrentSettingsVersion ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, local_GetDWORD( pBuf, dwSize, dwFlags ));
|
|
|
|
if(dwFlags & PROXY_TYPE_PROXY)
|
|
{
|
|
dwAccessType = INTERNET_OPEN_TYPE_PROXY;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, local_GetSTRING( pBuf, dwSize, strProxy ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, local_GetSTRING( pBuf, dwSize, strProxyBypass ));
|
|
}
|
|
else if(dwFlags & PROXY_TYPE_DIRECT)
|
|
{
|
|
dwAccessType = INTERNET_OPEN_TYPE_DIRECT;
|
|
}
|
|
else
|
|
{
|
|
dwAccessType = INTERNET_OPEN_TYPE_PRECONFIG;
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__MPC_FUNC_CLEANUP;
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
dwAccessType = 0;
|
|
strProxy = "";
|
|
strProxyBypass = "";
|
|
}
|
|
|
|
__MPC_FUNC_EXIT(hr);
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
|
|
MPC::Connectivity::Proxy::Proxy()
|
|
{
|
|
m_fInitialized = false; // bool m_fInitialized;
|
|
//
|
|
// MPC::string m_strProxy;
|
|
// MPC::string m_strProxyBypass;
|
|
// CComHGLOBAL m_hgConnection;
|
|
}
|
|
|
|
MPC::Connectivity::Proxy::~Proxy()
|
|
{
|
|
}
|
|
|
|
////////////////////
|
|
|
|
HRESULT MPC::Connectivity::Proxy::Initialize( /*[in]*/ bool fImpersonate )
|
|
{
|
|
__MPC_FUNC_ENTRY( COMMONID, "MPC::Connectivity::Proxy::Initialize" );
|
|
|
|
HRESULT hr;
|
|
MPC::Impersonation imp;
|
|
MPC::RegKey rk;
|
|
DWORD dwSize;
|
|
DWORD dwType;
|
|
bool fFound;
|
|
|
|
|
|
if(fImpersonate)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, imp.Initialize ());
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, imp.Impersonate());
|
|
}
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, rk.SetRoot( HKEY_CURRENT_USER, KEY_READ ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, rk.Attach( c_szIESettings ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, rk.Read ( m_strProxy , fFound, c_szIESettings_Proxy ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, rk.Read ( m_strProxyBypass, fFound, c_szIESettings_ProxyBypass ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, rk.Attach ( c_szIEConnections ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, rk.ReadDirect( c_szIEConnections_Settings, m_hgConnection, dwSize, dwType, fFound ));
|
|
|
|
m_fInitialized = true;
|
|
hr = S_OK;
|
|
|
|
|
|
__MPC_FUNC_CLEANUP;
|
|
|
|
__MPC_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT MPC::Connectivity::Proxy::Apply( /*[in]*/ HINTERNET hSession )
|
|
{
|
|
__MPC_FUNC_ENTRY( COMMONID, "MPC::Connectivity::Proxy::Apply" );
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
if(m_fInitialized)
|
|
{
|
|
DWORD dwSize = m_hgConnection.Size();
|
|
|
|
if(m_strProxy.size() == 0 && dwSize)
|
|
{
|
|
DWORD dwCurrentSettingsVersion;
|
|
DWORD dwFlags;
|
|
DWORD dwAccessType;
|
|
LPVOID ptr = m_hgConnection.Lock();
|
|
|
|
if(FAILED(local_GetProxyData( (BYTE*)ptr, dwSize, dwCurrentSettingsVersion, dwFlags, dwAccessType, m_strProxy, m_strProxyBypass )))
|
|
{
|
|
//
|
|
// Autoproxy cannot be set using the API, so we copy the whole registry value...
|
|
//
|
|
MPC::RegKey rk;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, rk.SetRoot ( HKEY_CURRENT_USER, KEY_ALL_ACCESS ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, rk.Attach ( c_szIEConnections ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, rk.WriteDirect( c_szIEConnections_Settings, ptr, dwSize, REG_BINARY ));
|
|
}
|
|
|
|
m_hgConnection.Unlock();
|
|
}
|
|
|
|
if(m_strProxy.size())
|
|
{
|
|
INTERNET_PROXY_INFOA info;
|
|
|
|
info.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
|
|
info.lpszProxy = m_strProxy .c_str();
|
|
info.lpszProxyBypass = m_strProxyBypass.c_str(); if(info.lpszProxyBypass[0] == 0) info.lpszProxyBypass = NULL;
|
|
|
|
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::InternetSetOptionA( hSession, INTERNET_OPTION_PROXY, &info, sizeof(info) ));
|
|
}
|
|
}
|
|
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__MPC_FUNC_CLEANUP;
|
|
|
|
__MPC_FUNC_EXIT(hr);
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
|
|
HRESULT MPC::Connectivity::operator>>( /*[in]*/ MPC::Serializer& streamIn, /*[out]*/ MPC::Connectivity::Proxy& val )
|
|
{
|
|
__MPC_FUNC_ENTRY( COMMONID, "operator>> MPC::Connectivity::Proxy" );
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> val.m_fInitialized );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> val.m_strProxy );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> val.m_strProxyBypass);
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> val.m_hgConnection );
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__MPC_FUNC_CLEANUP;
|
|
|
|
__MPC_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT MPC::Connectivity::operator<<( /*[in]*/ MPC::Serializer& streamOut, /*[in ]*/ const MPC::Connectivity::Proxy& val )
|
|
{
|
|
__MPC_FUNC_ENTRY( COMMONID, "operator<< MPC::Connectivity::Proxy" );
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << val.m_fInitialized );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << val.m_strProxy );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << val.m_strProxyBypass);
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << val.m_hgConnection );
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__MPC_FUNC_CLEANUP;
|
|
|
|
__MPC_FUNC_EXIT(hr);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
MPC::Connectivity::WinInetTimeout::WinInetTimeout( /*[in]*/ MPC::CComSafeAutoCriticalSection& cs, /*[in]*/ HINTERNET& hReq ) : m_cs( cs ), m_hReq( hReq )
|
|
{
|
|
// MPC::CComSafeAutoCriticalSection& m_cs;
|
|
// HINTERNET& m_hReq;
|
|
m_hTimer = INVALID_HANDLE_VALUE; // HANDLE m_hTimer;
|
|
m_dwTimeout = 0; // DWORD m_dwTimeout;
|
|
//
|
|
// INTERNET_STATUS_CALLBACK m_PreviousCallback;
|
|
m_PreviousContext = NULL; // DWORD_PTR m_PreviousContext;
|
|
|
|
|
|
#ifdef _IA64_
|
|
m_PreviousCallback = INTERNET_INVALID_STATUS_CALLBACK;
|
|
#else
|
|
m_PreviousCallback = ::InternetSetStatusCallback( m_hReq, InternetStatusCallback );
|
|
if(m_PreviousCallback != INTERNET_INVALID_STATUS_CALLBACK)
|
|
{
|
|
DWORD_PTR dwContext = (DWORD_PTR)this;
|
|
DWORD dwSize = sizeof(m_PreviousContext);
|
|
|
|
::InternetQueryOptionW( m_hReq, INTERNET_OPTION_CONTEXT_VALUE, &m_PreviousContext, &dwSize );
|
|
::InternetSetOptionW ( m_hReq, INTERNET_OPTION_CONTEXT_VALUE, &dwContext , sizeof(dwContext) );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
MPC::Connectivity::WinInetTimeout::~WinInetTimeout()
|
|
{
|
|
if(m_hReq)
|
|
{
|
|
if(m_PreviousCallback != INTERNET_INVALID_STATUS_CALLBACK)
|
|
{
|
|
::InternetSetOptionW ( m_hReq, INTERNET_OPTION_CONTEXT_VALUE, &m_PreviousContext, sizeof(m_PreviousContext) );
|
|
::InternetSetStatusCallback( m_hReq, m_PreviousCallback );
|
|
}
|
|
}
|
|
|
|
(void)Reset();
|
|
}
|
|
|
|
VOID CALLBACK MPC::Connectivity::WinInetTimeout::TimerFunction( PVOID lpParameter, BOOLEAN TimerOrWaitFired )
|
|
{
|
|
WinInetTimeout* pThis = (WinInetTimeout*)lpParameter;
|
|
|
|
pThis->m_cs.Lock();
|
|
|
|
if(pThis->m_hReq)
|
|
{
|
|
::InternetCloseHandle( pThis->m_hReq ); pThis->m_hReq = NULL;
|
|
}
|
|
|
|
pThis->m_cs.Unlock();
|
|
}
|
|
|
|
VOID CALLBACK MPC::Connectivity::WinInetTimeout::InternetStatusCallback( HINTERNET hInternet ,
|
|
DWORD_PTR dwContext ,
|
|
DWORD dwInternetStatus ,
|
|
LPVOID lpvStatusInformation ,
|
|
DWORD dwStatusInformationLength )
|
|
{
|
|
WinInetTimeout* pThis = (WinInetTimeout*)dwContext;
|
|
|
|
pThis->m_cs.Lock();
|
|
|
|
if(dwInternetStatus == INTERNET_STATUS_DETECTING_PROXY)
|
|
{
|
|
pThis->InternalReset();
|
|
}
|
|
else
|
|
{
|
|
if(pThis->m_hTimer == INVALID_HANDLE_VALUE)
|
|
{
|
|
(void)pThis->InternalSet();
|
|
}
|
|
}
|
|
|
|
pThis->m_cs.Unlock();
|
|
}
|
|
|
|
HRESULT MPC::Connectivity::WinInetTimeout::InternalSet()
|
|
{
|
|
__MPC_FUNC_ENTRY( COMMONID, "MPC::Connectivity::WinInetTimeout::InternalSet" );
|
|
|
|
HRESULT hr;
|
|
|
|
if(m_dwTimeout)
|
|
{
|
|
if(m_hTimer != INVALID_HANDLE_VALUE)
|
|
{
|
|
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::ChangeTimerQueueTimer( NULL, m_hTimer, m_dwTimeout, 0 ));
|
|
}
|
|
else
|
|
{
|
|
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::CreateTimerQueueTimer( &m_hTimer, NULL, TimerFunction, this, m_dwTimeout, 0, WT_EXECUTEINTIMERTHREAD ));
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__MPC_FUNC_CLEANUP;
|
|
|
|
__MPC_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT MPC::Connectivity::WinInetTimeout::InternalReset()
|
|
{
|
|
__MPC_FUNC_ENTRY( COMMONID, "MPC::Connectivity::WinInetTimeout::InternalReset" );
|
|
|
|
HRESULT hr;
|
|
|
|
if(m_hTimer != INVALID_HANDLE_VALUE)
|
|
{
|
|
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::DeleteTimerQueueTimer( NULL, m_hTimer, INVALID_HANDLE_VALUE ));
|
|
|
|
m_hTimer = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__MPC_FUNC_CLEANUP;
|
|
|
|
__MPC_FUNC_EXIT(hr);
|
|
}
|
|
|
|
|
|
HRESULT MPC::Connectivity::WinInetTimeout::Set( /*[in]*/ DWORD dwTimeout )
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
m_cs.Lock();
|
|
|
|
if(SUCCEEDED(hr = InternalReset()))
|
|
{
|
|
m_dwTimeout = dwTimeout;
|
|
|
|
hr = InternalSet();
|
|
}
|
|
|
|
m_cs.Unlock();
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT MPC::Connectivity::WinInetTimeout::Reset()
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
m_cs.Lock();
|
|
|
|
if(SUCCEEDED(hr = InternalReset()))
|
|
{
|
|
m_dwTimeout = 0;
|
|
}
|
|
|
|
m_cs.Unlock();
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static WCHAR s_DefaultDestination[] = L"http://www.microsoft.com";
|
|
static LPCWSTR s_AcceptTypes [] = { L"*/*", NULL }; // */
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT MPC::Connectivity::NetworkAlive( /*[in]*/ DWORD dwTimeout, /*[in]*/ MPC::Connectivity::Proxy* pProxy )
|
|
{
|
|
//
|
|
// Try to contact Microsoft.
|
|
//
|
|
return DestinationReachable( s_DefaultDestination, dwTimeout, pProxy );
|
|
}
|
|
|
|
HRESULT MPC::Connectivity::DestinationReachable( /*[in]*/ LPCWSTR szDestination, /*[in]*/ DWORD dwTimeout, /*[in]*/ MPC::Connectivity::Proxy* pProxy )
|
|
{
|
|
__MPC_FUNC_ENTRY( COMMONID, "MPC::Connectivity::DestinationReachable" );
|
|
|
|
HRESULT hr;
|
|
MPC::URL url;
|
|
INTERNET_SCHEME nScheme;
|
|
MPC::wstring strScheme;
|
|
MPC::wstring strHostName;
|
|
DWORD dwPort;
|
|
MPC::wstring strUrlPath;
|
|
MPC::wstring strExtraInfo;
|
|
HINTERNET hInternet = NULL;
|
|
HINTERNET hConnect = NULL;
|
|
HINTERNET hOpenRequest = NULL;
|
|
DWORD dwLength;
|
|
DWORD dwStatus;
|
|
DWORD dwFlags;
|
|
|
|
|
|
|
|
__MPC_PARAMCHECK_BEGIN(hr)
|
|
__MPC_PARAMCHECK_STRING_NOT_EMPTY(szDestination);
|
|
__MPC_PARAMCHECK_END();
|
|
|
|
|
|
//
|
|
// If there's no connection or we are in offline more, abort.
|
|
//
|
|
{
|
|
DWORD dwConnMethod;
|
|
|
|
|
|
if(!::InternetGetConnectedState( &dwConnMethod, 0 ) ||
|
|
(dwConnMethod & INTERNET_CONNECTION_OFFLINE) )
|
|
{
|
|
__MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_INTERNET_DISCONNECTED);
|
|
}
|
|
}
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, url.put_URL( szDestination ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, url.get_Scheme ( nScheme ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, url.get_Scheme ( strScheme ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, url.get_HostName ( strHostName ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, url.get_Port ( dwPort )); if(!dwPort) dwPort = INTERNET_DEFAULT_HTTP_PORT;
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, url.get_Path ( strUrlPath ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, url.get_ExtraInfo( strExtraInfo )); strUrlPath += strExtraInfo;
|
|
|
|
//
|
|
// If not a supported URL, just exit.
|
|
//
|
|
if(strScheme .size() == 0 ||
|
|
strHostName.size() == 0 )
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG);
|
|
}
|
|
|
|
if(nScheme != INTERNET_SCHEME_HTTP &&
|
|
nScheme != INTERNET_SCHEME_HTTPS )
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG);
|
|
}
|
|
|
|
dwFlags = INTERNET_FLAG_NO_CACHE_WRITE |
|
|
INTERNET_FLAG_PRAGMA_NOCACHE |
|
|
INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | // ex: https:// to http://
|
|
INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS | // ex: http:// to https://
|
|
INTERNET_FLAG_IGNORE_CERT_DATE_INVALID | // expired X509 Cert.
|
|
INTERNET_FLAG_IGNORE_CERT_CN_INVALID ; // bad common name in X509 Cert.
|
|
|
|
if(nScheme == INTERNET_SCHEME_HTTPS)
|
|
{
|
|
dwFlags |= INTERNET_FLAG_SECURE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Get handle to a connection
|
|
//
|
|
__MPC_EXIT_IF_CALL_RETURNS_NULL(hr, (hInternet = ::InternetOpenW( L"HelpSupportServices" ,
|
|
INTERNET_OPEN_TYPE_PRECONFIG ,
|
|
NULL ,
|
|
NULL ,
|
|
0 )));
|
|
|
|
//
|
|
// Optional proxy settings override.
|
|
//
|
|
if(pProxy)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, pProxy->Apply( hInternet ));
|
|
}
|
|
|
|
//
|
|
// Connect
|
|
//
|
|
__MPC_EXIT_IF_CALL_RETURNS_NULL(hr, (hConnect = ::InternetConnectW( hInternet ,
|
|
strHostName.c_str() ,
|
|
dwPort ,
|
|
NULL ,
|
|
NULL ,
|
|
INTERNET_SERVICE_HTTP ,
|
|
INTERNET_FLAG_NO_UI ,
|
|
0 )));
|
|
|
|
|
|
for(int pass=0; pass<2; pass++)
|
|
{
|
|
//
|
|
// Create a request to get the header for the page.
|
|
//
|
|
__MPC_EXIT_IF_CALL_RETURNS_NULL(hr, (hOpenRequest = ::HttpOpenRequestW( hConnect ,
|
|
pass == 0 ? L"HEAD" : L"GET" ,
|
|
strUrlPath.c_str() ,
|
|
L"HTTP/1.0" , // 1.0 to get filesize and time
|
|
NULL , // referer
|
|
s_AcceptTypes ,
|
|
dwFlags ,
|
|
0 )));
|
|
|
|
//
|
|
// Because WinINET timeout support has always been broken, we have to use an external timer to close the request object. This effectively will abort the request.
|
|
//
|
|
{
|
|
MPC::CComSafeAutoCriticalSection cs;
|
|
MPC::Connectivity::WinInetTimeout to( cs, hOpenRequest );
|
|
|
|
if(dwTimeout != INFINITE)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, to.Set( dwTimeout ));
|
|
}
|
|
|
|
//
|
|
// Send request to get request
|
|
//
|
|
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::HttpSendRequestW( hOpenRequest, NULL, 0, NULL, 0 ));
|
|
}
|
|
|
|
if(hOpenRequest == NULL)
|
|
{
|
|
__MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_INTERNET_DISCONNECTED);
|
|
}
|
|
|
|
//
|
|
// We have sent the request so now check the status and see if the
|
|
// request returned a proper status code as a 32 bit number
|
|
//
|
|
dwLength = sizeof(dwStatus);
|
|
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::HttpQueryInfoW( hOpenRequest ,
|
|
HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER ,
|
|
(LPVOID)&dwStatus ,
|
|
&dwLength ,
|
|
NULL ));
|
|
|
|
//
|
|
// Check status and if not OK then fail. If the status is OK this means
|
|
// that the object/file is on the server and is reachable to be viewed
|
|
// by downloading to the user
|
|
//
|
|
if(dwStatus < 400) break;
|
|
|
|
if(pass == 1)
|
|
{
|
|
switch(dwStatus)
|
|
{
|
|
case HTTP_STATUS_BAD_REQUEST : break;
|
|
case HTTP_STATUS_DENIED : break;
|
|
case HTTP_STATUS_PAYMENT_REQ : break;
|
|
case HTTP_STATUS_FORBIDDEN : break;
|
|
case HTTP_STATUS_NOT_FOUND : __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_FILE_NOT_FOUND);
|
|
case HTTP_STATUS_BAD_METHOD : break;
|
|
case HTTP_STATUS_NONE_ACCEPTABLE : break;
|
|
case HTTP_STATUS_PROXY_AUTH_REQ : break;
|
|
case HTTP_STATUS_REQUEST_TIMEOUT : __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_INTERNET_DISCONNECTED);
|
|
case HTTP_STATUS_CONFLICT : break;
|
|
case HTTP_STATUS_GONE : __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_FILE_NOT_FOUND);
|
|
case HTTP_STATUS_LENGTH_REQUIRED : break;
|
|
case HTTP_STATUS_PRECOND_FAILED : break;
|
|
case HTTP_STATUS_REQUEST_TOO_LARGE: break;
|
|
case HTTP_STATUS_URI_TOO_LONG : break;
|
|
case HTTP_STATUS_UNSUPPORTED_MEDIA: break;
|
|
case HTTP_STATUS_RETRY_WITH : break;
|
|
|
|
case HTTP_STATUS_SERVER_ERROR : break;
|
|
case HTTP_STATUS_NOT_SUPPORTED : break;
|
|
case HTTP_STATUS_BAD_GATEWAY : __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_FILE_NOT_FOUND);
|
|
case HTTP_STATUS_SERVICE_UNAVAIL : __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_FILE_NOT_FOUND);
|
|
case HTTP_STATUS_GATEWAY_TIMEOUT : __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_INTERNET_DISCONNECTED);
|
|
case HTTP_STATUS_VERSION_NOT_SUP : break;
|
|
}
|
|
|
|
}
|
|
|
|
::InternetCloseHandle( hOpenRequest ); hOpenRequest = NULL;
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__MPC_FUNC_CLEANUP;
|
|
|
|
if(hOpenRequest) ::InternetCloseHandle( hOpenRequest );
|
|
if(hInternet ) ::InternetCloseHandle( hInternet );
|
|
if(hConnect ) ::InternetCloseHandle( hConnect );
|
|
|
|
__MPC_FUNC_EXIT(hr);
|
|
}
|