From 32f83d9c2c884dfa516095c07f8590b2c4c99321 Mon Sep 17 00:00:00 2001
From: Michael Bruning <michael.bruning@theqtcompany.com>
Date: Thu, 3 Dec 2015 11:16:32 +0100
Subject: [PATCH] Reuse or clean up HttpNetworkSession when (re-) setting a
 cache type.

Not reusing or cleaning up the session led to race conditions which in
turn lead to crashes and asserts.

Reuse the session if parameters match, clean up and it recreate otherwise.

Task-number: QTBUG-49397
Change-Id: I4f846a448b50d80a3cf7c4f9bb833fa6d64974d7
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@theqtcompany.com>
---
 src/core/url_request_context_getter_qt.cpp | 102 ++++++++++++++++-----
 src/core/url_request_context_getter_qt.h   |   3 +
 2 files changed, 81 insertions(+), 24 deletions(-)

diff --git a/src/core/url_request_context_getter_qt.cpp b/src/core/url_request_context_getter_qt.cpp
index 10923e4cb..c2e592bc5 100644
--- a/src/core/url_request_context_getter_qt.cpp
+++ b/src/core/url_request_context_getter_qt.cpp
@@ -126,22 +126,29 @@ void URLRequestContextGetterQt::updateStorageSettings()
     }
 }
 
-void URLRequestContextGetterQt::generateStorage()
+void URLRequestContextGetterQt::cancelAllUrlRequests()
 {
     Q_ASSERT(m_urlRequestContext);
 
-    if (m_storage) {
-        // We must stop all requests before deleting their backends.
-        std::set<const net::URLRequest*>* url_requests = m_urlRequestContext->url_requests();
-        std::set<const net::URLRequest*>::const_iterator it = url_requests->begin();
-        std::set<const net::URLRequest*>::const_iterator end = url_requests->end();
-        for ( ; it != end; ++it) {
-            net::URLRequest* request = const_cast<net::URLRequest*>(*it);
-            if (request)
-                request->Cancel();
-        }
+    std::set<const net::URLRequest*>* url_requests = m_urlRequestContext->url_requests();
+    std::set<const net::URLRequest*>::const_iterator it = url_requests->begin();
+    std::set<const net::URLRequest*>::const_iterator end = url_requests->end();
+    for ( ; it != end; ++it) {
+        net::URLRequest* request = const_cast<net::URLRequest*>(*it);
+        if (request)
+            request->Cancel();
     }
 
+}
+
+void URLRequestContextGetterQt::generateStorage()
+{
+    Q_ASSERT(m_urlRequestContext);
+
+    // We must stop all requests before deleting their backends.
+    if (m_storage)
+        cancelAllUrlRequests();
+
     m_storage.reset(new net::URLRequestContextStorage(m_urlRequestContext.get()));
 
     net::ProxyConfigService *proxyConfigService = m_proxyConfigService.fetchAndStoreAcquire(0);
@@ -260,11 +267,56 @@ void URLRequestContextGetterQt::updateHttpCache()
     }
 }
 
+static bool doNetworkSessionParamsMatch(const net::HttpNetworkSession::Params &first, const net::HttpNetworkSession::Params &second)
+{
+    if (first.transport_security_state != second.transport_security_state)
+        return false;
+    if (first.cert_verifier != second.cert_verifier)
+        return false;
+    if (first.channel_id_service != second.channel_id_service)
+        return false;
+    if (first.proxy_service != second.proxy_service)
+        return false;
+    if (first.ssl_config_service != second.ssl_config_service)
+        return false;
+    if (first.http_auth_handler_factory != second.http_auth_handler_factory)
+        return false;
+    if (first.network_delegate != second.network_delegate)
+        return false;
+    if (first.http_server_properties.get() != second.http_server_properties.get())
+        return false;
+    if (first.ignore_certificate_errors != second.ignore_certificate_errors)
+        return false;
+    if (first.host_resolver != second.host_resolver)
+        return false;
+
+    return true;
+}
+
+net::HttpNetworkSession::Params URLRequestContextGetterQt::generateNetworkSessionParams()
+{
+    Q_ASSERT(m_urlRequestContext);
+
+    net::HttpNetworkSession::Params network_session_params;
+
+    network_session_params.transport_security_state     = m_urlRequestContext->transport_security_state();
+    network_session_params.cert_verifier                = m_urlRequestContext->cert_verifier();
+    network_session_params.channel_id_service           = m_urlRequestContext->channel_id_service();
+    network_session_params.proxy_service                = m_urlRequestContext->proxy_service();
+    network_session_params.ssl_config_service           = m_urlRequestContext->ssl_config_service();
+    network_session_params.http_auth_handler_factory    = m_urlRequestContext->http_auth_handler_factory();
+    network_session_params.network_delegate             = m_networkDelegate.get();
+    network_session_params.http_server_properties       = m_urlRequestContext->http_server_properties();
+    network_session_params.ignore_certificate_errors    = m_ignoreCertificateErrors;
+    network_session_params.host_resolver                = m_urlRequestContext->host_resolver();
+
+    return network_session_params;
+}
+
 void URLRequestContextGetterQt::generateHttpCache()
 {
     Q_ASSERT(m_urlRequestContext);
     Q_ASSERT(m_storage);
-    m_updateHttpCache = 0;
 
     net::HttpCache::DefaultBackend* main_backend = 0;
     switch (m_browserContext->httpCacheType()) {
@@ -290,19 +342,21 @@ void URLRequestContextGetterQt::generateHttpCache()
         break;
     }
 
-    net::HttpNetworkSession::Params network_session_params;
-    network_session_params.transport_security_state     = m_urlRequestContext->transport_security_state();
-    network_session_params.cert_verifier                = m_urlRequestContext->cert_verifier();
-    network_session_params.channel_id_service           = m_urlRequestContext->channel_id_service();
-    network_session_params.proxy_service                = m_urlRequestContext->proxy_service();
-    network_session_params.ssl_config_service           = m_urlRequestContext->ssl_config_service();
-    network_session_params.http_auth_handler_factory    = m_urlRequestContext->http_auth_handler_factory();
-    network_session_params.network_delegate             = m_networkDelegate.get();
-    network_session_params.http_server_properties       = m_urlRequestContext->http_server_properties();
-    network_session_params.ignore_certificate_errors    = m_ignoreCertificateErrors;
-    network_session_params.host_resolver                = m_urlRequestContext->host_resolver();
+    net::HttpCache *cache = 0;
+    net::HttpNetworkSession *network_session = 0;
+    net::HttpNetworkSession::Params network_session_params = generateNetworkSessionParams();
+
+    if (m_urlRequestContext->http_transaction_factory())
+        network_session = m_urlRequestContext->http_transaction_factory()->GetSession();
 
-    m_storage->set_http_transaction_factory(new net::HttpCache(network_session_params, main_backend));
+    if (!network_session || !doNetworkSessionParamsMatch(network_session_params, network_session->params())) {
+        cancelAllUrlRequests();
+        cache = new net::HttpCache(network_session_params, main_backend);
+    } else
+        cache = new net::HttpCache(network_session, main_backend);
+
+    m_storage->set_http_transaction_factory(cache);
+    m_updateHttpCache = 0;
 }
 
 void URLRequestContextGetterQt::generateJobFactory()
diff --git a/src/core/url_request_context_getter_qt.h b/src/core/url_request_context_getter_qt.h
index 38cfd7957..dc861f8da 100644
--- a/src/core/url_request_context_getter_qt.h
+++ b/src/core/url_request_context_getter_qt.h
@@ -45,6 +45,7 @@
 #include "base/single_thread_task_runner.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/common/url_constants.h"
+#include "net/http/http_network_session.h"
 #include "net/url_request/url_request_context_storage.h"
 #include "net/url_request/url_request_job_factory_impl.h"
 #include "net/proxy/dhcp_proxy_script_fetcher_factory.h"
@@ -84,6 +85,8 @@ private:
     void generateHttpCache();
     void generateUserAgent();
     void generateJobFactory();
+    void cancelAllUrlRequests();
+    net::HttpNetworkSession::Params generateNetworkSessionParams();
 
     bool m_ignoreCertificateErrors;
     QAtomicInt m_updateCookieStore;
-- 
GitLab