From 4ebb83e999baf42a45da5dfda1076355e9949d23 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jul 2016 16:51:31 +0900 Subject: [PATCH 01/17] Move the warning of registerStandardSchemes to native code --- atom/browser/api/atom_api_protocol.cc | 9 ++++++++- lib/browser/api/protocol.js | 8 +------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/atom/browser/api/atom_api_protocol.cc b/atom/browser/api/atom_api_protocol.cc index 8d542b36f9d7..6f4f158073d4 100644 --- a/atom/browser/api/atom_api_protocol.cc +++ b/atom/browser/api/atom_api_protocol.cc @@ -6,6 +6,7 @@ #include "atom/browser/atom_browser_client.h" #include "atom/browser/atom_browser_main_parts.h" +#include "atom/browser/browser.h" #include "atom/browser/net/url_request_async_asar_job.h" #include "atom/browser/net/url_request_buffer_job.h" #include "atom/browser/net/url_request_fetch_job.h" @@ -192,7 +193,13 @@ void Protocol::BuildPrototype( namespace { void RegisterStandardSchemes( - const std::vector& schemes) { + const std::vector& schemes, mate::Arguments* args) { + if (atom::Browser::Get()->is_ready()) { + args->ThrowError("protocol.registerStandardSchemes should be called before " + "app is ready"); + return; + } + auto policy = content::ChildProcessSecurityPolicy::GetInstance(); for (const auto& scheme : schemes) { url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITHOUT_PORT); diff --git a/lib/browser/api/protocol.js b/lib/browser/api/protocol.js index 1f729240016b..f7bf48a250c2 100644 --- a/lib/browser/api/protocol.js +++ b/lib/browser/api/protocol.js @@ -1,13 +1,7 @@ const {app, session} = require('electron') const {registerStandardSchemes} = process.atomBinding('protocol') -exports.registerStandardSchemes = function (schemes) { - if (app.isReady()) { - console.warn('protocol.registerStandardSchemes should be called before app is ready') - return - } - registerStandardSchemes(schemes) -} +exports.registerStandardSchemes = registerStandardSchemes const setupProtocol = function () { let protocol = session.defaultSession.protocol From fcd3357fb807b2666c6536c0beb68b184031cc04 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jul 2016 19:27:15 +0900 Subject: [PATCH 02/17] Use Proxy to provide protocol APIs In this way we can avoid initializing defaultSession when protocol module is used. --- lib/browser/api/protocol.js | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/browser/api/protocol.js b/lib/browser/api/protocol.js index f7bf48a250c2..d1c26991d0e3 100644 --- a/lib/browser/api/protocol.js +++ b/lib/browser/api/protocol.js @@ -1,17 +1,19 @@ -const {app, session} = require('electron') -const {registerStandardSchemes} = process.atomBinding('protocol') +const {session} = require('electron') -exports.registerStandardSchemes = registerStandardSchemes +// Global protocol APIs. +module.exports = process.atomBinding('protocol') -const setupProtocol = function () { - let protocol = session.defaultSession.protocol - for (let method in protocol) { - exports[method] = protocol[method].bind(protocol) +// Fallback protocol APIs of default session. +Object.setPrototypeOf(module.exports, new Proxy({}, { + get (target, property) { + return (...args) => session.defaultSession.protocol[property](...args) + }, + + ownKeys () { + return Object.getOwnPropertyNames(session.defaultSession.protocol) + }, + + getOwnPropertyDescriptor (target) { + return { configurable: true, enumerable: true } } -} - -if (app.isReady()) { - setupProtocol() -} else { - app.once('ready', setupProtocol) -} +})) From 45500701f18602d0d2af0efdd0cea449df193b59 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jul 2016 19:39:06 +0900 Subject: [PATCH 03/17] Do not access default session before app is ready --- lib/browser/api/protocol.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/browser/api/protocol.js b/lib/browser/api/protocol.js index d1c26991d0e3..9d8394f76754 100644 --- a/lib/browser/api/protocol.js +++ b/lib/browser/api/protocol.js @@ -1,4 +1,4 @@ -const {session} = require('electron') +const {app, session} = require('electron') // Global protocol APIs. module.exports = process.atomBinding('protocol') @@ -6,10 +6,18 @@ module.exports = process.atomBinding('protocol') // Fallback protocol APIs of default session. Object.setPrototypeOf(module.exports, new Proxy({}, { get (target, property) { - return (...args) => session.defaultSession.protocol[property](...args) + if (!app.isReady()) return + + const protocol = session.defaultSession.protocol + if (!protocol.hasOwnProperty(property)) return + + // Returning a native function directly would throw error. + return (...args) => protocol[property](...args) }, ownKeys () { + if (!app.isReady()) return [] + return Object.getOwnPropertyNames(session.defaultSession.protocol) }, From d739d8772cb1f501efe346b12c85209816625a2d Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jul 2016 20:06:08 +0900 Subject: [PATCH 04/17] Move session-created event to app This follows the convention of other *-created events. --- lib/browser/api/session.js | 13 +++++-------- lib/browser/chrome-extension.js | 4 ++-- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/browser/api/session.js b/lib/browser/api/session.js index 4cfb27f76d63..313cf4d96d9c 100644 --- a/lib/browser/api/session.js +++ b/lib/browser/api/session.js @@ -1,13 +1,12 @@ const {EventEmitter} = require('events') -const electron = require('electron') +const {app} = require('electron') const bindings = process.atomBinding('session') const PERSIST_PREFIX = 'persist:' -const Session = new EventEmitter() // Wrapper of binding.fromPartition that checks for ready event. const fromPartition = function (partition, persist) { - if (!electron.app.isReady()) { + if (!app.isReady()) { throw new Error('session module can only be used when app is ready') } @@ -15,7 +14,7 @@ const fromPartition = function (partition, persist) { } // Returns the Session from |partition| string. -Session.fromPartition = function (partition = '') { +exports.fromPartition = function (partition = '') { if (partition === '') return exports.defaultSession if (partition.startsWith(PERSIST_PREFIX)) { @@ -26,7 +25,7 @@ Session.fromPartition = function (partition = '') { } // Returns the default session. -Object.defineProperty(Session, 'defaultSession', { +Object.defineProperty(exports, 'defaultSession', { enumerable: true, get: function () { return fromPartition('', false) @@ -36,9 +35,7 @@ Object.defineProperty(Session, 'defaultSession', { const wrapSession = function (session) { // Session is an EventEmitter. Object.setPrototypeOf(session, EventEmitter.prototype) - Session.emit('session-created', session) + app.emit('session-created', session) } bindings._setWrapSession(wrapSession) - -module.exports = Session diff --git a/lib/browser/chrome-extension.js b/lib/browser/chrome-extension.js index 4bb4a51c191d..983560c58c24 100644 --- a/lib/browser/chrome-extension.js +++ b/lib/browser/chrome-extension.js @@ -1,4 +1,4 @@ -const {app, ipcMain, session, webContents, BrowserWindow} = require('electron') +const {app, ipcMain, webContents, BrowserWindow} = require('electron') const {getAllWebContents} = process.atomBinding('web_contents') const renderProcessPreferences = process.atomBinding('render_process_preferences').forAllWebContents() @@ -333,7 +333,7 @@ app.once('ready', function () { } }) } - session.on('session-created', function (ses) { + app.on('session-created', function (ses) { ses.protocol.registerBufferProtocol('chrome-extension', chromeExtensionHandler, function (error) { if (error) { console.error(`Unable to register chrome-extension protocol: ${error}`) From 06a41cedabd2c90c0aa2b0406465276d32041285 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jul 2016 20:21:59 +0900 Subject: [PATCH 05/17] Move check of isReady to native code --- atom/browser/api/atom_api_session.cc | 13 ++++++++++++- lib/browser/api/session.js | 18 ++++-------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index 87d42486d503..7ce902484eab 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -11,6 +11,7 @@ #include "atom/browser/api/atom_api_download_item.h" #include "atom/browser/api/atom_api_protocol.h" #include "atom/browser/api/atom_api_web_request.h" +#include "atom/browser/browser.h" #include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_permission_manager.h" @@ -576,11 +577,21 @@ void SetWrapSession(const WrapSessionCallback& callback) { namespace { +v8::Local FromPartition( + const std::string& partition, bool in_memory, mate::Arguments* args) { + if (!atom::Browser::Get()->is_ready()) { + args->ThrowError("Session can only be received when app is ready"); + return v8::Null(args->isolate()); + } + return atom::api::Session::FromPartition( + args->isolate(), partition, in_memory).ToV8(); +} + void Initialize(v8::Local exports, v8::Local unused, v8::Local context, void* priv) { v8::Isolate* isolate = context->GetIsolate(); mate::Dictionary dict(isolate, exports); - dict.SetMethod("fromPartition", &atom::api::Session::FromPartition); + dict.SetMethod("fromPartition", &FromPartition); dict.SetMethod("_setWrapSession", &atom::api::SetWrapSession); } diff --git a/lib/browser/api/session.js b/lib/browser/api/session.js index 313cf4d96d9c..2fa0baca98da 100644 --- a/lib/browser/api/session.js +++ b/lib/browser/api/session.js @@ -1,18 +1,9 @@ const {EventEmitter} = require('events') const {app} = require('electron') -const bindings = process.atomBinding('session') +const {fromPartition, _setWrapSession} = process.atomBinding('session') const PERSIST_PREFIX = 'persist:' -// Wrapper of binding.fromPartition that checks for ready event. -const fromPartition = function (partition, persist) { - if (!app.isReady()) { - throw new Error('session module can only be used when app is ready') - } - - return bindings.fromPartition(partition, persist) -} - // Returns the Session from |partition| string. exports.fromPartition = function (partition = '') { if (partition === '') return exports.defaultSession @@ -32,10 +23,9 @@ Object.defineProperty(exports, 'defaultSession', { } }) -const wrapSession = function (session) { +// Wraps native Session class. +_setWrapSession(function (session) { // Session is an EventEmitter. Object.setPrototypeOf(session, EventEmitter.prototype) app.emit('session-created', session) -} - -bindings._setWrapSession(wrapSession) +}) From 400bb8d0f3d79d5758ae21d23d4d48e60fd2ced1 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jul 2016 21:01:49 +0900 Subject: [PATCH 06/17] Hide in_memory parameter in native interface --- atom/browser/api/atom_api_session.cc | 24 +++++++++++++++------- atom/browser/api/atom_api_session.h | 4 ++-- atom/browser/api/atom_api_web_contents.cc | 11 +++------- lib/browser/api/session.js | 25 ++++++++--------------- 4 files changed, 30 insertions(+), 34 deletions(-) diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index 7ce902484eab..eecb2521b77a 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -164,6 +164,8 @@ namespace api { namespace { +const char kPersistPrefix[] = "persist:"; + // The wrapSession funtion which is implemented in JavaScript using WrapSessionCallback = base::Callback)>; WrapSessionCallback g_wrap_session; @@ -534,10 +536,19 @@ mate::Handle Session::CreateFrom( // static mate::Handle Session::FromPartition( - v8::Isolate* isolate, const std::string& partition, bool in_memory) { - auto browser_context = brightray::BrowserContext::From(partition, in_memory); - return CreateFrom(isolate, - static_cast(browser_context.get())); + v8::Isolate* isolate, const std::string& partition) { + scoped_refptr browser_context; + if (partition.empty()) { + browser_context = brightray::BrowserContext::From("", false); + } else if (base::StartsWith(partition, kPersistPrefix, + base::CompareCase::SENSITIVE)) { + std::string name = partition.substr(8); + browser_context = brightray::BrowserContext::From(name, false); + } else { + browser_context = brightray::BrowserContext::From(partition, true); + } + return CreateFrom( + isolate, static_cast(browser_context.get())); } // static @@ -578,13 +589,12 @@ void SetWrapSession(const WrapSessionCallback& callback) { namespace { v8::Local FromPartition( - const std::string& partition, bool in_memory, mate::Arguments* args) { + const std::string& partition, mate::Arguments* args) { if (!atom::Browser::Get()->is_ready()) { args->ThrowError("Session can only be received when app is ready"); return v8::Null(args->isolate()); } - return atom::api::Session::FromPartition( - args->isolate(), partition, in_memory).ToV8(); + return atom::api::Session::FromPartition(args->isolate(), partition).ToV8(); } void Initialize(v8::Local exports, v8::Local unused, diff --git a/atom/browser/api/atom_api_session.h b/atom/browser/api/atom_api_session.h index 0868cbe18bee..d1943ba6ed1e 100644 --- a/atom/browser/api/atom_api_session.h +++ b/atom/browser/api/atom_api_session.h @@ -47,9 +47,9 @@ class Session: public mate::TrackableObject, static mate::Handle CreateFrom( v8::Isolate* isolate, AtomBrowserContext* browser_context); - // Gets the Session of |partition| and |in_memory|. + // Gets the Session of |partition|. static mate::Handle FromPartition( - v8::Isolate* isolate, const std::string& partition, bool in_memory); + v8::Isolate* isolate, const std::string& partition); AtomBrowserContext* browser_context() const { return browser_context_.get(); } diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 8622942668b0..48ef3ce03e00 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -285,16 +285,11 @@ WebContents::WebContents(v8::Isolate* isolate, std::string partition; mate::Handle session; if (options.Get("session", &session)) { - } else if (options.Get("partition", &partition) && !partition.empty()) { - bool in_memory = true; - if (base::StartsWith(partition, "persist:", base::CompareCase::SENSITIVE)) { - in_memory = false; - partition = partition.substr(8); - } - session = Session::FromPartition(isolate, partition, in_memory); + } else if (options.Get("partition", &partition)) { + session = Session::FromPartition(isolate, partition); } else { // Use the default session if not specified. - session = Session::FromPartition(isolate, "", false); + session = Session::FromPartition(isolate, ""); } session_.Reset(isolate, session.ToV8()); diff --git a/lib/browser/api/session.js b/lib/browser/api/session.js index 2fa0baca98da..86a7902ef597 100644 --- a/lib/browser/api/session.js +++ b/lib/browser/api/session.js @@ -2,24 +2,15 @@ const {EventEmitter} = require('events') const {app} = require('electron') const {fromPartition, _setWrapSession} = process.atomBinding('session') -const PERSIST_PREFIX = 'persist:' - -// Returns the Session from |partition| string. -exports.fromPartition = function (partition = '') { - if (partition === '') return exports.defaultSession - - if (partition.startsWith(PERSIST_PREFIX)) { - return fromPartition(partition.substr(PERSIST_PREFIX.length), false) - } else { - return fromPartition(partition, true) - } -} - // Returns the default session. -Object.defineProperty(exports, 'defaultSession', { - enumerable: true, - get: function () { - return fromPartition('', false) +Object.defineProperties(exports, { + defaultSession: { + enumerable: true, + get () { return fromPartition('') } + }, + fromPartition: { + enumerable: true, + value: fromPartition } }) From 00804e5f989997e26cf02dabdde0ee5681be789c Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jul 2016 21:39:54 +0900 Subject: [PATCH 07/17] Move the ability to create BrowserContext to embedder --- atom/browser/api/atom_api_session.cc | 11 +++++------ atom/browser/atom_access_token_store.cc | 2 +- atom/browser/atom_browser_context.cc | 14 +++++++------- atom/browser/atom_browser_context.h | 10 ++++++++-- vendor/brightray | 2 +- 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index eecb2521b77a..a9447392f25e 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -537,18 +537,17 @@ mate::Handle Session::CreateFrom( // static mate::Handle Session::FromPartition( v8::Isolate* isolate, const std::string& partition) { - scoped_refptr browser_context; + scoped_refptr browser_context; if (partition.empty()) { - browser_context = brightray::BrowserContext::From("", false); + browser_context = AtomBrowserContext::From("", false); } else if (base::StartsWith(partition, kPersistPrefix, base::CompareCase::SENSITIVE)) { std::string name = partition.substr(8); - browser_context = brightray::BrowserContext::From(name, false); + browser_context = AtomBrowserContext::From(name, false); } else { - browser_context = brightray::BrowserContext::From(partition, true); + browser_context = AtomBrowserContext::From(partition, true); } - return CreateFrom( - isolate, static_cast(browser_context.get())); + return CreateFrom(isolate, browser_context.get()); } // static diff --git a/atom/browser/atom_access_token_store.cc b/atom/browser/atom_access_token_store.cc index 21ef8edaece9..5a4482b00b41 100644 --- a/atom/browser/atom_access_token_store.cc +++ b/atom/browser/atom_access_token_store.cc @@ -46,7 +46,7 @@ void AtomAccessTokenStore::SaveAccessToken(const GURL& server_url, } void AtomAccessTokenStore::GetRequestContextOnUIThread() { - auto browser_context = brightray::BrowserContext::From("", false); + auto browser_context = AtomBrowserContext::From("", false); request_context_getter_ = browser_context->GetRequestContext(); } diff --git a/atom/browser/atom_browser_context.cc b/atom/browser/atom_browser_context.cc index 94cc3ee03d50..9bb3f6455e60 100644 --- a/atom/browser/atom_browser_context.cc +++ b/atom/browser/atom_browser_context.cc @@ -190,14 +190,14 @@ void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) { pref_registry->RegisterDictionaryPref(prefs::kDevToolsFileSystemPaths); } -} // namespace atom - -namespace brightray { - // static -scoped_refptr BrowserContext::Create( +scoped_refptr AtomBrowserContext::From( const std::string& partition, bool in_memory) { - return make_scoped_refptr(new atom::AtomBrowserContext(partition, in_memory)); + auto browser_context = brightray::BrowserContext::Get(partition, in_memory); + if (browser_context) + return static_cast(browser_context.get()); + + return new AtomBrowserContext(partition, in_memory); } -} // namespace brightray +} // namespace atom diff --git a/atom/browser/atom_browser_context.h b/atom/browser/atom_browser_context.h index 732f1d045731..47c05a00cf4a 100644 --- a/atom/browser/atom_browser_context.h +++ b/atom/browser/atom_browser_context.h @@ -18,8 +18,10 @@ class WebViewManager; class AtomBrowserContext : public brightray::BrowserContext { public: - AtomBrowserContext(const std::string& partition, bool in_memory); - ~AtomBrowserContext() override; + // Get or create the BrowserContext according to its |partition| and + // |in_memory|. + static scoped_refptr From( + const std::string& partition, bool in_memory); void SetUserAgent(const std::string& user_agent); @@ -43,6 +45,10 @@ class AtomBrowserContext : public brightray::BrowserContext { AtomNetworkDelegate* network_delegate() const { return network_delegate_; } + protected: + AtomBrowserContext(const std::string& partition, bool in_memory); + ~AtomBrowserContext() override; + private: std::unique_ptr download_manager_delegate_; std::unique_ptr guest_manager_; diff --git a/vendor/brightray b/vendor/brightray index 3b993f9fd7ff..91abdb01a182 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit 3b993f9fd7ffdd0e92bb77521a8b7f32af5eba5b +Subproject commit 91abdb01a1825c12522fd5fc2349a7ba9a091a48 From e213e09c3e04c00217898f76ab98399a2bfc5328 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jul 2016 21:53:19 +0900 Subject: [PATCH 08/17] Add options to session.fromPartition --- atom/browser/api/atom_api_session.cc | 15 ++++++++++----- atom/browser/api/atom_api_session.h | 4 +++- atom/browser/atom_browser_context.cc | 3 ++- atom/browser/atom_browser_context.h | 6 ++++-- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index a9447392f25e..c1f4a1934ffd 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -21,6 +21,7 @@ #include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/native_mate_converters/net_converter.h" +#include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/node_includes.h" #include "base/files/file_path.h" #include "base/guid.h" @@ -536,16 +537,17 @@ mate::Handle Session::CreateFrom( // static mate::Handle Session::FromPartition( - v8::Isolate* isolate, const std::string& partition) { + v8::Isolate* isolate, const std::string& partition, + const base::DictionaryValue& options) { scoped_refptr browser_context; if (partition.empty()) { - browser_context = AtomBrowserContext::From("", false); + browser_context = AtomBrowserContext::From("", false, options); } else if (base::StartsWith(partition, kPersistPrefix, base::CompareCase::SENSITIVE)) { std::string name = partition.substr(8); - browser_context = AtomBrowserContext::From(name, false); + browser_context = AtomBrowserContext::From(name, false, options); } else { - browser_context = AtomBrowserContext::From(partition, true); + browser_context = AtomBrowserContext::From(partition, true, options); } return CreateFrom(isolate, browser_context.get()); } @@ -593,7 +595,10 @@ v8::Local FromPartition( args->ThrowError("Session can only be received when app is ready"); return v8::Null(args->isolate()); } - return atom::api::Session::FromPartition(args->isolate(), partition).ToV8(); + base::DictionaryValue options; + args->GetNext(&options); + return atom::api::Session::FromPartition( + args->isolate(), partition, options).ToV8(); } void Initialize(v8::Local exports, v8::Local unused, diff --git a/atom/browser/api/atom_api_session.h b/atom/browser/api/atom_api_session.h index d1943ba6ed1e..c3bb82eebaf4 100644 --- a/atom/browser/api/atom_api_session.h +++ b/atom/browser/api/atom_api_session.h @@ -8,6 +8,7 @@ #include #include "atom/browser/api/trackable_object.h" +#include "base/values.h" #include "content/public/browser/download_manager.h" #include "native_mate/handle.h" #include "net/base/completion_callback.h" @@ -49,7 +50,8 @@ class Session: public mate::TrackableObject, // Gets the Session of |partition|. static mate::Handle FromPartition( - v8::Isolate* isolate, const std::string& partition); + v8::Isolate* isolate, const std::string& partition, + const base::DictionaryValue& options = base::DictionaryValue()); AtomBrowserContext* browser_context() const { return browser_context_.get(); } diff --git a/atom/browser/atom_browser_context.cc b/atom/browser/atom_browser_context.cc index 9bb3f6455e60..1853f931b5e5 100644 --- a/atom/browser/atom_browser_context.cc +++ b/atom/browser/atom_browser_context.cc @@ -192,7 +192,8 @@ void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) { // static scoped_refptr AtomBrowserContext::From( - const std::string& partition, bool in_memory) { + const std::string& partition, bool in_memory, + const base::DictionaryValue& options) { auto browser_context = brightray::BrowserContext::Get(partition, in_memory); if (browser_context) return static_cast(browser_context.get()); diff --git a/atom/browser/atom_browser_context.h b/atom/browser/atom_browser_context.h index 47c05a00cf4a..5e83b69808d3 100644 --- a/atom/browser/atom_browser_context.h +++ b/atom/browser/atom_browser_context.h @@ -19,9 +19,11 @@ class WebViewManager; class AtomBrowserContext : public brightray::BrowserContext { public: // Get or create the BrowserContext according to its |partition| and - // |in_memory|. + // |in_memory|. The |options| will be passed to constructor when there is no + // existing BrowserContext. static scoped_refptr From( - const std::string& partition, bool in_memory); + const std::string& partition, bool in_memory, + const base::DictionaryValue& options = base::DictionaryValue()); void SetUserAgent(const std::string& user_agent); From 753e92c84554ba9195e3f4da79fe099660ab2b55 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jul 2016 22:05:07 +0900 Subject: [PATCH 09/17] Add cache option for session --- atom/browser/atom_browser_context.cc | 13 +++++++++---- atom/browser/atom_browser_context.h | 4 +++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/atom/browser/atom_browser_context.cc b/atom/browser/atom_browser_context.cc index 1853f931b5e5..3d42fe5d98dd 100644 --- a/atom/browser/atom_browser_context.cc +++ b/atom/browser/atom_browser_context.cc @@ -63,8 +63,9 @@ std::string RemoveWhitespace(const std::string& str) { } // namespace -AtomBrowserContext::AtomBrowserContext(const std::string& partition, - bool in_memory) +AtomBrowserContext::AtomBrowserContext( + const std::string& partition, bool in_memory, + const base::DictionaryValue& options) : brightray::BrowserContext(partition, in_memory), network_delegate_(new AtomNetworkDelegate) { // Construct user agent string. @@ -82,6 +83,10 @@ AtomBrowserContext::AtomBrowserContext(const std::string& partition, CHROME_VERSION_STRING); } user_agent_ = content::BuildUserAgentFromProduct(user_agent); + + // Read options. + use_cache_ = true; + options.GetBoolean("cache", &use_cache_); } AtomBrowserContext::~AtomBrowserContext() { @@ -144,7 +149,7 @@ net::HttpCache::BackendFactory* AtomBrowserContext::CreateHttpCacheBackendFactory( const base::FilePath& base_path) { base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(switches::kDisableHttpCache)) + if (!use_cache_ || command_line->HasSwitch(switches::kDisableHttpCache)) return new NoCacheBackend; else return brightray::BrowserContext::CreateHttpCacheBackendFactory(base_path); @@ -198,7 +203,7 @@ scoped_refptr AtomBrowserContext::From( if (browser_context) return static_cast(browser_context.get()); - return new AtomBrowserContext(partition, in_memory); + return new AtomBrowserContext(partition, in_memory, options); } } // namespace atom diff --git a/atom/browser/atom_browser_context.h b/atom/browser/atom_browser_context.h index 5e83b69808d3..ed3817da6033 100644 --- a/atom/browser/atom_browser_context.h +++ b/atom/browser/atom_browser_context.h @@ -48,7 +48,8 @@ class AtomBrowserContext : public brightray::BrowserContext { AtomNetworkDelegate* network_delegate() const { return network_delegate_; } protected: - AtomBrowserContext(const std::string& partition, bool in_memory); + AtomBrowserContext(const std::string& partition, bool in_memory, + const base::DictionaryValue& options); ~AtomBrowserContext() override; private: @@ -56,6 +57,7 @@ class AtomBrowserContext : public brightray::BrowserContext { std::unique_ptr guest_manager_; std::unique_ptr permission_manager_; std::string user_agent_; + bool use_cache_; // Managed by brightray::BrowserContext. AtomNetworkDelegate* network_delegate_; From e7666b0448f338bef1213424f9e7b036d82d9b10 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jul 2016 22:21:49 +0900 Subject: [PATCH 10/17] docs: options of session.fromPartition --- docs/api/session.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/api/session.md b/docs/api/session.md index 78b001fdab17..91ff30ad6ae4 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -20,17 +20,25 @@ const ses = win.webContents.session The `session` module has the following methods: -### session.fromPartition(partition) +### session.fromPartition(partition[, options]) * `partition` String +* `options` Object + * `cache` Boolean - Whether to enable cache. -Returns a new `Session` instance from `partition` string. +Returns a `Session` instance from `partition` string. When there is an existing +`Session` with the same `partition`, it will be returned; othewise a new +`Session` instance will be created with `options`. If `partition` starts with `persist:`, the page will use a persistent session available to all pages in the app with the same `partition`. if there is no `persist:` prefix, the page will use an in-memory session. If the `partition` is empty then default session of the app will be returned. +To create a `Session` with `options`, you have to ensure the `Session` with the +`partition` has never been used before. There is no way to change the `options` +of an existing `Session` object. + ## Properties The `session` module has the following properties: From 3ce3004595e8a9c21de41fb9bb6327d257ae738f Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jul 2016 22:24:09 +0900 Subject: [PATCH 11/17] spec: session.defaultSession test case --- spec/api-session-spec.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/api-session-spec.js b/spec/api-session-spec.js index 0557508e6da8..b8b944944bbb 100644 --- a/spec/api-session-spec.js +++ b/spec/api-session-spec.js @@ -35,6 +35,12 @@ describe('session module', function () { w = null }) + describe('session.defaultSession', function () { + it('returns the default session', function () { + assert.equal(session.defaultSession, session.fromPartition('')) + }) + }) + describe('session.cookies', function () { it('should get cookies', function (done) { var server = http.createServer(function (req, res) { From 62153f4117e64a8d90c4a6ca56e4c8808841f6b1 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jul 2016 22:25:09 +0900 Subject: [PATCH 12/17] spec: Name of tests should match docs --- spec/api-session-spec.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/api-session-spec.js b/spec/api-session-spec.js index b8b944944bbb..4f43ef04d30b 100644 --- a/spec/api-session-spec.js +++ b/spec/api-session-spec.js @@ -41,7 +41,7 @@ describe('session module', function () { }) }) - describe('session.cookies', function () { + describe('ses.cookies', function () { it('should get cookies', function (done) { var server = http.createServer(function (req, res) { res.setHeader('Set-Cookie', ['0=0']) @@ -147,7 +147,7 @@ describe('session module', function () { }) }) - describe('session.clearStorageData(options)', function () { + describe('ses.clearStorageData(options)', function () { fixtures = path.resolve(__dirname, 'fixtures') it('clears localstorage data', function (done) { ipcMain.on('count', function (event, count) { @@ -169,7 +169,7 @@ describe('session module', function () { }) }) - describe('session will-download event', function () { + describe('will-download event', function () { var w = null beforeEach(function () { @@ -286,7 +286,7 @@ describe('session module', function () { }) }) - describe('session.protocol', function () { + describe('ses.protocol', function () { const partitionName = 'temp' const protocolName = 'sp' const partitionProtocol = session.fromPartition(partitionName).protocol From fd73279d169a28875028673ce3f07fb3454807a9 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jul 2016 22:38:50 +0900 Subject: [PATCH 13/17] spec: Test lifetime of sessions returned by session.fromPartition --- spec/api-session-spec.js | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/spec/api-session-spec.js b/spec/api-session-spec.js index 4f43ef04d30b..95436c73b885 100644 --- a/spec/api-session-spec.js +++ b/spec/api-session-spec.js @@ -3,12 +3,8 @@ const http = require('http') const path = require('path') const fs = require('fs') -const ipcRenderer = require('electron').ipcRenderer -const remote = require('electron').remote - -const ipcMain = remote.ipcMain -const session = remote.session -const BrowserWindow = remote.BrowserWindow +const {ipcRenderer, remote} = require('electron') +const {ipcMain, session, webContents, BrowserWindow} = remote describe('session module', function () { this.timeout(10000) @@ -41,6 +37,23 @@ describe('session module', function () { }) }) + describe('session.fromPartition(partition, options)', function () { + it('returns existing session with same partition', function () { + assert.equal(session.fromPartition('test'), session.fromPartition('test')) + }) + + it('created session is ref-counted', function () { + const partition = 'test2' + const userAgent = 'test-agent' + const ses1 = session.fromPartition(partition) + ses1.setUserAgent(userAgent) + assert.equal(ses1.getUserAgent(), userAgent) + ses1.destroy() + const ses2 = session.fromPartition(partition) + assert.notEqual(ses2.getUserAgent(), userAgent) + }) + }) + describe('ses.cookies', function () { it('should get cookies', function (done) { var server = http.createServer(function (req, res) { From 6db75a345889b980718cf59a76fc403e35d9fe73 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jul 2016 22:45:15 +0900 Subject: [PATCH 14/17] Fix building on Linux --- atom/browser/api/atom_api_app.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index fc3d9e12a07d..8a66c041f4a2 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -497,7 +497,7 @@ bool App::IsAccessibilitySupportEnabled() { void App::ImportCertificate( const base::DictionaryValue& options, const net::CompletionCallback& callback) { - auto browser_context = brightray::BrowserContext::From("", false); + auto browser_context = AtomBrowserContext::From("", false); if (!certificate_manager_model_) { std::unique_ptr copy = options.CreateDeepCopy(); CertificateManagerModel::Create( From e653c67153f6ba4b51321deb0ad970d263c585ac Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jul 2016 22:57:38 +0900 Subject: [PATCH 15/17] Move chromeExtensionHandler out of ready handler This code were in ready handler because we could not require "protocol" before ready before. It is now safe to move the code out. --- lib/browser/chrome-extension.js | 65 +++++++++++++++++---------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/lib/browser/chrome-extension.js b/lib/browser/chrome-extension.js index 983560c58c24..d8d0f7806634 100644 --- a/lib/browser/chrome-extension.js +++ b/lib/browser/chrome-extension.js @@ -284,6 +284,39 @@ app.on('web-contents-created', function (event, webContents) { }) }) +// The chrome-extension: can map a extension URL request to real file path. +const chromeExtensionHandler = function (request, callback) { + const parsed = url.parse(request.url) + if (!parsed.hostname || !parsed.path) return callback() + + const manifest = manifestMap[parsed.hostname] + if (!manifest) return callback() + + const page = backgroundPages[parsed.hostname] + if (page && parsed.path === `/${page.name}`) { + return callback({ + mimeType: 'text/html', + data: page.html + }) + } + + fs.readFile(path.join(manifest.srcDirectory, parsed.path), function (err, content) { + if (err) { + return callback(-6) // FILE_NOT_FOUND + } else { + return callback(content) + } + }) +} + +app.on('session-created', function (ses) { + ses.protocol.registerBufferProtocol('chrome-extension', chromeExtensionHandler, function (error) { + if (error) { + console.error(`Unable to register chrome-extension protocol: ${error}`) + } + }) +}) + // The persistent path of "DevTools Extensions" preference file. let loadedExtensionsPath = null @@ -309,38 +342,6 @@ app.on('will-quit', function () { // We can not use protocol or BrowserWindow until app is ready. app.once('ready', function () { - // The chrome-extension: can map a extension URL request to real file path. - const chromeExtensionHandler = function (request, callback) { - const parsed = url.parse(request.url) - if (!parsed.hostname || !parsed.path) return callback() - - const manifest = manifestMap[parsed.hostname] - if (!manifest) return callback() - - const page = backgroundPages[parsed.hostname] - if (page && parsed.path === `/${page.name}`) { - return callback({ - mimeType: 'text/html', - data: page.html - }) - } - - fs.readFile(path.join(manifest.srcDirectory, parsed.path), function (err, content) { - if (err) { - return callback(-6) // FILE_NOT_FOUND - } else { - return callback(content) - } - }) - } - app.on('session-created', function (ses) { - ses.protocol.registerBufferProtocol('chrome-extension', chromeExtensionHandler, function (error) { - if (error) { - console.error(`Unable to register chrome-extension protocol: ${error}`) - } - }) - }) - // Load persisted extensions. loadedExtensionsPath = path.join(app.getPath('userData'), 'DevTools Extensions') try { From 749ed3473b9a4e9d350741b8abc6bd9166811f4b Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 13 Jul 2016 13:34:19 +0900 Subject: [PATCH 16/17] spec: Fix js lint warning --- spec/api-session-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/api-session-spec.js b/spec/api-session-spec.js index 95436c73b885..1696fedc4feb 100644 --- a/spec/api-session-spec.js +++ b/spec/api-session-spec.js @@ -4,7 +4,7 @@ const path = require('path') const fs = require('fs') const {ipcRenderer, remote} = require('electron') -const {ipcMain, session, webContents, BrowserWindow} = remote +const {ipcMain, session, BrowserWindow} = remote describe('session module', function () { this.timeout(10000) From 41d27995142334fe6ecfcf256674ca433e78f689 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 13 Jul 2016 16:22:55 +0900 Subject: [PATCH 17/17] Run background pages in separate partition This avoids the default partition always being created on startup, so it gives users a chance to run session.fromParititon. --- lib/browser/chrome-extension.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/browser/chrome-extension.js b/lib/browser/chrome-extension.js index d8d0f7806634..96f750897d09 100644 --- a/lib/browser/chrome-extension.js +++ b/lib/browser/chrome-extension.js @@ -86,6 +86,7 @@ const startBackgroundPages = function (manifest) { } const contents = webContents.create({ + partition: 'persist:__chrome_extension', isBackgroundPage: true, commandLineSwitches: ['--background-page'] })