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: Mike Kaganski <mike.kaganski@collabora.com>
This commit is contained in:
@@ -119,10 +119,10 @@ public:
|
|||||||
* If host is not empty this parameter must always contain a valid
|
* If host is not empty this parameter must always contain a valid
|
||||||
* port number, for instance the default port for the requested
|
* port number, for instance the default port for the requested
|
||||||
* protocol(i.e. 80 or http).
|
* 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.
|
* InternetProxyServer is empty no proxy server is to be used.
|
||||||
*/
|
*/
|
||||||
const InternetProxyServer &
|
InternetProxyServer
|
||||||
getProxy( const OUString & rProtocol,
|
getProxy( const OUString & rProtocol,
|
||||||
const OUString & rHost,
|
const OUString & rHost,
|
||||||
sal_Int32 nPort ) const;
|
sal_Int32 nPort ) const;
|
||||||
|
@@ -1696,7 +1696,7 @@ void NeonSession::abort()
|
|||||||
SAL_INFO( "ucb.ucp.webdav", "neon commands cannot be aborted" );
|
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" )
|
if ( m_aScheme == "http" || m_aScheme == "https" )
|
||||||
{
|
{
|
||||||
|
@@ -219,7 +219,7 @@ private:
|
|||||||
const OUString & inPath,
|
const OUString & inPath,
|
||||||
const DAVRequestEnvironment & rEnv );
|
const DAVRequestEnvironment & rEnv );
|
||||||
|
|
||||||
const ucbhelper::InternetProxyServer & getProxySettings() const;
|
ucbhelper::InternetProxyServer getProxySettings() const;
|
||||||
|
|
||||||
bool removeExpiredLocktoken( const OUString & inURL,
|
bool removeExpiredLocktoken( const OUString & inURL,
|
||||||
const DAVRequestEnvironment & rEnv );
|
const DAVRequestEnvironment & rEnv );
|
||||||
|
@@ -50,5 +50,9 @@ $(eval $(call gb_Library_add_exception_objects,ucbhelper,\
|
|||||||
ucbhelper/source/provider/simplenameclashresolverequest \
|
ucbhelper/source/provider/simplenameclashresolverequest \
|
||||||
))
|
))
|
||||||
|
|
||||||
|
$(eval $(call gb_Library_use_system_win32_libs,ucbhelper,\
|
||||||
|
Winhttp \
|
||||||
|
))
|
||||||
|
|
||||||
# vim: set noet sw=4 ts=4:
|
# vim: set noet sw=4 ts=4:
|
||||||
|
|
||||||
|
@@ -34,6 +34,13 @@
|
|||||||
#include <cppuhelper/implbase.hxx>
|
#include <cppuhelper/implbase.hxx>
|
||||||
#include <ucbhelper/proxydecider.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 com::sun::star;
|
||||||
using namespace ucbhelper;
|
using namespace ucbhelper;
|
||||||
|
|
||||||
@@ -131,7 +138,7 @@ public:
|
|||||||
|
|
||||||
void dispose();
|
void dispose();
|
||||||
|
|
||||||
const InternetProxyServer & getProxy( const OUString & rProtocol,
|
InternetProxyServer getProxy(const OUString& rProtocol,
|
||||||
const OUString & rHost,
|
const OUString & rHost,
|
||||||
sal_Int32 nPort ) const;
|
sal_Int32 nPort ) const;
|
||||||
|
|
||||||
@@ -428,8 +435,138 @@ bool InternetProxyDecider_Impl::shouldUseProxy( const OUString & rHost,
|
|||||||
return true;
|
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;
|
||||||
|
|
||||||
const InternetProxyServer & InternetProxyDecider_Impl::getProxy(
|
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
|
||||||
|
|
||||||
|
InternetProxyServer InternetProxyDecider_Impl::getProxy(
|
||||||
const OUString & rProtocol,
|
const OUString & rProtocol,
|
||||||
const OUString & rHost,
|
const OUString & rHost,
|
||||||
sal_Int32 nPort ) const
|
sal_Int32 nPort ) const
|
||||||
@@ -442,6 +579,17 @@ const InternetProxyServer & InternetProxyDecider_Impl::getProxy(
|
|||||||
return m_aEmptyProxy;
|
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() )
|
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 & rProtocol,
|
||||||
const OUString & rHost,
|
const OUString & rHost,
|
||||||
sal_Int32 nPort ) const
|
sal_Int32 nPort ) const
|
||||||
|
Reference in New Issue
Block a user