diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2018-06-26 14:39:49 +1000 |
---|---|---|
committer | Andras Timar <andras.timar@collabora.com> | 2018-07-02 10:50:19 +0200 |
commit | dc58872a7296c0577e7dbe2ba41c33246386749d (patch) | |
tree | 245480c60bfc9654f666360880c7201e1dccb526 /ucbhelper | |
parent | 79d7b69076feddaafdcde34fc747d83371464239 (diff) |
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>
(cherry picked from commit 2e142c0ee54744d35517f0b9c49a24302fb32d47)
Reviewed-on: https://gerrit.libreoffice.org/56688
Reviewed-by: Andras Timar <andras.timar@collabora.com>
Tested-by: Andras Timar <andras.timar@collabora.com>
Diffstat (limited to 'ucbhelper')
-rw-r--r-- | ucbhelper/Library_ucbhelper.mk | 4 | ||||
-rw-r--r-- | ucbhelper/source/client/proxydecider.cxx | 154 |
2 files changed, 155 insertions, 3 deletions
diff --git a/ucbhelper/Library_ucbhelper.mk b/ucbhelper/Library_ucbhelper.mk index 85c8e16f1573..8734c5291d91 100644 --- a/ucbhelper/Library_ucbhelper.mk +++ b/ucbhelper/Library_ucbhelper.mk @@ -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: diff --git a/ucbhelper/source/client/proxydecider.cxx b/ucbhelper/source/client/proxydecider.cxx index cc0dd60afeab..fdf4506add26 100644 --- a/ucbhelper/source/client/proxydecider.cxx +++ b/ucbhelper/source/client/proxydecider.cxx @@ -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 |