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.
4904 lines
122 KiB
4904 lines
122 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
autoprox.cxx
|
|
|
|
Abstract:
|
|
|
|
Contains class implementation for auto-proxy DLLs which can extent WININET's
|
|
abilities (logic) for deciding what proxies to use.
|
|
|
|
How auto-proxy works:
|
|
By offloading requests to a specialized Win32 Thread which picks
|
|
up queued up message requests for Queries, Shutdown, and Initialization
|
|
|
|
|
|
Contents:
|
|
InternetInitializeAutoProxyDll
|
|
AUTO_PROXY_DLLS::CheckForTimerConfigChanges
|
|
AUTO_PROXY_DLLS::DoNestedProxyInfoDownload
|
|
AUTO_PROXY_DLLS::SelectAutoProxyByMime
|
|
AUTO_PROXY_DLLS::SelectAutoProxyByFileExtension
|
|
AUTO_PROXY_DLLS::SelectAutoProxyByDefault
|
|
AUTO_PROXY_DLLS::ReadAutoProxyRegistrySettings
|
|
AUTO_PROXY_DLLS::IsAutoProxyEnabled
|
|
AUTO_PROXY_DLLS::IsAutoProxyGetProxyInfoCallNeeded
|
|
AUTO_PROXY_DLLS::QueueAsyncAutoProxyRequest
|
|
AUTO_PROXY_DLLS::ProcessProxyQueryForInfo
|
|
AUTO_PROXY_DLLS::SafeThreadShutdown
|
|
AUTO_PROXY_DLLS::DoThreadProcessing
|
|
AUTO_PROXY_DLLS::ProcessAsyncAutoProxyRequest
|
|
AUTO_PROXY_DLLS::SignalAsyncRequestCompleted
|
|
AUTO_PROXY_DLLS::FreeAutoProxyInfo
|
|
|
|
AUTO_PROXY_LIST_ENTRY::LoadEntry
|
|
AUTO_PROXY_LIST_ENTRY::GetProxyInfoEx
|
|
AUTO_PROXY_LIST_ENTRY::ProxyInfoInvalid
|
|
AUTO_PROXY_LIST_ENTRY::ProxyDllInit
|
|
AUTO_PROXY_LIST_ENTRY::ProxyDllDeInit
|
|
|
|
(MatchFileExtensionWithUrl)
|
|
(AutoProxyThreadFunc)
|
|
|
|
Author:
|
|
|
|
Arthur L Bierer (arthurbi) 17-Dec-1996
|
|
|
|
Revision History:
|
|
|
|
17-Dec-1996 arthurbi
|
|
Created
|
|
|
|
--*/
|
|
|
|
#include <wininetp.h>
|
|
#include "autodial.h"
|
|
#include "apdetect.h"
|
|
|
|
//
|
|
// definitions
|
|
//
|
|
|
|
#define DEFAULT_SCRIPT_BUFFER_SIZE 4000 // bytes.
|
|
|
|
//
|
|
// BUGBUG [arthurbi] This structures are shared between
|
|
// wininet.dll && jsproxy.dll, shouldn't we move them
|
|
// into a central file???
|
|
//
|
|
|
|
#define AUTO_PROXY_REG_FLAG_ALLOW_STRUC 0x0001
|
|
|
|
typedef struct {
|
|
|
|
//
|
|
// Size of struct
|
|
//
|
|
|
|
DWORD dwStructSize;
|
|
|
|
//
|
|
// Buffer to Pass
|
|
//
|
|
|
|
LPSTR lpszScriptBuffer;
|
|
|
|
//
|
|
// Size of buffer above
|
|
//
|
|
|
|
DWORD dwScriptBufferSize;
|
|
|
|
} AUTO_PROXY_EXTERN_STRUC, *LPAUTO_PROXY_EXTERN_STRUC;
|
|
|
|
|
|
//
|
|
// private templates
|
|
//
|
|
|
|
PRIVATE
|
|
BOOL
|
|
MatchFileExtensionWithUrl(
|
|
IN LPCSTR lpszFileExtensionList,
|
|
IN LPCSTR lpszUrl
|
|
);
|
|
|
|
|
|
//
|
|
// private vars
|
|
//
|
|
|
|
|
|
//
|
|
// functions
|
|
//
|
|
|
|
INTERNETAPI_(BOOL)
|
|
InternetInitializeAutoProxyDll(
|
|
DWORD dwReserved
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Stub to make INETCPL work. Since they expect to call this function.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
BOOL
|
|
TRUE - success
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
BOOL fSuccess;
|
|
DWORD error = ERROR_SUCCESS;
|
|
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
Bool,
|
|
"InternetInitializeAutoProxyDll",
|
|
""
|
|
));
|
|
|
|
if (!GlobalDataInitialized) {
|
|
error = GlobalDataInitialize();
|
|
}
|
|
if (error == ERROR_SUCCESS) {
|
|
GlobalProxyInfo.ClearBadProxyList();
|
|
FixProxySettingsForCurrentConnection(TRUE);
|
|
GlobalProxyInfo.RefreshProxySettings(TRUE);
|
|
}
|
|
|
|
fSuccess = (error == ERROR_SUCCESS ) ? TRUE : FALSE;
|
|
|
|
DEBUG_LEAVE(fSuccess);
|
|
|
|
return fSuccess;
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
AutoProxyThreadFunc(
|
|
LPVOID lpAutoProxyObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialization Win32 Proc called when the auto-proxy thread is started.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
ERROR_SUCCESS - success
|
|
|
|
Win32 Error code - failure
|
|
|
|
--*/
|
|
|
|
{
|
|
return GlobalProxyInfo.DoThreadProcessing(lpAutoProxyObject);
|
|
}
|
|
|
|
|
|
//
|
|
// methods
|
|
//
|
|
|
|
DWORD
|
|
AUTO_PROXY_DLLS::CheckForTimerConfigChanges(
|
|
IN DWORD dwMinsToPoll
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Exames the registry to see if a timer has been turned so
|
|
that we poll auto-proxy every so often to check for updates
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
ERROR_SUCCESS - success
|
|
|
|
Win32 Error code - failure
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD error = ERROR_SUCCESS;
|
|
DWORD dwReloadMins = dwMinsToPoll;
|
|
BOOL fEnableTimer = FALSE;
|
|
|
|
//
|
|
// Now check to determine if we have to enable the auto-proxy e
|
|
// this is used to force a re-download every "X" minutes.
|
|
//
|
|
|
|
if ( dwReloadMins != 0 )
|
|
{
|
|
if ( dwReloadMins > MAX_RELOAD_DELAY ) // too big?...
|
|
{
|
|
dwReloadMins = MAX_RELOAD_DELAY;
|
|
}
|
|
|
|
dwReloadMins *= ( 1000 * 60 ); // convert mins to miliseconds
|
|
fEnableTimer = TRUE;
|
|
}
|
|
|
|
//
|
|
// enable/disable timer for auto-proxy refresh.
|
|
//
|
|
|
|
ResetTimerCounter(
|
|
fEnableTimer, // TRUE/FALSE enable/disable
|
|
dwReloadMins // conv-ed already to msecs
|
|
);
|
|
|
|
error = ERROR_SUCCESS;
|
|
|
|
return error;
|
|
}
|
|
|
|
DWORD
|
|
AUTO_PROXY_DLLS::StartDownloadOfProxyInfo(
|
|
IN BOOL fForceRefresh
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Does the Overall download of proxy-information from an internally accessable Web Server.
|
|
Handles the case where we may have to redownload a secondary script also takes
|
|
care of launching detection for proxies.
|
|
|
|
Arguments:
|
|
|
|
fForceRefresh - TRUE if we are to attempt to refresh the auto-proxy URLs, and force a redection
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
ERROR_SUCCESS - success
|
|
|
|
Win32 Error code - failure
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD error = ERROR_SUCCESS;
|
|
BOOL fLocked = FALSE;
|
|
DWORD dwcbAutoConfigProxy = 0;
|
|
LPCSTR lpszAutoProxyUrl = NULL;
|
|
INTERNET_PROXY_INFO_EX ProxySettings;
|
|
BOOL fProxySettingsAlloced = FALSE;
|
|
BOOL fNeedRegWrite = FALSE;
|
|
BOOL fCachedDialupDetection = FALSE;
|
|
BOOL fNeedHostIPChk = FALSE;
|
|
|
|
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
Dword,
|
|
"AUTO_PROXY_DLLS::StartDownloadOfProxyInfo",
|
|
"%B",
|
|
fForceRefresh
|
|
));
|
|
|
|
|
|
if ( IsOffline() )
|
|
{
|
|
error = ERROR_INTERNET_OFFLINE;
|
|
goto quit;
|
|
}
|
|
|
|
LockAutoProxy();
|
|
fLocked = TRUE;
|
|
|
|
error = GetProxySettings(&ProxySettings);
|
|
|
|
if (error != ERROR_SUCCESS ) {
|
|
goto quit;
|
|
}
|
|
|
|
fProxySettingsAlloced = TRUE;
|
|
|
|
//
|
|
// Now read from the registry, closing any stale stuff that we may still have
|
|
// around. Do we still really need this? Lets only do this for Refresh cases.
|
|
//
|
|
|
|
if ( fForceRefresh )
|
|
{
|
|
DestroyAutoProxyDll(TRUE); // unloads DLLs and frees up reg vars.
|
|
SelectAutoProxy(NULL);
|
|
|
|
_Error = ReadAutoProxyRegistrySettings();
|
|
error = _Error;
|
|
|
|
if (error != ERROR_SUCCESS ||
|
|
!IsConfigValidForAutoProxyThread() )
|
|
{
|
|
SetState(AUTO_PROXY_DISABLED);
|
|
goto quit;
|
|
}
|
|
|
|
if ( GetState() == AUTO_PROXY_DISABLED )
|
|
{
|
|
INET_ASSERT(FALSE); // do we need this code?
|
|
goto quit;
|
|
}
|
|
}
|
|
|
|
//INET_ASSERT(GetState() == AUTO_PROXY_BLOCKED ||
|
|
// GetState() == AUTO_PROXY_PENDING);
|
|
|
|
fLocked = FALSE;
|
|
UnlockAutoProxy();
|
|
|
|
//
|
|
// Now begin the work, we should no longer need to touch the Proxy_DLL object
|
|
// settings until we grab the AutoProxy Lock again.
|
|
//
|
|
|
|
do
|
|
{
|
|
if ( IsProxyAutoDetectEnabled(&ProxySettings) )
|
|
{
|
|
CHAR szUrl[1024];
|
|
BOOL fRet;
|
|
DWORD dwDetectFlags = PROXY_AUTO_DETECT_TYPE_DNS_A;
|
|
|
|
|
|
if ( fForceRefresh ||
|
|
IsProxyAutoDetectNeeded(&ProxySettings) )
|
|
{
|
|
|
|
//
|
|
// Release Old Auto-config URL
|
|
//
|
|
|
|
if ( ProxySettings.lpszLastKnownGoodAutoConfigUrl) {
|
|
FREE_MEMORY(ProxySettings.lpszLastKnownGoodAutoConfigUrl);
|
|
ProxySettings.lpszLastKnownGoodAutoConfigUrl = NULL;
|
|
}
|
|
|
|
// only do dhcp on net connections
|
|
if ( ProxySettings.lpszConnectionName == NULL ) {
|
|
dwDetectFlags |= PROXY_AUTO_DETECT_TYPE_DHCP;
|
|
}
|
|
|
|
//
|
|
// Save out the Host IP addresses, before we start the detection,
|
|
// after the detection is complete, we confirm that we're still
|
|
// on the same set of Host IPs, in case the user switched connections.
|
|
//
|
|
|
|
error = GetHostAddresses(&(ProxySettings.pdwDetectedInterfaceIp),
|
|
&(ProxySettings.dwDetectedInterfaceIpCount));
|
|
|
|
if ( error != ERROR_SUCCESS) {
|
|
goto quit;
|
|
}
|
|
|
|
fNeedHostIPChk = TRUE; // because we've saved our IPs
|
|
|
|
//
|
|
// Do the actual Detection work
|
|
//
|
|
|
|
fRet = DetectAutoProxyUrl(
|
|
szUrl,
|
|
ARRAY_ELEMENTS(szUrl),
|
|
dwDetectFlags
|
|
);
|
|
|
|
GetCurrentGmtTime(&ProxySettings.ftLastKnownDetectTime); // mark when detection was run.
|
|
|
|
//
|
|
// Process the Results of detection.
|
|
//
|
|
|
|
if ( fRet )
|
|
{
|
|
ProxySettings.dwAutoDiscoveryFlags |= AUTO_PROXY_FLAG_DETECTION_RUN;
|
|
|
|
ProxySettings.lpszLastKnownGoodAutoConfigUrl = NewString(szUrl);
|
|
if ( ProxySettings.lpszLastKnownGoodAutoConfigUrl == NULL )
|
|
{
|
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto quit;
|
|
}
|
|
|
|
SetExpiredUrl(szUrl);
|
|
fNeedRegWrite = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Disable auto-detection, if we failed
|
|
//
|
|
|
|
if ( ! (ProxySettings.dwAutoDiscoveryFlags & (AUTO_PROXY_FLAG_DETECTION_RUN | AUTO_PROXY_FLAG_USER_SET)) )
|
|
{
|
|
ProxySettings.dwFlags &= ~(PROXY_TYPE_AUTO_DETECT);
|
|
}
|
|
|
|
ProxySettings.dwAutoDiscoveryFlags |= AUTO_PROXY_FLAG_DETECTION_RUN;
|
|
fNeedRegWrite = TRUE;
|
|
}
|
|
}
|
|
else if ( ProxySettings.lpszLastKnownGoodAutoConfigUrl != NULL &&
|
|
ProxySettings.lpszConnectionName != NULL )
|
|
|
|
{
|
|
//
|
|
// If we're not doing any detection, and we're on a dial-up adapter,
|
|
// then we should remember that fact, since we may be called upon
|
|
// to actually force a detect, in case the cached URL was stale/bad.
|
|
//
|
|
|
|
INET_ASSERT(! fForceRefresh );
|
|
|
|
fCachedDialupDetection = TRUE;
|
|
}
|
|
|
|
lpszAutoProxyUrl = ProxySettings.lpszLastKnownGoodAutoConfigUrl;
|
|
}
|
|
|
|
//
|
|
// Falback if we are unable to detect something
|
|
//
|
|
|
|
if ( lpszAutoProxyUrl == NULL &&
|
|
IsProxyAutoConfigEnabled(&ProxySettings))
|
|
{
|
|
lpszAutoProxyUrl = ProxySettings.lpszAutoconfigUrl;
|
|
}
|
|
|
|
//
|
|
// Do the actual download of the file
|
|
//
|
|
|
|
if (lpszAutoProxyUrl != NULL)
|
|
{
|
|
error = DoNestedProxyInfoDownload(lpszAutoProxyUrl, &ProxySettings, fForceRefresh);
|
|
|
|
if ( error != ERROR_SUCCESS )
|
|
{
|
|
|
|
//
|
|
// If we're cached + on a dialup, and we fail with the URL,
|
|
// then perhaps the URL/net is really expired.
|
|
//
|
|
|
|
if ( fCachedDialupDetection &&
|
|
! fForceRefresh )
|
|
{
|
|
fForceRefresh = TRUE;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Fallback to autoconfig if we failed and we were using
|
|
// auto-detect
|
|
//
|
|
|
|
if ( IsProxyAutoConfigEnabled(&ProxySettings) &&
|
|
lpszAutoProxyUrl != ProxySettings.lpszAutoconfigUrl &&
|
|
ProxySettings.lpszAutoconfigUrl != NULL )
|
|
{
|
|
lpszAutoProxyUrl = ProxySettings.lpszAutoconfigUrl;
|
|
error = DoNestedProxyInfoDownload(lpszAutoProxyUrl, &ProxySettings, fForceRefresh);
|
|
}
|
|
}
|
|
}
|
|
} while (FALSE);
|
|
|
|
LockAutoProxy();
|
|
fLocked = TRUE;
|
|
|
|
if (lpszAutoProxyUrl == NULL)
|
|
{
|
|
SetState(AUTO_PROXY_DISABLED);
|
|
goto quit;
|
|
}
|
|
else
|
|
{
|
|
// stamp version so we know we just ran detection
|
|
_dwUpdatedProxySettingsVersion =
|
|
ProxySettings.dwCurrentSettingsVersion;
|
|
SetState(AUTO_PROXY_ENABLED);
|
|
}
|
|
|
|
CheckForTimerConfigChanges(ProxySettings.dwAutoconfigReloadDelayMins);
|
|
|
|
quit:
|
|
|
|
if ( error != ERROR_SUCCESS )
|
|
{
|
|
if (!fLocked)
|
|
{
|
|
LockAutoProxy();
|
|
fLocked = TRUE;
|
|
}
|
|
|
|
SetState(AUTO_PROXY_DISABLED);
|
|
}
|
|
|
|
//
|
|
// Unlock the AutoProxy
|
|
//
|
|
|
|
if ( fLocked ) {
|
|
UnlockAutoProxy();
|
|
}
|
|
|
|
if ( fProxySettingsAlloced )
|
|
{
|
|
//
|
|
// We need to save results to registry,
|
|
// then stamp the version in our global we now we detected for this,
|
|
// and then finally clean up any allocated stuff.
|
|
//
|
|
|
|
SaveDetectedProxySettings(&ProxySettings, fNeedHostIPChk);
|
|
|
|
WipeProxySettings(&ProxySettings);
|
|
}
|
|
|
|
DEBUG_LEAVE(error);
|
|
|
|
return error;
|
|
}
|
|
|
|
DWORD
|
|
AUTO_PROXY_DLLS::DoNestedProxyInfoDownload(
|
|
IN LPCSTR lpszAutoProxy,
|
|
IN LPINTERNET_PROXY_INFO_EX lpProxySettings,
|
|
IN BOOL fForceRefresh
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Does the download of proxy-information from an internally accessable Web Server.
|
|
Handles the case where we may have to redownload a secondary script and then
|
|
calls on to DownloadProxyInfo to actually do the dirty work.
|
|
|
|
Arguments:
|
|
|
|
lpszAutoProxy - URL to download
|
|
|
|
lpProxySettings - active Proxy Settings Copy for auto-proxy thread.
|
|
|
|
fForceRefresh - force refresh of downloaded file
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
ERROR_SUCCESS - success
|
|
|
|
Win32 Error code - failure
|
|
|
|
--*/
|
|
|
|
{
|
|
LPCSTR lpszNestedAutoProxyUrl = NULL;
|
|
DWORD error;
|
|
|
|
_pTempProxySettings = lpProxySettings; // in case they reset proxy settings
|
|
|
|
if ( _fInAutoProxyThreadShutDown )
|
|
{
|
|
error = ERROR_INTERNET_SHUTDOWN;
|
|
goto quit;
|
|
|
|
}
|
|
|
|
//
|
|
// IEAK flag, don't retry INS file unless either one of the following:
|
|
// 1) INS URL is expired
|
|
// 2) caching INS run is disabled
|
|
// 3) we're not forcing a refresh
|
|
//
|
|
|
|
if ( !(lpProxySettings->dwAutoDiscoveryFlags & AUTO_PROXY_FLAG_CACHE_INIT_RUN ) ||
|
|
// !(ProxySettings.dwAutoDiscoveryFlags & AUTO_PROXY_FLAG_DETECTION_RUN ) ||
|
|
!fForceRefresh ||
|
|
IsExpiredUrl(lpszAutoProxy))
|
|
{
|
|
|
|
//
|
|
// Now do the actual download of the proxy info.
|
|
//
|
|
|
|
error =
|
|
DownloadProxyInfo(lpszAutoProxy, fForceRefresh);
|
|
|
|
if ( error != ERROR_SUCCESS )
|
|
{
|
|
goto quit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now check to determine if we have an overriding Auto-Proxy that
|
|
// supersides the one we just download. If we do, we will
|
|
// need to redownload auto-proxy
|
|
//
|
|
lpszNestedAutoProxyUrl = lpProxySettings->lpszAutoconfigSecondaryUrl;
|
|
|
|
if ( lpszNestedAutoProxyUrl )
|
|
{
|
|
//
|
|
// Success - now restart the download process for this special Url
|
|
//
|
|
|
|
error = DownloadProxyInfo(
|
|
lpszNestedAutoProxyUrl,
|
|
fForceRefresh
|
|
);
|
|
}
|
|
|
|
// fall through even in error
|
|
|
|
error = ERROR_SUCCESS;
|
|
|
|
quit:
|
|
|
|
INET_ASSERT(_pTempProxySettings);
|
|
_pTempProxySettings = NULL;
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
AUTO_PROXY_DLLS::DownloadProxyInfo(
|
|
IN LPCSTR lpszAutoProxy,
|
|
IN BOOL fForceRefresh
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Does the download of proxy-information from an internally accessable Web Server.
|
|
The data will be checked, written to a temp file, and then an associated
|
|
DLL will be called to handle it.
|
|
|
|
Arguments:
|
|
|
|
lpszUrl - The URL to download.
|
|
|
|
fForceRefresh - force file to be reloaded from the wire
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
ERROR_SUCCESS - success
|
|
|
|
Win32 Error code - failure
|
|
|
|
--*/
|
|
|
|
{
|
|
HINTERNET hInternet = NULL;
|
|
HINTERNET hRequest = NULL;
|
|
HANDLE hFile = NULL;
|
|
CHAR szTemporyFile[MAX_PATH+1];
|
|
DWORD dwTempFileSize;
|
|
|
|
HANDLE hLockHandle = NULL;
|
|
|
|
BOOL fSuccess;
|
|
DWORD error = ERROR_SUCCESS;
|
|
|
|
CHAR szBuffer[MAX_PATH+1];
|
|
DWORD dwBytesRead;
|
|
|
|
BOOL fCleanupFile = FALSE;
|
|
BOOL fLocked = FALSE;
|
|
BOOL fBuffering = FALSE;
|
|
|
|
LPSTR lpszScriptBuffer = NULL;
|
|
DWORD dwScriptBufferSize;
|
|
|
|
DWORD dwStatusCode = ERROR_SUCCESS;
|
|
DWORD cbSize = sizeof(DWORD);
|
|
int nRetries = 3; // Num auth attempts
|
|
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
Dword,
|
|
"AUTO_PROXY_DLLS::DownloadProxyInfo",
|
|
"%q",
|
|
lpszAutoProxy
|
|
));
|
|
|
|
INET_ASSERT(lpszAutoProxy);
|
|
|
|
//
|
|
// Fire up a mini InternetOpen/InternetOpenUrl to download a
|
|
// config file found on some internal server.
|
|
//
|
|
|
|
hInternet = InternetOpen(
|
|
(_lpszUserAgent) ? _lpszUserAgent : gszDefaultUserAgent,
|
|
INTERNET_OPEN_TYPE_DIRECT,
|
|
NULL,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
|
|
if ( !hInternet )
|
|
{
|
|
error = GetLastError();
|
|
INET_ASSERT(error != ERROR_SUCCESS);
|
|
goto quit;
|
|
}
|
|
|
|
|
|
do
|
|
{
|
|
hRequest = InternetOpenUrl(
|
|
hInternet,
|
|
lpszAutoProxy,
|
|
"Accept: */*\r\n",
|
|
(DWORD) -1,
|
|
(fForceRefresh ?
|
|
INTERNET_FLAG_RELOAD :
|
|
0) |
|
|
INTERNET_FLAG_NEED_FILE,
|
|
INTERNET_NO_CALLBACK
|
|
);
|
|
|
|
|
|
if ( !hRequest )
|
|
{
|
|
//error = ERROR_INTERNET_UNABLE_TO_DOWNLOAD_SCRIPT;
|
|
error = GetLastError();
|
|
if(GlobalDisplayScriptDownloadFailureUI && !GlobalIsProcessNtService)
|
|
{
|
|
InternetErrorDlg(
|
|
GetDesktopWindow(),
|
|
hRequest,
|
|
ERROR_INTERNET_UNABLE_TO_DOWNLOAD_SCRIPT,
|
|
FLAGS_ERROR_UI_FILTER_FOR_ERRORS,
|
|
NULL);
|
|
}
|
|
goto quit;
|
|
}
|
|
|
|
cbSize = sizeof(dwStatusCode);
|
|
if (HttpQueryInfo(
|
|
hRequest,
|
|
HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
|
|
(LPVOID) &dwStatusCode,
|
|
&cbSize,
|
|
NULL
|
|
) && HTTP_STATUS_DENIED == dwStatusCode)
|
|
{
|
|
if (GlobalIsProcessNtService)
|
|
{
|
|
error = ERROR_INTERNET_INTERNAL_ERROR;
|
|
goto quit;
|
|
}
|
|
|
|
// Check the status code and throw an InternetErrorDlg
|
|
// if auth is needed and try again.
|
|
if (InternetErrorDlg(
|
|
GetDesktopWindow(),
|
|
hRequest,
|
|
ERROR_INTERNET_INCORRECT_PASSWORD,
|
|
FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS,
|
|
NULL
|
|
) != ERROR_INTERNET_FORCE_RETRY)
|
|
{
|
|
nRetries = 0;
|
|
}
|
|
else
|
|
{
|
|
cbSize = sizeof(szBuffer);
|
|
HttpQueryInfo(
|
|
hRequest,
|
|
HTTP_QUERY_WWW_AUTHENTICATE,
|
|
(LPVOID) szBuffer,
|
|
&cbSize,
|
|
NULL
|
|
);
|
|
szBuffer[5]='\0';
|
|
if (!lstrcmpi(szBuffer, "Basic"))
|
|
{
|
|
HttpSendRequest(
|
|
hRequest,
|
|
"Accept: */*\r\n",
|
|
(DWORD)-1,
|
|
NULL,
|
|
0);
|
|
cbSize = sizeof(dwStatusCode);
|
|
if (HttpQueryInfo(
|
|
hRequest,
|
|
HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
|
|
(LPVOID) &dwStatusCode,
|
|
&cbSize,
|
|
NULL
|
|
) && HTTP_STATUS_DENIED == dwStatusCode)
|
|
{
|
|
InternetCloseHandle(hRequest);
|
|
}
|
|
else
|
|
{
|
|
GlobalAutoProxyNeedsInit = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
InternetCloseHandle(hRequest);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Call it good
|
|
GlobalAutoProxyNeedsInit = FALSE;
|
|
break;
|
|
}
|
|
} while ( --nRetries>0);
|
|
|
|
if(nRetries <= 0)
|
|
{
|
|
// Still haven't initialized.
|
|
GlobalAutoProxyNeedsInit = TRUE;
|
|
}
|
|
|
|
// Reset to success
|
|
error = ERROR_SUCCESS;
|
|
|
|
if(HTTP_STATUS_NOT_FOUND == dwStatusCode)
|
|
{
|
|
error = ERROR_INTERNET_UNABLE_TO_DOWNLOAD_SCRIPT;
|
|
if(GlobalDisplayScriptDownloadFailureUI && !GlobalIsProcessNtService)
|
|
{
|
|
InternetErrorDlg(
|
|
GetDesktopWindow(),
|
|
hRequest,
|
|
ERROR_INTERNET_UNABLE_TO_DOWNLOAD_SCRIPT,
|
|
FLAGS_ERROR_UI_FILTER_FOR_ERRORS,
|
|
NULL);
|
|
}
|
|
goto quit;
|
|
}
|
|
|
|
|
|
DWORD dwIndex;
|
|
DWORD dwTempSize;
|
|
|
|
dwIndex = 0;
|
|
dwTempSize = sizeof(dwScriptBufferSize);
|
|
|
|
dwScriptBufferSize = 0;
|
|
|
|
if ( ! HttpQueryInfo(hRequest,
|
|
(HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER),
|
|
(LPVOID) &dwScriptBufferSize,
|
|
&dwTempSize,
|
|
&dwIndex) )
|
|
{
|
|
// failure, just defaults
|
|
dwScriptBufferSize = DEFAULT_SCRIPT_BUFFER_SIZE;
|
|
fBuffering = TRUE;
|
|
}
|
|
else if ( dwScriptBufferSize > DEFAULT_SCRIPT_BUFFER_SIZE )
|
|
{
|
|
// success, but too big.
|
|
dwScriptBufferSize = DEFAULT_SCRIPT_BUFFER_SIZE;
|
|
fBuffering = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// success, and this one is just right.
|
|
fBuffering = TRUE;
|
|
}
|
|
|
|
lpszScriptBuffer = (LPSTR)
|
|
ALLOCATE_MEMORY(LMEM_FIXED, ((dwScriptBufferSize+1)
|
|
* sizeof(CHAR)));
|
|
|
|
if ( lpszScriptBuffer == NULL )
|
|
{
|
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto quit;
|
|
}
|
|
|
|
//
|
|
// pull down bytes, and write to file
|
|
//
|
|
|
|
DWORD dwBytes;
|
|
dwBytesRead = 0;
|
|
|
|
do
|
|
{
|
|
DWORD dwBytesLeft;
|
|
LPSTR lpszDest;
|
|
|
|
dwBytes = 0;
|
|
lpszDest = lpszScriptBuffer;
|
|
dwBytesLeft = dwScriptBufferSize;
|
|
|
|
fSuccess = InternetReadFile(
|
|
hRequest,
|
|
lpszDest,
|
|
dwBytesLeft,
|
|
&dwBytes
|
|
);
|
|
|
|
if ( ! fSuccess )
|
|
{
|
|
error = GetLastError();
|
|
goto quit;
|
|
}
|
|
|
|
if ( _fInAutoProxyThreadShutDown )
|
|
{
|
|
error = ERROR_INTERNET_SHUTDOWN;
|
|
goto quit;
|
|
}
|
|
|
|
if ( dwBytes > 0 )
|
|
{
|
|
if ( dwBytesRead > 0 )
|
|
{
|
|
fBuffering = FALSE;
|
|
}
|
|
|
|
dwBytesRead += dwBytes;
|
|
}
|
|
} while ( dwBytes != 0 );
|
|
|
|
//
|
|
// Figure out what kind of file we're dealing with.
|
|
// ONLY allow files with the correct extension or the correct MIME type.
|
|
//
|
|
|
|
szBuffer[0] = '\0';
|
|
dwBytes = ARRAY_ELEMENTS(szBuffer)-1;
|
|
|
|
fSuccess = HttpQueryInfo( hRequest,
|
|
HTTP_QUERY_CONTENT_TYPE,
|
|
szBuffer,
|
|
&dwBytes,
|
|
NULL );
|
|
|
|
fLocked = TRUE;
|
|
LockAutoProxy();
|
|
|
|
if ( !(fSuccess
|
|
&& SelectAutoProxyByMime(szBuffer)) )
|
|
{
|
|
if ( ! SelectAutoProxyByFileExtension(lpszAutoProxy) )
|
|
{
|
|
if ( ! SelectAutoProxyByDefault() )
|
|
{
|
|
//
|
|
// Could not find a registered handler for this data.
|
|
//
|
|
|
|
error = ERROR_INTERNET_BAD_AUTO_PROXY_SCRIPT;
|
|
goto quit;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now, launch the handler to tell them about the file.
|
|
// we downloaded it first.
|
|
//
|
|
|
|
AUTO_PROXY_LIST_ENTRY * papleAutoProxy;
|
|
AUTO_PROXY_EXTERN_STRUC apeStruct;
|
|
LPAUTO_PROXY_EXTERN_STRUC pExtraStruct;
|
|
|
|
|
|
papleAutoProxy = GetSelectedAutoProxyEntry();
|
|
pExtraStruct = NULL;
|
|
|
|
//
|
|
// Get a temp file from cache if we need it.
|
|
//
|
|
|
|
if ( fBuffering &&
|
|
(papleAutoProxy->_dwFlags & AUTO_PROXY_REG_FLAG_ALLOW_STRUC) &&
|
|
dwBytesRead > 0 )
|
|
{
|
|
// slam a \0 terminator
|
|
INET_ASSERT(dwBytesRead <= dwScriptBufferSize);
|
|
lpszScriptBuffer[dwBytesRead] = '\0';
|
|
|
|
pExtraStruct = &apeStruct;
|
|
apeStruct.dwStructSize = sizeof(AUTO_PROXY_EXTERN_STRUC);
|
|
apeStruct.lpszScriptBuffer = lpszScriptBuffer;
|
|
apeStruct.dwScriptBufferSize = dwBytesRead + 1;
|
|
}
|
|
else
|
|
{
|
|
fCleanupFile = TRUE;
|
|
|
|
//Qfe 3430: When parsing ins file, with reference to pac file, wininet needs to
|
|
//know the connectoid name in order to set the pac file correctly. Currently there
|
|
//is no way for wininet to pass the connectoid name to branding dll. To workaround
|
|
//this, we use the AUTO_PROXY_EXTERN_STRUC to pass the connectoid name in lpszScriptBuffer
|
|
//variable.
|
|
if(!(papleAutoProxy->_dwFlags & AUTO_PROXY_REG_FLAG_ALLOW_STRUC))
|
|
{
|
|
pExtraStruct = &apeStruct;
|
|
apeStruct.dwStructSize = sizeof(AUTO_PROXY_EXTERN_STRUC);
|
|
apeStruct.lpszScriptBuffer = GlobalProxyInfo.GetConnectionName();
|
|
}
|
|
|
|
if ( ! InternetLockRequestFile(hRequest, &hLockHandle) )
|
|
{
|
|
fCleanupFile = FALSE;
|
|
}
|
|
|
|
dwTempFileSize = MAX_PATH;
|
|
|
|
if ( ! InternetQueryOption(hRequest, INTERNET_OPTION_DATAFILE_NAME,
|
|
szTemporyFile, &dwTempFileSize ) ||
|
|
dwTempFileSize == 0 )
|
|
{
|
|
error = ERROR_INTERNET_BAD_AUTO_PROXY_SCRIPT;
|
|
goto quit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The loading and unloading of DLLs is owned/allowed
|
|
// only by the auto-proxy thread, ONCE THIS THREAD IS RUNNING
|
|
// so once we're here, we can be assured its safe to
|
|
// make the following calls without holding the crit sec.
|
|
//
|
|
|
|
INET_ASSERT(fLocked);
|
|
UnlockAutoProxy();
|
|
fLocked = FALSE;
|
|
fSuccess = TRUE;
|
|
|
|
//
|
|
// If we're not configured, or cannot match the URL
|
|
// with a Handler to actually run the script,
|
|
// then we need to error out
|
|
//
|
|
|
|
if ( papleAutoProxy == NULL)
|
|
{
|
|
error = ERROR_INTERNET_UNABLE_TO_DOWNLOAD_SCRIPT;
|
|
goto quit;
|
|
}
|
|
|
|
if ( ! papleAutoProxy->_hAutoConfigDLL )
|
|
{
|
|
if ( _fInAutoProxyThreadShutDown )
|
|
{
|
|
error = ERROR_INTERNET_SHUTDOWN;
|
|
goto quit;
|
|
}
|
|
|
|
error = papleAutoProxy->LoadEntry();
|
|
|
|
if ( error != ERROR_SUCCESS )
|
|
{
|
|
goto quit;
|
|
}
|
|
}
|
|
else if ( papleAutoProxy->_fInitializedSuccessfully &&
|
|
papleAutoProxy->_pProxyDllInit &&
|
|
papleAutoProxy->_pProxyDllDeInit )
|
|
{
|
|
//
|
|
// If this DLL has already been loaded,
|
|
// then unitialize it before re-initalizeing with
|
|
// new data, otherwise we risk leaking some its
|
|
// objects
|
|
//
|
|
|
|
papleAutoProxy->ProxyDllDeInit(
|
|
szBuffer,
|
|
0
|
|
);
|
|
INET_ASSERT(papleAutoProxy->_fUnInited);
|
|
}
|
|
|
|
//
|
|
// Make the call into the external DLL,
|
|
// and let it run, possibly initilization and doing a bunch
|
|
// of stuff.
|
|
//
|
|
|
|
|
|
fSuccess = papleAutoProxy->ProxyDllInit (
|
|
AUTO_PROXY_VERSION,
|
|
szTemporyFile, // temp file we down loaded
|
|
szBuffer, // mime
|
|
&_aphAutoProxyAPIs,
|
|
(DWORD_PTR) pExtraStruct
|
|
);
|
|
|
|
if ( _fInAutoProxyThreadShutDown )
|
|
{
|
|
error = ERROR_INTERNET_SHUTDOWN;
|
|
goto quit;
|
|
}
|
|
|
|
if ( ! fSuccess )
|
|
{
|
|
error = ERROR_INTERNET_BAD_AUTO_PROXY_SCRIPT;
|
|
goto quit;
|
|
}
|
|
|
|
|
|
if ( papleAutoProxy->IsGetProxyInfoEx() ||
|
|
papleAutoProxy->IsGetProxyInfo() )
|
|
{
|
|
SetState(AUTO_PROXY_ENABLED);
|
|
}
|
|
else
|
|
{
|
|
SetState(AUTO_PROXY_DISABLED);
|
|
}
|
|
|
|
quit:
|
|
|
|
if ( error != ERROR_SUCCESS )
|
|
{
|
|
if (!fLocked)
|
|
{
|
|
LockAutoProxy();
|
|
fLocked = TRUE;
|
|
}
|
|
|
|
SetState(AUTO_PROXY_DISABLED);
|
|
}
|
|
|
|
if ( fLocked )
|
|
{
|
|
UnlockAutoProxy();
|
|
}
|
|
|
|
if ( fCleanupFile )
|
|
{
|
|
InternetUnlockRequestFile(hLockHandle);
|
|
}
|
|
|
|
if ( lpszScriptBuffer )
|
|
{
|
|
FREE_MEMORY(lpszScriptBuffer);
|
|
}
|
|
|
|
if ( hRequest )
|
|
{
|
|
InternetCloseHandle(hRequest);
|
|
}
|
|
|
|
if ( hInternet )
|
|
{
|
|
InternetCloseHandle(hInternet);
|
|
}
|
|
|
|
SetAbortHandle(NULL);
|
|
|
|
DEBUG_LEAVE(error);
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
AUTO_PROXY_DLLS::IsAutoProxyEnabled(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines whether the auto-proxy thread is enabled and ready
|
|
to accept async proxy requests. This is needed to prevent
|
|
senceless calls to the auto-proxy thread when the request
|
|
could made more directly to the PROXY_INFO object.
|
|
|
|
Return Value:
|
|
|
|
BOOL
|
|
TRUE - the AutoProxy thread is accepting async requests
|
|
|
|
FALSE - the AutoProxy thread is refusung async requests.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL fIsGetProxyCallProxyNeeded = FALSE;
|
|
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
Bool,
|
|
"AUTO_PROXY_DLLS::IsAutoProxyEnabled",
|
|
""
|
|
));
|
|
|
|
|
|
LockAutoProxy();
|
|
|
|
//
|
|
// If we're downloading new information, OR we have a async thread ready to process
|
|
// autoproxy queries, then go async and do the request. The worst case will
|
|
// result in the async thread being created and then returning the request
|
|
// unprocessed ( the FSM will resubmit it to the general proxy code )
|
|
//
|
|
|
|
if ( GetState() == AUTO_PROXY_ENABLED ||
|
|
GetState() == AUTO_PROXY_BLOCKED ||
|
|
GetState() == AUTO_PROXY_PENDING )
|
|
{
|
|
fIsGetProxyCallProxyNeeded = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fIsGetProxyCallProxyNeeded = FALSE;
|
|
}
|
|
|
|
UnlockAutoProxy();
|
|
|
|
DEBUG_LEAVE(fIsGetProxyCallProxyNeeded);
|
|
|
|
return fIsGetProxyCallProxyNeeded;
|
|
}
|
|
|
|
|
|
BOOL
|
|
AUTO_PROXY_DLLS::IsAutoProxyGetProxyInfoCallNeeded(
|
|
IN AUTO_PROXY_ASYNC_MSG *pQueryForInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wrapper for IsAutoProxyEnabled, verifies that the message object (pQueryForInfo)
|
|
in question is capible of going async.
|
|
|
|
Arguments:
|
|
|
|
pQueryForInfo - Pointer to Message object that contains state information
|
|
used in the query.
|
|
|
|
Return Value:
|
|
|
|
BOOL
|
|
TRUE - the AutoProxy thread is accepting async requests
|
|
|
|
FALSE - the AutoProxy thread is refusung async requests.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
INET_ASSERT(pQueryForInfo);
|
|
|
|
//
|
|
// The caller has explicitly banned auto-proxy calls.
|
|
//
|
|
|
|
if ( pQueryForInfo->IsAvoidAsyncCall() )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// We cannot process this request to auto-proxy unless we have an URL
|
|
//
|
|
|
|
if ( ! pQueryForInfo->IsUrl() )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Now check to see if its really enabled.
|
|
//
|
|
|
|
return IsAutoProxyEnabled();
|
|
|
|
}
|
|
|
|
DWORD
|
|
AUTO_PROXY_DLLS::QueueAsyncAutoProxyRequest(
|
|
IN OUT AUTO_PROXY_ASYNC_MSG **ppQueryForInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Submits the *ppQueryForInfo Object on the async queue for processing
|
|
by the async auto-proxy thread.
|
|
|
|
Arguments:
|
|
|
|
ppQueryForInfo - Pointer to pointer to Message object that contains state information
|
|
used in the query. If the object needs to be allocated on the heap
|
|
then the pointer will change to reflect the new object ptr.
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
Success - ERROR_SUCCESS
|
|
|
|
Failure -
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();
|
|
BOOL fLocked = FALSE;
|
|
DWORD error = ERROR_SUCCESS;
|
|
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
Dword,
|
|
"AUTO_PROXY_DLLS::QueueAsyncAutoProxyRequest",
|
|
"%x",
|
|
ppQueryForInfo
|
|
));
|
|
|
|
|
|
//
|
|
// First allocate an object, if its not allocated,
|
|
// cause we can't pass local stack vars to another thread (duh..)
|
|
//
|
|
|
|
if ( ! (*ppQueryForInfo)->IsAlloced() )
|
|
{
|
|
*ppQueryForInfo = new AUTO_PROXY_ASYNC_MSG(*ppQueryForInfo);
|
|
|
|
if ( *ppQueryForInfo == NULL )
|
|
{
|
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto quit;
|
|
}
|
|
}
|
|
|
|
LockAutoProxy(); // lock object to prevent anyone messing with thread handles
|
|
fLocked = TRUE;
|
|
|
|
//
|
|
// Busy wait for thread to be shutdown before restarting.
|
|
//
|
|
|
|
while ( _fInAutoProxyThreadShutDown )
|
|
{
|
|
UnlockAutoProxy();
|
|
Sleep(100);
|
|
LockAutoProxy();
|
|
}
|
|
|
|
if ( _hAutoProxyThread == NULL )
|
|
{
|
|
|
|
_hAutoProxyThreadEvent = CreateEvent(
|
|
NULL, // pointer to security attributes
|
|
FALSE, // flag for manual-reset event
|
|
TRUE, // flag for initial state
|
|
NULL // event-object name
|
|
);
|
|
|
|
|
|
if ( _hAutoProxyThreadEvent == NULL )
|
|
{
|
|
error = GetLastError();
|
|
goto quit;
|
|
}
|
|
|
|
//
|
|
// We block on this event until the thread is actually running,
|
|
// otherwise we may PROCESS_DETEACH while the auto-proxy
|
|
// thread is in this quasi-state of having been created, but not actually run.
|
|
//
|
|
|
|
_hAutoProxyStartEvent = CreateEvent(
|
|
NULL, // pointer to security attributes
|
|
TRUE, // flag for manual-reset event
|
|
FALSE, // flag for initial state
|
|
NULL // event-object name
|
|
);
|
|
|
|
|
|
if ( _hAutoProxyStartEvent == NULL )
|
|
{
|
|
error = GetLastError();
|
|
goto quit;
|
|
}
|
|
|
|
ResetEvent(_hAutoProxyStartEvent);
|
|
|
|
_hAutoProxyThread = CreateThread(
|
|
NULL, // pointer to thread security attributes
|
|
0, // starting stack size
|
|
AutoProxyThreadFunc,
|
|
this, // argument
|
|
0, // flags
|
|
&_dwAutoProxyThreadId
|
|
);
|
|
|
|
|
|
if ( _hAutoProxyThread == NULL )
|
|
{
|
|
error = GetLastError();
|
|
CloseHandle(_hAutoProxyThreadEvent);
|
|
CloseHandle(_hAutoProxyStartEvent);
|
|
_hAutoProxyThreadEvent = NULL;
|
|
_hAutoProxyStartEvent = NULL;
|
|
goto quit;
|
|
}
|
|
|
|
const HANDLE aWaitHandles[2] = {_hAutoProxyStartEvent, _hAutoProxyThread};
|
|
|
|
// wait on the thread handle too in case it terminates for some unknown reason
|
|
error = WaitForMultipleObjects(ARRAYSIZE(aWaitHandles),
|
|
aWaitHandles,
|
|
FALSE,
|
|
INFINITE);
|
|
if ( error != WAIT_OBJECT_0 )
|
|
{
|
|
INET_ASSERT(FALSE);
|
|
TerminateThread(_hAutoProxyThread, ERROR_SUCCESS);
|
|
|
|
CloseHandle(_hAutoProxyThreadEvent);
|
|
CloseHandle(_hAutoProxyStartEvent);
|
|
CloseHandle(_hAutoProxyThread);
|
|
_hAutoProxyStartEvent = NULL;
|
|
_hAutoProxyThread = NULL;
|
|
_hAutoProxyThreadEvent = NULL;
|
|
_dwAutoProxyThreadId = NULL;
|
|
|
|
error = ERROR_INTERNET_INTERNAL_ERROR;
|
|
goto quit;
|
|
}
|
|
else
|
|
{
|
|
CloseHandle(_hAutoProxyStartEvent);
|
|
_hAutoProxyStartEvent = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Now Block the Thread we're on...
|
|
//
|
|
|
|
if ( (*ppQueryForInfo)->IsBlockUntilCompletetion() )
|
|
{
|
|
if ( lpThreadInfo &&
|
|
lpThreadInfo->Fsm &&
|
|
lpThreadInfo->IsAsyncWorkerThread &&
|
|
!(lpThreadInfo->Fsm->IsBlocking()))
|
|
{
|
|
//
|
|
// In a FSM, use FSM - thread pool handler to block this.
|
|
//
|
|
|
|
(*ppQueryForInfo)->SetBlockedOnFsm(TRUE);
|
|
|
|
lpThreadInfo->Fsm->SetState(FSM_STATE_CONTINUE);
|
|
lpThreadInfo->Fsm->SetNextState(FSM_STATE_CONTINUE);
|
|
|
|
error = BlockWorkItem(
|
|
lpThreadInfo->Fsm,
|
|
(DWORD_PTR) *ppQueryForInfo, // block the FSM on ourselves
|
|
INFINITE // we block foreever
|
|
);
|
|
|
|
|
|
if ( error != ERROR_SUCCESS )
|
|
{
|
|
goto quit;
|
|
}
|
|
|
|
InsertAtTailOfSerializedList(&_AsyncQueueList, &(*ppQueryForInfo)->_List);
|
|
SetEvent(_hAutoProxyThreadEvent);
|
|
|
|
error = ERROR_IO_PENDING;
|
|
}
|
|
else
|
|
{
|
|
AcquireBlockedRequestQueue();
|
|
|
|
InsertAtTailOfSerializedList(&_AsyncQueueList, &(*ppQueryForInfo)->_List);
|
|
SetEvent(_hAutoProxyThreadEvent);
|
|
|
|
UnlockAutoProxy();
|
|
fLocked = FALSE;
|
|
|
|
error = BlockThreadOnEvent(
|
|
(DWORD_PTR) *ppQueryForInfo,
|
|
INFINITE, // we need to block forever !
|
|
TRUE // release BlockedRequestQueue
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
InsertAtTailOfSerializedList(&_AsyncQueueList, &(*ppQueryForInfo)->_List);
|
|
SetEvent(_hAutoProxyThreadEvent);
|
|
}
|
|
|
|
quit:
|
|
|
|
if ( fLocked )
|
|
{
|
|
UnlockAutoProxy();
|
|
fLocked = FALSE;
|
|
}
|
|
|
|
DEBUG_LEAVE(error);
|
|
|
|
return error;
|
|
}
|
|
|
|
DWORD
|
|
AUTO_PROXY_DLLS::ProcessProxyQueryForInfo(
|
|
IN OUT AUTO_PROXY_ASYNC_MSG **ppQueryForInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs a query for proxy information using an external DLL's entry points to
|
|
anwser our query. If we are not on the correct thread, we call QueueAsyncAutoProxyRequest
|
|
to marshall our call across to it.
|
|
|
|
Arguments:
|
|
|
|
ppQueryForInfo - Pointer to pointer to Message object that contains state information
|
|
used in the query. If the object needs to be allocated on the heap
|
|
then the pointer will change to reflect the new object ptr.
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
Success - ERROR_SUCCESS
|
|
|
|
Failure -
|
|
|
|
--*/
|
|
|
|
{
|
|
AUTO_PROXY_LIST_ENTRY * papleAutoProxy;
|
|
DWORD error = ERROR_SUCCESS;
|
|
BOOL fUnlocked = FALSE;
|
|
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
Dword,
|
|
"AUTO_PROXY_DLLS::ProcessProxyQueryForInfo",
|
|
"%x",
|
|
ppQueryForInfo
|
|
));
|
|
|
|
|
|
INET_ASSERT(ppQueryForInfo);
|
|
INET_ASSERT(*ppQueryForInfo);
|
|
INET_ASSERT((*ppQueryForInfo)->QueryForInfoMessage() == PROXY_MSG_GET_PROXY_INFO);
|
|
INET_ASSERT(IsOnAsyncAutoProxyThread());
|
|
|
|
LockAutoProxy();
|
|
|
|
//
|
|
// this function should only ever be executed on the auto-proxy thread
|
|
//
|
|
|
|
if ( GetState() == AUTO_PROXY_DISABLED )
|
|
{
|
|
//
|
|
// Fall back to a normal proxy query.
|
|
//
|
|
|
|
(*ppQueryForInfo)->SetAvoidAsyncCall(TRUE);
|
|
goto quit;
|
|
}
|
|
|
|
papleAutoProxy =
|
|
GetSelectedAutoProxyEntry();
|
|
|
|
//
|
|
// We should be the only ones to create or destroy
|
|
// auto-proxy info, therefore we release the holly
|
|
// lock of auto-proxy. If I'm wrong another thread
|
|
// could cause us trouble ...
|
|
//
|
|
|
|
UnlockAutoProxy();
|
|
fUnlocked = TRUE;
|
|
|
|
if ( papleAutoProxy )
|
|
{
|
|
//
|
|
// If GetProxyInfoEx is supported, we defer to it to handle
|
|
// everything.
|
|
//
|
|
|
|
if ( papleAutoProxy->IsGetProxyInfoEx() )
|
|
{
|
|
error = papleAutoProxy->GetProxyInfoEx(
|
|
*ppQueryForInfo
|
|
);
|
|
|
|
goto quit;
|
|
}
|
|
else if ( papleAutoProxy->IsGetProxyInfo() )
|
|
{
|
|
error = papleAutoProxy->GetProxyInfo(
|
|
*ppQueryForInfo
|
|
);
|
|
|
|
goto quit;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Fall back to a normal proxy query.
|
|
//
|
|
|
|
(*ppQueryForInfo)->SetAvoidAsyncCall(TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Fall back to a normal proxy query.
|
|
//
|
|
|
|
(*ppQueryForInfo)->SetAvoidAsyncCall(TRUE);
|
|
}
|
|
|
|
|
|
quit:
|
|
|
|
if ( !fUnlocked )
|
|
{
|
|
UnlockAutoProxy();
|
|
}
|
|
|
|
DEBUG_LEAVE(error);
|
|
|
|
return error;
|
|
}
|
|
|
|
VOID
|
|
AUTO_PROXY_DLLS::SafeThreadShutdown(
|
|
BOOL fItsTheFinalShutDown
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs a shutdown of the auto-proxy thread by the auto-proxy thread itself.
|
|
|
|
Arguments:
|
|
|
|
fItsTheFinalShutDown - TRUE, if we are shutting down at the end of a process
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
None,
|
|
"AUTO_PROXY_DLLS::SafeThreadShutdown",
|
|
"%B",
|
|
fItsTheFinalShutDown
|
|
));
|
|
|
|
|
|
//
|
|
// Attempt to Shut down thread due to no-activity OR
|
|
// due to process shutdown.
|
|
//
|
|
|
|
LockAutoProxy();
|
|
|
|
if ( IsSerializedListEmpty(&_AsyncQueueList) ||
|
|
fItsTheFinalShutDown )
|
|
{
|
|
//HANDLE hAutoProxyThreadEvent = _hAutoProxyThreadEvent;
|
|
//HANDLE hAutoProxyThread = _hAutoProxyThread;
|
|
|
|
//_hAutoProxyThread = NULL;
|
|
//_hAutoProxyThreadEvent = NULL;
|
|
_dwAutoProxyThreadId = 0;
|
|
|
|
//CloseHandle(hAutoProxyThreadEvent);
|
|
//CloseHandle(hAutoProxyThread);
|
|
|
|
UnlockAutoProxy();
|
|
|
|
if ( fItsTheFinalShutDown )
|
|
{
|
|
//DestroyAutoProxyMsgQueue();
|
|
DestroyAutoProxyDll(TRUE); // unloads DLLs and frees up reg vars
|
|
}
|
|
|
|
DEBUG_LEAVE(0);
|
|
|
|
ExitThread(ERROR_SUCCESS);
|
|
|
|
INET_ASSERT(FALSE); //we will never get here...
|
|
}
|
|
|
|
UnlockAutoProxy();
|
|
|
|
DEBUG_LEAVE(0);
|
|
|
|
}
|
|
|
|
#define NLA_ERROR_RETRY_INTERVAL (5*60*1000)
|
|
|
|
class NLA_NET_CHANGE {
|
|
private:
|
|
HANDLE _hLookup;
|
|
WSAOVERLAPPED _ovlp;
|
|
DWORD _lastInitAttempt;
|
|
|
|
BOOLEAN
|
|
Initialize ();
|
|
|
|
BOOLEAN
|
|
EnumerateNetChanges ();
|
|
|
|
public:
|
|
NLA_NET_CHANGE () {
|
|
_ovlp.hEvent = NULL;
|
|
if (GlobalPlatformWhistler &&
|
|
_I_WSALookupServiceBeginW!=NULL) {
|
|
_hLookup = NULL;
|
|
_lastInitAttempt = GetTickCount ()-NLA_ERROR_RETRY_INTERVAL-1;
|
|
}
|
|
else {
|
|
#if DBG
|
|
dprintf ("NLA not available: whistler-%ld, lookup:-%#x\n",
|
|
GlobalPlatformWhistler, _I_WSALookupServiceBeginW);
|
|
#endif
|
|
_hLookup = INVALID_HANDLE_VALUE;
|
|
}
|
|
};
|
|
|
|
~NLA_NET_CHANGE () {
|
|
if (_hLookup!=NULL && _hLookup!=INVALID_HANDLE_VALUE) {
|
|
#if DBG
|
|
dprintf ("NLA - cleaning up");
|
|
#endif
|
|
_I_WSALookupServiceEnd (_hLookup);
|
|
CloseHandle (_ovlp.hEvent);
|
|
}
|
|
};
|
|
|
|
BOOLEAN
|
|
IsNetChanged () {
|
|
if (_hLookup!=INVALID_HANDLE_VALUE) {
|
|
if ((_hLookup!=NULL) ||
|
|
( ((GetTickCount ()-_lastInitAttempt)
|
|
>NLA_ERROR_RETRY_INTERVAL) &&
|
|
Initialize () ) ) {
|
|
if (HasOverlappedIoCompleted (&_ovlp)) {
|
|
#if DBG
|
|
dprintf ("NLA change detected, status:%lx\n",
|
|
_ovlp.Internal);
|
|
#endif
|
|
return EnumerateNetChanges ();
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
};
|
|
|
|
HANDLE
|
|
GetChangeEvent () {
|
|
return _ovlp.hEvent;
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
BOOLEAN
|
|
NLA_NET_CHANGE::Initialize (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes Network Location Awareness lookup query.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE - succes
|
|
FALSE - failure
|
|
|
|
--*/
|
|
{
|
|
WSAQUERYSETW qset;
|
|
GUID nlaServiceClassId = NLA_SERVICE_CLASS_GUID;
|
|
DWORD qSize;
|
|
INT error;
|
|
|
|
INET_ASSERT (_ovlp.hEvent==NULL);
|
|
INET_ASSERT (_hLookup==NULL);
|
|
|
|
//
|
|
// Create event for async notifications.
|
|
//
|
|
_ovlp.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
|
|
if (_ovlp.hEvent!=NULL) {
|
|
|
|
ZeroMemory (&qset, sizeof (qset));
|
|
qset.dwSize = sizeof (qset);
|
|
qset.lpServiceClassId = &nlaServiceClassId;
|
|
qset.dwNameSpace = NS_NLA;
|
|
|
|
if (_I_WSALookupServiceBeginW (
|
|
&qset,
|
|
LUP_RETURN_NAME|LUP_RETURN_BLOB,
|
|
&_hLookup)!=SOCKET_ERROR) {
|
|
DEBUG_PRINT (PROXY, INFO, ("Nla Lookup created\n"));
|
|
#if DBG
|
|
dprintf ("NLA Lookup created, handle:%#x\n", _hLookup);
|
|
#endif
|
|
|
|
//
|
|
// Just walk through the net list and setup notification.
|
|
//
|
|
return EnumerateNetChanges ();
|
|
|
|
}
|
|
else {
|
|
error = GetLastError ();
|
|
DEBUG_PRINT (PROXY, ERROR,
|
|
("NLA Lookup creation failed, err: %ld\n",
|
|
error));
|
|
#if DBG
|
|
dprintf ("NLA Lookup creation failed, err: %ld\n",error);
|
|
#endif
|
|
}
|
|
_hLookup = NULL;
|
|
CloseHandle (_ovlp.hEvent);
|
|
_ovlp.hEvent = NULL;
|
|
}
|
|
else {
|
|
error = GetLastError ();
|
|
DEBUG_PRINT (PROXY, ERROR,
|
|
("NLA notification event creation failed, err: %ld\n",
|
|
error));
|
|
#if DBG
|
|
dprintf ("NLA notification event creation failed, err: %ld\n",
|
|
error);
|
|
#endif
|
|
}
|
|
|
|
INET_ASSERT (error!=NO_ERROR);
|
|
|
|
//
|
|
// Remember when we failed, so we do not retry very often.
|
|
//
|
|
_lastInitAttempt = GetTickCountWrap ();
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
NLA_NET_CHANGE::EnumerateNetChanges (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enumerates Network entries returned by the NLA query.
|
|
If this is called after change notification, only
|
|
changes since last enumeration are returned.
|
|
|
|
Arguments:
|
|
None.
|
|
|
|
Return Value:
|
|
TRUE - there were any relevant changes
|
|
FALSE - no relevant changes.
|
|
|
|
--*/
|
|
{
|
|
DWORD error = NO_ERROR;
|
|
|
|
// Stack buffer which should be sufficient for most cases.
|
|
struct {
|
|
WSAQUERYSETW set;
|
|
WCHAR name[128];
|
|
NLA_BLOB blob;
|
|
} q;
|
|
LPWSAQUERYSETW pqSet = &q.set;
|
|
DWORD qSize = sizeof (q), retSize;
|
|
BOOLEAN changed = FALSE;
|
|
|
|
INET_ASSERT (_hLookup!=NULL && _hLookup!=INVALID_HANDLE_VALUE);
|
|
INET_ASSERT (_ovlp.hEvent!=NULL);
|
|
INET_ASSERT (HasOverlappedIoCompleted (&_ovlp));
|
|
|
|
do {// Outer loop - keep calling while we are getting notifications.
|
|
|
|
do {// Inner loop - keep calling while enumerating through networks.
|
|
retSize = qSize;
|
|
error = _I_WSALookupServiceNextW (
|
|
_hLookup,
|
|
0,
|
|
&retSize,
|
|
pqSet);
|
|
if (error!=SOCKET_ERROR) {
|
|
INET_ASSERT (error==NO_ERROR);
|
|
//
|
|
// Success, see if results in this query are relevant
|
|
//
|
|
DEBUG_PRINT (PROXY, INFO,
|
|
("NLA change for %ws-%lx\n",
|
|
pqSet->lpszServiceInstanceName,
|
|
pqSet->dwOutputFlags));
|
|
#if DBG
|
|
dprintf ("NLA change for %ws-%lx\n",
|
|
pqSet->lpszServiceInstanceName,
|
|
pqSet->dwOutputFlags);
|
|
#endif
|
|
if ((pqSet->lpBlob!=NULL) &&
|
|
(pqSet->lpBlob->pBlobData!=NULL) &&
|
|
(((LPNLA_BLOB)pqSet->lpBlob->pBlobData)->header.type==NLA_INTERFACE) ) {
|
|
#if DBG
|
|
dprintf (" type:%ld, speed:%ld, name: %s\n",
|
|
((LPNLA_BLOB)pqSet->lpBlob->pBlobData)->data.interfaceData.dwType,
|
|
((LPNLA_BLOB)pqSet->lpBlob->pBlobData)->data.interfaceData.dwSpeed,
|
|
((LPNLA_BLOB)pqSet->lpBlob->pBlobData)->data.interfaceData.adapterName);
|
|
#endif
|
|
changed = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
error = GetLastError ();
|
|
INET_ASSERT (error!=NO_ERROR);
|
|
if (error==WSAEFAULT) {
|
|
|
|
INET_ASSERT (qSize<retSize);
|
|
|
|
//
|
|
// Not enough space for query results.
|
|
// Allocate whatever is requested.
|
|
// First free what we have know is necessary.
|
|
//
|
|
if (pqSet!=NULL && pqSet!=&q.set) {
|
|
FREE_MEMORY (pqSet);
|
|
}
|
|
pqSet = (LPWSAQUERYSETW)ALLOCATE_MEMORY (LMEM_FIXED, retSize);
|
|
if (pqSet!=NULL) {
|
|
qSize = retSize;
|
|
error = NO_ERROR;
|
|
}
|
|
else {
|
|
DEBUG_PRINT (PROXY, ERROR,
|
|
("NLA - Failed to allocate %ld bytes for query\n",
|
|
retSize));
|
|
#if DBG
|
|
dprintf
|
|
("NLA - Failed to allocate %ld bytes for query\n",
|
|
retSize);
|
|
#endif
|
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while ( error==NO_ERROR );
|
|
|
|
if (error == WSA_E_NO_MORE) {
|
|
WSACOMPLETION wsacmpl;
|
|
DWORD count;
|
|
|
|
//
|
|
// This is expected error indicating that we got all that
|
|
// was available at the moment. Set up new notification.
|
|
//
|
|
wsacmpl.Type = NSP_NOTIFY_EVENT;
|
|
wsacmpl.Parameters.Event.lpOverlapped = &_ovlp;
|
|
error = _I_WSANSPIoctl (_hLookup, SIO_NSP_NOTIFY_CHANGE, NULL, 0, NULL, 0, &count, &wsacmpl);
|
|
if (error!=SOCKET_ERROR) {
|
|
//
|
|
// Something has changed, we need to enumerate again.
|
|
//
|
|
INET_ASSERT (error==NO_ERROR);
|
|
#if DBG
|
|
dprintf ("NLA notification signaled immediately");
|
|
#endif
|
|
}
|
|
else {
|
|
//
|
|
// Failure, get the error and get out.
|
|
//
|
|
error = GetLastError ();
|
|
INET_ASSERT (error!=NO_ERROR);
|
|
}
|
|
}
|
|
}
|
|
while (error==NO_ERROR);
|
|
|
|
if (pqSet!=NULL && pqSet!=&q.set) {
|
|
FREE_MEMORY (pqSet);
|
|
}
|
|
else {
|
|
INET_ASSERT (qSize==sizeof (q));
|
|
}
|
|
|
|
if (error!=WSA_IO_PENDING) {
|
|
DEBUG_PRINT (PROXY, ERROR,
|
|
("NLA - Failed to setup notification, error: %ld\n",
|
|
error));
|
|
#if DBG
|
|
dprintf (
|
|
"NLA - Failed to setup notification, error: %ld\n",
|
|
error);
|
|
#endif
|
|
//
|
|
// Error other then pending means that we failed.
|
|
// Cleanup everything - query will get recreated
|
|
// next time someone asks for changes.
|
|
//
|
|
CloseHandle (_ovlp.hEvent);
|
|
_ovlp.hEvent = NULL;
|
|
_I_WSALookupServiceEnd (_hLookup);
|
|
_hLookup = NULL;
|
|
//
|
|
// Remember when we failed, so we do not retry very often.
|
|
//
|
|
_lastInitAttempt = GetTickCountWrap ();
|
|
}
|
|
|
|
|
|
return changed;
|
|
}
|
|
|
|
|
|
DWORD
|
|
AUTO_PROXY_DLLS::DoThreadProcessing(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Main function for the auto-proxy thread, maintains a generic loop
|
|
that dispatchs events/messages sent to our thread for processing
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
DWORD error = ERROR_SUCCESS;
|
|
LPINTERNET_THREAD_INFO lpThreadInfo;
|
|
HANDLE EventArray[2];
|
|
NLA_NET_CHANGE nlaChange;
|
|
BOOLEAN needRefresh;
|
|
|
|
EventArray[0] = _hAutoProxyThreadEvent;
|
|
|
|
INET_ASSERT(IsOnAsyncAutoProxyThread());
|
|
INET_ASSERT(_hAutoProxyStartEvent);
|
|
|
|
SetEvent(_hAutoProxyStartEvent);
|
|
|
|
lpThreadInfo = InternetGetThreadInfo();
|
|
|
|
if (lpThreadInfo == NULL) {
|
|
error = ERROR_INTERNET_INTERNAL_ERROR;
|
|
goto quit;
|
|
}
|
|
|
|
//
|
|
// Mark ourselves as the Auto-proxy thread...
|
|
//
|
|
|
|
_InternetSetAutoProxy(lpThreadInfo);
|
|
|
|
while ( TRUE )
|
|
{
|
|
BOOLEAN networkChanged;
|
|
//
|
|
// 1. Check for shut down.
|
|
//
|
|
|
|
if ( _fInAutoProxyThreadShutDown )
|
|
{
|
|
SafeThreadShutdown(GlobalDynaUnload);
|
|
}
|
|
|
|
|
|
//
|
|
// 2. Check for timer causing a refresh of registry settings
|
|
// and network location changes,
|
|
// thus causing a redownload of settings
|
|
// Be carefull to call both functions since they have side-effects.
|
|
//
|
|
|
|
needRefresh = nlaChange.IsNetChanged ();
|
|
needRefresh = ChkForAndUpdateTimerCounter() || needRefresh;
|
|
if (needRefresh)
|
|
{
|
|
|
|
//
|
|
// Finally, start a download of the new stuff.
|
|
//
|
|
|
|
error = StartDownloadOfProxyInfo(FALSE /*full refresh*/);
|
|
}
|
|
|
|
//
|
|
// 3. Wait for new messages to come in,
|
|
// for shutdown we should pass right past it
|
|
//
|
|
|
|
|
|
error = WaitForMultipleObjects(
|
|
(EventArray[1]=nlaChange.GetChangeEvent())==NULL ? 1 : 2,
|
|
EventArray,
|
|
FALSE,
|
|
_dwWaitTimeOut
|
|
);
|
|
if (error==WAIT_OBJECT_0+1) {
|
|
//
|
|
// NLA change identified, skip processing, just redownload.
|
|
//
|
|
#if DBG
|
|
dprintf ("NLA change event signalled\n");
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
|
|
//
|
|
// 4. Check to see if we're ready to shut down the thread,
|
|
// due to a process termination or whatnot.
|
|
//
|
|
|
|
if ( _fInAutoProxyThreadShutDown )
|
|
{
|
|
SafeThreadShutdown(TRUE);
|
|
}
|
|
|
|
GlobalProxyInfo.CheckForExpiredEntries();
|
|
|
|
//
|
|
// 5. If we've idled let us shut down until we're needed again
|
|
//
|
|
|
|
//
|
|
// BUGBUG [arthurbi] Theoredically this should work,
|
|
// and the thread should shutdown on idle, too risky?
|
|
//
|
|
|
|
//if ( error == WAIT_FAILED && GetLastError() == WAIT_TIMEOUT)
|
|
//{
|
|
//SafeThreadShutdown(FALSE);
|
|
//}
|
|
|
|
//
|
|
// 6. Walk and process the list the messages to our thread asking for
|
|
// information or reinitalization
|
|
//
|
|
|
|
error = ProcessAsyncAutoProxyRequest();
|
|
|
|
INET_ASSERT( (error == ERROR_INTERNET_SHUTDOWN) ? _fInAutoProxyThreadShutDown : TRUE );
|
|
}
|
|
|
|
quit:
|
|
|
|
return error;
|
|
}
|
|
|
|
DWORD
|
|
AUTO_PROXY_DLLS::ProcessAsyncAutoProxyRequest(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Walks the list of queued messages and processes them one by one by
|
|
either rerunning the download/initalization or executing a query for
|
|
proxy information
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DWORD error = ERROR_SUCCESS;
|
|
BOOL fForceRefresh;
|
|
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
Dword,
|
|
"AUTO_PROXY_DLLS::ProcessAsyncAutoProxyRequest",
|
|
""
|
|
));
|
|
|
|
while (!IsSerializedListEmpty(&_AsyncQueueList)) {
|
|
|
|
//
|
|
// If we're shuting down, then quit right away
|
|
//
|
|
|
|
if ( _fInAutoProxyThreadShutDown )
|
|
{
|
|
error = ERROR_INTERNET_SHUTDOWN;
|
|
goto quit;
|
|
|
|
}
|
|
|
|
LPVOID entry = SlDequeueHead(&_AsyncQueueList);
|
|
AUTO_PROXY_ASYNC_MSG *pQueryForInfo =
|
|
CONTAINING_RECORD(entry, AUTO_PROXY_ASYNC_MSG, _List);
|
|
|
|
|
|
//
|
|
// If the request has been unblocked, then destroy
|
|
// the request. ( this is typically due to cancel )
|
|
//
|
|
|
|
if ( pQueryForInfo->IsBlockUntilCompletetion() )
|
|
{
|
|
DWORD dwBlockCnt;
|
|
|
|
if ( pQueryForInfo->IsBlockedOnFsm() )
|
|
{
|
|
|
|
dwBlockCnt = CheckForBlockedWorkItems(
|
|
1,
|
|
(DWORD_PTR) pQueryForInfo // blocked on message
|
|
);
|
|
|
|
if ( dwBlockCnt == 0 )
|
|
{
|
|
delete pQueryForInfo;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
switch ( pQueryForInfo->QueryForInfoMessage() )
|
|
{
|
|
case PROXY_MSG_INIT:
|
|
|
|
fForceRefresh = pQueryForInfo->IsForceRefresh();
|
|
|
|
//
|
|
// First peak ahead to make sure we're not asked to download
|
|
// the same darn thing over and over again.
|
|
//
|
|
|
|
while (!IsSerializedListEmpty(&_AsyncQueueList))
|
|
{
|
|
|
|
LPVOID entry = SlDequeueHead(&_AsyncQueueList);
|
|
AUTO_PROXY_ASYNC_MSG *pQueryForInfo =
|
|
CONTAINING_RECORD(entry, AUTO_PROXY_ASYNC_MSG, _List);
|
|
|
|
if ( pQueryForInfo->QueryForInfoMessage() == PROXY_MSG_INIT )
|
|
{
|
|
INET_ASSERT(!pQueryForInfo->IsBlockUntilCompletetion());
|
|
if ( pQueryForInfo->IsForceRefresh() ) {
|
|
fForceRefresh = TRUE;
|
|
}
|
|
delete pQueryForInfo;
|
|
}
|
|
else
|
|
{
|
|
InsertAtHeadOfSerializedList(&_AsyncQueueList, &pQueryForInfo->_List);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Finally, start a download of the new stuff.
|
|
//
|
|
|
|
if ( error == ERROR_SUCCESS )
|
|
{
|
|
error = StartDownloadOfProxyInfo(fForceRefresh);
|
|
}
|
|
|
|
if ( error == ERROR_INTERNET_SHUTDOWN )
|
|
{
|
|
goto quit;
|
|
}
|
|
|
|
break;
|
|
|
|
case PROXY_MSG_SELF_DESTRUCT:
|
|
|
|
//
|
|
// Destroy ourselves and AUTO_PROXY_DLLS object.
|
|
//
|
|
//
|
|
|
|
SafeThreadShutdown(TRUE);
|
|
|
|
INET_ASSERT(FALSE); // never returns...
|
|
|
|
break;
|
|
|
|
|
|
case PROXY_MSG_GET_PROXY_INFO:
|
|
|
|
//
|
|
// If we've been updated then we need refresh settings from
|
|
// the net.
|
|
//
|
|
|
|
if ( (_dwUpdatedProxySettingsVersion != _ProxySettings.dwCurrentSettingsVersion) )
|
|
{
|
|
error = StartDownloadOfProxyInfo(FALSE /* no full refresh*/);
|
|
}
|
|
|
|
|
|
//
|
|
// The strait call into GetProxyInfo
|
|
//
|
|
|
|
error = ProcessProxyQueryForInfo(
|
|
&pQueryForInfo
|
|
);
|
|
|
|
if ( error == ERROR_INTERNET_SHUTDOWN )
|
|
{
|
|
goto quit;
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case PROXY_MSG_SET_BAD_PROXY:
|
|
case PROXY_MSG_DEINIT:
|
|
case PROXY_MSG_INVALID:
|
|
default:
|
|
|
|
INET_ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Wake up the caller if they are blocking on this completeion
|
|
//
|
|
|
|
if ( pQueryForInfo->IsBlockUntilCompletetion() )
|
|
{
|
|
SignalAsyncRequestCompleted(pQueryForInfo); // the thread that gets woken up now owns the object
|
|
}
|
|
else
|
|
{
|
|
delete pQueryForInfo;
|
|
}
|
|
}
|
|
|
|
quit:
|
|
|
|
DEBUG_LEAVE(error);
|
|
|
|
return error;
|
|
}
|
|
|
|
DWORD
|
|
AUTO_PROXY_DLLS::SignalAsyncRequestCompleted(
|
|
IN AUTO_PROXY_ASYNC_MSG *pQueryForInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Notifies a blocked thread or FSM that we have completed its message based request and
|
|
it now can continue.
|
|
|
|
Arguments:
|
|
|
|
pQueryForInfo - the orginating request
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwCntUnBlocked;
|
|
|
|
INET_ASSERT ( pQueryForInfo );
|
|
|
|
if ( pQueryForInfo->IsBlockedOnFsm() )
|
|
{
|
|
dwCntUnBlocked = UnblockWorkItems(
|
|
1,
|
|
(DWORD_PTR) pQueryForInfo, // blocked on message
|
|
ERROR_SUCCESS,
|
|
TP_NO_PRIORITY_CHANGE
|
|
);
|
|
|
|
//
|
|
// If we were unable to unblock it, then we need to free it.
|
|
//
|
|
|
|
if ( dwCntUnBlocked == 0 )
|
|
{
|
|
delete pQueryForInfo;
|
|
pQueryForInfo = NULL;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
dwCntUnBlocked = SignalThreadOnEvent(
|
|
(DWORD_PTR) pQueryForInfo, // blocked on message
|
|
1, // should only be one item thats blocked by us
|
|
ERROR_SUCCESS
|
|
);
|
|
|
|
//if ( dwCntUnBlocked == 0 )
|
|
//{
|
|
// delete pQueryForInfo;
|
|
// pQueryForInfo = NULL;
|
|
//}
|
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
AUTO_PROXY_DLLS::WipeProxySettings(
|
|
LPINTERNET_PROXY_INFO_EX lpProxySettings
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees proxy settings
|
|
|
|
Arguments:
|
|
|
|
lpProxySettings - pointer to listing of proxy settings
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
if ( lpProxySettings )
|
|
{
|
|
if ( lpProxySettings->lpszConnectionName ) {
|
|
FREE_MEMORY(lpProxySettings->lpszConnectionName);
|
|
}
|
|
|
|
if ( lpProxySettings->lpszProxy ) {
|
|
FREE_MEMORY(lpProxySettings->lpszProxy);
|
|
}
|
|
|
|
if ( lpProxySettings->lpszProxyBypass ) {
|
|
FREE_MEMORY(lpProxySettings->lpszProxyBypass);
|
|
}
|
|
|
|
if ( lpProxySettings->lpszLastKnownGoodAutoConfigUrl ) {
|
|
FREE_MEMORY(lpProxySettings->lpszLastKnownGoodAutoConfigUrl);
|
|
}
|
|
|
|
if (lpProxySettings->lpszAutoconfigUrl) {
|
|
FREE_MEMORY(lpProxySettings->lpszAutoconfigUrl);
|
|
}
|
|
|
|
if (lpProxySettings->lpszAutoconfigSecondaryUrl) {
|
|
FREE_MEMORY(lpProxySettings->lpszAutoconfigSecondaryUrl);
|
|
}
|
|
|
|
if (lpProxySettings->pdwDetectedInterfaceIp) {
|
|
FREE_MEMORY(lpProxySettings->pdwDetectedInterfaceIp);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
DWORD
|
|
AUTO_PROXY_DLLS::SetProxySettings(
|
|
IN LPINTERNET_PROXY_INFO_EX lpProxySettings,
|
|
IN BOOL fModifiedInProcess,
|
|
IN BOOL fAllowOverwrite
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write Auto-proxy Settings on the current auto-proxy object,
|
|
this writes the settings into the object, but does not
|
|
refresh it.
|
|
|
|
Arguments:
|
|
|
|
lpProxySettings - List of new settings that we'd like to write
|
|
|
|
fAllowOverwrite - Allow update of the settings in the object even if the version counter
|
|
hasn't changed
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
ERROR_SUCCESS - if we have a valid proxy config
|
|
|
|
other-errors - if we were not able to make the settings
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
DWORD error = ERROR_SUCCESS;
|
|
BOOL fGoPending = FALSE;
|
|
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
Dword,
|
|
"AUTO_PROXY_DLLS::SetProxySettings",
|
|
"%x %B, %B",
|
|
lpProxySettings,
|
|
fModifiedInProcess,
|
|
fAllowOverwrite
|
|
));
|
|
|
|
LockAutoProxy();
|
|
|
|
if ( fAllowOverwrite ||
|
|
lpProxySettings->dwCurrentSettingsVersion == _ProxySettings.dwCurrentSettingsVersion )
|
|
{
|
|
BOOL fConnectionNameChange = FALSE;
|
|
|
|
_fModifiedInProcess = fModifiedInProcess;
|
|
|
|
UPDATE_GLOBAL_PROXY_VERSION();
|
|
|
|
//
|
|
// Check to see if we're changing the connection name,
|
|
// if so than this means we should plan on resetting
|
|
// the version below, so that we can redetect the new
|
|
// connection.
|
|
//
|
|
|
|
if ( ! IsConnectionMatch(
|
|
_ProxySettings.lpszConnectionName,
|
|
lpProxySettings->lpszConnectionName))
|
|
{
|
|
fConnectionNameChange = TRUE;
|
|
}
|
|
|
|
WipeProxySettings();
|
|
|
|
_ProxySettings = *lpProxySettings;
|
|
|
|
if ( fModifiedInProcess ) {
|
|
// update version, only if we don't plan to write out these settings
|
|
_ProxySettings.dwCurrentSettingsVersion++;
|
|
}
|
|
|
|
//
|
|
// minus -1 so that when we get to the auto-proxy thread,
|
|
// we can reload/detect or do what's needed to keep settings current
|
|
//
|
|
|
|
if ( _dwUpdatedProxySettingsVersion != _ProxySettings.dwCurrentSettingsVersion ||
|
|
_dwUpdatedProxySettingsVersion == 0 /* init state */ ||
|
|
fConnectionNameChange /* connection switch */ )
|
|
{
|
|
_dwUpdatedProxySettingsVersion = (DWORD) (_ProxySettings.dwCurrentSettingsVersion - 1);
|
|
fGoPending = TRUE;
|
|
}
|
|
|
|
//
|
|
// we shouldn't care about these settings,
|
|
// but we need to copy them anyway in
|
|
// case we save the stuff to the registry store
|
|
//
|
|
|
|
_ProxySettings.lpszProxy =
|
|
lpProxySettings->lpszProxy ?
|
|
NewString(lpProxySettings->lpszProxy) :
|
|
NULL;
|
|
|
|
_ProxySettings.lpszProxyBypass =
|
|
lpProxySettings->lpszProxyBypass ?
|
|
NewString(lpProxySettings->lpszProxyBypass) :
|
|
NULL;
|
|
|
|
_ProxySettings.lpszConnectionName =
|
|
lpProxySettings->lpszConnectionName ?
|
|
NewString(lpProxySettings->lpszConnectionName) :
|
|
NULL;
|
|
|
|
|
|
//
|
|
// Copy strings, cause we may be on another thread
|
|
//
|
|
|
|
_ProxySettings.lpszAutoconfigUrl =
|
|
lpProxySettings->lpszAutoconfigUrl ?
|
|
NewString(lpProxySettings->lpszAutoconfigUrl) :
|
|
NULL;
|
|
|
|
_ProxySettings.lpszAutoconfigSecondaryUrl =
|
|
lpProxySettings->lpszAutoconfigSecondaryUrl ?
|
|
NewString(lpProxySettings->lpszAutoconfigSecondaryUrl) :
|
|
NULL;
|
|
|
|
_ProxySettings.lpszLastKnownGoodAutoConfigUrl =
|
|
lpProxySettings->lpszLastKnownGoodAutoConfigUrl ?
|
|
NewString(lpProxySettings->lpszLastKnownGoodAutoConfigUrl) :
|
|
NULL;
|
|
|
|
//
|
|
// Copy of IP host addresses from last detection
|
|
//
|
|
|
|
if ( lpProxySettings->dwDetectedInterfaceIpCount > 0 &&
|
|
lpProxySettings->pdwDetectedInterfaceIp != NULL )
|
|
{
|
|
_ProxySettings.pdwDetectedInterfaceIp = (LPDWORD)
|
|
ALLOCATE_MEMORY(LMEM_FIXED, lpProxySettings->dwDetectedInterfaceIpCount
|
|
* sizeof(DWORD));
|
|
|
|
if (_ProxySettings.pdwDetectedInterfaceIp == NULL )
|
|
{
|
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto quit;
|
|
}
|
|
|
|
memcpy(_ProxySettings.pdwDetectedInterfaceIp, lpProxySettings->pdwDetectedInterfaceIp,
|
|
lpProxySettings->dwDetectedInterfaceIpCount * sizeof(DWORD));
|
|
}
|
|
|
|
|
|
if (fGoPending &&
|
|
IsConfigValidForAutoProxyThread())
|
|
{
|
|
//
|
|
// Enable a forced refresh if the user orders it through the UI,
|
|
// for unknown new connections we don't block the user on auto-detect,
|
|
// since he didn't really order it
|
|
//
|
|
|
|
if ( IsStaticFallbackEnabled() ) {
|
|
SetState(AUTO_PROXY_PENDING);
|
|
} else {
|
|
SetState(AUTO_PROXY_BLOCKED);
|
|
}
|
|
}
|
|
}
|
|
|
|
quit:
|
|
|
|
UnlockAutoProxy();
|
|
|
|
DEBUG_LEAVE(error);
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
DWORD
|
|
AUTO_PROXY_DLLS::GetProxySettings(
|
|
OUT LPINTERNET_PROXY_INFO_EX lpProxySettings,
|
|
IN BOOL fCheckVersion
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads Auto-proxy Settings off the current auto-proxy object,
|
|
this allocates individual fields as needed to store the result
|
|
|
|
Arguments:
|
|
|
|
lpProxySettings - Returns the result of the auto-proxy settings
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
ERROR_SUCCESS - if we have a valid proxy config
|
|
|
|
other-errors - if we were not able to make the settings
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD error = ERROR_SUCCESS;
|
|
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
Dword,
|
|
"AUTO_PROXY_DLLS::GetProxySettings",
|
|
"%x %B",
|
|
lpProxySettings
|
|
));
|
|
|
|
LockAutoProxy();
|
|
|
|
if ( fCheckVersion &&
|
|
lpProxySettings->dwCurrentSettingsVersion == _ProxySettings.dwCurrentSettingsVersion )
|
|
{
|
|
goto quit; // no change
|
|
}
|
|
|
|
|
|
*lpProxySettings = _ProxySettings;
|
|
|
|
//
|
|
// Copy strings, cause we may be on another thread
|
|
//
|
|
|
|
lpProxySettings->lpszProxy =
|
|
_ProxySettings.lpszProxy ?
|
|
NewString(_ProxySettings.lpszProxy) :
|
|
NULL;
|
|
|
|
lpProxySettings->lpszProxyBypass =
|
|
_ProxySettings.lpszProxyBypass ?
|
|
NewString(_ProxySettings.lpszProxyBypass) :
|
|
NULL;
|
|
|
|
lpProxySettings->lpszConnectionName =
|
|
_ProxySettings.lpszConnectionName ?
|
|
NewString(_ProxySettings.lpszConnectionName) :
|
|
NULL;
|
|
|
|
lpProxySettings->lpszAutoconfigUrl =
|
|
_ProxySettings.lpszAutoconfigUrl ?
|
|
NewString(_ProxySettings.lpszAutoconfigUrl) :
|
|
NULL;
|
|
|
|
lpProxySettings->lpszAutoconfigSecondaryUrl =
|
|
_ProxySettings.lpszAutoconfigSecondaryUrl ?
|
|
NewString(_ProxySettings.lpszAutoconfigSecondaryUrl) :
|
|
NULL;
|
|
|
|
lpProxySettings->lpszLastKnownGoodAutoConfigUrl =
|
|
_ProxySettings.lpszLastKnownGoodAutoConfigUrl ?
|
|
NewString(_ProxySettings.lpszLastKnownGoodAutoConfigUrl) :
|
|
NULL;
|
|
|
|
//
|
|
// Copy of IP host addresses from last detection
|
|
//
|
|
|
|
if ( _ProxySettings.dwDetectedInterfaceIpCount > 0 &&
|
|
_ProxySettings.pdwDetectedInterfaceIp != NULL )
|
|
{
|
|
lpProxySettings->pdwDetectedInterfaceIp = (LPDWORD)
|
|
ALLOCATE_MEMORY(LMEM_FIXED, _ProxySettings.dwDetectedInterfaceIpCount
|
|
* sizeof(DWORD));
|
|
|
|
if (lpProxySettings->pdwDetectedInterfaceIp == NULL )
|
|
{
|
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto quit;
|
|
}
|
|
|
|
memcpy(lpProxySettings->pdwDetectedInterfaceIp, _ProxySettings.pdwDetectedInterfaceIp,
|
|
_ProxySettings.dwDetectedInterfaceIpCount * sizeof(DWORD));
|
|
}
|
|
|
|
quit:
|
|
|
|
UnlockAutoProxy();
|
|
|
|
DEBUG_LEAVE(error);
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
DWORD
|
|
AUTO_PROXY_DLLS::RefreshProxySettings(
|
|
IN BOOL fForceRefresh
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Syncronizes the Auto-Proxy engine with the state of the various settings,
|
|
and updates the various state keepers of the results.
|
|
|
|
- If there is no proxy settings, or auto-proxy is not needed or not detected,
|
|
we disable the auto-proxy system.
|
|
|
|
- If we have auto-proxy information or need to detect for some, then we fire up
|
|
the auto-proxy thread and send it a message to initalize itself.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
ERROR_SUCCESS - success
|
|
|
|
Win32 Error code - failure
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
DWORD error = ERROR_SUCCESS;
|
|
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
Dword,
|
|
"AUTO_PROXY_DLLS::RefreshProxySettings",
|
|
"%B",
|
|
fForceRefresh
|
|
));
|
|
|
|
LockAutoProxy();
|
|
|
|
if (! IsOnAsyncAutoProxyThread() )
|
|
{
|
|
AUTO_PROXY_ASYNC_MSG *pQueryForInfo;
|
|
|
|
error = _Error;
|
|
if ( error != ERROR_SUCCESS)
|
|
{
|
|
goto quit; // obj is not initalized properly
|
|
}
|
|
|
|
if (!IsConfigValidForAutoProxyThread() )
|
|
{
|
|
goto quit; // disable & bail, we're not setup for this
|
|
}
|
|
|
|
pQueryForInfo = new AUTO_PROXY_ASYNC_MSG(PROXY_MSG_INIT);
|
|
|
|
if (pQueryForInfo == NULL )
|
|
{
|
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto quit;
|
|
}
|
|
|
|
//
|
|
// Enabled a forced refresh if the user orders it through the UI,
|
|
// for unknown new connections we don't block the user on auto-detect,
|
|
// since he didn't really order it
|
|
//
|
|
|
|
pQueryForInfo->SetForceRefresh(fForceRefresh);
|
|
|
|
if ( !fForceRefresh && IsStaticFallbackEnabled() ) {
|
|
SetState(AUTO_PROXY_PENDING);
|
|
} else {
|
|
SetState(AUTO_PROXY_BLOCKED);
|
|
}
|
|
|
|
error = QueueAsyncAutoProxyRequest(
|
|
&pQueryForInfo // don't worry, this request won't block us.
|
|
);
|
|
}
|
|
|
|
quit:
|
|
|
|
if ( error != ERROR_SUCCESS &&
|
|
error != ERROR_IO_PENDING )
|
|
{
|
|
SetState(AUTO_PROXY_DISABLED); // disable in case something critical happens
|
|
}
|
|
|
|
UnlockAutoProxy();
|
|
|
|
DEBUG_LEAVE(error);
|
|
|
|
return error;
|
|
}
|
|
|
|
DWORD
|
|
AUTO_PROXY_DLLS::StartBackroundDetectionIfNeeded(
|
|
VOID
|
|
)
|
|
{
|
|
DWORD error = ERROR_SUCCESS;
|
|
|
|
LockAutoProxy();
|
|
if ( _hAutoProxyThread == NULL ) {
|
|
error = RefreshProxySettings(FALSE);
|
|
}
|
|
UnlockAutoProxy();
|
|
|
|
return error;
|
|
}
|
|
|
|
DWORD
|
|
AUTO_PROXY_DLLS::QueryProxySettings(
|
|
IN OUT AUTO_PROXY_ASYNC_MSG **ppQueryForInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs a query for proxy information using auto-proxy to anwser our query.
|
|
|
|
Assumes this is not called from auto-proxy thread/
|
|
|
|
Arguments:
|
|
|
|
ppQueryForInfo - Pointer to pointer to Message object that contains state information
|
|
used in the query. If the object needs to be allocated on the heap
|
|
then the pointer will change to reflect the new object ptr.
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
Success - ERROR_SUCCESS
|
|
|
|
Failure -
|
|
|
|
--*/
|
|
|
|
{
|
|
AUTO_PROXY_LIST_ENTRY * papleAutoProxy;
|
|
DWORD error = ERROR_SUCCESS;
|
|
BOOL fUnlocked = FALSE;
|
|
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
Dword,
|
|
"AUTO_PROXY_DLLS::QueryProxySettings",
|
|
"%x",
|
|
ppQueryForInfo
|
|
));
|
|
|
|
|
|
INET_ASSERT(ppQueryForInfo);
|
|
INET_ASSERT(*ppQueryForInfo);
|
|
INET_ASSERT((*ppQueryForInfo)->QueryForInfoMessage() == PROXY_MSG_GET_PROXY_INFO);
|
|
//INET_ASSERT(!IsOnAsyncAutoProxyThread());
|
|
|
|
LockAutoProxy();
|
|
|
|
//
|
|
// ALWAYS force this function to exec it auto-proxy calls on the
|
|
// async auto-proxy thread.
|
|
//
|
|
|
|
if ( IsAutoProxy() &&
|
|
!IsOnAsyncAutoProxyThread() &&
|
|
IsAutoProxyGetProxyInfoCallNeeded(*ppQueryForInfo))
|
|
{
|
|
if ( GetState() == AUTO_PROXY_PENDING )
|
|
{
|
|
|
|
//
|
|
// If we're doing a pending detection, then
|
|
// fallback to standby settings, and if we fail
|
|
// with standby settings, we should get re-called to here
|
|
// and if we're then still detecting, then
|
|
// we'll block on the detection result
|
|
//
|
|
|
|
if ( ! (*ppQueryForInfo)->IsBackroundDetectionPending() )
|
|
{
|
|
error = StartBackroundDetectionIfNeeded();
|
|
if (error != ERROR_SUCCESS ) {
|
|
goto quit;
|
|
}
|
|
(*ppQueryForInfo)->SetBackroundDetectionPending(TRUE);
|
|
if ( ! (*ppQueryForInfo)->IsAlloced() )
|
|
{
|
|
*ppQueryForInfo = new AUTO_PROXY_ASYNC_MSG(*ppQueryForInfo);
|
|
|
|
if ( *ppQueryForInfo == NULL ) {
|
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
goto quit;
|
|
}
|
|
}
|
|
else if (!(_ProxySettings.dwAutoDiscoveryFlags & AUTO_PROXY_FLAG_DONT_CACHE_PROXY_RESULT) &&
|
|
GlobalAutoProxyCacheEnable)
|
|
{
|
|
(*ppQueryForInfo)->SetCanCacheResult(TRUE);
|
|
}
|
|
|
|
//
|
|
// If we need to show indication during detection,
|
|
// then do so now before we block
|
|
//
|
|
|
|
if ( (*ppQueryForInfo)->IsShowIndication() &&
|
|
(GetState() == AUTO_PROXY_PENDING ||
|
|
GetState() == AUTO_PROXY_BLOCKED))
|
|
{
|
|
UnlockAutoProxy();
|
|
fUnlocked = TRUE;
|
|
|
|
InternetIndicateStatus(INTERNET_STATUS_DETECTING_PROXY, NULL, 0);
|
|
}
|
|
else
|
|
{
|
|
UnlockAutoProxy();
|
|
fUnlocked = TRUE;
|
|
}
|
|
|
|
// always disable unless we're ready to renter on a failure
|
|
(*ppQueryForInfo)->SetBackroundDetectionPending(FALSE);
|
|
|
|
error = QueueAsyncAutoProxyRequest(ppQueryForInfo);
|
|
goto quit;
|
|
}
|
|
|
|
// always disabled it unless we're ready to reenter on a failure
|
|
(*ppQueryForInfo)->SetBackroundDetectionPending(FALSE);
|
|
|
|
quit:
|
|
|
|
if ( !fUnlocked )
|
|
{
|
|
UnlockAutoProxy();
|
|
}
|
|
|
|
DEBUG_LEAVE(error);
|
|
|
|
return error;
|
|
}
|
|
|
|
BOOL
|
|
AUTO_PROXY_DLLS::IsConfigValidForAutoProxyThread(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Decide if we need the auto-thread to either download auto-proxy ot
|
|
go off and detect for auto-proxy on the network
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
BOOL
|
|
TRUE - if we have a valid proxy config
|
|
|
|
FALSE - if we not valid
|
|
|
|
--*/
|
|
|
|
{
|
|
LPINTERNET_PROXY_INFO_EX lpProxySettings = &_ProxySettings;
|
|
|
|
if ( (lpProxySettings->dwFlags & PROXY_TYPE_AUTO_PROXY_URL) &&
|
|
lpProxySettings->lpszAutoconfigUrl != NULL &&
|
|
*lpProxySettings->lpszAutoconfigUrl != '\0' )
|
|
{
|
|
return TRUE; // old behavior for auto-proxy URL config
|
|
}
|
|
|
|
if ( IsProxyAutoDetectEnabled(lpProxySettings))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE; // do nothing
|
|
}
|
|
|
|
BOOL
|
|
AUTO_PROXY_DLLS::IsStaticFallbackEnabled(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Decide if we need to block on the auto-proxy information,
|
|
or if we can fallback to static settings when auto-proxy is initalizing/detecting.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
BOOL
|
|
TRUE - if we keep going with static settings
|
|
|
|
FALSE - we'll need to block requests until auto-proxy is intialized
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
if ( (_ProxySettings.dwFlags & PROXY_TYPE_AUTO_PROXY_URL) &&
|
|
_ProxySettings.lpszAutoconfigUrl != NULL &&
|
|
*_ProxySettings.lpszAutoconfigUrl != '\0' )
|
|
{
|
|
return FALSE; // block, don't bypass, this is old behavior for Auto-proxy URLs
|
|
}
|
|
|
|
if ( IsProxyAutoDetectEnabled() )
|
|
|
|
{
|
|
if ( !(_ProxySettings.dwAutoDiscoveryFlags & (AUTO_PROXY_FLAG_DETECTION_RUN | AUTO_PROXY_FLAG_USER_SET)) ) {
|
|
return TRUE; // detection SHOULD NOT BLOCK THE FIRST TIME, in case it doesn't work
|
|
}
|
|
|
|
if ( _ProxySettings.lpszConnectionName != NULL )
|
|
{
|
|
if ( _ProxySettings.lpszLastKnownGoodAutoConfigUrl == NULL )
|
|
{
|
|
return TRUE; // detection SHOULD NOT BE DEPENDED upon with Dialup, unless it has something
|
|
}
|
|
|
|
if ( _ProxySettings.dwAutoDiscoveryFlags & AUTO_PROXY_FLAG_DETECTION_SUSPECT)
|
|
{
|
|
return TRUE; // detection should not block when we're in a hosed state.
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return FALSE; // block
|
|
}
|
|
|
|
VOID
|
|
AUTO_PROXY_DLLS::SetExpiredUrl(
|
|
LPCSTR lpszUrl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets default expiry time on the if none is specified on the cached URL.
|
|
|
|
Arguments:
|
|
|
|
lpszUrl -
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
ERROR_SUCCESS - success
|
|
|
|
Win32 Error code - failure
|
|
|
|
--*/
|
|
{
|
|
CACHE_ENTRY_INFOEX Cei;
|
|
DWORD dwCeiSize = sizeof(INTERNET_CACHE_ENTRY_INFOA);
|
|
BOOL fRet;
|
|
|
|
fRet = GetUrlCacheEntryInfoExA(
|
|
lpszUrl,
|
|
(INTERNET_CACHE_ENTRY_INFOA *) &Cei,
|
|
&dwCeiSize,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
INTERNET_CACHE_FLAG_GET_STRUCT_ONLY
|
|
);
|
|
|
|
|
|
if ( fRet &&
|
|
(FT2LL(Cei.ExpireTime) == LONGLONG_ZERO))
|
|
{
|
|
//
|
|
// Set default expiry as: current time + some default expiry
|
|
//
|
|
|
|
GetCurrentGmtTime(&Cei.ExpireTime);
|
|
|
|
*(LONGLONG *) &(Cei.ExpireTime) += (12 * (24 * ONE_HOUR_DELTA));
|
|
|
|
//
|
|
// Re-Save Cache entry with updated default expiry time for PAC/INS file.
|
|
//
|
|
|
|
SetUrlCacheEntryInfoA(
|
|
lpszUrl,
|
|
(INTERNET_CACHE_ENTRY_INFOA *) &Cei,
|
|
CACHE_ENTRY_EXPTIME_FC
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BOOL
|
|
AUTO_PROXY_DLLS::IsExpiredUrl(
|
|
LPCSTR lpszUrl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Is Url Expired? If it isn't don't force a reload/update of data
|
|
|
|
Arguments:
|
|
|
|
lpszUrl -
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
ERROR_SUCCESS - success
|
|
|
|
Win32 Error code - failure
|
|
|
|
--*/
|
|
{
|
|
CACHE_ENTRY_INFOEX Cei;
|
|
DWORD dwCeiSize = sizeof(INTERNET_CACHE_ENTRY_INFOA);
|
|
BOOL fRet;
|
|
|
|
fRet = GetUrlCacheEntryInfoExA(
|
|
lpszUrl,
|
|
(INTERNET_CACHE_ENTRY_INFOA *) &Cei,
|
|
&dwCeiSize,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
INTERNET_CACHE_FLAG_GET_STRUCT_ONLY
|
|
);
|
|
|
|
if (!fRet) {
|
|
return TRUE; // expired, not in the cache
|
|
}
|
|
|
|
if ( IsExpired(&Cei, 0, &fRet) )
|
|
{
|
|
return TRUE; // expired, like really it is
|
|
}
|
|
|
|
return FALSE; // not expired
|
|
}
|
|
|
|
|
|
BOOL
|
|
AUTO_PROXY_DLLS::IsProxyAutoDetectNeeded(
|
|
LPINTERNET_PROXY_INFO_EX lpProxySettings
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Detects whether we need to actually run a detection on the network,
|
|
or whether we can resuse current results from previous runs
|
|
|
|
Arguments:
|
|
|
|
lpProxySettings - structure to fill
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
ERROR_SUCCESS - success
|
|
|
|
Win32 Error code - failure
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD addressCount;
|
|
LPDWORD * addressList;
|
|
LPHOSTENT lpHostent;
|
|
BOOL fSuspectBadDetect = FALSE;
|
|
|
|
INET_ASSERT(IsProxyAutoDetectEnabled(lpProxySettings));
|
|
|
|
// we haven't detected before on this connection, so we need to do it.
|
|
if ( !(lpProxySettings->dwAutoDiscoveryFlags & AUTO_PROXY_FLAG_DETECTION_RUN) ) {
|
|
return TRUE; // detect needed
|
|
}
|
|
|
|
// if we're flagged to ALWAYS force detection, then do this
|
|
if (lpProxySettings->dwAutoDiscoveryFlags & AUTO_PROXY_FLAG_ALWAYS_DETECT) {
|
|
return TRUE; // detect needed
|
|
}
|
|
|
|
//
|
|
// Check for an expired detected Url, detect it its expired
|
|
// Since this is RAS we can't rely on the host IP staying
|
|
// the same everytime.
|
|
//
|
|
|
|
if ( lpProxySettings->lpszLastKnownGoodAutoConfigUrl &&
|
|
lpProxySettings->lpszConnectionName &&
|
|
! IsExpiredUrl(lpProxySettings->lpszLastKnownGoodAutoConfigUrl))
|
|
{
|
|
// if we're suspecting bad settings, make sure to redirect.
|
|
if ( ! (lpProxySettings->dwAutoDiscoveryFlags & AUTO_PROXY_FLAG_DETECTION_SUSPECT) ) {
|
|
return FALSE;
|
|
}
|
|
|
|
//otherwise, we'll be careful
|
|
fSuspectBadDetect = TRUE;
|
|
}
|
|
|
|
//
|
|
// Check for IP addresses that no longer match, indicating a network change
|
|
//
|
|
|
|
__try
|
|
{
|
|
lpHostent = _I_gethostbyname(NULL);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
g_fGetHostByNameNULLFails = TRUE;
|
|
lpHostent = NULL;
|
|
}
|
|
ENDEXCEPT
|
|
|
|
if (lpHostent &&
|
|
lpProxySettings->pdwDetectedInterfaceIp == NULL)
|
|
{
|
|
return TRUE; // detect needed, no current IPs saved from last run
|
|
}
|
|
|
|
if ( lpHostent != NULL &&
|
|
lpProxySettings->pdwDetectedInterfaceIp != NULL)
|
|
{
|
|
|
|
for ( addressCount = 0;
|
|
lpHostent->h_addr_list[addressCount] != NULL;
|
|
addressCount++ ); // gather count
|
|
|
|
if ( addressCount != lpProxySettings->dwDetectedInterfaceIpCount ) {
|
|
return TRUE; // detect needed, the IP count is different
|
|
}
|
|
|
|
if ( fSuspectBadDetect) {
|
|
return FALSE; // detect NOT needed, because the IP addresses may change from dialup/to dialup
|
|
}
|
|
|
|
for (DWORD i = 0; i < addressCount; i++)
|
|
{
|
|
//dwAddress[iCount] = *((LPDWORD)(ph->h_addr_list[iCount]));
|
|
|
|
if ( *((LPDWORD)(lpHostent->h_addr_list[i])) != lpProxySettings->pdwDetectedInterfaceIp[i] ) {
|
|
return TRUE; // detect needed, mismatched values
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return FALSE; // default, do not need to redetect
|
|
}
|
|
|
|
|
|
DWORD
|
|
AUTO_PROXY_DLLS::GetHostAddresses(
|
|
DWORD ** ppdwDetectedInterfaceIp,
|
|
DWORD * pdwDetectedInterfaceIpCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copies out the current host information into an
|
|
a array/ProxyInfoStruct for later comparision.
|
|
|
|
Arguments:
|
|
|
|
lpProxySettings - structure to fill
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
ERROR_SUCCESS - success
|
|
|
|
Win32 Error code - failure
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD addressCount;
|
|
LPDWORD * addressList;
|
|
LPHOSTENT lpHostent;
|
|
DWORD error = ERROR_SUCCESS;
|
|
|
|
*pdwDetectedInterfaceIpCount = 0;
|
|
|
|
if ( *ppdwDetectedInterfaceIp )
|
|
{
|
|
FREE_MEMORY(*ppdwDetectedInterfaceIp);
|
|
*ppdwDetectedInterfaceIp = NULL;
|
|
}
|
|
|
|
//
|
|
// Gather IP addresses and start copying them over
|
|
//
|
|
|
|
__try
|
|
{
|
|
lpHostent = _I_gethostbyname(NULL);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
g_fGetHostByNameNULLFails = TRUE;
|
|
lpHostent = NULL;
|
|
}
|
|
ENDEXCEPT
|
|
|
|
if (lpHostent == NULL ) {
|
|
goto quit;
|
|
}
|
|
|
|
for ( addressCount = 0;
|
|
lpHostent->h_addr_list[addressCount] != NULL;
|
|
addressCount++ ); // gather count
|
|
|
|
*ppdwDetectedInterfaceIp = (LPDWORD)
|
|
ALLOCATE_MEMORY(LMEM_FIXED, addressCount
|
|
* sizeof(DWORD));
|
|
|
|
if ( *ppdwDetectedInterfaceIp == NULL )
|
|
{
|
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto quit;
|
|
}
|
|
|
|
if ( *ppdwDetectedInterfaceIp != NULL)
|
|
{
|
|
*pdwDetectedInterfaceIpCount = addressCount;
|
|
|
|
for (DWORD i = 0; i < addressCount; i++)
|
|
{
|
|
(*ppdwDetectedInterfaceIp)[i] =
|
|
*((LPDWORD)(lpHostent->h_addr_list[i]));
|
|
}
|
|
}
|
|
|
|
quit:
|
|
return error;
|
|
}
|
|
|
|
|
|
VOID
|
|
AUTO_PROXY_DLLS::FreeAutoProxyInfo(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Attempts to shutdown the auto-proxy thread (from outside of it), by first signalling
|
|
it with an event and boolean, and then if that fails, forcibly forcing a shutdown
|
|
with TerminateThread.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwError;
|
|
|
|
LockAutoProxy();
|
|
|
|
if ( _hAutoProxyThread != NULL &&
|
|
! IsOnAsyncAutoProxyThread() )
|
|
{
|
|
HANDLE hAutoProxyThread;
|
|
BOOL fAlreadyInShutDown;
|
|
|
|
fAlreadyInShutDown =
|
|
InterlockedExchange((LPLONG)&_fInAutoProxyThreadShutDown, TRUE);
|
|
|
|
INET_ASSERT ( ! fAlreadyInShutDown );
|
|
|
|
SetEvent(_hAutoProxyThreadEvent);
|
|
|
|
if ( _hInternetAbortHandle != NULL )
|
|
{
|
|
InternetCloseHandle(_hInternetAbortHandle);
|
|
}
|
|
|
|
hAutoProxyThread = _hAutoProxyThread;
|
|
|
|
UnlockAutoProxy();
|
|
|
|
//
|
|
// Wait for shutdown of auto-proxy thread.
|
|
//
|
|
|
|
if ( hAutoProxyThread )
|
|
{
|
|
dwError = WaitForSingleObject(hAutoProxyThread,
|
|
GlobalIsProcessNtService? INFINITE : 60000);
|
|
|
|
if ( dwError != WAIT_OBJECT_0 )
|
|
{
|
|
INET_ASSERT(FALSE);
|
|
// Whistler bug #124628: delete the autoproxy critical section
|
|
// before terminating the autoproxy thread in case the thread
|
|
// is holding the CS.
|
|
SuspendThread(hAutoProxyThread);
|
|
DeleteCriticalSection(&_CritSec);
|
|
|
|
// reinitialize cs since it will be deleted in the destructor
|
|
memset((LPVOID) &_CritSec, 0, sizeof(CRITICAL_SECTION));
|
|
InitializeCriticalSection(&_CritSec);
|
|
|
|
TerminateThread(hAutoProxyThread,ERROR_SUCCESS);
|
|
|
|
_hAutoProxyThreadEvent = NULL;
|
|
_hAutoProxyThread = NULL;
|
|
|
|
InterlockedExchange((LPLONG)&_fInAutoProxyThreadShutDown, FALSE);
|
|
return;
|
|
}
|
|
}
|
|
|
|
LockAutoProxy();
|
|
|
|
CloseHandle(_hAutoProxyThread);
|
|
CloseHandle(_hAutoProxyThreadEvent);
|
|
|
|
_hAutoProxyThreadEvent = NULL;
|
|
_hAutoProxyThread = NULL;
|
|
|
|
InterlockedExchange((LPLONG)&_fInAutoProxyThreadShutDown, FALSE);
|
|
|
|
UnlockAutoProxy();
|
|
}
|
|
else
|
|
{
|
|
UnlockAutoProxy();
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
AUTO_PROXY_LIST_ENTRY::ProxyInfoInvalid(
|
|
IN LPSTR lpszMime,
|
|
IN LPSTR lpszUrl,
|
|
IN DWORD dwUrlLength,
|
|
IN LPSTR lpszProxyHostName,
|
|
IN DWORD dwProxyHostNameLength
|
|
)
|
|
{
|
|
BOOL success = TRUE; // don't care if it doesn't succeed
|
|
|
|
if ( ! _hAutoConfigDLL )
|
|
{
|
|
if ( LoadEntry() != ERROR_SUCCESS )
|
|
return FALSE;
|
|
}
|
|
|
|
if ( ! _fInitializedSuccessfully )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if ( _pProxyInfoInvalid )
|
|
{
|
|
|
|
INET_ASSERT(_hAutoConfigDLL);
|
|
INET_ASSERT(!IsBadCodePtr((FARPROC)_pProxyInfoInvalid));
|
|
|
|
success = (_pProxyInfoInvalid) ( lpszMime,
|
|
lpszUrl,
|
|
dwUrlLength,
|
|
lpszProxyHostName,
|
|
dwProxyHostNameLength
|
|
);
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
AUTO_PROXY_LIST_ENTRY::ProxyDllDeInit(
|
|
IN LPSTR lpszMime,
|
|
IN DWORD dwReserved
|
|
)
|
|
{
|
|
BOOL success = TRUE; // don't care if it doesn't succeed
|
|
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
Bool,
|
|
"AUTO_PROXY_LIST_ENTRY::ProxyDllDeInit",
|
|
"%s, %u",
|
|
lpszMime,
|
|
dwReserved
|
|
));
|
|
|
|
|
|
INET_ASSERT(_hAutoConfigDLL);
|
|
|
|
if ( !_hAutoConfigDLL )
|
|
{
|
|
DEBUG_LEAVE(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
if ( ! _fInitializedSuccessfully )
|
|
{
|
|
DEBUG_LEAVE(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
if ( _pProxyDllDeInit )
|
|
{
|
|
|
|
INET_ASSERT(_hAutoConfigDLL);
|
|
INET_ASSERT(!IsBadCodePtr((FARPROC)_pProxyDllDeInit));
|
|
#ifdef INET_DEBUG
|
|
INET_ASSERT(!_fUnInited);
|
|
|
|
_fUnInited = TRUE;
|
|
#endif
|
|
|
|
success = (_pProxyDllDeInit) ( lpszMime,
|
|
dwReserved
|
|
);
|
|
}
|
|
|
|
DEBUG_LEAVE(success);
|
|
return success;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
AUTO_PROXY_LIST_ENTRY::GetProxyInfoEx(
|
|
IN AUTO_PROXY_ASYNC_MSG *pQueryForProxyInfo
|
|
)
|
|
{
|
|
BOOL success = FALSE;
|
|
DWORD error = ERROR_SUCCESS;
|
|
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
Dword,
|
|
"AUTO_PROXY_LIST_ENTRY::GetProxyInfoEx",
|
|
"%x [%s, %s, %u, %s, %d, %x, %x]",
|
|
pQueryForProxyInfo,
|
|
InternetMapScheme(pQueryForProxyInfo->_tUrlProtocol),
|
|
pQueryForProxyInfo->_lpszUrl,
|
|
pQueryForProxyInfo->_dwUrlLength,
|
|
pQueryForProxyInfo->_lpszUrlHostName,
|
|
pQueryForProxyInfo->_dwUrlHostNameLength,
|
|
pQueryForProxyInfo->_lpszProxyHostName,
|
|
&pQueryForProxyInfo->_dwProxyHostNameLength
|
|
));
|
|
|
|
//if ( ! _hAutoConfigDLL )
|
|
//{
|
|
// if ( LoadEntry() != ERROR_SUCCESS )
|
|
// {
|
|
// DEBUG_LEAVE(FALSE);
|
|
// return FALSE;
|
|
// }
|
|
//}
|
|
|
|
if ( ! _fInitializedSuccessfully )
|
|
{
|
|
DEBUG_LEAVE(FALSE);
|
|
error = ERROR_INTERNET_INTERNAL_ERROR;
|
|
goto quit;
|
|
}
|
|
|
|
INET_ASSERT(_hAutoConfigDLL);
|
|
INET_ASSERT(_pGetProxyInfoEx);
|
|
INET_ASSERT(!IsBadCodePtr((FARPROC)_pGetProxyInfoEx));
|
|
|
|
success = (_pGetProxyInfoEx) ( pQueryForProxyInfo->_tUrlProtocol,
|
|
pQueryForProxyInfo->_lpszUrl,
|
|
pQueryForProxyInfo->_dwUrlLength,
|
|
pQueryForProxyInfo->_lpszUrlHostName,
|
|
pQueryForProxyInfo->_dwUrlHostNameLength,
|
|
pQueryForProxyInfo->_nUrlPort,
|
|
&(pQueryForProxyInfo->_tProxyScheme),
|
|
&(pQueryForProxyInfo->_lpszProxyHostName),
|
|
&(pQueryForProxyInfo->_dwProxyHostNameLength),
|
|
&(pQueryForProxyInfo->_nProxyHostPort)
|
|
);
|
|
|
|
quit:
|
|
|
|
pQueryForProxyInfo->_dwQueryResult = (DWORD) success;
|
|
|
|
DEBUG_LEAVE(error);
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
AUTO_PROXY_LIST_ENTRY::GetProxyInfo(
|
|
IN AUTO_PROXY_ASYNC_MSG *pQueryForProxyInfo
|
|
)
|
|
{
|
|
BOOL success = FALSE;
|
|
DWORD error = ERROR_SUCCESS;
|
|
LPSTR lpszAutoProxyReturnInfo;
|
|
DWORD dwAutoProxyReturnInfoSize;
|
|
|
|
INET_ASSERT(pQueryForProxyInfo);
|
|
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
Dword,
|
|
"AUTO_PROXY_LIST_ENTRY::GetProxyInfo",
|
|
"%x [%s, %u, %s, %d, %x, %x]",
|
|
pQueryForProxyInfo,
|
|
pQueryForProxyInfo->_lpszUrl,
|
|
pQueryForProxyInfo->_dwUrlLength,
|
|
pQueryForProxyInfo->_lpszUrlHostName,
|
|
pQueryForProxyInfo->_dwUrlHostNameLength,
|
|
pQueryForProxyInfo->_lpszProxyHostName,
|
|
&pQueryForProxyInfo->_dwProxyHostNameLength
|
|
));
|
|
|
|
//if ( ! _hAutoConfigDLL )
|
|
//{
|
|
// if ( LoadEntry() != ERROR_SUCCESS )
|
|
// {
|
|
// DEBUG_LEAVE(FALSE);
|
|
// return FALSE;
|
|
// }
|
|
//}
|
|
|
|
if ( ! _fInitializedSuccessfully )
|
|
{
|
|
DEBUG_LEAVE(FALSE);
|
|
error = ERROR_INTERNET_INTERNAL_ERROR;
|
|
goto quit;
|
|
}
|
|
|
|
INET_ASSERT ( _pGetProxyInfo );
|
|
INET_ASSERT(_hAutoConfigDLL);
|
|
INET_ASSERT(!IsBadCodePtr((FARPROC)_pGetProxyInfo));
|
|
|
|
success = (_pGetProxyInfo) ( pQueryForProxyInfo->_lpszUrl,
|
|
pQueryForProxyInfo->_dwUrlLength,
|
|
pQueryForProxyInfo->_lpszUrlHostName,
|
|
pQueryForProxyInfo->_dwUrlHostNameLength,
|
|
&lpszAutoProxyReturnInfo,
|
|
&dwAutoProxyReturnInfoSize
|
|
);
|
|
|
|
|
|
if ( success )
|
|
{
|
|
if ( pQueryForProxyInfo->_tUrlProtocol == INTERNET_SCHEME_HTTPS )
|
|
{
|
|
pQueryForProxyInfo->_tProxyScheme = INTERNET_SCHEME_HTTPS;
|
|
}
|
|
else
|
|
{
|
|
pQueryForProxyInfo->_tProxyScheme = INTERNET_SCHEME_HTTP;
|
|
}
|
|
|
|
INET_ASSERT(pQueryForProxyInfo->_pProxyState == NULL);
|
|
|
|
pQueryForProxyInfo->_pProxyState = new PROXY_STATE(lpszAutoProxyReturnInfo,
|
|
dwAutoProxyReturnInfoSize,
|
|
TRUE, // parse netscape-style proxy list
|
|
pQueryForProxyInfo->_tProxyScheme,
|
|
pQueryForProxyInfo->_nProxyHostPort
|
|
);
|
|
|
|
|
|
INET_ASSERT(lpszAutoProxyReturnInfo);
|
|
GlobalFree(lpszAutoProxyReturnInfo); // clean up jsproxy.dll return string
|
|
|
|
if ( pQueryForProxyInfo->_pProxyState == NULL )
|
|
{
|
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto quit;
|
|
}
|
|
|
|
error = pQueryForProxyInfo->_pProxyState->GetError();
|
|
|
|
if ( error != ERROR_SUCCESS )
|
|
{
|
|
goto quit;
|
|
}
|
|
}
|
|
|
|
|
|
quit:
|
|
|
|
pQueryForProxyInfo->_dwQueryResult = (DWORD) success;
|
|
|
|
DEBUG_LEAVE(error);
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
AUTO_PROXY_LIST_ENTRY::ProxyDllInit (
|
|
IN DWORD dwVersion,
|
|
IN LPSTR lpszDownloadedTempFile,
|
|
IN LPSTR lpszMime,
|
|
IN AUTO_PROXY_HELPER_APIS *pAutoProxyCallbacks,
|
|
IN DWORD_PTR dwReserved
|
|
)
|
|
{
|
|
BOOL success = FALSE;
|
|
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
Bool,
|
|
"AUTO_PROXY_LIST_ENTRY::ProxyDllInit",
|
|
"%u, %s, %s, %x, %u",
|
|
dwVersion,
|
|
lpszDownloadedTempFile,
|
|
lpszMime,
|
|
pAutoProxyCallbacks,
|
|
dwReserved
|
|
));
|
|
|
|
|
|
INET_ASSERT ( _hAutoConfigDLL );
|
|
|
|
if ( _pProxyDllInit )
|
|
{
|
|
|
|
INET_ASSERT(_hAutoConfigDLL);
|
|
INET_ASSERT(!IsBadCodePtr((FARPROC)_pProxyDllInit));
|
|
|
|
success = (_pProxyDllInit) ( dwVersion,
|
|
lpszDownloadedTempFile,
|
|
lpszMime,
|
|
pAutoProxyCallbacks,
|
|
dwReserved
|
|
);
|
|
|
|
#ifdef INET_DEBUG
|
|
_fUnInited = FALSE;
|
|
#endif
|
|
_fInitializedSuccessfully = success;
|
|
|
|
}
|
|
|
|
DEBUG_LEAVE(success);
|
|
return success;
|
|
}
|
|
|
|
VOID
|
|
AUTO_PROXY_LIST_ENTRY::UnloadEntry(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unloads the DLL function entry points for an Auto-Proxy DLL.
|
|
|
|
WARNING: Must be called only on Auto-proxy thread context!
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
DEBUG_ENTER((DBG_OBJECTS,
|
|
None,
|
|
"AUTO_PROXY_LIST_ENTRY::UnloadEntry",
|
|
NULL
|
|
));
|
|
|
|
|
|
if ( _fInitializedSuccessfully &&
|
|
_pProxyDllDeInit )
|
|
{
|
|
ProxyDllDeInit(
|
|
_lpszMimeType,
|
|
0
|
|
);
|
|
}
|
|
|
|
if ( _hAutoConfigDLL )
|
|
{
|
|
// HACK HACK This call will block an dll unload time because of the
|
|
// loader critical section. Ideally we should move this free to the
|
|
// main thread, but since we are in the midst of IE5 RC's we are doing
|
|
// the least risky change i.e. leaking jsproxy.dll in the process.
|
|
if (!GlobalDynaUnload)
|
|
{
|
|
FreeLibrary(_hAutoConfigDLL);
|
|
}
|
|
|
|
_pGetProxyInfo = NULL;
|
|
_pGetProxyInfoEx = NULL;
|
|
_pProxyDllInit = NULL;
|
|
_pProxyDllDeInit = NULL;
|
|
_pProxyInfoInvalid = NULL;
|
|
}
|
|
|
|
DEBUG_LEAVE(0);
|
|
}
|
|
|
|
|
|
DWORD
|
|
AUTO_PROXY_LIST_ENTRY::LoadEntry(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Loads the DLL function entry points for an Auto-Proxy DLL.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
ERROR_SUCCESS - success
|
|
|
|
Win32 Error code - failure
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD error = ERROR_SUCCESS;
|
|
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
Dword,
|
|
"AUTO_PROXY_LIST_ENTRY::LoadEntry",
|
|
""
|
|
));
|
|
|
|
if ( _lpszFileExtensions == NULL ||
|
|
_lpszDllFilePath == NULL )
|
|
{
|
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto quit;
|
|
}
|
|
|
|
_pGetProxyInfo = NULL;
|
|
_pProxyInfoInvalid = NULL;
|
|
_pProxyDllDeInit = NULL;
|
|
_pProxyDllInit = NULL;
|
|
_pGetProxyInfoEx = NULL;
|
|
|
|
if ( _hAutoConfigDLL )
|
|
{
|
|
FreeLibrary(_hAutoConfigDLL);
|
|
_hAutoConfigDLL = NULL;
|
|
}
|
|
|
|
_hAutoConfigDLL = LoadLibrary(_lpszDllFilePath);
|
|
|
|
if ( _hAutoConfigDLL == NULL )
|
|
{
|
|
error = GetLastError();
|
|
goto quit;
|
|
}
|
|
|
|
|
|
|
|
_pGetProxyInfo = (GET_PROXY_INFO_FN)
|
|
GetProcAddress(_hAutoConfigDLL, GET_PROXY_INFO_FN_NAME);
|
|
|
|
|
|
_pGetProxyInfoEx = (GET_PROXY_INFO_EX_FN)
|
|
GetProcAddress(_hAutoConfigDLL, GET_PROXY_INFO_EX_FN_NAME);
|
|
|
|
|
|
_pProxyInfoInvalid = (PROXY_INFO_INVALID_FN)
|
|
GetProcAddress(_hAutoConfigDLL, PROXY_INFO_INVALID_FN_NAME);
|
|
|
|
|
|
_pProxyDllDeInit = (PROXY_DLL_DEINIT_FN)
|
|
GetProcAddress(_hAutoConfigDLL, PROXY_DLL_DEINIT_FN_NAME);
|
|
|
|
|
|
_pProxyDllInit = (PROXY_DLL_INIT_FN)
|
|
GetProcAddress(_hAutoConfigDLL, PROXY_DLL_INIT_FN_NAME );
|
|
|
|
|
|
if ( !_pProxyDllInit && !_pProxyDllDeInit && !_pProxyInfoInvalid && !_pGetProxyInfo && !_pGetProxyInfoEx)
|
|
{
|
|
error = GetLastError();
|
|
goto quit;
|
|
}
|
|
|
|
if ( !_pProxyDllInit )
|
|
{
|
|
//
|
|
// If they don't export this entry point, than we can't initialize them, so
|
|
// we pretend to have initialized them.
|
|
//
|
|
|
|
_fInitializedSuccessfully = TRUE;
|
|
}
|
|
|
|
quit:
|
|
|
|
DEBUG_LEAVE(error);
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
BOOL
|
|
AUTO_PROXY_DLLS::SelectAutoProxyByMime(
|
|
IN LPSTR lpszMimeType
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets an internal pointer inside the object to point to a found auto-proxy DLL.
|
|
The MIME type given is used to find the match.
|
|
|
|
Arguments:
|
|
|
|
lpszMimeType - The Mime type to search on.
|
|
|
|
Return Value:
|
|
|
|
BOOL
|
|
TRUE - success
|
|
|
|
FALSE - failure
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
Bool,
|
|
"AUTO_PROXY_DLLS::SelectAutoProxyByMime",
|
|
"%s",
|
|
lpszMimeType
|
|
));
|
|
|
|
BOOL found = FALSE;
|
|
AUTO_PROXY_LIST_ENTRY * info = NULL;
|
|
|
|
LockAutoProxy();
|
|
|
|
LockSerializedList(&_List);
|
|
|
|
for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
|
|
entry != (PLIST_ENTRY)SlSelf(&_List);
|
|
entry = entry->Flink)
|
|
{
|
|
info = CONTAINING_RECORD(entry, AUTO_PROXY_LIST_ENTRY, _List);
|
|
|
|
if (info->_lpszMimeType && lstrcmpi(lpszMimeType, info->_lpszMimeType) == 0 )
|
|
{
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
UnlockSerializedList(&_List);
|
|
|
|
if ( found )
|
|
{
|
|
SelectAutoProxy(info);
|
|
}
|
|
|
|
UnlockAutoProxy();
|
|
|
|
DEBUG_LEAVE(found);
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
BOOL
|
|
AUTO_PROXY_DLLS::SelectAutoProxyByDefault(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
Bool,
|
|
"AUTO_PROXY_DLLS::SelectAutoProxyByDefault",
|
|
NULL
|
|
));
|
|
|
|
BOOL found = FALSE;
|
|
AUTO_PROXY_LIST_ENTRY * info = NULL;
|
|
|
|
LockAutoProxy();
|
|
|
|
LockSerializedList(&_List);
|
|
|
|
for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
|
|
entry != (PLIST_ENTRY)SlSelf(&_List);
|
|
entry = entry->Flink)
|
|
{
|
|
info = CONTAINING_RECORD(entry, AUTO_PROXY_LIST_ENTRY, _List);
|
|
|
|
if (info->IsDefault() )
|
|
{
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
UnlockSerializedList(&_List);
|
|
|
|
if ( found )
|
|
{
|
|
SelectAutoProxy(info);
|
|
}
|
|
|
|
DEBUG_LEAVE(found);
|
|
|
|
UnlockAutoProxy();
|
|
|
|
return found;
|
|
}
|
|
|
|
BOOL
|
|
AUTO_PROXY_DLLS::SelectAutoProxyByFileExtension(
|
|
LPCSTR lpszAutoProxyPath
|
|
)
|
|
{
|
|
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
Bool,
|
|
"AUTO_PROXY_DLLS::SelectAutoProxyByFileExtension",
|
|
"%s",
|
|
lpszAutoProxyPath
|
|
));
|
|
|
|
BOOL found = FALSE;
|
|
AUTO_PROXY_LIST_ENTRY * info = NULL;
|
|
|
|
LockAutoProxy();
|
|
|
|
LockSerializedList(&_List);
|
|
|
|
for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
|
|
entry != (PLIST_ENTRY)SlSelf(&_List);
|
|
entry = entry->Flink)
|
|
{
|
|
info = CONTAINING_RECORD(entry, AUTO_PROXY_LIST_ENTRY, _List);
|
|
|
|
if (info->_lpszFileExtensions &&
|
|
MatchFileExtensionWithUrl(info->_lpszFileExtensions, lpszAutoProxyPath) )
|
|
{
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
UnlockSerializedList(&_List);
|
|
|
|
if ( found )
|
|
{
|
|
SelectAutoProxy(info);
|
|
}
|
|
|
|
UnlockAutoProxy();
|
|
|
|
DEBUG_LEAVE(found);
|
|
|
|
return found;
|
|
}
|
|
|
|
DWORD
|
|
AUTO_PROXY_DLLS::GetAutoProxyStringEntry(
|
|
IN LPSTR lpszRegName,
|
|
IN OUT LPSTR * lplpszAllocatedRegValue
|
|
)
|
|
{
|
|
DWORD dwcbNewValue = 0;
|
|
DWORD error = ERROR_SUCCESS;
|
|
|
|
if ( *lplpszAllocatedRegValue )
|
|
{
|
|
FREE_MEMORY(*lplpszAllocatedRegValue);
|
|
*lplpszAllocatedRegValue = NULL;
|
|
}
|
|
|
|
error =
|
|
InternetReadRegistryString(
|
|
lpszRegName,
|
|
NULL,
|
|
&dwcbNewValue
|
|
);
|
|
|
|
if ( error == ERROR_SUCCESS )
|
|
{
|
|
dwcbNewValue++;
|
|
*lplpszAllocatedRegValue = (LPSTR) ALLOCATE_MEMORY(LMEM_FIXED, dwcbNewValue);
|
|
|
|
if ( *lplpszAllocatedRegValue == NULL )
|
|
{
|
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto quit;
|
|
}
|
|
|
|
error =
|
|
InternetReadRegistryString(
|
|
lpszRegName,
|
|
*lplpszAllocatedRegValue,
|
|
&dwcbNewValue
|
|
);
|
|
|
|
if ( error != ERROR_SUCCESS )
|
|
{
|
|
INET_ASSERT((error == ERROR_SUCCESS));
|
|
FREE_MEMORY(*lplpszAllocatedRegValue);
|
|
*lplpszAllocatedRegValue = NULL;
|
|
}
|
|
}
|
|
|
|
quit:
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
AUTO_PROXY_DLLS::ReadAutoProxyRegistrySettings(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Scans Registry for, and builds linked list of AutoProxy DLLs.
|
|
|
|
Return Value:
|
|
|
|
Success - ERROR_SUCCESS
|
|
|
|
Failure -
|
|
|
|
--*/
|
|
|
|
{
|
|
HKEY hkSecurity = NULL; // main security key
|
|
DWORD error = ERROR_SUCCESS;
|
|
DWORD dwcbAutoConfigProxy = 0;
|
|
HKEY hkSPMKey = NULL;
|
|
const static CHAR cszMainSecKey[]
|
|
= CSZMAINSECKEY;
|
|
DEBUG_ENTER((DBG_PROXY,
|
|
Dword,
|
|
"AUTO_PROXY_DLLS::ReadAutoProxyRegistrySettings",
|
|
""
|
|
));
|
|
|
|
LockAutoProxy();
|
|
|
|
//
|
|
// QFE 1169: Use the HKCU value as the user agent string if told to do so.
|
|
// Yes this looks ugly, but it's just to prevent a whole bunch
|
|
// of ifs and handlers for failures.
|
|
|
|
DWORD dwcbBufLen = 0;
|
|
|
|
if (ERROR_SUCCESS == InternetReadRegistryDwordKey(
|
|
HKEY_CURRENT_USER,
|
|
"AutoConfigCustomUA",
|
|
&dwcbBufLen) &&
|
|
dwcbBufLen)
|
|
{
|
|
if (NULL == _hInstUrlmon)
|
|
{
|
|
_hInstUrlmon = LoadLibrary("Urlmon.dll");
|
|
}
|
|
if (_hInstUrlmon)
|
|
{
|
|
typedef HRESULT (*PFNOBTAINUA)(DWORD, LPSTR, DWORD*);
|
|
CHAR lpszUserAgent[MAX_PATH];
|
|
DWORD cbSize = MAX_PATH;
|
|
|
|
PFNOBTAINUA pfnUA = (PFNOBTAINUA)GetProcAddress(_hInstUrlmon,"ObtainUserAgentString");
|
|
if (pfnUA)
|
|
{
|
|
HRESULT hr = (*pfnUA)(0, lpszUserAgent, &cbSize);
|
|
if(S_OK == hr)
|
|
{
|
|
if ( _lpszUserAgent && (lstrcmpi(_lpszUserAgent, lpszUserAgent) != 0) )
|
|
{
|
|
_lpszUserAgent = (LPSTR)
|
|
FREE_MEMORY(_lpszUserAgent);
|
|
}
|
|
if ( _lpszUserAgent == NULL )
|
|
{
|
|
_lpszUserAgent = NewString(lpszUserAgent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (REGOPENKEY( HKEY_CLASSES_ROOT, cszMainSecKey, &hkSecurity ) != ERROR_SUCCESS)
|
|
{
|
|
error = GetLastError();
|
|
goto quit;
|
|
}
|
|
|
|
|
|
DWORD dwIndex;
|
|
dwIndex = 0;
|
|
|
|
do
|
|
{
|
|
CHAR szMime[256];
|
|
#ifdef unix
|
|
CHAR szUnixHackMime[256];
|
|
#endif /* unix */
|
|
if ( hkSPMKey != NULL )
|
|
{
|
|
REGCLOSEKEY(hkSPMKey);
|
|
hkSPMKey = NULL;
|
|
}
|
|
|
|
//
|
|
// Enumerate a List of MIME types, that we accept for auto-proxy
|
|
//
|
|
|
|
if (RegEnumKey( hkSecurity, dwIndex, szMime, sizeof(szMime)) != ERROR_SUCCESS )
|
|
{
|
|
goto quit;
|
|
}
|
|
|
|
dwIndex++;
|
|
|
|
//
|
|
// Open a potential MIME type entry.
|
|
//
|
|
|
|
if (REGOPENKEY( hkSecurity, szMime, &hkSPMKey ) != ERROR_SUCCESS)
|
|
{
|
|
INET_ASSERT(0);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Grab the DLL file name
|
|
//
|
|
|
|
DWORD dwType, cbBuf;
|
|
|
|
char szDll[MAX_PATH];
|
|
cbBuf = sizeof(szDll);
|
|
if (ERROR_SUCCESS != RegQueryValueEx
|
|
(hkSPMKey, "DllFile", NULL, &dwType, (LPBYTE) szDll, &cbBuf)
|
|
|| ((dwType != REG_SZ) && (dwType != REG_EXPAND_SZ)) )
|
|
{
|
|
continue; // no DLL name
|
|
}
|
|
|
|
|
|
if ( dwType == REG_EXPAND_SZ )
|
|
{
|
|
DWORD dwSize;
|
|
char szDllPathBeforeExpansion[MAX_PATH];
|
|
|
|
lstrcpy(szDllPathBeforeExpansion, szDll);
|
|
|
|
dwSize = ExpandEnvironmentStrings(szDllPathBeforeExpansion, szDll, ARRAY_ELEMENTS(szDll));
|
|
|
|
if (dwSize > ARRAY_ELEMENTS(szDll) || dwSize == 0 )
|
|
{
|
|
INET_ASSERT(FALSE);
|
|
continue; // not enough room to expand vars?
|
|
}
|
|
}
|
|
|
|
//
|
|
// Grab the list of File extensions that are permitted for this Mime Type
|
|
//
|
|
|
|
|
|
char szFileExtensions[MAX_PATH];
|
|
cbBuf = sizeof(szFileExtensions);
|
|
if (ERROR_SUCCESS != RegQueryValueEx
|
|
(hkSPMKey, "FileExtensions", NULL, &dwType, (LPBYTE) szFileExtensions, &cbBuf)
|
|
|| (dwType != REG_SZ))
|
|
{
|
|
continue; // no DLL name
|
|
}
|
|
|
|
|
|
//
|
|
// Determine whether its the defaut entry.
|
|
//
|
|
|
|
DWORD fIsDefault;
|
|
cbBuf = sizeof(fIsDefault);
|
|
if (ERROR_SUCCESS != RegQueryValueEx
|
|
(hkSPMKey, "Default", NULL, &dwType, (LPBYTE) &fIsDefault, &cbBuf)
|
|
|| ((dwType != REG_DWORD) && (dwType != REG_BINARY)))
|
|
{
|
|
INET_ASSERT (cbBuf == sizeof(DWORD));
|
|
fIsDefault = 0;
|
|
}
|
|
|
|
//
|
|
// Determine whether we have any Flags that need to be read
|
|
// from the registry.
|
|
//
|
|
|
|
DWORD dwFlags;
|
|
|
|
cbBuf = sizeof(dwFlags);
|
|
if (ERROR_SUCCESS != RegQueryValueEx
|
|
(hkSPMKey, "Flags", NULL, &dwType, (LPBYTE) &dwFlags, &cbBuf)
|
|
|| ((dwType != REG_DWORD) && (dwType != REG_BINARY)))
|
|
{
|
|
dwFlags = 0;
|
|
}
|
|
|
|
|
|
//
|
|
// Now build an entry for it, and add it to our list.
|
|
//
|
|
#ifndef unix
|
|
AUTO_PROXY_LIST_ENTRY *apleAutoProxy
|
|
= new AUTO_PROXY_LIST_ENTRY(szDll, szFileExtensions, szMime, fIsDefault, dwFlags);
|
|
#else
|
|
strcpy(szUnixHackMime,"application/");
|
|
strcat(szUnixHackMime,szMime);
|
|
AUTO_PROXY_LIST_ENTRY *apleAutoProxy
|
|
= new AUTO_PROXY_LIST_ENTRY(szDll, szFileExtensions, szUnixHackMime, fIsDefault, dwFlags);
|
|
#endif /* unix */
|
|
if (!apleAutoProxy)
|
|
{
|
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto quit;
|
|
}
|
|
|
|
if (fIsDefault)
|
|
{
|
|
InsertAtTailOfSerializedList(&_List, &apleAutoProxy->_List);
|
|
}
|
|
else
|
|
{
|
|
InsertAtHeadOfSerializedList(&_List, &apleAutoProxy->_List);
|
|
}
|
|
|
|
} while (1);
|
|
|
|
error = ERROR_SUCCESS;
|
|
|
|
quit:
|
|
|
|
if ( hkSPMKey != NULL )
|
|
{
|
|
REGCLOSEKEY(hkSPMKey);
|
|
}
|
|
|
|
if ( hkSecurity != NULL )
|
|
{
|
|
REGCLOSEKEY(hkSecurity);
|
|
}
|
|
|
|
UnlockAutoProxy();
|
|
|
|
DEBUG_LEAVE(error);
|
|
|
|
return error;
|
|
}
|
|
|
|
AUTO_PROXY_ASYNC_MSG::AUTO_PROXY_ASYNC_MSG(
|
|
IN INTERNET_SCHEME isUrlScheme,
|
|
IN LPSTR lpszUrl,
|
|
IN LPSTR lpszUrlHostName,
|
|
IN DWORD dwUrlHostNameLength
|
|
)
|
|
{
|
|
URL_COMPONENTS urlComponents;
|
|
|
|
Initalize();
|
|
|
|
if ( lpszUrl )
|
|
{
|
|
_lpszUrl = lpszUrl;
|
|
_dwUrlLength = lstrlen(lpszUrl);
|
|
_tUrlProtocol = isUrlScheme;
|
|
_pmProxyQuery = PROXY_MSG_GET_PROXY_INFO;
|
|
_pmaAllocMode = MSG_ALLOC_STACK_ONLY;
|
|
|
|
memset(&urlComponents, 0, sizeof(urlComponents));
|
|
urlComponents.dwStructSize = sizeof(urlComponents);
|
|
urlComponents.lpszHostName = lpszUrlHostName;
|
|
urlComponents.dwHostNameLength = dwUrlHostNameLength;
|
|
|
|
//
|
|
// parse out the host name and port. The host name will be decoded; the
|
|
// original URL will not be modified
|
|
//
|
|
|
|
if (InternetCrackUrl(lpszUrl, 0, ICU_DECODE, &urlComponents))
|
|
{
|
|
_nUrlPort = urlComponents.nPort;
|
|
_lpszUrlHostName = urlComponents.lpszHostName;
|
|
_dwUrlHostNameLength = urlComponents.dwHostNameLength;
|
|
|
|
if ( _tUrlProtocol == INTERNET_SCHEME_UNKNOWN )
|
|
{
|
|
_tUrlProtocol = urlComponents.nScheme;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
_Error = GetLastError();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_Error = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
|
|
AUTO_PROXY_ASYNC_MSG::AUTO_PROXY_ASYNC_MSG(
|
|
IN INTERNET_SCHEME isUrlScheme,
|
|
IN LPSTR lpszUrlHostName,
|
|
IN DWORD dwUrlHostNameLength
|
|
)
|
|
{
|
|
|
|
Initalize();
|
|
|
|
_tUrlProtocol = isUrlScheme;
|
|
_pmProxyQuery = PROXY_MSG_GET_PROXY_INFO;
|
|
_pmaAllocMode = MSG_ALLOC_STACK_ONLY;
|
|
_lpszUrlHostName = lpszUrlHostName;
|
|
_dwUrlHostNameLength = dwUrlHostNameLength;
|
|
}
|
|
|
|
AUTO_PROXY_ASYNC_MSG::AUTO_PROXY_ASYNC_MSG(
|
|
IN INTERNET_SCHEME isUrlScheme,
|
|
IN LPSTR lpszUrl,
|
|
IN DWORD dwUrlLength,
|
|
IN LPSTR lpszUrlHostName,
|
|
IN DWORD dwUrlHostNameLength,
|
|
IN INTERNET_PORT nUrlPort
|
|
)
|
|
{
|
|
Initalize();
|
|
|
|
_tUrlProtocol = isUrlScheme;
|
|
_pmProxyQuery = PROXY_MSG_GET_PROXY_INFO;
|
|
_pmaAllocMode = MSG_ALLOC_STACK_ONLY;
|
|
_nUrlPort = nUrlPort;
|
|
_lpszUrlHostName = lpszUrlHostName;
|
|
_dwUrlHostNameLength = dwUrlHostNameLength;
|
|
_lpszUrl = lpszUrl;
|
|
_dwUrlLength = dwUrlLength;
|
|
|
|
}
|
|
|
|
VOID
|
|
AUTO_PROXY_ASYNC_MSG::SetProxyMsg(
|
|
IN INTERNET_SCHEME isUrlScheme,
|
|
IN LPSTR lpszUrl,
|
|
IN DWORD dwUrlLength,
|
|
IN LPSTR lpszUrlHostName,
|
|
IN DWORD dwUrlHostNameLength,
|
|
IN INTERNET_PORT nUrlPort
|
|
)
|
|
{
|
|
_tUrlProtocol = isUrlScheme;
|
|
_pmProxyQuery = PROXY_MSG_GET_PROXY_INFO;
|
|
_pmaAllocMode = MSG_ALLOC_STACK_ONLY;
|
|
_nUrlPort = nUrlPort;
|
|
_lpszUrlHostName = lpszUrlHostName;
|
|
_dwUrlHostNameLength = dwUrlHostNameLength;
|
|
_lpszUrl = lpszUrl;
|
|
_dwUrlLength = dwUrlLength;
|
|
}
|
|
|
|
|
|
AUTO_PROXY_ASYNC_MSG::AUTO_PROXY_ASYNC_MSG(
|
|
IN PROXY_MESSAGE_TYPE pmProxyQuery
|
|
)
|
|
{
|
|
Initalize();
|
|
|
|
_pmaAllocMode = MSG_ALLOC_HEAP_MSG_OBJ_OWNS;
|
|
_pmProxyQuery = pmProxyQuery;
|
|
}
|
|
|
|
AUTO_PROXY_ASYNC_MSG::AUTO_PROXY_ASYNC_MSG(
|
|
IN AUTO_PROXY_ASYNC_MSG *pStaticAutoProxy
|
|
)
|
|
{
|
|
Initalize();
|
|
|
|
_tUrlProtocol = pStaticAutoProxy->_tUrlProtocol;
|
|
_lpszUrl = (pStaticAutoProxy->_lpszUrl) ? NewString(pStaticAutoProxy->_lpszUrl) : NULL;
|
|
_dwUrlLength = pStaticAutoProxy->_dwUrlLength;
|
|
_lpszUrlHostName =
|
|
(pStaticAutoProxy->_lpszUrlHostName ) ?
|
|
NewString(pStaticAutoProxy->_lpszUrlHostName, pStaticAutoProxy->_dwUrlHostNameLength) :
|
|
NULL;
|
|
_dwUrlHostNameLength = pStaticAutoProxy->_dwUrlHostNameLength;
|
|
_nUrlPort = pStaticAutoProxy->_nUrlPort;
|
|
_tProxyScheme = pStaticAutoProxy->_tProxyScheme;
|
|
|
|
//
|
|
// ProxyHostName is something that is generated by the request,
|
|
// therefore it should not be copied OR freed.
|
|
//
|
|
|
|
INET_ASSERT( pStaticAutoProxy->_lpszProxyHostName == NULL );
|
|
//_lpszProxyHostName = (pStaticAutoProxy->_lpszProxyHostName ) ? NewString(pStaticAutoProxy->_lpszProxyHostName) : NULL;
|
|
|
|
|
|
_dwProxyHostNameLength = pStaticAutoProxy->_dwProxyHostNameLength;
|
|
_nProxyHostPort = pStaticAutoProxy->_nProxyHostPort;
|
|
_pmProxyQuery = pStaticAutoProxy->_pmProxyQuery;
|
|
_pmaAllocMode = MSG_ALLOC_HEAP_MSG_OBJ_OWNS;
|
|
_pProxyState = pStaticAutoProxy->_pProxyState;
|
|
|
|
INET_ASSERT(_pProxyState == NULL);
|
|
|
|
_dwQueryResult = pStaticAutoProxy->_dwQueryResult;
|
|
_Error = pStaticAutoProxy->_Error;
|
|
_MessageFlags.Dword = pStaticAutoProxy->_MessageFlags.Dword;
|
|
_dwProxyVersion = pStaticAutoProxy->_dwProxyVersion;
|
|
}
|
|
|
|
AUTO_PROXY_ASYNC_MSG::~AUTO_PROXY_ASYNC_MSG(
|
|
VOID
|
|
)
|
|
{
|
|
DEBUG_ENTER((DBG_OBJECTS,
|
|
None,
|
|
"~AUTO_PROXY_ASYNC_MSG",
|
|
NULL
|
|
));
|
|
|
|
if ( IsAlloced() )
|
|
{
|
|
DEBUG_PRINT(OBJECTS,
|
|
INFO,
|
|
("Freeing Allocated MSG ptr=%x\n",
|
|
this
|
|
));
|
|
|
|
|
|
if ( _lpszUrl )
|
|
{
|
|
//DEBUG_PRINT(OBJECTS,
|
|
// INFO,
|
|
// ("Url ptr=%x, %q\n",
|
|
// _lpszUrl,
|
|
// _lpszUrl
|
|
// ));
|
|
|
|
FREE_MEMORY(_lpszUrl);
|
|
}
|
|
|
|
if ( _lpszUrlHostName )
|
|
{
|
|
FREE_MEMORY(_lpszUrlHostName);
|
|
}
|
|
|
|
|
|
if ( _pProxyState )
|
|
{
|
|
delete _pProxyState;
|
|
}
|
|
}
|
|
if (_bFreeProxyHostName && (_lpszProxyHostName != NULL)) {
|
|
FREE_MEMORY(_lpszProxyHostName);
|
|
}
|
|
|
|
DEBUG_LEAVE(0);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// functions
|
|
//
|
|
|
|
|
|
PRIVATE
|
|
BOOL
|
|
MatchFileExtensionWithUrl(
|
|
IN LPCSTR lpszFileExtensionList,
|
|
IN LPCSTR lpszUrl
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Matches a Url with a string of externsions (looks like ".ins;.jv").
|
|
Confims the Url is using one the approved externsions.
|
|
|
|
Arguments:
|
|
|
|
lpszFileExtensionList - the list of file extensions to check the Url against.
|
|
|
|
lpszUrl - the url to examine.
|
|
|
|
Return Value:
|
|
|
|
BOOL
|
|
TRUE - success
|
|
|
|
FALSE - the Url does not contain any of the extensions.
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
|
|
LPCSTR lpszExtension, lpszExtensionOffset;
|
|
LPCSTR lpszQuestion;
|
|
|
|
//
|
|
// We need to be careful about checking for a period on the end of an URL
|
|
// Example: if we have: "http://auto-proxy-srv/fooboo.exe?autogenator.com.ex" ?
|
|
//
|
|
|
|
lpszQuestion = strchr( lpszUrl, '?' );
|
|
|
|
lpszUrl = ( lpszQuestion ) ? lpszQuestion : lpszUrl;
|
|
|
|
lpszExtension = strrchr( lpszUrl, '.' );
|
|
|
|
|
|
if ( lpszExtension )
|
|
{
|
|
lpszExtensionOffset = lpszExtension;
|
|
BOOL fMatching = FALSE;
|
|
BOOL fCurrentMatch = FALSE;
|
|
BOOL fFirstByte = TRUE;
|
|
|
|
while ( *lpszFileExtensionList && *lpszExtensionOffset )
|
|
{
|
|
|
|
if ( toupper(*lpszFileExtensionList) == toupper(*lpszExtensionOffset) )
|
|
{
|
|
fCurrentMatch = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fCurrentMatch = FALSE;
|
|
}
|
|
|
|
if ( *lpszFileExtensionList == ';')
|
|
{
|
|
lpszExtensionOffset = lpszExtension-1;
|
|
fFirstByte = TRUE;
|
|
|
|
if ( fMatching )
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
else if ( fFirstByte || fMatching )
|
|
{
|
|
fMatching = fCurrentMatch;
|
|
fFirstByte = FALSE;
|
|
}
|
|
|
|
lpszExtensionOffset++;
|
|
lpszFileExtensionList++;
|
|
|
|
if ( *lpszExtensionOffset == '\0' )
|
|
{
|
|
lpszExtensionOffset = lpszExtension;
|
|
}
|
|
}
|
|
|
|
if ( fMatching )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef unix
|
|
static BOOL fForceAutoProxSync = TRUE;
|
|
extern "C"
|
|
void unixForceAutoProxSync()
|
|
{
|
|
if(fForceAutoProxSync)
|
|
{
|
|
if (!GlobalDataInitialized)
|
|
GlobalDataInitialize();
|
|
|
|
if (GlobalDataInitialized)
|
|
{
|
|
GlobalProxyInfo.SetRefreshDisabled(FALSE);
|
|
FixProxySettingsForCurrentConnection(TRUE);
|
|
GlobalProxyInfo.ReleaseQueuedRefresh();
|
|
fForceAutoProxSync = FALSE;
|
|
}
|
|
}
|
|
}
|
|
#endif /* unix */
|
|
|