summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2018-06-26 14:39:49 +1000
committerMike Kaganski <mike.kaganski@collabora.com>2018-06-26 09:33:24 +0200
commit2e142c0ee54744d35517f0b9c49a24302fb32d47 (patch)
treee828e65d70fc4a908f0d0ad8f04cd2cf4df8ecd4
parent20c4a9ce69e73a182d60718e9b52510d66c8f20e (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>
-rw-r--r--include/ucbhelper/proxydecider.hxx4
-rw-r--r--ucb/source/ucp/webdav-neon/NeonSession.cxx2
-rw-r--r--ucb/source/ucp/webdav-neon/NeonSession.hxx2
-rw-r--r--ucbhelper/Library_ucbhelper.mk4
-rw-r--r--ucbhelper/source/client/proxydecider.cxx154
5 files changed, 159 insertions, 7 deletions
diff --git a/include/ucbhelper/proxydecider.hxx b/include/ucbhelper/proxydecider.hxx
index 0ee4400a1392..3c873e2fe193 100644
--- a/include/ucbhelper/proxydecider.hxx
+++ b/include/ucbhelper/proxydecider.hxx
@@ -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;
diff --git a/ucb/source/ucp/webdav-neon/NeonSession.cxx b/ucb/source/ucp/webdav-neon/NeonSession.cxx
index 40bbb9d13568..aac868e3d87a 100644
--- a/ucb/source/ucp/webdav-neon/NeonSession.cxx
+++ b/ucb/source/ucp/webdav-neon/NeonSession.cxx
@@ -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" )
{
diff --git a/ucb/source/ucp/webdav-neon/NeonSession.hxx b/ucb/source/ucp/webdav-neon/NeonSession.hxx
index ec080f1f0473..87026ad23ec4 100644
--- a/ucb/source/ucp/webdav-neon/NeonSession.hxx
+++ b/ucb/source/ucp/webdav-neon/NeonSession.hxx
@@ -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 );
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