Browse Source

fix: notify request context shutdown on IO before cleanup (#14058)

Robo 6 years ago
parent
commit
9989195f19

+ 5 - 3
atom/browser/api/atom_api_cookies.cc

@@ -5,6 +5,7 @@
 #include "atom/browser/api/atom_api_cookies.h"
 
 #include "atom/browser/atom_browser_context.h"
+#include "atom/browser/request_context_delegate.h"
 #include "atom/common/native_mate_converters/callback.h"
 #include "atom/common/native_mate_converters/gurl_converter.h"
 #include "atom/common/native_mate_converters/value_converter.h"
@@ -253,9 +254,10 @@ void SetCookieOnIO(scoped_refptr<net::URLRequestContextGetter> getter,
 Cookies::Cookies(v8::Isolate* isolate, AtomBrowserContext* browser_context)
     : browser_context_(browser_context) {
   Init(isolate);
-  auto subscription = browser_context->RegisterCookieChangeCallback(
-      base::Bind(&Cookies::OnCookieChanged, base::Unretained(this)));
-  browser_context->set_cookie_change_subscription(std::move(subscription));
+  cookie_change_subscription_ =
+      browser_context->GetRequestContextDelegate()
+          ->RegisterCookieChangeCallback(
+              base::Bind(&Cookies::OnCookieChanged, base::Unretained(this)));
 }
 
 Cookies::~Cookies() {}

+ 3 - 1
atom/browser/api/atom_api_cookies.h

@@ -9,7 +9,7 @@
 
 #include "atom/browser/api/trackable_object.h"
 #include "atom/browser/net/cookie_details.h"
-#include "base/callback.h"
+#include "base/callback_list.h"
 #include "native_mate/handle.h"
 #include "net/cookies/canonical_cookie.h"
 
@@ -59,6 +59,8 @@ class Cookies : public mate::TrackableObject<Cookies> {
   void OnCookieChanged(const CookieDetails*);
 
  private:
+  std::unique_ptr<base::CallbackList<void(const CookieDetails*)>::Subscription>
+      cookie_change_subscription_;
   scoped_refptr<AtomBrowserContext> browser_context_;
 
   DISALLOW_COPY_AND_ASSIGN(Cookies);

+ 2 - 2
atom/browser/api/atom_api_protocol.h

@@ -78,13 +78,13 @@ class Protocol : public mate::TrackableObject<Protocol> {
         net::URLRequest* request,
         net::NetworkDelegate* network_delegate) const override {
       RequestJob* request_job = new RequestJob(request, network_delegate);
-      request_job->SetHandlerInfo(isolate_, request_context_.get(), handler_);
+      request_job->SetHandlerInfo(isolate_, request_context_, handler_);
       return request_job;
     }
 
    private:
     v8::Isolate* isolate_;
-    scoped_refptr<net::URLRequestContextGetter> request_context_;
+    net::URLRequestContextGetter* request_context_;
     Protocol::Handler handler_;
 
     DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);

+ 7 - 22
atom/browser/api/atom_api_session.cc

@@ -244,7 +244,7 @@ class ResolveProxyHelper {
       : callback_(callback),
         original_thread_(base::ThreadTaskRunnerHandle::Get()) {
     scoped_refptr<net::URLRequestContextGetter> context_getter =
-        browser_context->url_request_context_getter();
+        browser_context->GetRequestContext();
     context_getter->GetNetworkTaskRunner()->PostTask(
         FROM_HERE, base::BindOnce(&ResolveProxyHelper::ResolveProxy,
                                   base::Unretained(this), context_getter, url));
@@ -453,15 +453,6 @@ void SetDevToolsNetworkEmulationClientIdInIO(
   network_delegate->SetDevToolsNetworkEmulationClientId(client_id);
 }
 
-// Clear protocol handlers in IO thread.
-void ClearJobFactoryInIO(
-    scoped_refptr<brightray::URLRequestContextGetter> request_context_getter) {
-  auto* job_factory = static_cast<AtomURLRequestJobFactory*>(
-      request_context_getter->job_factory());
-  if (job_factory)
-    job_factory->Clear();
-}
-
 void DestroyGlobalHandle(v8::Isolate* isolate,
                          const v8::Global<v8::Value>& global_handle) {
   v8::Locker locker(isolate);
@@ -495,10 +486,6 @@ Session::Session(v8::Isolate* isolate, AtomBrowserContext* browser_context)
 }
 
 Session::~Session() {
-  auto* getter = browser_context_->GetRequestContext();
-  content::BrowserThread::PostTask(
-      content::BrowserThread::IO, FROM_HERE,
-      base::BindOnce(ClearJobFactoryInIO, base::RetainedRef(getter)));
   content::BrowserContext::GetDownloadManager(browser_context())
       ->RemoveObserver(this);
   DestroyGlobalHandle(isolate(), cookies_);
@@ -597,10 +584,9 @@ void Session::EnableNetworkEmulation(const mate::Dictionary& options) {
       devtools_network_emulation_client_id_, std::move(conditions));
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
-      base::BindOnce(
-          &SetDevToolsNetworkEmulationClientIdInIO,
-          base::RetainedRef(browser_context_->url_request_context_getter()),
-          devtools_network_emulation_client_id_));
+      base::BindOnce(&SetDevToolsNetworkEmulationClientIdInIO,
+                     base::RetainedRef(browser_context_->GetRequestContext()),
+                     devtools_network_emulation_client_id_));
 }
 
 void Session::DisableNetworkEmulation() {
@@ -609,10 +595,9 @@ void Session::DisableNetworkEmulation() {
       devtools_network_emulation_client_id_, std::move(conditions));
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
-      base::BindOnce(
-          &SetDevToolsNetworkEmulationClientIdInIO,
-          base::RetainedRef(browser_context_->url_request_context_getter()),
-          std::string()));
+      base::BindOnce(&SetDevToolsNetworkEmulationClientIdInIO,
+                     base::RetainedRef(browser_context_->GetRequestContext()),
+                     std::string()));
 }
 
 void Session::SetCertVerifyProc(v8::Local<v8::Value> val,

+ 1 - 1
atom/browser/api/atom_api_web_request.cc

@@ -95,7 +95,7 @@ void WebRequest::SetListener(Method method, Event type, mate::Arguments* args) {
   }
 
   brightray::URLRequestContextGetter* url_request_context_getter =
-      browser_context_->url_request_context_getter();
+      browser_context_->GetRequestContext();
   if (!url_request_context_getter)
     return;
   BrowserThread::PostTask(

+ 21 - 122
atom/browser/atom_browser_context.cc

@@ -4,59 +4,30 @@
 
 #include "atom/browser/atom_browser_context.h"
 
-#include "atom/browser/api/atom_api_protocol.h"
 #include "atom/browser/atom_blob_reader.h"
 #include "atom/browser/atom_browser_main_parts.h"
 #include "atom/browser/atom_download_manager_delegate.h"
 #include "atom/browser/atom_permission_manager.h"
 #include "atom/browser/browser.h"
-#include "atom/browser/net/about_protocol_handler.h"
-#include "atom/browser/net/asar/asar_protocol_handler.h"
-#include "atom/browser/net/atom_cert_verifier.h"
-#include "atom/browser/net/atom_network_delegate.h"
-#include "atom/browser/net/atom_url_request_job_factory.h"
-#include "atom/browser/net/cookie_details.h"
-#include "atom/browser/net/http_protocol_handler.h"
+#include "atom/browser/request_context_delegate.h"
 #include "atom/browser/web_view_manager.h"
 #include "atom/common/atom_version.h"
 #include "atom/common/chrome_version.h"
 #include "atom/common/options_switches.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
-#include "base/memory/ptr_util.h"
 #include "base/path_service.h"
-#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/task_scheduler/post_task.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/storage_partition.h"
-#include "content/public/common/url_constants.h"
 #include "content/public/common/user_agent.h"
-#include "net/ftp/ftp_network_layer.h"
-#include "net/url_request/data_protocol_handler.h"
-#include "net/url_request/ftp_protocol_handler.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_intercepting_job_factory.h"
-#include "url/url_constants.h"
-
-using content::BrowserThread;
 
 namespace atom {
 
 namespace {
 
-class NoCacheBackend : public net::HttpCache::BackendFactory {
-  int CreateBackend(net::NetLog* net_log,
-                    std::unique_ptr<disk_cache::Backend>* backend,
-                    const net::CompletionCallback& callback) override {
-    return net::ERR_FAILED;
-  }
-};
-
 std::string RemoveWhitespace(const std::string& str) {
   std::string trimmed;
   if (base::RemoveChars(str, " ", &trimmed))
@@ -70,7 +41,8 @@ std::string RemoveWhitespace(const std::string& str) {
 AtomBrowserContext::AtomBrowserContext(const std::string& partition,
                                        bool in_memory,
                                        const base::DictionaryValue& options)
-    : brightray::BrowserContext(partition, in_memory) {
+    : brightray::BrowserContext(partition, in_memory),
+      url_request_context_getter_(nullptr) {
   // Construct user agent string.
   Browser* browser = Browser::Get();
   std::string name = RemoveWhitespace(browser->GetName());
@@ -86,87 +58,24 @@ AtomBrowserContext::AtomBrowserContext(const std::string& partition,
   user_agent_ = content::BuildUserAgentFromProduct(user_agent);
 
   // Read options.
-  use_cache_ = true;
-  options.GetBoolean("cache", &use_cache_);
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  bool use_cache = !command_line->HasSwitch(switches::kDisableHttpCache);
+  options.GetBoolean("cache", &use_cache);
+
+  request_context_delegate_.reset(new RequestContextDelegate(use_cache));
 
   // Initialize Pref Registry in brightray.
   InitPrefs();
 }
 
-AtomBrowserContext::~AtomBrowserContext() {}
+AtomBrowserContext::~AtomBrowserContext() {
+  url_request_context_getter_->set_delegate(nullptr);
+}
 
 void AtomBrowserContext::SetUserAgent(const std::string& user_agent) {
   user_agent_ = user_agent;
 }
 
-std::unique_ptr<base::CallbackList<void(const CookieDetails*)>::Subscription>
-AtomBrowserContext::RegisterCookieChangeCallback(
-    const base::Callback<void(const CookieDetails*)>& cb) {
-  return cookie_change_sub_list_.Add(cb);
-}
-
-std::unique_ptr<net::NetworkDelegate>
-AtomBrowserContext::CreateNetworkDelegate() {
-  return std::make_unique<AtomNetworkDelegate>();
-}
-
-std::string AtomBrowserContext::GetUserAgent() {
-  return user_agent_;
-}
-
-std::unique_ptr<net::URLRequestJobFactory>
-AtomBrowserContext::CreateURLRequestJobFactory(
-    content::ProtocolHandlerMap* protocol_handlers) {
-  std::unique_ptr<AtomURLRequestJobFactory> job_factory(
-      new AtomURLRequestJobFactory);
-
-  for (auto& it : *protocol_handlers) {
-    job_factory->SetProtocolHandler(it.first,
-                                    base::WrapUnique(it.second.release()));
-  }
-  protocol_handlers->clear();
-
-  job_factory->SetProtocolHandler(url::kAboutScheme,
-                                  base::WrapUnique(new AboutProtocolHandler));
-  job_factory->SetProtocolHandler(
-      url::kDataScheme, base::WrapUnique(new net::DataProtocolHandler));
-  job_factory->SetProtocolHandler(
-      url::kFileScheme,
-      base::WrapUnique(
-          new asar::AsarProtocolHandler(base::CreateTaskRunnerWithTraits(
-              {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
-               base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}))));
-  job_factory->SetProtocolHandler(
-      url::kHttpScheme,
-      base::WrapUnique(new HttpProtocolHandler(url::kHttpScheme)));
-  job_factory->SetProtocolHandler(
-      url::kHttpsScheme,
-      base::WrapUnique(new HttpProtocolHandler(url::kHttpsScheme)));
-  job_factory->SetProtocolHandler(
-      url::kWsScheme,
-      base::WrapUnique(new HttpProtocolHandler(url::kWsScheme)));
-  job_factory->SetProtocolHandler(
-      url::kWssScheme,
-      base::WrapUnique(new HttpProtocolHandler(url::kWssScheme)));
-
-  auto* host_resolver =
-      url_request_context_getter()->GetURLRequestContext()->host_resolver();
-  job_factory->SetProtocolHandler(
-      url::kFtpScheme, net::FtpProtocolHandler::Create(host_resolver));
-
-  return std::move(job_factory);
-}
-
-net::HttpCache::BackendFactory*
-AtomBrowserContext::CreateHttpCacheBackendFactory(
-    const base::FilePath& base_path) {
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  if (!use_cache_ || command_line->HasSwitch(switches::kDisableHttpCache))
-    return new NoCacheBackend;
-  else
-    return brightray::BrowserContext::CreateHttpCacheBackendFactory(base_path);
-}
-
 content::DownloadManagerDelegate*
 AtomBrowserContext::GetDownloadManagerDelegate() {
   if (!download_manager_delegate_.get()) {
@@ -189,26 +98,6 @@ content::PermissionManager* AtomBrowserContext::GetPermissionManager() {
   return permission_manager_.get();
 }
 
-std::unique_ptr<net::CertVerifier> AtomBrowserContext::CreateCertVerifier(
-    brightray::RequireCTDelegate* ct_delegate) {
-  return base::WrapUnique(new AtomCertVerifier(ct_delegate));
-}
-
-std::vector<std::string> AtomBrowserContext::GetCookieableSchemes() {
-  auto default_schemes = brightray::BrowserContext::GetCookieableSchemes();
-  const auto& standard_schemes = atom::api::GetStandardSchemes();
-  default_schemes.insert(default_schemes.end(), standard_schemes.begin(),
-                         standard_schemes.end());
-  return default_schemes;
-}
-
-void AtomBrowserContext::NotifyCookieChange(const net::CanonicalCookie& cookie,
-                                            bool removed,
-                                            net::CookieChangeCause cause) {
-  CookieDetails cookie_details(&cookie, removed, cause);
-  cookie_change_sub_list_.Notify(&cookie_details);
-}
-
 void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) {
   pref_registry->RegisterFilePathPref(prefs::kSelectFileLastDirectory,
                                       base::FilePath());
@@ -219,6 +108,16 @@ void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) {
   pref_registry->RegisterDictionaryPref(prefs::kDevToolsFileSystemPaths);
 }
 
+std::string AtomBrowserContext::GetUserAgent() const {
+  return user_agent_;
+}
+
+void AtomBrowserContext::OnMainRequestContextCreated(
+    brightray::URLRequestContextGetter* getter) {
+  getter->set_delegate(request_context_delegate_.get());
+  url_request_context_getter_ = getter;
+}
+
 AtomBlobReader* AtomBrowserContext::GetBlobReader() {
   if (!blob_reader_.get()) {
     content::ChromeBlobStorageContext* blob_context =

+ 10 - 33
atom/browser/atom_browser_context.h

@@ -8,17 +8,15 @@
 #include <string>
 #include <vector>
 
-#include "base/callback_list.h"
 #include "brightray/browser/browser_context.h"
 
 namespace atom {
 
 class AtomBlobReader;
 class AtomDownloadManagerDelegate;
-class AtomNetworkDelegate;
 class AtomPermissionManager;
+class RequestContextDelegate;
 class WebViewManager;
-struct CookieDetails;
 
 class AtomBrowserContext : public brightray::BrowserContext {
  public:
@@ -31,24 +29,7 @@ class AtomBrowserContext : public brightray::BrowserContext {
       const base::DictionaryValue& options = base::DictionaryValue());
 
   void SetUserAgent(const std::string& user_agent);
-  // Register callbacks that needs to notified on any cookie store changes.
-  std::unique_ptr<base::CallbackList<void(const CookieDetails*)>::Subscription>
-  RegisterCookieChangeCallback(
-      const base::Callback<void(const CookieDetails*)>& cb);
-
-  // brightray::URLRequestContextGetter::Delegate:
-  std::unique_ptr<net::NetworkDelegate> CreateNetworkDelegate() override;
-  std::string GetUserAgent() override;
-  std::unique_ptr<net::URLRequestJobFactory> CreateURLRequestJobFactory(
-      content::ProtocolHandlerMap* protocol_handlers) override;
-  net::HttpCache::BackendFactory* CreateHttpCacheBackendFactory(
-      const base::FilePath& base_path) override;
-  std::unique_ptr<net::CertVerifier> CreateCertVerifier(
-      brightray::RequireCTDelegate* ct_delegate) override;
-  std::vector<std::string> GetCookieableSchemes() override;
-  void NotifyCookieChange(const net::CanonicalCookie& cookie,
-                          bool removed,
-                          net::CookieChangeCause cause) override;
+  AtomBlobReader* GetBlobReader();
 
   // content::BrowserContext:
   content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;
@@ -57,14 +38,12 @@ class AtomBrowserContext : public brightray::BrowserContext {
 
   // brightray::BrowserContext:
   void RegisterPrefs(PrefRegistrySimple* pref_registry) override;
+  std::string GetUserAgent() const override;
+  void OnMainRequestContextCreated(
+      brightray::URLRequestContextGetter* getter) override;
 
-  AtomBlobReader* GetBlobReader();
-
-  void set_cookie_change_subscription(
-      std::unique_ptr<
-          base::CallbackList<void(const CookieDetails*)>::Subscription>
-          subscription) {
-    cookie_change_subscription_.swap(subscription);
+  RequestContextDelegate* GetRequestContextDelegate() const {
+    return request_context_delegate_.get();
   }
 
  protected:
@@ -74,16 +53,14 @@ class AtomBrowserContext : public brightray::BrowserContext {
   ~AtomBrowserContext() override;
 
  private:
+  brightray::URLRequestContextGetter* url_request_context_getter_;
+
   std::unique_ptr<AtomDownloadManagerDelegate> download_manager_delegate_;
   std::unique_ptr<WebViewManager> guest_manager_;
   std::unique_ptr<AtomPermissionManager> permission_manager_;
   std::unique_ptr<AtomBlobReader> blob_reader_;
+  std::unique_ptr<RequestContextDelegate> request_context_delegate_;
   std::string user_agent_;
-  bool use_cache_;
-
-  base::CallbackList<void(const CookieDetails*)> cookie_change_sub_list_;
-  std::unique_ptr<base::CallbackList<void(const CookieDetails*)>::Subscription>
-      cookie_change_subscription_;
 
   DISALLOW_COPY_AND_ASSIGN(AtomBrowserContext);
 };

+ 1 - 4
atom/browser/net/atom_url_request.cc

@@ -70,11 +70,8 @@ scoped_refptr<AtomURLRequest> AtomURLRequest::Create(
     return nullptr;
   }
   scoped_refptr<brightray::URLRequestContextGetter> request_context_getter(
-      browser_context->url_request_context_getter());
+      browser_context->GetRequestContext());
   DCHECK(request_context_getter);
-  if (!request_context_getter) {
-    return nullptr;
-  }
   scoped_refptr<AtomURLRequest> atom_url_request(new AtomURLRequest(delegate));
   if (content::BrowserThread::PostTask(
           content::BrowserThread::IO, FROM_HERE,

+ 6 - 6
atom/browser/net/url_request_fetch_job.cc

@@ -9,6 +9,7 @@
 
 #include "atom/browser/api/atom_api_session.h"
 #include "atom/browser/atom_browser_context.h"
+#include "base/guid.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_util.h"
 #include "native_mate/dictionary.h"
@@ -93,16 +94,15 @@ void URLRequestFetchJob::BeforeStartInUI(v8::Isolate* isolate,
   if (options.Get("session", &val)) {
     if (val->IsNull()) {
       // We have to create the URLRequestContextGetter on UI thread.
-      url_request_context_getter_ = new brightray::URLRequestContextGetter(
-          this, nullptr, base::FilePath(), true,
-          BrowserThread::GetTaskRunnerForThread(BrowserThread::IO), nullptr,
-          content::URLRequestInterceptorScopedVector());
+      custom_browser_context_ =
+          AtomBrowserContext::From(base::GenerateGUID(), true);
+      url_request_context_getter_ =
+          custom_browser_context_->GetRequestContext();
     } else {
       mate::Handle<api::Session> session;
       if (mate::ConvertFromV8(isolate, val, &session) && !session.IsEmpty()) {
         AtomBrowserContext* browser_context = session->browser_context();
-        url_request_context_getter_ =
-            browser_context->url_request_context_getter();
+        url_request_context_getter_ = browser_context->GetRequestContext();
       }
     }
   }

+ 5 - 3
atom/browser/net/url_request_fetch_job.h

@@ -8,16 +8,17 @@
 #include <string>
 
 #include "atom/browser/net/js_asker.h"
-#include "brightray/browser/url_request_context_getter.h"
 #include "content/browser/streams/stream.h"
 #include "content/browser/streams/stream_read_observer.h"
 #include "net/url_request/url_fetcher_delegate.h"
+#include "net/url_request/url_request_context_getter.h"
 
 namespace atom {
 
+class AtomBrowserContext;
+
 class URLRequestFetchJob : public JsAsker<net::URLRequestJob>,
-                           public net::URLFetcherDelegate,
-                           public brightray::URLRequestContextGetter::Delegate {
+                           public net::URLFetcherDelegate {
  public:
   URLRequestFetchJob(net::URLRequest*, net::NetworkDelegate*);
   ~URLRequestFetchJob() override;
@@ -51,6 +52,7 @@ class URLRequestFetchJob : public JsAsker<net::URLRequestJob>,
   void ClearPendingBuffer();
   void ClearWriteBuffer();
 
+  scoped_refptr<AtomBrowserContext> custom_browser_context_;
   scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
   std::unique_ptr<net::URLFetcher> fetcher_;
   std::unique_ptr<net::HttpResponseInfo> response_info_;

+ 163 - 0
atom/browser/request_context_delegate.cc

@@ -0,0 +1,163 @@
+// Copyright (c) 2018 GitHub, Inc.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#include "atom/browser/request_context_delegate.h"
+
+#include "atom/browser/api/atom_api_protocol.h"
+#include "atom/browser/net/about_protocol_handler.h"
+#include "atom/browser/net/asar/asar_protocol_handler.h"
+#include "atom/browser/net/atom_cert_verifier.h"
+#include "atom/browser/net/atom_network_delegate.h"
+#include "atom/browser/net/atom_url_request_job_factory.h"
+#include "atom/browser/net/cookie_details.h"
+#include "atom/browser/net/http_protocol_handler.h"
+#include "atom/common/options_switches.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/task_scheduler/post_task.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/common/url_constants.h"
+#include "net/ftp/ftp_network_layer.h"
+#include "net/url_request/data_protocol_handler.h"
+#include "net/url_request/ftp_protocol_handler.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_intercepting_job_factory.h"
+#include "url/url_constants.h"
+
+using content::BrowserThread;
+
+namespace atom {
+
+namespace {
+
+class NoCacheBackend : public net::HttpCache::BackendFactory {
+  int CreateBackend(net::NetLog* net_log,
+                    std::unique_ptr<disk_cache::Backend>* backend,
+                    const net::CompletionCallback& callback) override {
+    return net::ERR_FAILED;
+  }
+};
+
+}  // namespace
+
+RequestContextDelegate::RequestContextDelegate(bool use_cache)
+    : use_cache_(use_cache), weak_factory_(this) {}
+
+RequestContextDelegate::~RequestContextDelegate() {}
+
+std::unique_ptr<base::CallbackList<void(const CookieDetails*)>::Subscription>
+RequestContextDelegate::RegisterCookieChangeCallback(
+    const base::Callback<void(const CookieDetails*)>& cb) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  return cookie_change_sub_list_.Add(cb);
+}
+
+void RequestContextDelegate::NotifyCookieChange(
+    const net::CanonicalCookie& cookie,
+    net::CookieChangeCause cause) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  CookieDetails cookie_details(
+      &cookie, !(cause == net::CookieChangeCause::INSERTED), cause);
+  cookie_change_sub_list_.Notify(&cookie_details);
+}
+
+std::unique_ptr<net::NetworkDelegate>
+RequestContextDelegate::CreateNetworkDelegate() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  return std::make_unique<AtomNetworkDelegate>();
+}
+
+std::unique_ptr<net::URLRequestJobFactory>
+RequestContextDelegate::CreateURLRequestJobFactory(
+    net::URLRequestContext* url_request_context,
+    content::ProtocolHandlerMap* protocol_handlers) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  std::unique_ptr<AtomURLRequestJobFactory> job_factory(
+      new AtomURLRequestJobFactory);
+
+  for (auto& it : *protocol_handlers) {
+    job_factory->SetProtocolHandler(it.first,
+                                    base::WrapUnique(it.second.release()));
+  }
+  protocol_handlers->clear();
+
+  job_factory->SetProtocolHandler(url::kAboutScheme,
+                                  base::WrapUnique(new AboutProtocolHandler));
+  job_factory->SetProtocolHandler(
+      url::kDataScheme, base::WrapUnique(new net::DataProtocolHandler));
+  job_factory->SetProtocolHandler(
+      url::kFileScheme,
+      base::WrapUnique(
+          new asar::AsarProtocolHandler(base::CreateTaskRunnerWithTraits(
+              {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
+               base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}))));
+  job_factory->SetProtocolHandler(
+      url::kHttpScheme,
+      base::WrapUnique(new HttpProtocolHandler(url::kHttpScheme)));
+  job_factory->SetProtocolHandler(
+      url::kHttpsScheme,
+      base::WrapUnique(new HttpProtocolHandler(url::kHttpsScheme)));
+  job_factory->SetProtocolHandler(
+      url::kWsScheme,
+      base::WrapUnique(new HttpProtocolHandler(url::kWsScheme)));
+  job_factory->SetProtocolHandler(
+      url::kWssScheme,
+      base::WrapUnique(new HttpProtocolHandler(url::kWssScheme)));
+
+  auto* host_resolver = url_request_context->host_resolver();
+  job_factory->SetProtocolHandler(
+      url::kFtpScheme, net::FtpProtocolHandler::Create(host_resolver));
+
+  return std::move(job_factory);
+}
+
+net::HttpCache::BackendFactory*
+RequestContextDelegate::CreateHttpCacheBackendFactory(
+    const base::FilePath& base_path) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  if (!use_cache_) {
+    return new NoCacheBackend;
+  } else {
+    int max_size = 0;
+    base::StringToInt(
+        command_line->GetSwitchValueASCII(switches::kDiskCacheSize), &max_size);
+
+    base::FilePath cache_path = base_path.Append(FILE_PATH_LITERAL("Cache"));
+    return new net::HttpCache::DefaultBackend(
+        net::DISK_CACHE, net::CACHE_BACKEND_DEFAULT, cache_path, max_size);
+  }
+}
+
+std::unique_ptr<net::CertVerifier> RequestContextDelegate::CreateCertVerifier(
+    brightray::RequireCTDelegate* ct_delegate) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  return std::make_unique<AtomCertVerifier>(ct_delegate);
+}
+
+void RequestContextDelegate::GetCookieableSchemes(
+    std::vector<std::string>* cookie_schemes) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  const auto& standard_schemes = atom::api::GetStandardSchemes();
+  cookie_schemes->insert(cookie_schemes->end(), standard_schemes.begin(),
+                         standard_schemes.end());
+}
+
+void RequestContextDelegate::OnCookieChanged(const net::CanonicalCookie& cookie,
+                                             net::CookieChangeCause cause) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::BindRepeating(&RequestContextDelegate::NotifyCookieChange,
+                          weak_factory_.GetWeakPtr(), cookie, cause));
+}
+
+}  // namespace atom

+ 58 - 0
atom/browser/request_context_delegate.h

@@ -0,0 +1,58 @@
+// Copyright (c) 2018 GitHub, Inc.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#ifndef ATOM_BROWSER_REQUEST_CONTEXT_DELEGATE_H_
+#define ATOM_BROWSER_REQUEST_CONTEXT_DELEGATE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback_list.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "brightray/browser/url_request_context_getter.h"
+
+namespace atom {
+
+struct CookieDetails;
+
+class RequestContextDelegate
+    : public brightray::URLRequestContextGetter::Delegate {
+ public:
+  explicit RequestContextDelegate(bool use_cache);
+  ~RequestContextDelegate() override;
+
+  // Register callbacks that needs to notified on any cookie store changes.
+  std::unique_ptr<base::CallbackList<void(const CookieDetails*)>::Subscription>
+  RegisterCookieChangeCallback(
+      const base::Callback<void(const CookieDetails*)>& cb);
+
+ protected:
+  std::unique_ptr<net::NetworkDelegate> CreateNetworkDelegate() override;
+  std::unique_ptr<net::URLRequestJobFactory> CreateURLRequestJobFactory(
+      net::URLRequestContext* url_request_context,
+      content::ProtocolHandlerMap* protocol_handlers) override;
+  net::HttpCache::BackendFactory* CreateHttpCacheBackendFactory(
+      const base::FilePath& base_path) override;
+  std::unique_ptr<net::CertVerifier> CreateCertVerifier(
+      brightray::RequireCTDelegate* ct_delegate) override;
+  void GetCookieableSchemes(std::vector<std::string>* cookie_schemes) override;
+  void OnCookieChanged(const net::CanonicalCookie& cookie,
+                       net::CookieChangeCause cause) override;
+
+ private:
+  void NotifyCookieChange(const net::CanonicalCookie& cookie,
+                          net::CookieChangeCause cause);
+
+  base::CallbackList<void(const CookieDetails*)> cookie_change_sub_list_;
+  bool use_cache_ = true;
+
+  base::WeakPtrFactory<RequestContextDelegate> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(RequestContextDelegate);
+};
+
+}  // namespace atom
+
+#endif  // ATOM_BROWSER_REQUEST_CONTEXT_DELEGATE_H_

+ 3 - 0
atom/common/options_switches.cc

@@ -210,6 +210,9 @@ const char kWidevineCdmPath[] = "widevine-cdm-path";
 // Widevine CDM version.
 const char kWidevineCdmVersion[] = "widevine-cdm-version";
 
+// Forces the maximum disk space to be used by the disk cache, in bytes.
+const char kDiskCacheSize[] = "disk-cache-size";
+
 }  // namespace switches
 
 }  // namespace atom

+ 2 - 0
atom/common/options_switches.h

@@ -109,6 +109,8 @@ extern const char kWebviewTag[];
 extern const char kWidevineCdmPath[];
 extern const char kWidevineCdmVersion[];
 
+extern const char kDiskCacheSize[];
+
 }  // namespace switches
 
 }  // namespace atom

+ 22 - 42
brightray/browser/browser_context.cc

@@ -11,7 +11,6 @@
 #include "brightray/browser/brightray_paths.h"
 #include "brightray/browser/browser_client.h"
 #include "brightray/browser/inspectable_web_contents_impl.h"
-#include "brightray/browser/network_delegate.h"
 #include "brightray/browser/special_storage_policy.h"
 #include "brightray/browser/zoom_level_delegate.h"
 #include "brightray/common/application_info.h"
@@ -20,7 +19,6 @@
 #include "components/prefs/pref_service.h"
 #include "components/prefs/pref_service_factory.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/resource_context.h"
 #include "content/public/browser/storage_partition.h"
 #include "net/base/escape.h"
 
@@ -37,25 +35,10 @@ std::string MakePartitionName(const std::string& input) {
 
 }  // namespace
 
-class BrowserContext::ResourceContext : public content::ResourceContext {
- public:
-  ResourceContext() : getter_(nullptr) {}
-
-  void set_url_request_context_getter(URLRequestContextGetter* getter) {
-    getter_ = getter;
-  }
-
- private:
-  net::HostResolver* GetHostResolver() override {
-    return getter_->host_resolver();
-  }
-
-  net::URLRequestContext* GetRequestContext() override {
-    return getter_->GetURLRequestContext();
-  }
-
-  URLRequestContextGetter* getter_;
-};
+// static
+void BrowserContextDeleter::Destruct(const BrowserContext* browser_context) {
+  browser_context->OnDestruct();
+}
 
 // static
 BrowserContext::BrowserContextMap BrowserContext::browser_context_map_;
@@ -72,7 +55,6 @@ scoped_refptr<BrowserContext> BrowserContext::Get(const std::string& partition,
 
 BrowserContext::BrowserContext(const std::string& partition, bool in_memory)
     : in_memory_(in_memory),
-      resource_context_(new ResourceContext),
       storage_policy_(new SpecialStoragePolicy),
       weak_factory_(this) {
   if (!PathService::Get(DIR_USER_DATA, &path_)) {
@@ -88,6 +70,8 @@ BrowserContext::BrowserContext(const std::string& partition, bool in_memory)
 
   content::BrowserContext::Initialize(this, path_);
 
+  io_handle_ = new URLRequestContextGetter::Handle(GetWeakPtr());
+
   browser_context_map_[PartitionKey(partition, in_memory)] = GetWeakPtr();
 }
 
@@ -95,13 +79,14 @@ BrowserContext::~BrowserContext() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   NotifyWillBeDestroyed(this);
   ShutdownStoragePartitions();
-  if (BrowserThread::IsMessageLoopValid(BrowserThread::IO)) {
-    BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE,
-                              resource_context_.release());
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::BindOnce(&URLRequestContextGetter::NotifyContextShutdownOnIO,
-                       base::RetainedRef(url_request_getter_)));
+  io_handle_->ShutdownOnUIThread();
+}
+
+void BrowserContext::OnDestruct() const {
+  if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+    delete this;
+  } else {
+    BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this);
   }
 }
 
@@ -135,17 +120,10 @@ URLRequestContextGetter* BrowserContext::GetRequestContext() {
 net::URLRequestContextGetter* BrowserContext::CreateRequestContext(
     content::ProtocolHandlerMap* protocol_handlers,
     content::URLRequestInterceptorScopedVector protocol_interceptors) {
-  DCHECK(!url_request_getter_.get());
-  url_request_getter_ = new URLRequestContextGetter(
-      this, static_cast<NetLog*>(BrowserClient::Get()->GetNetLog()), GetPath(),
-      in_memory_, BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
-      protocol_handlers, std::move(protocol_interceptors));
-  resource_context_->set_url_request_context_getter(url_request_getter_.get());
-  return url_request_getter_.get();
-}
-
-std::unique_ptr<net::NetworkDelegate> BrowserContext::CreateNetworkDelegate() {
-  return std::make_unique<NetworkDelegate>();
+  return io_handle_
+      ->CreateMainRequestContextGetter(protocol_handlers,
+                                       std::move(protocol_interceptors))
+      .get();
 }
 
 std::string BrowserContext::GetMediaDeviceIDSalt() {
@@ -171,7 +149,7 @@ bool BrowserContext::IsOffTheRecord() const {
 }
 
 content::ResourceContext* BrowserContext::GetResourceContext() {
-  return resource_context_.get();
+  return io_handle_->GetResourceContext();
 }
 
 content::DownloadManagerDelegate* BrowserContext::GetDownloadManagerDelegate() {
@@ -214,17 +192,19 @@ BrowserContext::CreateRequestContextForStoragePartition(
     bool in_memory,
     content::ProtocolHandlerMap* protocol_handlers,
     content::URLRequestInterceptorScopedVector request_interceptors) {
+  NOTREACHED();
   return nullptr;
 }
 
 net::URLRequestContextGetter* BrowserContext::CreateMediaRequestContext() {
-  return url_request_getter_.get();
+  return io_handle_->GetMainRequestContextGetter().get();
 }
 
 net::URLRequestContextGetter*
 BrowserContext::CreateMediaRequestContextForStoragePartition(
     const base::FilePath& partition_path,
     bool in_memory) {
+  NOTREACHED();
   return nullptr;
 }
 

+ 21 - 16
brightray/browser/browser_context.h

@@ -23,9 +23,15 @@ class SpecialStoragePolicy;
 
 namespace brightray {
 
-class BrowserContext : public base::RefCounted<BrowserContext>,
-                       public content::BrowserContext,
-                       public brightray::URLRequestContextGetter::Delegate {
+class BrowserContext;
+
+struct BrowserContextDeleter {
+  static void Destruct(const BrowserContext* browser_context);
+};
+
+class BrowserContext
+    : public base::RefCountedThreadSafe<BrowserContext, BrowserContextDeleter>,
+      public content::BrowserContext {
  public:
   // Get the BrowserContext according to its |partition| and |in_memory|,
   // empty pointer when be returned when there is no matching BrowserContext.
@@ -66,14 +72,14 @@ class BrowserContext : public base::RefCounted<BrowserContext>,
       const base::FilePath& partition_path,
       bool in_memory) override;
   std::string GetMediaDeviceIDSalt() override;
-
-  URLRequestContextGetter* url_request_context_getter() const {
-    return url_request_getter_.get();
-  }
+  base::FilePath GetPath() const override;
 
   void InitPrefs();
   PrefService* prefs() { return prefs_.get(); }
 
+  virtual std::string GetUserAgent() const = 0;
+  virtual void OnMainRequestContextCreated(URLRequestContextGetter* getter) {}
+
  protected:
   BrowserContext(const std::string& partition, bool in_memory);
   ~BrowserContext() override;
@@ -81,16 +87,14 @@ class BrowserContext : public base::RefCounted<BrowserContext>,
   // Subclasses should override this to register custom preferences.
   virtual void RegisterPrefs(PrefRegistrySimple* pref_registry) {}
 
-  // URLRequestContextGetter::Delegate:
-  std::unique_ptr<net::NetworkDelegate> CreateNetworkDelegate() override;
-
-  base::FilePath GetPath() const override;
-
  private:
-  friend class base::RefCounted<BrowserContext>;
-  class ResourceContext;
+  friend class base::RefCountedThreadSafe<BrowserContext,
+                                          BrowserContextDeleter>;
+  friend class base::DeleteHelper<BrowserContext>;
+  friend struct BrowserContextDeleter;
 
   void RegisterInternalPrefs(PrefRegistrySimple* pref_registry);
+  void OnDestruct() const;
 
   // partition_id => browser_context
   struct PartitionKey {
@@ -117,11 +121,12 @@ class BrowserContext : public base::RefCounted<BrowserContext>,
   base::FilePath path_;
   bool in_memory_;
 
-  std::unique_ptr<ResourceContext> resource_context_;
-  scoped_refptr<URLRequestContextGetter> url_request_getter_;
   scoped_refptr<storage::SpecialStoragePolicy> storage_policy_;
   std::unique_ptr<PrefService> prefs_;
   std::unique_ptr<MediaDeviceIDSalt> media_device_id_salt_;
+  // Self-destructing class responsible for creating URLRequestContextGetter
+  // on the UI thread and deletes itself on the IO thread.
+  URLRequestContextGetter::Handle* io_handle_;
 
   base::WeakPtrFactory<BrowserContext> weak_factory_;
 

+ 1 - 1
brightray/browser/inspectable_web_contents_impl.cc

@@ -472,7 +472,7 @@ void InspectableWebContentsImpl::LoadNetworkResource(
   net::URLFetcher* fetcher =
       (net::URLFetcher::Create(gurl, net::URLFetcher::GET, this)).release();
   pending_requests_[fetcher] = callback;
-  fetcher->SetRequestContext(browser_context->url_request_context_getter());
+  fetcher->SetRequestContext(browser_context->GetRequestContext());
   fetcher->SetExtraRequestHeaders(headers);
   fetcher->SaveResponseWithWriter(
       std::unique_ptr<net::URLFetcherResponseWriter>(

+ 114 - 94
brightray/browser/url_request_context_getter.cc

@@ -12,6 +12,7 @@
 #include "base/strings/string_util.h"
 #include "base/task_scheduler/post_task.h"
 #include "brightray/browser/browser_client.h"
+#include "brightray/browser/browser_context.h"
 #include "brightray/browser/net/require_ct_delegate.h"
 #include "brightray/browser/net_log.h"
 #include "brightray/browser/network_delegate.h"
@@ -20,6 +21,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/cookie_store_factory.h"
 #include "content/public/browser/devtools_network_transaction_factory.h"
+#include "content/public/browser/resource_context.h"
 #include "net/base/host_mapping_rules.h"
 #include "net/cert/cert_verifier.h"
 #include "net/cert/ct_known_logs.h"
@@ -58,83 +60,107 @@ using content::BrowserThread;
 
 namespace brightray {
 
-std::string URLRequestContextGetter::Delegate::GetUserAgent() {
-  return base::EmptyString();
-}
-
-std::unique_ptr<net::NetworkDelegate>
-URLRequestContextGetter::Delegate::CreateNetworkDelegate() {
-  return nullptr;
-}
+class ResourceContext : public content::ResourceContext {
+ public:
+  ResourceContext() = default;
+  ~ResourceContext() override = default;
 
-std::unique_ptr<net::URLRequestJobFactory>
-URLRequestContextGetter::Delegate::CreateURLRequestJobFactory(
-    content::ProtocolHandlerMap* protocol_handlers) {
-  std::unique_ptr<net::URLRequestJobFactoryImpl> job_factory(
-      new net::URLRequestJobFactoryImpl);
+  net::HostResolver* GetHostResolver() override {
+    if (request_context_)
+      return request_context_->host_resolver();
+    return nullptr;
+  }
 
-  for (auto& it : *protocol_handlers) {
-    job_factory->SetProtocolHandler(it.first,
-                                    base::WrapUnique(it.second.release()));
+  net::URLRequestContext* GetRequestContext() override {
+    return request_context_;
   }
-  protocol_handlers->clear();
-
-  job_factory->SetProtocolHandler(
-      url::kDataScheme, base::WrapUnique(new net::DataProtocolHandler));
-  job_factory->SetProtocolHandler(
-      url::kFileScheme,
-      base::WrapUnique(
-          new net::FileProtocolHandler(base::CreateTaskRunnerWithTraits(
-              {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
-               base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}))));
-
-  return std::move(job_factory);
+
+ private:
+  friend class URLRequestContextGetter;
+
+  net::URLRequestContext* request_context_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(ResourceContext);
+};
+
+URLRequestContextGetter::Handle::Handle(
+    base::WeakPtr<BrowserContext> browser_context)
+    : resource_context_(new ResourceContext),
+      browser_context_(browser_context),
+      initialized_(false) {}
+
+URLRequestContextGetter::Handle::~Handle() {}
+
+content::ResourceContext* URLRequestContextGetter::Handle::GetResourceContext()
+    const {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  LazyInitialize();
+  return resource_context_.get();
 }
 
-net::HttpCache::BackendFactory*
-URLRequestContextGetter::Delegate::CreateHttpCacheBackendFactory(
-    const base::FilePath& base_path) {
-  auto* command_line = base::CommandLine::ForCurrentProcess();
-  int max_size = 0;
-  base::StringToInt(command_line->GetSwitchValueASCII(switches::kDiskCacheSize),
-                    &max_size);
-
-  base::FilePath cache_path = base_path.Append(FILE_PATH_LITERAL("Cache"));
-  return new net::HttpCache::DefaultBackend(
-      net::DISK_CACHE, net::CACHE_BACKEND_DEFAULT, cache_path, max_size);
+scoped_refptr<URLRequestContextGetter>
+URLRequestContextGetter::Handle::CreateMainRequestContextGetter(
+    content::ProtocolHandlerMap* protocol_handlers,
+    content::URLRequestInterceptorScopedVector protocol_interceptors) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(!main_request_context_getter_.get());
+  main_request_context_getter_ = new URLRequestContextGetter(
+      BrowserClient::Get()->GetNetLog(), resource_context_.get(),
+      browser_context_->IsOffTheRecord(), browser_context_->GetUserAgent(),
+      browser_context_->GetPath(), protocol_handlers,
+      std::move(protocol_interceptors));
+  browser_context_->OnMainRequestContextCreated(
+      main_request_context_getter_.get());
+  return main_request_context_getter_;
 }
 
-std::unique_ptr<net::CertVerifier>
-URLRequestContextGetter::Delegate::CreateCertVerifier(
-    RequireCTDelegate* ct_delegate) {
-  return net::CertVerifier::CreateDefault();
+scoped_refptr<URLRequestContextGetter>
+URLRequestContextGetter::Handle::GetMainRequestContextGetter() const {
+  return main_request_context_getter_;
 }
 
-net::SSLConfigService*
-URLRequestContextGetter::Delegate::CreateSSLConfigService() {
-  return new net::SSLConfigServiceDefaults;
+void URLRequestContextGetter::Handle::LazyInitialize() const {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (initialized_)
+    return;
+
+  initialized_ = true;
+  content::BrowserContext::EnsureResourceContextInitialized(
+      browser_context_.get());
 }
 
-std::vector<std::string>
-URLRequestContextGetter::Delegate::GetCookieableSchemes() {
-  return {"http", "https", "ws", "wss"};
+void URLRequestContextGetter::Handle::ShutdownOnUIThread() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (main_request_context_getter_.get()) {
+    if (BrowserThread::IsThreadInitialized(BrowserThread::IO)) {
+      BrowserThread::PostTask(
+          BrowserThread::IO, FROM_HERE,
+          base::BindOnce(&URLRequestContextGetter::NotifyContextShuttingDown,
+                         base::RetainedRef(main_request_context_getter_),
+                         std::move(resource_context_)));
+    }
+  }
+
+  if (!BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, this))
+    delete this;
 }
 
 URLRequestContextGetter::URLRequestContextGetter(
-    Delegate* delegate,
     NetLog* net_log,
-    const base::FilePath& base_path,
+    ResourceContext* resource_context,
     bool in_memory,
-    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+    const std::string& user_agent,
+    const base::FilePath& base_path,
     content::ProtocolHandlerMap* protocol_handlers,
     content::URLRequestInterceptorScopedVector protocol_interceptors)
-    : delegate_(delegate),
+    : job_factory_(nullptr),
+      delegate_(nullptr),
       net_log_(net_log),
+      resource_context_(resource_context),
+      protocol_interceptors_(std::move(protocol_interceptors)),
       base_path_(base_path),
       in_memory_(in_memory),
-      io_task_runner_(io_task_runner),
-      protocol_interceptors_(std::move(protocol_interceptors)),
-      job_factory_(nullptr),
+      user_agent_(user_agent),
       context_shutting_down_(false) {
   // Must first be created on the UI thread.
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -142,48 +168,30 @@ URLRequestContextGetter::URLRequestContextGetter(
   if (protocol_handlers)
     std::swap(protocol_handlers_, *protocol_handlers);
 
-  if (delegate_)
-    user_agent_ = delegate_->GetUserAgent();
-
   // We must create the proxy config service on the UI loop on Linux because it
   // must synchronously run on the glib message loop. This will be passed to
   // the URLRequestContextStorage on the IO thread in GetURLRequestContext().
   proxy_config_service_ =
       net::ProxyResolutionService::CreateSystemProxyConfigService(
-          io_task_runner_);
+          BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
 }
 
 URLRequestContextGetter::~URLRequestContextGetter() {}
 
-void URLRequestContextGetter::NotifyContextShutdownOnIO() {
+void URLRequestContextGetter::NotifyContextShuttingDown(
+    std::unique_ptr<ResourceContext> resource_context) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
   context_shutting_down_ = true;
   cookie_change_sub_.reset();
+  resource_context.reset();
+  net::URLRequestContextGetter::NotifyContextShuttingDown();
+  url_request_context_.reset();
+  storage_.reset();
   http_network_session_.reset();
   http_auth_preferences_.reset();
   host_mapping_rules_.reset();
-  url_request_context_.reset();
-  storage_.reset();
   ct_delegate_.reset();
-  net::URLRequestContextGetter::NotifyContextShuttingDown();
-}
-
-void URLRequestContextGetter::OnCookieChanged(
-    const net::CanonicalCookie& cookie,
-    net::CookieChangeCause cause) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
-  if (!delegate_ || context_shutting_down_)
-    return;
-
-  content::BrowserThread::PostTask(
-      content::BrowserThread::UI, FROM_HERE,
-      base::BindOnce(&Delegate::NotifyCookieChange, base::Unretained(delegate_),
-                     cookie, !(cause == net::CookieChangeCause::INSERTED),
-                     cause));
-}
-
-net::HostResolver* URLRequestContextGetter::host_resolver() {
-  return url_request_context_->host_resolver();
 }
 
 net::URLRequestContext* URLRequestContextGetter::GetURLRequestContext() {
@@ -211,22 +219,23 @@ net::URLRequestContext* URLRequestContextGetter::GetURLRequestContext() {
     auto cookie_path = in_memory_
                            ? base::FilePath()
                            : base_path_.Append(FILE_PATH_LITERAL("Cookies"));
-    std::unique_ptr<net::CookieStore> cookie_store =
-        content::CreateCookieStore(content::CookieStoreConfig(
-            cookie_path, false, false, nullptr));
+    std::unique_ptr<net::CookieStore> cookie_store = content::CreateCookieStore(
+        content::CookieStoreConfig(cookie_path, false, false, nullptr));
     storage_->set_cookie_store(std::move(cookie_store));
 
     // Set custom schemes that can accept cookies.
     net::CookieMonster* cookie_monster =
         static_cast<net::CookieMonster*>(url_request_context_->cookie_store());
-    cookie_monster->SetCookieableSchemes(delegate_->GetCookieableSchemes());
+    std::vector<std::string> cookie_schemes({"http", "https", "ws", "wss"});
+    delegate_->GetCookieableSchemes(&cookie_schemes);
+    cookie_monster->SetCookieableSchemes(cookie_schemes);
     // Cookie store will outlive notifier by order of declaration
     // in the header.
-    cookie_change_sub_ =
-        url_request_context_->cookie_store()
-            ->GetChangeDispatcher()
-            .AddCallbackForAllChanges(
-                base::Bind(&URLRequestContextGetter::OnCookieChanged, this));
+    cookie_change_sub_ = url_request_context_->cookie_store()
+                             ->GetChangeDispatcher()
+                             .AddCallbackForAllChanges(base::Bind(
+                                 &URLRequestContextGetter::OnCookieChanged,
+                                 base::RetainedRef(this)));
 
     storage_->set_channel_id_service(std::make_unique<net::ChannelIDService>(
         new net::DefaultChannelIDStore(nullptr)));
@@ -307,7 +316,7 @@ net::URLRequestContext* URLRequestContextGetter::GetURLRequestContext() {
     storage_->set_transport_security_state(std::move(transport_security_state));
     storage_->set_cert_verifier(
         delegate_->CreateCertVerifier(ct_delegate_.get()));
-    storage_->set_ssl_config_service(delegate_->CreateSSLConfigService());
+    storage_->set_ssl_config_service(new net::SSLConfigServiceDefaults());
     storage_->set_http_auth_handler_factory(std::move(auth_handler_factory));
     std::unique_ptr<net::HttpServerProperties> server_properties(
         new net::HttpServerPropertiesImpl);
@@ -360,7 +369,8 @@ net::URLRequestContext* URLRequestContextGetter::GetURLRequestContext() {
         std::move(backend), false));
 
     std::unique_ptr<net::URLRequestJobFactory> job_factory =
-        delegate_->CreateURLRequestJobFactory(&protocol_handlers_);
+        delegate_->CreateURLRequestJobFactory(url_request_context_.get(),
+                                              &protocol_handlers_);
     job_factory_ = job_factory.get();
 
     // Set up interceptors in the reverse order.
@@ -378,6 +388,9 @@ net::URLRequestContext* URLRequestContextGetter::GetURLRequestContext() {
     storage_->set_job_factory(std::move(top_job_factory));
   }
 
+  if (resource_context_)
+    resource_context_->request_context_ = url_request_context_.get();
+
   return url_request_context_.get();
 }
 
@@ -386,4 +399,11 @@ URLRequestContextGetter::GetNetworkTaskRunner() const {
   return BrowserThread::GetTaskRunnerForThread(BrowserThread::IO);
 }
 
+void URLRequestContextGetter::OnCookieChanged(
+    const net::CanonicalCookie& cookie,
+    net::CookieChangeCause cause) const {
+  if (delegate_)
+    delegate_->OnCookieChanged(cookie, cause);
+}
+
 }  // namespace brightray

+ 57 - 33
brightray/browser/url_request_context_getter.h

@@ -22,10 +22,6 @@
 #include "base/debug/leak_tracker.h"
 #endif
 
-namespace base {
-class MessageLoop;
-}
-
 namespace net {
 class HostMappingRules;
 class HostResolver;
@@ -38,6 +34,8 @@ class URLRequestJobFactory;
 
 namespace brightray {
 
+class BrowserContext;
+class ResourceContext;
 class RequireCTDelegate;
 class NetLog;
 
@@ -48,55 +46,76 @@ class URLRequestContextGetter : public net::URLRequestContextGetter {
     Delegate() {}
     virtual ~Delegate() {}
 
-    virtual std::unique_ptr<net::NetworkDelegate> CreateNetworkDelegate();
-    virtual std::string GetUserAgent();
+    virtual std::unique_ptr<net::NetworkDelegate> CreateNetworkDelegate() = 0;
     virtual std::unique_ptr<net::URLRequestJobFactory>
-    CreateURLRequestJobFactory(content::ProtocolHandlerMap* protocol_handlers);
+    CreateURLRequestJobFactory(
+        net::URLRequestContext* url_request_context,
+        content::ProtocolHandlerMap* protocol_handlers) = 0;
     virtual net::HttpCache::BackendFactory* CreateHttpCacheBackendFactory(
-        const base::FilePath& base_path);
+        const base::FilePath& base_path) = 0;
     virtual std::unique_ptr<net::CertVerifier> CreateCertVerifier(
-        RequireCTDelegate* ct_delegate);
-    virtual net::SSLConfigService* CreateSSLConfigService();
-    virtual std::vector<std::string> GetCookieableSchemes();
-    virtual void NotifyCookieChange(const net::CanonicalCookie& cookie,
-                                    bool removed,
-                                    net::CookieChangeCause cause) {}
+        RequireCTDelegate* ct_delegate) = 0;
+    virtual void GetCookieableSchemes(
+        std::vector<std::string>* cookie_schemes) {}
+    virtual void OnCookieChanged(const net::CanonicalCookie& cookie,
+                                 net::CookieChangeCause cause) {}
   };
 
   URLRequestContextGetter(
-      Delegate* delegate,
       NetLog* net_log,
-      const base::FilePath& base_path,
+      ResourceContext* resource_context,
       bool in_memory,
-      scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+      const std::string& user_agent,
+      const base::FilePath& base_path,
       content::ProtocolHandlerMap* protocol_handlers,
       content::URLRequestInterceptorScopedVector protocol_interceptors);
 
-  // net::CookieChangeDispatcher::CookieChangedCallback implementation.
-  void OnCookieChanged(const net::CanonicalCookie& cookie,
-                       net::CookieChangeCause cause);
-
   // net::URLRequestContextGetter:
   net::URLRequestContext* GetURLRequestContext() override;
   scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
       const override;
 
-  net::HostResolver* host_resolver();
   net::URLRequestJobFactory* job_factory() const { return job_factory_; }
+  void set_delegate(Delegate* delegate) { delegate_ = delegate; }
 
-  void NotifyContextShutdownOnIO();
+  // Discard reference to URLRequestContext and inform observers to
+  // shutdown. Must be called only on IO thread.
+  void NotifyContextShuttingDown(std::unique_ptr<ResourceContext>);
 
  private:
-  ~URLRequestContextGetter() override;
+  friend class BrowserContext;
 
-  Delegate* delegate_;
+  // Responsible for destroying URLRequestContextGetter
+  // on the IO thread.
+  class Handle {
+   public:
+    explicit Handle(base::WeakPtr<BrowserContext> browser_context);
+    ~Handle();
 
-  NetLog* net_log_;
-  base::FilePath base_path_;
-  bool in_memory_;
-  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+    scoped_refptr<URLRequestContextGetter> CreateMainRequestContextGetter(
+        content::ProtocolHandlerMap* protocol_handlers,
+        content::URLRequestInterceptorScopedVector protocol_interceptors);
+    content::ResourceContext* GetResourceContext() const;
+    scoped_refptr<URLRequestContextGetter> GetMainRequestContextGetter() const;
 
-  std::string user_agent_;
+    void ShutdownOnUIThread();
+
+   private:
+    void LazyInitialize() const;
+
+    scoped_refptr<URLRequestContextGetter> main_request_context_getter_;
+    std::unique_ptr<ResourceContext> resource_context_;
+    base::WeakPtr<BrowserContext> browser_context_;
+    mutable bool initialized_;
+
+    DISALLOW_COPY_AND_ASSIGN(Handle);
+  };
+
+  ~URLRequestContextGetter() override;
+
+  // net::CookieChangeDispatcher::CookieChangedCallback implementation.
+  void OnCookieChanged(const net::CanonicalCookie& cookie,
+                       net::CookieChangeCause cause) const;
 
 #if DCHECK_IS_ON()
   base::debug::LeakTracker<URLRequestContextGetter> leak_tracker_;
@@ -110,11 +129,16 @@ class URLRequestContextGetter : public net::URLRequestContextGetter {
   std::unique_ptr<net::HttpAuthPreferences> http_auth_preferences_;
   std::unique_ptr<net::HttpNetworkSession> http_network_session_;
   std::unique_ptr<net::CookieChangeSubscription> cookie_change_sub_;
+
+  net::URLRequestJobFactory* job_factory_;
+  Delegate* delegate_;
+  NetLog* net_log_;
+  ResourceContext* resource_context_;
   content::ProtocolHandlerMap protocol_handlers_;
   content::URLRequestInterceptorScopedVector protocol_interceptors_;
-
-  net::URLRequestJobFactory* job_factory_;  // weak ref
-
+  base::FilePath base_path_;
+  bool in_memory_;
+  std::string user_agent_;
   bool context_shutting_down_;
 
   DISALLOW_COPY_AND_ASSIGN(URLRequestContextGetter);

+ 0 - 3
brightray/common/switches.cc

@@ -50,9 +50,6 @@ const char kAuthServerWhitelist[] = "auth-server-whitelist";
 const char kAuthNegotiateDelegateWhitelist[] =
     "auth-negotiate-delegate-whitelist";
 
-// Forces the maximum disk space to be used by the disk cache, in bytes.
-const char kDiskCacheSize[] = "disk-cache-size";
-
 }  // namespace switches
 
 }  // namespace brightray

+ 0 - 1
brightray/common/switches.h

@@ -17,7 +17,6 @@ extern const char kProxyPacUrl[];
 extern const char kDisableHttp2[];
 extern const char kAuthServerWhitelist[];
 extern const char kAuthNegotiateDelegateWhitelist[];
-extern const char kDiskCacheSize[];
 
 }  // namespace switches
 

+ 2 - 0
filenames.gypi

@@ -313,6 +313,8 @@
       'atom/browser/relauncher.h',
       'atom/browser/render_process_preferences.cc',
       'atom/browser/render_process_preferences.h',
+      'atom/browser/request_context_delegate.cc',
+      'atom/browser/request_context_delegate.h',
       'atom/browser/session_preferences.cc',
       'atom/browser/session_preferences.h',
       'atom/browser/ui/accelerator_util.cc',