fix: browser contexts live forever (#24964)

This commit is contained in:
Jeremy Rose 2020-08-17 13:21:53 -07:00 committed by GitHub
parent befbbc27d8
commit bac2f46ba9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 68 additions and 73 deletions

View file

@ -1197,10 +1197,10 @@ void App::ImportCertificate(gin_helper::ErrorThrower thrower,
return;
}
auto browser_context = ElectronBrowserContext::From("", false);
auto* browser_context = ElectronBrowserContext::From("", false);
if (!certificate_manager_model_) {
CertificateManagerModel::Create(
browser_context.get(),
browser_context,
base::BindOnce(&App::OnCertificateManagerModelCreated,
base::Unretained(this), std::move(options),
std::move(callback)));

View file

@ -276,7 +276,7 @@ Session::Session(v8::Isolate* isolate, ElectronBrowserContext* browser_context)
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
SpellcheckService* service =
SpellcheckServiceFactory::GetForContext(browser_context_.get());
SpellcheckServiceFactory::GetForContext(browser_context_);
if (service) {
service->SetHunspellObserver(this);
}
@ -289,7 +289,7 @@ Session::~Session() {
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
SpellcheckService* service =
SpellcheckServiceFactory::GetForContext(browser_context_.get());
SpellcheckServiceFactory::GetForContext(browser_context_);
if (service) {
service->SetHunspellObserver(nullptr);
}
@ -351,7 +351,7 @@ v8::Local<v8::Promise> Session::GetCacheSize() {
gin_helper::Promise<int64_t> promise(isolate);
auto handle = promise.GetHandle();
content::BrowserContext::GetDefaultStoragePartition(browser_context_.get())
content::BrowserContext::GetDefaultStoragePartition(browser_context_)
->GetNetworkContext()
->ComputeHttpCacheSize(
base::Time(), base::Time::Max(),
@ -375,7 +375,7 @@ v8::Local<v8::Promise> Session::ClearCache() {
gin_helper::Promise<void> promise(isolate);
auto handle = promise.GetHandle();
content::BrowserContext::GetDefaultStoragePartition(browser_context_.get())
content::BrowserContext::GetDefaultStoragePartition(browser_context_)
->GetNetworkContext()
->ClearHttpCache(base::Time(), base::Time::Max(), nullptr,
base::BindOnce(gin_helper::Promise<void>::ResolvePromise,
@ -471,17 +471,17 @@ void Session::EnableNetworkEmulation(const gin_helper::Dictionary& options) {
conditions->latency = base::TimeDelta::FromMillisecondsD(latency);
}
auto* network_context = content::BrowserContext::GetDefaultStoragePartition(
browser_context_.get())
->GetNetworkContext();
auto* network_context =
content::BrowserContext::GetDefaultStoragePartition(browser_context_)
->GetNetworkContext();
network_context->SetNetworkConditions(network_emulation_token_,
std::move(conditions));
}
void Session::DisableNetworkEmulation() {
auto* network_context = content::BrowserContext::GetDefaultStoragePartition(
browser_context_.get())
->GetNetworkContext();
auto* network_context =
content::BrowserContext::GetDefaultStoragePartition(browser_context_)
->GetNetworkContext();
network_context->SetNetworkConditions(
network_emulation_token_, network::mojom::NetworkConditions::New());
}
@ -501,7 +501,7 @@ void Session::SetCertVerifyProc(v8::Local<v8::Value> val,
std::make_unique<CertVerifierClient>(proc),
cert_verifier_client_remote.InitWithNewPipeAndPassReceiver());
}
content::BrowserContext::GetDefaultStoragePartition(browser_context_.get())
content::BrowserContext::GetDefaultStoragePartition(browser_context_)
->GetNetworkContext()
->SetCertVerifierClient(std::move(cert_verifier_client_remote));
@ -553,7 +553,7 @@ v8::Local<v8::Promise> Session::ClearHostResolverCache(gin::Arguments* args) {
gin_helper::Promise<void> promise(isolate);
v8::Local<v8::Promise> handle = promise.GetHandle();
content::BrowserContext::GetDefaultStoragePartition(browser_context_.get())
content::BrowserContext::GetDefaultStoragePartition(browser_context_)
->GetNetworkContext()
->ClearHostCache(nullptr,
base::BindOnce(gin_helper::Promise<void>::ResolvePromise,
@ -567,7 +567,7 @@ v8::Local<v8::Promise> Session::ClearAuthCache() {
gin_helper::Promise<void> promise(isolate);
v8::Local<v8::Promise> handle = promise.GetHandle();
content::BrowserContext::GetDefaultStoragePartition(browser_context_.get())
content::BrowserContext::GetDefaultStoragePartition(browser_context_)
->GetNetworkContext()
->ClearHttpAuthCache(
base::Time(),
@ -593,9 +593,9 @@ void Session::AllowNTLMCredentialsForDomains(const std::string& domains) {
void Session::SetUserAgent(const std::string& user_agent,
gin::Arguments* args) {
browser_context_->SetUserAgent(user_agent);
auto* network_context = content::BrowserContext::GetDefaultStoragePartition(
browser_context_.get())
->GetNetworkContext();
auto* network_context =
content::BrowserContext::GetDefaultStoragePartition(browser_context_)
->GetNetworkContext();
network_context->SetUserAgent(user_agent);
std::string accept_lang;
@ -781,10 +781,9 @@ v8::Local<v8::Value> Session::NetLog(v8::Isolate* isolate) {
return net_log_.Get(isolate);
}
static void StartPreconnectOnUI(
scoped_refptr<ElectronBrowserContext> browser_context,
const GURL& url,
int num_sockets_to_preconnect) {
static void StartPreconnectOnUI(ElectronBrowserContext* browser_context,
const GURL& url,
int num_sockets_to_preconnect) {
std::vector<predictors::PreconnectRequest> requests = {
{url::Origin::Create(url), num_sockets_to_preconnect,
net::NetworkIsolationKey()}};
@ -815,7 +814,7 @@ void Session::Preconnect(const gin_helper::Dictionary& options,
DCHECK_GT(num_sockets_to_preconnect, 0);
base::PostTask(
FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(&StartPreconnectOnUI, base::RetainedRef(browser_context_),
base::BindOnce(&StartPreconnectOnUI, base::Unretained(browser_context_),
url, num_sockets_to_preconnect));
}
@ -860,7 +859,7 @@ v8::Local<v8::Promise> Session::ListWordsInSpellCheckerDictionary() {
v8::Local<v8::Promise> handle = promise.GetHandle();
SpellcheckService* spellcheck =
SpellcheckServiceFactory::GetForContext(browser_context_.get());
SpellcheckServiceFactory::GetForContext(browser_context_);
if (!spellcheck)
promise.RejectWithErrorMessage(
@ -886,7 +885,7 @@ bool Session::AddWordToSpellCheckerDictionary(const std::string& word) {
return false;
SpellcheckService* service =
SpellcheckServiceFactory::GetForContext(browser_context_.get());
SpellcheckServiceFactory::GetForContext(browser_context_);
if (!service)
return false;
@ -907,7 +906,7 @@ bool Session::RemoveWordFromSpellCheckerDictionary(const std::string& word) {
return false;
SpellcheckService* service =
SpellcheckServiceFactory::GetForContext(browser_context_.get());
SpellcheckServiceFactory::GetForContext(browser_context_);
if (!service)
return false;
@ -953,7 +952,7 @@ gin::Handle<Session> Session::CreateFrom(
gin::Handle<Session> Session::FromPartition(v8::Isolate* isolate,
const std::string& partition,
base::DictionaryValue options) {
scoped_refptr<ElectronBrowserContext> browser_context;
ElectronBrowserContext* browser_context;
if (partition.empty()) {
browser_context =
ElectronBrowserContext::From("", false, std::move(options));
@ -966,7 +965,7 @@ gin::Handle<Session> Session::FromPartition(v8::Isolate* isolate,
browser_context =
ElectronBrowserContext::From(partition, true, std::move(options));
}
return CreateFrom(isolate, browser_context.get());
return CreateFrom(isolate, browser_context);
}
gin::ObjectTemplateBuilder Session::GetObjectTemplateBuilder(

View file

@ -71,9 +71,7 @@ class Session : public gin::Wrappable<Session>,
const std::string& partition,
base::DictionaryValue options = base::DictionaryValue());
ElectronBrowserContext* browser_context() const {
return browser_context_.get();
}
ElectronBrowserContext* browser_context() const { return browser_context_; }
// gin::Wrappable
static gin::WrapperInfo kWrapperInfo;
@ -159,7 +157,7 @@ class Session : public gin::Wrappable<Session>,
// The client id to enable the network throttler.
base::UnguessableToken network_emulation_token_;
scoped_refptr<ElectronBrowserContext> browser_context_;
ElectronBrowserContext* browser_context_;
DISALLOW_COPY_AND_ASSIGN(Session);
};

View file

@ -250,14 +250,8 @@ void CommonWebContentsDelegate::ResetManagedWebContents(bool async) {
// is destroyed.
// //electron/patches/chromium/content_browser_main_loop.patch
// is required to get the right quit closure for the main message loop.
base::ThreadTaskRunnerHandle::Get()->PostNonNestableTask(
FROM_HERE,
base::BindOnce(
[](scoped_refptr<ElectronBrowserContext> browser_context,
std::unique_ptr<InspectableWebContents> web_contents) {
web_contents.reset();
},
base::RetainedRef(browser_context_), std::move(web_contents_)));
base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE,
web_contents_.release());
} else {
web_contents_.reset();
}

View file

@ -171,8 +171,7 @@ class CommonWebContentsDelegate : public content::WebContentsDelegate,
scoped_refptr<DevToolsFileSystemIndexer> devtools_file_system_indexer_;
// Make sure BrowserContext is alwasys destroyed after WebContents.
scoped_refptr<ElectronBrowserContext> browser_context_;
ElectronBrowserContext* browser_context_;
// The stored InspectableWebContents object.
// Notice that web_contents_ must be placed after dialog_manager_, so we can

View file

@ -10,6 +10,7 @@
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/no_destructor.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/task/post_task.h"
@ -91,15 +92,17 @@ std::string MakePartitionName(const std::string& input) {
} // namespace
// static
ElectronBrowserContext::BrowserContextMap
ElectronBrowserContext::browser_context_map_;
ElectronBrowserContext::BrowserContextMap&
ElectronBrowserContext::browser_context_map() {
static base::NoDestructor<ElectronBrowserContext::BrowserContextMap>
browser_context_map;
return *browser_context_map;
}
ElectronBrowserContext::ElectronBrowserContext(const std::string& partition,
bool in_memory,
base::DictionaryValue options)
: base::RefCountedDeleteOnSequence<ElectronBrowserContext>(
base::ThreadTaskRunnerHandle::Get()),
in_memory_pref_store_(nullptr),
: in_memory_pref_store_(nullptr),
storage_policy_(new SpecialStoragePolicy),
protocol_registry_(new ProtocolRegistry),
in_memory_(in_memory),
@ -444,19 +447,21 @@ ResolveProxyHelper* ElectronBrowserContext::GetResolveProxyHelper() {
}
// static
scoped_refptr<ElectronBrowserContext> ElectronBrowserContext::From(
ElectronBrowserContext* ElectronBrowserContext::From(
const std::string& partition,
bool in_memory,
base::DictionaryValue options) {
PartitionKey key(partition, in_memory);
auto* browser_context = browser_context_map_[key].get();
if (browser_context)
return scoped_refptr<ElectronBrowserContext>(browser_context);
ElectronBrowserContext* browser_context = browser_context_map()[key].get();
if (browser_context) {
return browser_context;
}
auto* new_context =
new ElectronBrowserContext(partition, in_memory, std::move(options));
browser_context_map_[key] = new_context->GetWeakPtr();
return scoped_refptr<ElectronBrowserContext>(new_context);
browser_context_map()[key] =
std::unique_ptr<ElectronBrowserContext>(new_context);
return new_context;
}
} // namespace electron

View file

@ -10,7 +10,6 @@
#include <string>
#include <vector>
#include "base/memory/ref_counted_delete_on_sequence.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/predictors/preconnect_manager.h"
#include "content/public/browser/browser_context.h"
@ -50,8 +49,7 @@ class WebViewManager;
class ProtocolRegistry;
class ElectronBrowserContext
: public base::RefCountedDeleteOnSequence<ElectronBrowserContext>,
public content::BrowserContext,
: public content::BrowserContext,
public network::mojom::TrustedURLLoaderAuthClient {
public:
// partition_id => browser_context
@ -73,19 +71,17 @@ class ElectronBrowserContext
}
};
using BrowserContextMap =
std::map<PartitionKey, base::WeakPtr<ElectronBrowserContext>>;
std::map<PartitionKey, std::unique_ptr<ElectronBrowserContext>>;
// Get or create the BrowserContext according to its |partition| and
// |in_memory|. The |options| will be passed to constructor when there is no
// existing BrowserContext.
static scoped_refptr<ElectronBrowserContext> From(
static ElectronBrowserContext* From(
const std::string& partition,
bool in_memory,
base::DictionaryValue options = base::DictionaryValue());
static BrowserContextMap browser_context_map() {
return browser_context_map_;
}
static BrowserContextMap& browser_context_map();
void SetUserAgent(const std::string& user_agent);
std::string GetUserAgent() const;
@ -151,15 +147,12 @@ class ElectronBrowserContext
return protocol_registry_.get();
}
protected:
ElectronBrowserContext(const std::string& partition,
bool in_memory,
base::DictionaryValue options);
~ElectronBrowserContext() override;
private:
friend class base::RefCountedDeleteOnSequence<ElectronBrowserContext>;
friend class base::DeleteHelper<ElectronBrowserContext>;
ElectronBrowserContext(const std::string& partition,
bool in_memory,
base::DictionaryValue options);
void OnLoaderCreated(int32_t request_id,
mojo::PendingReceiver<network::mojom::TrustedAuthClient>
@ -168,8 +161,6 @@ class ElectronBrowserContext
// Initialize pref registry.
void InitPrefs();
static BrowserContextMap browser_context_map_;
ValueMapPrefStore* in_memory_pref_store_;
std::unique_ptr<content::ResourceContext> resource_context_;

View file

@ -553,6 +553,8 @@ void ElectronBrowserMainParts::PostMainMessageLoopRun() {
js_env_->OnMessageLoopDestroying();
node_env_.reset();
ElectronBrowserContext::browser_context_map().clear();
fake_browser_process_->PostMainMessageLoopRun();
content::DevToolsAgentHost::StopRemoteDebuggingPipeHandler();
}

View file

@ -85,7 +85,7 @@ bool ElectronExtensionsBrowserClient::AreExtensionsDisabled(
}
bool ElectronExtensionsBrowserClient::IsValidContext(BrowserContext* context) {
auto context_map = ElectronBrowserContext::browser_context_map();
auto& context_map = ElectronBrowserContext::browser_context_map();
for (auto const& entry : context_map) {
if (entry.second && entry.second.get() == context)
return true;
@ -113,7 +113,7 @@ BrowserContext* ElectronExtensionsBrowserClient::GetOriginalContext(
BrowserContext* context) {
DCHECK(context);
if (context->IsOffTheRecord()) {
return ElectronBrowserContext::From("", false).get();
return ElectronBrowserContext::From("", false);
} else {
return context;
}
@ -311,7 +311,7 @@ void ElectronExtensionsBrowserClient::BroadcastEventToRenderers(
std::unique_ptr<extensions::Event> event(
new extensions::Event(histogram_value, event_name, std::move(args)));
auto context_map = ElectronBrowserContext::browser_context_map();
auto& context_map = ElectronBrowserContext::browser_context_map();
for (auto const& entry : context_map) {
if (entry.second) {
extensions::EventRouter::Get(entry.second.get())

View file

@ -419,7 +419,7 @@ void ElectronURLLoaderFactory::StartLoadingHttp(
if (request->method != "GET" && request->method != "HEAD")
dict.Get("uploadData", &upload_data);
scoped_refptr<ElectronBrowserContext> browser_context =
ElectronBrowserContext* browser_context =
ElectronBrowserContext::From("", false);
v8::Local<v8::Value> value;
if (dict.Get("session", &value)) {

View file

@ -0,0 +1,7 @@
const { app, BrowserWindow } = require('electron');
app.on('ready', async () => {
const win = new BrowserWindow({ show: false, webPreferences: { partition: '123321' } });
await win.loadURL('data:text/html,<body>');
setTimeout(() => app.quit());
});