Kaydet (Commit) 2e142c0e authored tarafından Mike Kaganski's avatar Mike Kaganski

tdf#114227: Add support for PAC to ucbhelper::InternetProxyDecider on Windows

Change-Id: I62c76efb354949699615a44d9482df24e3eaa314
Reviewed-on: https://gerrit.libreoffice.org/56433
Tested-by: Jenkins
Reviewed-by: 's avatarMike Kaganski <mike.kaganski@collabora.com>
üst 20c4a9ce
......@@ -119,10 +119,10 @@ public:
* If host is not empty this parameter must always contain a valid
* port number, for instance the default port for the requested
* protocol(i.e. 80 or http).
* @return a InternetProxyServer reference. If member aName of the
* @return a InternetProxyServer struct. If member aName of the
* InternetProxyServer is empty no proxy server is to be used.
*/
const InternetProxyServer &
InternetProxyServer
getProxy( const OUString & rProtocol,
const OUString & rHost,
sal_Int32 nPort ) const;
......
......@@ -1696,7 +1696,7 @@ void NeonSession::abort()
SAL_INFO( "ucb.ucp.webdav", "neon commands cannot be aborted" );
}
const ucbhelper::InternetProxyServer & NeonSession::getProxySettings() const
ucbhelper::InternetProxyServer NeonSession::getProxySettings() const
{
if ( m_aScheme == "http" || m_aScheme == "https" )
{
......
......@@ -219,7 +219,7 @@ private:
const OUString & inPath,
const DAVRequestEnvironment & rEnv );
const ucbhelper::InternetProxyServer & getProxySettings() const;
ucbhelper::InternetProxyServer getProxySettings() const;
bool removeExpiredLocktoken( const OUString & inURL,
const DAVRequestEnvironment & rEnv );
......
......@@ -50,5 +50,9 @@ $(eval $(call gb_Library_add_exception_objects,ucbhelper,\
ucbhelper/source/provider/simplenameclashresolverequest \
))
$(eval $(call gb_Library_use_system_win32_libs,ucbhelper,\
Winhttp \
))
# vim: set noet sw=4 ts=4:
......@@ -34,6 +34,13 @@
#include <cppuhelper/implbase.hxx>
#include <ucbhelper/proxydecider.hxx>
#ifdef _WIN32
#include <o3tl/char16_t2wchar_t.hxx>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <Winhttp.h>
#endif
using namespace com::sun::star;
using namespace ucbhelper;
......@@ -131,7 +138,7 @@ public:
void dispose();
const InternetProxyServer & getProxy( const OUString & rProtocol,
InternetProxyServer getProxy(const OUString& rProtocol,
const OUString & rHost,
sal_Int32 nPort ) const;
......@@ -428,8 +435,138 @@ bool InternetProxyDecider_Impl::shouldUseProxy( const OUString & rHost,
return true;
}
#ifdef _WIN32
namespace
{
struct GetPACProxyData
{
const OUString& m_rProtocol;
const OUString& m_rHost;
sal_Int32 m_nPort;
bool m_bAutoDetect = false;
OUString m_sAutoConfigUrl;
InternetProxyServer m_ProxyServer;
GetPACProxyData(const OUString& rProtocol, const OUString& rHost, sal_Int32 nPort)
: m_rProtocol(rProtocol)
, m_rHost(rHost)
, m_nPort(nPort)
{
}
};
// Tries to get proxy configuration using WinHttpGetProxyForUrl, which supports Web Proxy Auto-Discovery
// (WPAD) protocol and manually configured address to get Proxy Auto-Configuration (PAC) file.
// The WinINet/WinHTTP functions cannot correctly run in a STA COM thread, so use a dedicated thread
DWORD WINAPI GetPACProxyThread(_In_ LPVOID lpParameter)
{
assert(lpParameter);
GetPACProxyData* pData = static_cast<GetPACProxyData*>(lpParameter);
OUString url(pData->m_rProtocol + "://" + pData->m_rHost + ":"
+ OUString::number(pData->m_nPort));
HINTERNET hInternet = WinHttpOpen(L"Mozilla 5.0", WINHTTP_ACCESS_TYPE_NO_PROXY,
WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
DWORD nError = GetLastError();
if (!hInternet)
return nError;
WINHTTP_AUTOPROXY_OPTIONS AutoProxyOptions{};
if (pData->m_bAutoDetect)
{
AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
AutoProxyOptions.dwAutoDetectFlags
= WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
}
if (!pData->m_sAutoConfigUrl.isEmpty())
{
AutoProxyOptions.dwFlags |= WINHTTP_AUTOPROXY_CONFIG_URL;
AutoProxyOptions.lpszAutoConfigUrl = o3tl::toW(pData->m_sAutoConfigUrl.getStr());
}
// First, try without autologon. According to
// https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/web/winhttp/WinhttpProxySample/GetProxy.cpp
// autologon prevents caching, and so causes repetitive network traffic.
AutoProxyOptions.fAutoLogonIfChallenged = FALSE;
WINHTTP_PROXY_INFO ProxyInfo{};
BOOL bResult
= WinHttpGetProxyForUrl(hInternet, o3tl::toW(url.getStr()), &AutoProxyOptions, &ProxyInfo);
nError = GetLastError();
if (!bResult && nError == ERROR_WINHTTP_LOGIN_FAILURE)
{
AutoProxyOptions.fAutoLogonIfChallenged = TRUE;
bResult = WinHttpGetProxyForUrl(hInternet, o3tl::toW(url.getStr()),
&AutoProxyOptions, &ProxyInfo);
nError = GetLastError();
}
WinHttpCloseHandle(hInternet);
if (bResult)
{
if (ProxyInfo.lpszProxyBypass)
GlobalFree(ProxyInfo.lpszProxyBypass);
if (ProxyInfo.lpszProxy)
{
OUString sProxyResult = o3tl::toU(ProxyInfo.lpszProxy);
GlobalFree(ProxyInfo.lpszProxy);
// Get the first of possibly multiple results
sProxyResult = sProxyResult.getToken(0, ';');
sal_Int32 nPortSepPos = sProxyResult.indexOf(':');
if (nPortSepPos != -1)
{
pData->m_ProxyServer.nPort = sProxyResult.copy(nPortSepPos + 1).toInt32();
sProxyResult = sProxyResult.copy(0, nPortSepPos);
}
else
{
pData->m_ProxyServer.nPort = 0;
}
pData->m_ProxyServer.aName = sProxyResult;
}
}
return nError;
}
InternetProxyServer GetPACProxy(const OUString& rProtocol, const OUString& rHost, sal_Int32 nPort)
{
GetPACProxyData aData(rProtocol, rHost, nPort);
// WinHTTP only supports http(s), so don't try for other protocols
if (!(rProtocol.equalsIgnoreAsciiCase("http") || rProtocol.equalsIgnoreAsciiCase("https")))
return aData.m_ProxyServer;
// Only try to get configuration from PAC (with all the overhead, including new thread)
// if configured to do so
{
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG aProxyConfig{};
BOOL bResult = WinHttpGetIEProxyConfigForCurrentUser(&aProxyConfig);
if (aProxyConfig.lpszProxy)
GlobalFree(aProxyConfig.lpszProxy);
if (aProxyConfig.lpszProxyBypass)
GlobalFree(aProxyConfig.lpszProxyBypass);
// Don't try WPAD if AutoDetection or AutoConfig script URL are not configured
if (!bResult || !(aProxyConfig.fAutoDetect || aProxyConfig.lpszAutoConfigUrl))
return aData.m_ProxyServer;
aData.m_bAutoDetect = aProxyConfig.fAutoDetect;
if (aProxyConfig.lpszAutoConfigUrl)
{
aData.m_sAutoConfigUrl = o3tl::toU(aProxyConfig.lpszAutoConfigUrl);
GlobalFree(aProxyConfig.lpszAutoConfigUrl);
}
}
HANDLE hThread = CreateThread(nullptr, 0, GetPACProxyThread, &aData, 0, nullptr);
if (hThread)
{
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
return aData.m_ProxyServer;
}
}
#endif // _WIN32
const InternetProxyServer & InternetProxyDecider_Impl::getProxy(
InternetProxyServer InternetProxyDecider_Impl::getProxy(
const OUString & rProtocol,
const OUString & rHost,
sal_Int32 nPort ) const
......@@ -442,6 +579,17 @@ const InternetProxyServer & InternetProxyDecider_Impl::getProxy(
return m_aEmptyProxy;
}
#ifdef _WIN32
// If get from system
if (m_nProxyType == 1 && !rHost.isEmpty())
{
InternetProxyServer aProxy(GetPACProxy(rProtocol, rHost, nPort));
if (!aProxy.aName.isEmpty())
return aProxy;
}
#endif // _WIN32
if ( !rHost.isEmpty() && !m_aNoProxyList.empty() )
{
......@@ -767,7 +915,7 @@ bool InternetProxyDecider::shouldUseProxy( const OUString & rProtocol,
}
const InternetProxyServer & InternetProxyDecider::getProxy(
InternetProxyServer InternetProxyDecider::getProxy(
const OUString & rProtocol,
const OUString & rHost,
sal_Int32 nPort ) const
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment