From b5c8c48a87a19618b23d6d4fc5035915a9322117 Mon Sep 17 00:00:00 2001
From: Kai Koehne <kai.koehne@qt.io>
Date: Thu, 20 Jul 2017 16:14:47 +0200
Subject: [PATCH] Fix logic to check for proxy settings

The previous code tried to find out whether a user has set an
application proxy by checking the type of the applicationProxy.
This is wrong, because a system proxy will actually also change the
applicationProxy type.

Instead, we now rely on QNetworkProxyFactory::usesSystemConfiguration
to decide whether to use QtNetwork's application proxy, or Chromium's
logic for the system proxy. We also save the state of
QNetworkProxy::useSystemConfiguration to be able to track changes.

[ChangeLog][Networking] Fixed an issue where system proxy settings were
not picked up correctly.

Task-number: QTBUG-61910
Change-Id: I1d9af3f6006ba187266fe50c645f425a46632e41
Reviewed-by: Peter Varga <pvarga@inf.u-szeged.hu>
---
 src/core/proxy_config_service_qt.cpp | 92 ++++++++++++++++++----------
 src/core/proxy_config_service_qt.h   |  6 +-
 2 files changed, 63 insertions(+), 35 deletions(-)

diff --git a/src/core/proxy_config_service_qt.cpp b/src/core/proxy_config_service_qt.cpp
index b7ed83624..491131e42 100644
--- a/src/core/proxy_config_service_qt.cpp
+++ b/src/core/proxy_config_service_qt.cpp
@@ -36,6 +36,9 @@
 ** $QT_END_LICENSE$
 **
 ****************************************************************************/
+
+
+//================ Based on ChromeProxyConfigService =======================
 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
@@ -67,11 +70,10 @@ net::ProxyServer ProxyConfigServiceQt::fromQNetworkProxy(const QNetworkProxy &qt
     return net::ProxyServer(proxyScheme, net::HostPortPair(qtProxy.hostName().toStdString(), qtProxy.port()));
 }
 
-//================ Based on ChromeProxyConfigService =======================
-
 ProxyConfigServiceQt::ProxyConfigServiceQt(std::unique_ptr<ProxyConfigService> baseService)
     : m_baseService(baseService.release()),
-      m_registeredObserver(false)
+      m_registeredObserver(false),
+      m_usesSystemConfiguration(false)
 {
 }
 
@@ -83,7 +85,6 @@ ProxyConfigServiceQt::~ProxyConfigServiceQt()
 
 void ProxyConfigServiceQt::AddObserver(net::ProxyConfigService::Observer *observer)
 {
-    RegisterObserver();
     m_observers.AddObserver(observer);
 }
 
@@ -94,28 +95,31 @@ void ProxyConfigServiceQt::RemoveObserver(net::ProxyConfigService::Observer *obs
 
 net::ProxyConfigService::ConfigAvailability ProxyConfigServiceQt::GetLatestProxyConfig(net::ProxyConfig *config)
 {
-    RegisterObserver();
-
-    // Ask the base service if available.
-    net::ProxyConfig systemConfig;
-    ConfigAvailability systemAvailability = net::ProxyConfigService::CONFIG_UNSET;
-    if (m_baseService.get())
-        systemAvailability = m_baseService->GetLatestProxyConfig(&systemConfig);
+#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
+    m_usesSystemConfiguration = QNetworkProxyFactory::usesSystemConfiguration();
+#endif
+    if (m_usesSystemConfiguration) {
+        // Use Chromium's base service to retrieve system settings
+        net::ProxyConfig systemConfig;
+        ConfigAvailability systemAvailability = net::ProxyConfigService::CONFIG_UNSET;
+        if (m_baseService.get())
+            systemAvailability = m_baseService->GetLatestProxyConfig(&systemConfig);
+        *config = systemConfig;
+        // make sure to get updates via OnProxyConfigChanged
+        RegisterObserver();
+        return systemAvailability;
+    }
 
+    // Use QNetworkProxy::applicationProxy settings
     const QNetworkProxy &qtProxy = QNetworkProxy::applicationProxy();
     if (qtProxy == m_qtApplicationProxy && !m_qtProxyConfig.proxy_rules().empty()) {
+        // no changes
         *config = m_qtProxyConfig;
         return CONFIG_VALID;
     }
+
     m_qtApplicationProxy = qtProxy;
     m_qtProxyConfig = net::ProxyConfig();
-#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
-    if (qtProxy.type() == QNetworkProxy::NoProxy
-            && QNetworkProxyFactory::usesSystemConfiguration()) {
-        *config = systemConfig;
-        return systemAvailability;
-    }
-#endif
 
     net::ProxyConfig::ProxyRules qtRules;
     net::ProxyServer server = fromQNetworkProxy(qtProxy);
@@ -145,31 +149,51 @@ net::ProxyConfigService::ConfigAvailability ProxyConfigServiceQt::GetLatestProxy
 
 void ProxyConfigServiceQt::OnLazyPoll()
 {
-    if (m_qtApplicationProxy != QNetworkProxy::applicationProxy()) {
-        net::ProxyConfig unusedConfig;
-        OnProxyConfigChanged(unusedConfig, CONFIG_VALID);
+    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
+    // We need to update if
+    // - setUseSystemConfiguration() was called in between
+    // - user changed application proxy
+    if (m_usesSystemConfiguration != QNetworkProxyFactory::usesSystemConfiguration()
+        || (!m_usesSystemConfiguration && m_qtApplicationProxy != QNetworkProxy::applicationProxy())) {
+        Update();
+    } else if (m_usesSystemConfiguration) {
+        if (m_baseService.get())
+            m_baseService->OnLazyPoll();
     }
-    if (m_baseService.get())
-        m_baseService->OnLazyPoll();
+#else
+    if (m_qtApplicationProxy != QNetworkProxy::applicationProxy())
+        Update();
+#endif
 }
 
-
+// Called when the base service changed
 void ProxyConfigServiceQt::OnProxyConfigChanged(const net::ProxyConfig &config, ConfigAvailability availability)
 {
-    Q_UNUSED(config);
     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+    Q_UNUSED(config);
 
-    if (m_qtApplicationProxy != QNetworkProxy::applicationProxy()
-            || m_qtApplicationProxy.type() == QNetworkProxy::NoProxy) {
-        net::ProxyConfig actual_config;
-        availability = GetLatestProxyConfig(&actual_config);
-        if (availability == CONFIG_PENDING)
-            return;
-        for (net::ProxyConfigService::Observer &observer: m_observers)
-            observer.OnProxyConfigChanged(actual_config, availability);
-    }
+    if (!m_usesSystemConfiguration)
+        return;
+
+    Update();
+}
+
+// Update our observers
+void ProxyConfigServiceQt::Update()
+{
+    net::ProxyConfig actual_config;
+    ConfigAvailability availability = GetLatestProxyConfig(&actual_config);
+    if (availability == CONFIG_PENDING)
+        return;
+    for (net::ProxyConfigService::Observer &observer: m_observers)
+        observer.OnProxyConfigChanged(actual_config, availability);
 }
 
+// Register ourselves as observer of the base service.
+// This has to be done on the IO thread, and therefore cannot be done
+// in the constructor.
 void ProxyConfigServiceQt::RegisterObserver()
 {
     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
diff --git a/src/core/proxy_config_service_qt.h b/src/core/proxy_config_service_qt.h
index f2f9a2210..7be3289d0 100644
--- a/src/core/proxy_config_service_qt.h
+++ b/src/core/proxy_config_service_qt.h
@@ -69,13 +69,17 @@ private:
     void OnProxyConfigChanged(const net::ProxyConfig& config,
                               ConfigAvailability availability) override;
 
+    // Retrieve new proxy settings and notify observers.
+    void Update();
+
     // Makes sure that the observer registration with the base service is set up.
     void RegisterObserver();
 
     std::unique_ptr<net::ProxyConfigService> m_baseService;
     base::ObserverList<net::ProxyConfigService::Observer, true> m_observers;
 
-    // Keep the last QNetworkProxy::applicationProxy state around.
+    // Keep the last state around.
+    bool m_usesSystemConfiguration;
     QNetworkProxy m_qtApplicationProxy;
     net::ProxyConfig m_qtProxyConfig;
 
-- 
GitLab