[Libreoffice-commits] core.git: Branch 'libreoffice-6-1' - include/ucbhelper ucbhelper/Library_ucbhelper.mk ucbhelper/source ucb/source

Mike Kaganski mike.kaganski at collabora.com
Sat Jun 30 17:28:14 UTC 2018


 include/ucbhelper/proxydecider.hxx         |    4 
 ucb/source/ucp/webdav-neon/NeonSession.cxx |    2 
 ucb/source/ucp/webdav-neon/NeonSession.hxx |    2 
 ucbhelper/Library_ucbhelper.mk             |    4 
 ucbhelper/source/client/proxydecider.cxx   |  154 ++++++++++++++++++++++++++++-
 5 files changed, 159 insertions(+), 7 deletions(-)

New commits:
commit 76c0b3c516f6b0d43136522b4d476eb60211cec1
Author: Mike Kaganski <mike.kaganski at collabora.com>
Date:   Tue Jun 26 14:39:49 2018 +1000

    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 at collabora.com>
    (cherry picked from commit 2e142c0ee54744d35517f0b9c49a24302fb32d47)
    Reviewed-on: https://gerrit.libreoffice.org/56757
    Reviewed-by: Noel Grandin <noel.grandin at collabora.co.uk>

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


More information about the Libreoffice-commits mailing list