From d180d3b1682e2d633ceb4e09bb675a1c463d8da5 Mon Sep 17 00:00:00 2001 From: Robo Date: Thu, 6 Aug 2015 20:31:05 +0530 Subject: [PATCH 1/6] webview: fix partition attribute --- atom/browser/api/atom_api_web_contents.cc | 10 ++++-- atom/browser/api/atom_api_web_view_manager.cc | 3 +- atom/browser/atom_browser_main_parts.cc | 32 +++++++++++++++++++ atom/browser/atom_browser_main_parts.h | 10 ++++++ atom/browser/lib/guest-view-manager.coffee | 13 +++++++- atom/browser/web_view_manager.cc | 15 +++++---- atom/browser/web_view_manager.h | 4 ++- 7 files changed, 74 insertions(+), 13 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 5b723801cdeb..da33451c1e7c 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -159,16 +159,20 @@ WebContents::WebContents(const mate::Dictionary& options) { type_ = is_guest ? WEB_VIEW : BROWSER_WINDOW; - auto browser_context = AtomBrowserMainParts::Get()->browser_context(); content::WebContents* web_contents; if (is_guest) { - content::SiteInstance* site_instance = content::SiteInstance::CreateForURL( - browser_context, GURL("chrome-guest://fake-host")); + GURL guest_site; + options.Get("partition", &guest_site); + auto browser_context = + AtomBrowserMainParts::Get()->GetBrowserContextForPartition(guest_site); + auto site_instance = + content::SiteInstance::CreateForURL(browser_context, guest_site); content::WebContents::CreateParams params(browser_context, site_instance); guest_delegate_.reset(new WebViewGuestDelegate); params.guest_delegate = guest_delegate_.get(); web_contents = content::WebContents::Create(params); } else { + auto browser_context = AtomBrowserMainParts::Get()->browser_context(); content::WebContents::CreateParams params(browser_context); web_contents = content::WebContents::Create(params); } diff --git a/atom/browser/api/atom_api_web_view_manager.cc b/atom/browser/api/atom_api_web_view_manager.cc index d77ea18d6d0c..c69285a6980d 100644 --- a/atom/browser/api/atom_api_web_view_manager.cc +++ b/atom/browser/api/atom_api_web_view_manager.cc @@ -43,7 +43,8 @@ struct Converter { return options.Get("nodeIntegration", &(out->node_integration)) && options.Get("plugins", &(out->plugins)) && - options.Get("disableWebSecurity", &(out->disable_web_security)); + options.Get("disableWebSecurity", &(out->disable_web_security)) && + options.Get("partitionId", &(out->partition_id)); } }; diff --git a/atom/browser/atom_browser_main_parts.cc b/atom/browser/atom_browser_main_parts.cc index b4f61d0f195e..189fc938698e 100644 --- a/atom/browser/atom_browser_main_parts.cc +++ b/atom/browser/atom_browser_main_parts.cc @@ -26,6 +26,21 @@ namespace atom { +namespace { + +const base::FilePath::CharType kStoragePartitionDirName[] = "Partitions"; + +void GetStoragePartitionConfig(const GURL& partition, + base::FilePath* partition_path, + bool* in_memory, + std::string* id) { + *in_memory = (partition.path() != "/persist"); + *id = partition.query(); + *partition_path = base::FilePath(kStoragePartitionDirName).AppendASCII(*id); +} + +} // namespace + // static AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL; @@ -40,6 +55,7 @@ AtomBrowserMainParts::AtomBrowserMainParts() } AtomBrowserMainParts::~AtomBrowserMainParts() { + STLDeleteValues(&browser_context_map_); for (const auto& callback : destruction_callbacks_) callback.Run(); } @@ -50,6 +66,22 @@ AtomBrowserMainParts* AtomBrowserMainParts::Get() { return self_; } +content::BrowserContext* AtomBrowserMainParts::GetBrowserContextForPartition( + const GURL& partition) { + std::string id; + bool in_memory; + base::FilePath partition_path; + GetStoragePartitionConfig(partition, &partition_path, &in_memory, &id); + auto item = browser_context_map_.find(id); + if (item != browser_context_map_.end()) + return item->second; + + auto browser_context = CreateBrowserContext(); + browser_context->Initialize(partition_path, in_memory); + browser_context_map_[id] = browser_context; + return browser_context; +} + void AtomBrowserMainParts::RegisterDestructionCallback( const base::Closure& callback) { destruction_callbacks_.push_back(callback); diff --git a/atom/browser/atom_browser_main_parts.h b/atom/browser/atom_browser_main_parts.h index a2909cac53d0..993340bfb422 100644 --- a/atom/browser/atom_browser_main_parts.h +++ b/atom/browser/atom_browser_main_parts.h @@ -6,10 +6,13 @@ #define ATOM_BROWSER_ATOM_BROWSER_MAIN_PARTS_H_ #include +#include +#include #include "base/callback.h" #include "base/timer/timer.h" #include "brightray/browser/browser_main_parts.h" +#include "content/public/browser/browser_context.h" class BrowserProcess; @@ -29,6 +32,10 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts { static AtomBrowserMainParts* Get(); + // Returns the BrowserContext associated with the partition. + content::BrowserContext* GetBrowserContextForPartition( + const GURL& partition); + // Register a callback that should be destroyed before JavaScript environment // gets destroyed. void RegisterDestructionCallback(const base::Closure& callback); @@ -70,6 +77,9 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts { // List of callbacks should be executed before destroying JS env. std::list destruction_callbacks_; + // partition_id => browser_context + std::map browser_context_map_; + static AtomBrowserMainParts* self_; DISALLOW_COPY_AND_ASSIGN(AtomBrowserMainParts); diff --git a/atom/browser/lib/guest-view-manager.coffee b/atom/browser/lib/guest-view-manager.coffee index 398cdb5d9495..c0a87a7ac1cb 100644 --- a/atom/browser/lib/guest-view-manager.coffee +++ b/atom/browser/lib/guest-view-manager.coffee @@ -1,3 +1,4 @@ +crypto = require 'crypto' ipc = require 'ipc' webContents = require 'web-contents' webViewManager = null # Doesn't exist in early initialization. @@ -38,12 +39,21 @@ moveLastToFirst = (list) -> getNextInstanceId = (webContents) -> ++nextInstanceId +# Generate URL encoded partition id. +getPartitionId = (partition='default') -> + persist = partition.startsWith('persist:') + # Guest site url will be chrome-guest://fake-host/{persist}?{partitionId} + partitionId = "chrome-guest://fake-host/" + partitionId += if persist then 'persist?' else '?' + partitionId += crypto.createHash('sha256').update(partition).digest('hex') + # Create a new guest instance. createGuest = (embedder, params) -> webViewManager ?= process.atomBinding 'web_view_manager' id = getNextInstanceId embedder - guest = webContents.create {isGuest: true, embedder} + partitionId = getPartitionId params.partition + guest = webContents.create {isGuest: true, partition: partitionId, embedder} guestInstances[id] = {guest, embedder} # Destroy guest when the embedder is gone or navigated. @@ -120,6 +130,7 @@ attachGuest = (embedder, elementInstanceId, guestInstanceId, params) -> plugins: params.plugins disableWebSecurity: params.disablewebsecurity preloadUrl: params.preload ? '' + partitionId: getPartitionId(params.partition) guest.attachParams = params embedderElementsMap[key] = guestInstanceId diff --git a/atom/browser/web_view_manager.cc b/atom/browser/web_view_manager.cc index 7dba6c06dd38..50e07230197f 100644 --- a/atom/browser/web_view_manager.cc +++ b/atom/browser/web_view_manager.cc @@ -48,7 +48,7 @@ void WebViewManager::AddGuest(int guest_instance_id, content::WebContents* web_contents, const WebViewInfo& info) { base::AutoLock auto_lock(lock_); - web_contents_embdder_map_[guest_instance_id] = { web_contents, embedder }; + web_contents_embedder_map_[guest_instance_id] = { web_contents, embedder }; webview_info_map_[web_contents] = info; // Map the element in embedder to guest. @@ -59,11 +59,12 @@ void WebViewManager::AddGuest(int guest_instance_id, void WebViewManager::RemoveGuest(int guest_instance_id) { base::AutoLock auto_lock(lock_); - if (!ContainsKey(web_contents_embdder_map_, guest_instance_id)) + if (!ContainsKey(web_contents_embedder_map_, guest_instance_id)) return; - auto web_contents = web_contents_embdder_map_[guest_instance_id].web_contents; - web_contents_embdder_map_.erase(guest_instance_id); + auto web_contents = + web_contents_embedder_map_[guest_instance_id].web_contents; + web_contents_embedder_map_.erase(guest_instance_id); webview_info_map_.erase(web_contents); // Remove the record of element in embedder too. @@ -82,15 +83,15 @@ content::WebContents* WebViewManager::GetGuestByInstanceID( return nullptr; int guest_instance_id = element_instance_id_to_guest_map_[key]; - if (ContainsKey(web_contents_embdder_map_, guest_instance_id)) - return web_contents_embdder_map_[guest_instance_id].web_contents; + if (ContainsKey(web_contents_embedder_map_, guest_instance_id)) + return web_contents_embedder_map_[guest_instance_id].web_contents; else return nullptr; } bool WebViewManager::ForEachGuest(content::WebContents* embedder_web_contents, const GuestCallback& callback) { - for (auto& item : web_contents_embdder_map_) + for (auto& item : web_contents_embedder_map_) if (item.second.embedder == embedder_web_contents && callback.Run(item.second.web_contents)) return true; diff --git a/atom/browser/web_view_manager.h b/atom/browser/web_view_manager.h index b1bea92702cc..d8ed857b444f 100644 --- a/atom/browser/web_view_manager.h +++ b/atom/browser/web_view_manager.h @@ -10,6 +10,7 @@ #include "base/files/file_path.h" #include "base/synchronization/lock.h" #include "content/public/browser/browser_plugin_guest_manager.h" +#include "content/public/browser/site_instance.h" namespace content { class BrowserContext; @@ -27,6 +28,7 @@ class WebViewManager : public content::BrowserPluginGuestManager { bool plugins; bool disable_web_security; base::FilePath preload_script; + GURL partition_id; }; // Finds the WebViewManager attached with |web_contents| and returns the @@ -57,7 +59,7 @@ class WebViewManager : public content::BrowserPluginGuestManager { content::WebContents* embedder; }; // guest_instance_id => (web_contents, embedder) - std::map web_contents_embdder_map_; + std::map web_contents_embedder_map_; struct ElementInstanceKey { int embedder_process_id; From 5189147021d9ca6d80c7cd53649b6a3b999dd7cb Mon Sep 17 00:00:00 2001 From: Robo Date: Thu, 27 Aug 2015 05:58:06 +0530 Subject: [PATCH 2/6] use embedders' browser context to retrieve webviewmanager --- atom/browser/web_view_manager.cc | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/atom/browser/web_view_manager.cc b/atom/browser/web_view_manager.cc index 50e07230197f..76915264c6fd 100644 --- a/atom/browser/web_view_manager.cc +++ b/atom/browser/web_view_manager.cc @@ -5,27 +5,18 @@ #include "atom/browser/web_view_manager.h" #include "atom/browser/atom_browser_context.h" +#include "atom/browser/atom_browser_main_parts.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents.h" namespace atom { -namespace { - -WebViewManager* GetManagerFromWebContents( - const content::WebContents* web_contents) { - auto context = web_contents->GetBrowserContext(); - if (!context) - return nullptr; - return static_cast(context->GetGuestManager()); -} - -} // namespace - // static bool WebViewManager::GetInfoForWebContents( const content::WebContents* web_contents, WebViewInfo* info) { - auto manager = GetManagerFromWebContents(web_contents); + // use embedders' browser context to retrieve WebViewManager. + auto manager = static_cast( + AtomBrowserMainParts::Get()->browser_context()->GetGuestManager()); if (!manager) return false; base::AutoLock auto_lock(manager->lock_); From 150b540e722c971a74304b303f2b16325b9477c5 Mon Sep 17 00:00:00 2001 From: Robo Date: Thu, 27 Aug 2015 06:57:03 +0530 Subject: [PATCH 3/6] add spec and docs --- docs/api/web-view-tag.md | 17 ++++++++++++++++ spec/fixtures/pages/partition/one.html | 5 +++++ spec/fixtures/pages/partition/two.html | 4 ++++ spec/webview-spec.coffee | 27 ++++++++++++++++++++++++++ 4 files changed, 53 insertions(+) create mode 100644 spec/fixtures/pages/partition/one.html create mode 100644 spec/fixtures/pages/partition/two.html diff --git a/docs/api/web-view-tag.md b/docs/api/web-view-tag.md index 6b64a0269c52..ec8529655272 100644 --- a/docs/api/web-view-tag.md +++ b/docs/api/web-view-tag.md @@ -131,6 +131,23 @@ page is loaded, use the `setUserAgent` method to change the user agent. If "on", the guest page will have web security disabled. +### partition + +```html + + +``` + +Sets the storage partition used by the `webview`. If the storage partition ID starts with `persist:`, +the `webview` will use a persistent storage partition available to all `webview` in the app with +the same storage partition ID. If the ID is unset or if there is no `persist:` prefix, the `webview` will +use an in-memory storage partition. By assigning the same partition ID, multiple `webview` +can share the same storage partition. + +This value can only be modified before the first navigation, since the storage partition of an active +renderer process cannot change. Subsequent attempts to modify the value will fail with a +DOM exception. + ## Methods The `webview` tag has the following methods: diff --git a/spec/fixtures/pages/partition/one.html b/spec/fixtures/pages/partition/one.html new file mode 100644 index 000000000000..765f721883f3 --- /dev/null +++ b/spec/fixtures/pages/partition/one.html @@ -0,0 +1,5 @@ + diff --git a/spec/fixtures/pages/partition/two.html b/spec/fixtures/pages/partition/two.html new file mode 100644 index 000000000000..ad22c341df95 --- /dev/null +++ b/spec/fixtures/pages/partition/two.html @@ -0,0 +1,4 @@ + diff --git a/spec/webview-spec.coffee b/spec/webview-spec.coffee index 6eb391ac9483..ae8cd5d45579 100644 --- a/spec/webview-spec.coffee +++ b/spec/webview-spec.coffee @@ -154,6 +154,33 @@ describe ' tag', -> webview.src = "data:text/html;base64,#{encoded}" document.body.appendChild webview + describe 'partition attribute', -> + isolatedWebview = null + beforeEach -> + isolatedWebview = new WebView + + afterEach -> + document.body.removeChild isolatedWebview + + it 'isolates storage for different id', (done) -> + listener = (e) -> + document.body.appendChild isolatedWebview + webview.removeEventListener 'did-finish-load', listener + listener2 = (e) -> + assert.equal e.message, "one 1" + webview.removeEventListener 'console-message', listener2 + listener3 = (e) -> + assert.equal e.message, " 0" + isolatedWebview.removeEventListener 'console-message', listener3 + done() + webview.addEventListener 'did-finish-load', listener + webview.addEventListener 'console-message', listener2 + webview.src = "file://#{fixtures}/pages/partition/one.html" + isolatedWebview.addEventListener 'console-message', listener3 + isolatedWebview.setAttribute 'partition', 'test' + isolatedWebview.src = "file://#{fixtures}/pages/partition/two.html" + document.body.appendChild webview + describe 'new-window event', -> it 'emits when window.open is called', (done) -> webview.addEventListener 'new-window', (e) -> From da5bac42f3efb9f28ed9dbb00747ba6052bc6250 Mon Sep 17 00:00:00 2001 From: Robo Date: Fri, 28 Aug 2015 13:00:50 +0530 Subject: [PATCH 4/6] use embedders' browser context when partition is not specified --- atom/browser/api/atom_api_web_contents.cc | 10 +++++++--- atom/browser/lib/guest-view-manager.coffee | 8 +++++--- docs/api/web-view-tag.md | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index da33451c1e7c..7cefe8e45e3d 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -159,12 +159,17 @@ WebContents::WebContents(const mate::Dictionary& options) { type_ = is_guest ? WEB_VIEW : BROWSER_WINDOW; + content::BrowserContext* browser_context = + AtomBrowserMainParts::Get()->browser_context(); content::WebContents* web_contents; if (is_guest) { GURL guest_site; options.Get("partition", &guest_site); - auto browser_context = - AtomBrowserMainParts::Get()->GetBrowserContextForPartition(guest_site); + // use hosts' browser_context when no partition is specified. + if (!guest_site.query().empty()) { + browser_context = AtomBrowserMainParts::Get() + ->GetBrowserContextForPartition(guest_site); + } auto site_instance = content::SiteInstance::CreateForURL(browser_context, guest_site); content::WebContents::CreateParams params(browser_context, site_instance); @@ -172,7 +177,6 @@ WebContents::WebContents(const mate::Dictionary& options) { params.guest_delegate = guest_delegate_.get(); web_contents = content::WebContents::Create(params); } else { - auto browser_context = AtomBrowserMainParts::Get()->browser_context(); content::WebContents::CreateParams params(browser_context); web_contents = content::WebContents::Create(params); } diff --git a/atom/browser/lib/guest-view-manager.coffee b/atom/browser/lib/guest-view-manager.coffee index c0a87a7ac1cb..8d86e8fae911 100644 --- a/atom/browser/lib/guest-view-manager.coffee +++ b/atom/browser/lib/guest-view-manager.coffee @@ -40,12 +40,14 @@ getNextInstanceId = (webContents) -> ++nextInstanceId # Generate URL encoded partition id. -getPartitionId = (partition='default') -> +getPartitionId = (partition) -> persist = partition.startsWith('persist:') # Guest site url will be chrome-guest://fake-host/{persist}?{partitionId} partitionId = "chrome-guest://fake-host/" - partitionId += if persist then 'persist?' else '?' - partitionId += crypto.createHash('sha256').update(partition).digest('hex') + if partition + partitionId += if persist then 'persist?' else '?' + partitionId += crypto.createHash('sha256').update(partition).digest('hex') + return partitionId # Create a new guest instance. createGuest = (embedder, params) -> diff --git a/docs/api/web-view-tag.md b/docs/api/web-view-tag.md index ec8529655272..cafcc5762e7a 100644 --- a/docs/api/web-view-tag.md +++ b/docs/api/web-view-tag.md @@ -140,7 +140,7 @@ If "on", the guest page will have web security disabled. Sets the storage partition used by the `webview`. If the storage partition ID starts with `persist:`, the `webview` will use a persistent storage partition available to all `webview` in the app with -the same storage partition ID. If the ID is unset or if there is no `persist:` prefix, the `webview` will +the same storage partition ID. if there is no `persist:` prefix, the `webview` will use an in-memory storage partition. By assigning the same partition ID, multiple `webview` can share the same storage partition. From 8f59c0b642b133a0df7bacd3a7a4c15b951ba259 Mon Sep 17 00:00:00 2001 From: Robo Date: Mon, 31 Aug 2015 23:53:31 +0530 Subject: [PATCH 5/6] create partitionId with encodedURIcomponent --- atom/browser/atom_browser_main_parts.cc | 22 +++++++-------- atom/browser/atom_browser_main_parts.h | 4 ++- atom/browser/lib/guest-view-manager.coffee | 11 +++++--- docs/api/web-view-tag.md | 3 +- spec/fixtures/pages/partition/one.html | 1 - spec/fixtures/pages/partition/two.html | 4 --- spec/webview-spec.coffee | 33 +++++++++------------- 7 files changed, 37 insertions(+), 41 deletions(-) delete mode 100644 spec/fixtures/pages/partition/two.html diff --git a/atom/browser/atom_browser_main_parts.cc b/atom/browser/atom_browser_main_parts.cc index 189fc938698e..4463115cfee5 100644 --- a/atom/browser/atom_browser_main_parts.cc +++ b/atom/browser/atom_browser_main_parts.cc @@ -28,15 +28,17 @@ namespace atom { namespace { -const base::FilePath::CharType kStoragePartitionDirName[] = "Partitions"; +const base::FilePath::CharType kStoragePartitionDirname[] = "Partitions"; void GetStoragePartitionConfig(const GURL& partition, base::FilePath* partition_path, bool* in_memory, std::string* id) { *in_memory = (partition.path() != "/persist"); - *id = partition.query(); - *partition_path = base::FilePath(kStoragePartitionDirName).AppendASCII(*id); + net::UnescapeRule::Type flags = + net::UnescapeRule::SPACES | net::UnescapeRule::URL_SPECIAL_CHARS; + *id = net::UnescapeURLComponent(partition.query(), flags); + *partition_path = base::FilePath(kStoragePartitionDirname).AppendASCII(*id); } } // namespace @@ -55,7 +57,6 @@ AtomBrowserMainParts::AtomBrowserMainParts() } AtomBrowserMainParts::~AtomBrowserMainParts() { - STLDeleteValues(&browser_context_map_); for (const auto& callback : destruction_callbacks_) callback.Run(); } @@ -72,14 +73,13 @@ content::BrowserContext* AtomBrowserMainParts::GetBrowserContextForPartition( bool in_memory; base::FilePath partition_path; GetStoragePartitionConfig(partition, &partition_path, &in_memory, &id); - auto item = browser_context_map_.find(id); - if (item != browser_context_map_.end()) - return item->second; + if (browser_context_map_.contains(id)) + return browser_context_map_.get(id); - auto browser_context = CreateBrowserContext(); - browser_context->Initialize(partition_path, in_memory); - browser_context_map_[id] = browser_context; - return browser_context; + scoped_ptr browser_context(CreateBrowserContext()); + browser_context->Initialize(partition_path.value(), in_memory); + browser_context_map_.set(id, browser_context.Pass()); + return browser_context_map_.get(id); } void AtomBrowserMainParts::RegisterDestructionCallback( diff --git a/atom/browser/atom_browser_main_parts.h b/atom/browser/atom_browser_main_parts.h index 993340bfb422..d952f432882f 100644 --- a/atom/browser/atom_browser_main_parts.h +++ b/atom/browser/atom_browser_main_parts.h @@ -10,6 +10,7 @@ #include #include "base/callback.h" +#include "base/containers/scoped_ptr_hash_map.h" #include "base/timer/timer.h" #include "brightray/browser/browser_main_parts.h" #include "content/public/browser/browser_context.h" @@ -78,7 +79,8 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts { std::list destruction_callbacks_; // partition_id => browser_context - std::map browser_context_map_; + base::ScopedPtrHashMap> + browser_context_map_; static AtomBrowserMainParts* self_; diff --git a/atom/browser/lib/guest-view-manager.coffee b/atom/browser/lib/guest-view-manager.coffee index 8d86e8fae911..2f1c8312155a 100644 --- a/atom/browser/lib/guest-view-manager.coffee +++ b/atom/browser/lib/guest-view-manager.coffee @@ -1,4 +1,3 @@ -crypto = require 'crypto' ipc = require 'ipc' webContents = require 'web-contents' webViewManager = null # Doesn't exist in early initialization. @@ -41,12 +40,16 @@ getNextInstanceId = (webContents) -> # Generate URL encoded partition id. getPartitionId = (partition) -> - persist = partition.startsWith('persist:') # Guest site url will be chrome-guest://fake-host/{persist}?{partitionId} partitionId = "chrome-guest://fake-host/" if partition - partitionId += if persist then 'persist?' else '?' - partitionId += crypto.createHash('sha256').update(partition).digest('hex') + persist = partition.startsWith('persist:') + if persist + partition = partition.substring('persist:'.length) + partitionId += 'persist?' + else + partitionId += '?' + partitionId += encodeURIComponent(partition) return partitionId # Create a new guest instance. diff --git a/docs/api/web-view-tag.md b/docs/api/web-view-tag.md index cafcc5762e7a..c1b1f705e95b 100644 --- a/docs/api/web-view-tag.md +++ b/docs/api/web-view-tag.md @@ -142,7 +142,8 @@ Sets the storage partition used by the `webview`. If the storage partition ID st the `webview` will use a persistent storage partition available to all `webview` in the app with the same storage partition ID. if there is no `persist:` prefix, the `webview` will use an in-memory storage partition. By assigning the same partition ID, multiple `webview` -can share the same storage partition. +can share the same storage partition. If the storage partition ID is unset then default storage +of the app will be used. This value can only be modified before the first navigation, since the storage partition of an active renderer process cannot change. Subsequent attempts to modify the value will fail with a diff --git a/spec/fixtures/pages/partition/one.html b/spec/fixtures/pages/partition/one.html index 765f721883f3..ad22c341df95 100644 --- a/spec/fixtures/pages/partition/one.html +++ b/spec/fixtures/pages/partition/one.html @@ -1,5 +1,4 @@ diff --git a/spec/fixtures/pages/partition/two.html b/spec/fixtures/pages/partition/two.html deleted file mode 100644 index ad22c341df95..000000000000 --- a/spec/fixtures/pages/partition/two.html +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/spec/webview-spec.coffee b/spec/webview-spec.coffee index ae8cd5d45579..486efaa6ffb4 100644 --- a/spec/webview-spec.coffee +++ b/spec/webview-spec.coffee @@ -155,30 +155,25 @@ describe ' tag', -> document.body.appendChild webview describe 'partition attribute', -> - isolatedWebview = null - beforeEach -> - isolatedWebview = new WebView - - afterEach -> - document.body.removeChild isolatedWebview - it 'isolates storage for different id', (done) -> listener = (e) -> - document.body.appendChild isolatedWebview - webview.removeEventListener 'did-finish-load', listener - listener2 = (e) -> - assert.equal e.message, "one 1" - webview.removeEventListener 'console-message', listener2 - listener3 = (e) -> assert.equal e.message, " 0" - isolatedWebview.removeEventListener 'console-message', listener3 + webview.removeEventListener 'console-message', listener done() - webview.addEventListener 'did-finish-load', listener - webview.addEventListener 'console-message', listener2 + window.localStorage.setItem 'test', 'one' + webview.addEventListener 'console-message', listener + webview.src = "file://#{fixtures}/pages/partition/one.html" + webview.partition = "test" + document.body.appendChild webview + + it 'uses current session storage when no id is provided', (done) -> + listener = (e) -> + assert.equal e.message, "one 1" + webview.removeEventListener 'console-message', listener + done() + window.localStorage.setItem 'test', 'one' + webview.addEventListener 'console-message', listener webview.src = "file://#{fixtures}/pages/partition/one.html" - isolatedWebview.addEventListener 'console-message', listener3 - isolatedWebview.setAttribute 'partition', 'test' - isolatedWebview.src = "file://#{fixtures}/pages/partition/two.html" document.body.appendChild webview describe 'new-window event', -> From 03ba9533fbfbce42e1770c581b04fde9fcec4856 Mon Sep 17 00:00:00 2001 From: Robo Date: Thu, 3 Sep 2015 06:17:58 +0530 Subject: [PATCH 6/6] store webviewinfo as web contents userdata --- atom/browser/api/atom_api_web_view_manager.cc | 26 +++++++++++------- atom/browser/atom_browser_client.cc | 14 +++++++--- atom/browser/lib/guest-view-manager.coffee | 2 ++ atom/browser/web_view_constants.cc | 24 +++++++++++++++++ atom/browser/web_view_constants.h | 27 +++++++++++++++++++ atom/browser/web_view_guest_delegate.cc | 10 ++----- atom/browser/web_view_manager.cc | 23 +--------------- atom/browser/web_view_manager.h | 23 +++++++++------- filenames.gypi | 2 ++ spec/webview-spec.coffee | 17 ++++++++++++ 10 files changed, 114 insertions(+), 54 deletions(-) create mode 100644 atom/browser/web_view_constants.cc create mode 100644 atom/browser/web_view_constants.h diff --git a/atom/browser/api/atom_api_web_view_manager.cc b/atom/browser/api/atom_api_web_view_manager.cc index c69285a6980d..221d0d7118b4 100644 --- a/atom/browser/api/atom_api_web_view_manager.cc +++ b/atom/browser/api/atom_api_web_view_manager.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "atom/browser/api/atom_api_web_contents.h" +#include "atom/browser/web_view_constants.h" #include "atom/browser/web_view_manager.h" #include "atom/common/native_mate_converters/gurl_converter.h" #include "content/public/browser/browser_context.h" @@ -34,17 +35,19 @@ struct Converter { return false; GURL preload_url; - if (!options.Get("preloadUrl", &preload_url)) + if (!options.Get(atom::web_view::kPreloadUrl, &preload_url)) return false; if (!preload_url.is_empty() && !net::FileURLToFilePath(preload_url, &(out->preload_script))) return false; - return options.Get("nodeIntegration", &(out->node_integration)) && - options.Get("plugins", &(out->plugins)) && - options.Get("disableWebSecurity", &(out->disable_web_security)) && - options.Get("partitionId", &(out->partition_id)); + return options.Get(atom::web_view::kNodeIntegration, + &(out->node_integration)) && + options.Get(atom::web_view::kPlugins, &(out->plugins)) && + options.Get(atom::web_view::kPartitionId, &(out->partition_id)) && + options.Get(atom::web_view::kDisableWebSecurity, + &(out->disable_web_security)); } }; @@ -68,12 +71,15 @@ void AddGuest(int guest_instance_id, content::WebContents* guest_web_contents, atom::WebViewManager::WebViewInfo info) { auto manager = GetWebViewManager(embedder); - if (manager) { - info.guest_instance_id = guest_instance_id; - info.embedder = embedder; + if (manager) manager->AddGuest(guest_instance_id, element_instance_id, embedder, - guest_web_contents, info); - } + guest_web_contents); + + info.guest_instance_id = guest_instance_id; + info.embedder = embedder; + auto data = new atom::WebViewManager::WebViewInfoUserData(info); + guest_web_contents->SetUserData( + atom::web_view::kWebViewInfoKeyName, data); } void RemoveGuest(content::WebContents* embedder, int guest_instance_id) { diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index 8db71fd3030d..fad952d53365 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -16,6 +16,7 @@ #include "atom/browser/browser.h" #include "atom/browser/native_window.h" #include "atom/browser/web_view_manager.h" +#include "atom/browser/web_view_constants.h" #include "atom/browser/window_list.h" #include "atom/common/options_switches.h" #include "base/command_line.h" @@ -74,8 +75,12 @@ ProcessOwner GetProcessOwner(int process_id, return OWNER_NATIVE_WINDOW; // Then search for guest WebContents. - if (WebViewManager::GetInfoForWebContents(web_contents, info)) + auto data = static_cast( + web_contents->GetUserData(web_view::kWebViewInfoKeyName)); + if (data) { + *info = data->web_view_info(); return OWNER_GUEST_WEB_CONTENTS; + } return OWNER_NONE; } @@ -155,9 +160,10 @@ void AtomBrowserClient::OverrideWebkitPrefs( // Custom preferences of guest page. auto web_contents = content::WebContents::FromRenderViewHost(host); - WebViewManager::WebViewInfo info; - if (WebViewManager::GetInfoForWebContents(web_contents, &info)) { - prefs->web_security_enabled = !info.disable_web_security; + auto info = static_cast( + web_contents->GetUserData(web_view::kWebViewInfoKeyName)); + if (info) { + prefs->web_security_enabled = !info->web_view_info().disable_web_security; return; } diff --git a/atom/browser/lib/guest-view-manager.coffee b/atom/browser/lib/guest-view-manager.coffee index 2f1c8312155a..581274699085 100644 --- a/atom/browser/lib/guest-view-manager.coffee +++ b/atom/browser/lib/guest-view-manager.coffee @@ -48,6 +48,8 @@ getPartitionId = (partition) -> partition = partition.substring('persist:'.length) partitionId += 'persist?' else + # Just to differentiate from same persistant ID + partition += "_temp" partitionId += '?' partitionId += encodeURIComponent(partition) return partitionId diff --git a/atom/browser/web_view_constants.cc b/atom/browser/web_view_constants.cc new file mode 100644 index 000000000000..6f8314cbcf36 --- /dev/null +++ b/atom/browser/web_view_constants.cc @@ -0,0 +1,24 @@ +// Copyright (c) 2015 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/web_view_constants.h" + +namespace atom { + +namespace web_view { + +const char kPreloadUrl[] = "preloadUrl"; +const char kNodeIntegration[] = "nodeIntegration"; +const char kPlugins[] = "plugins"; +const char kDisableWebSecurity[] = "disableWebSecurity"; +const char kPartitionId[] = "partitionId"; + +const int kDefaultWidth = 300; +const int kDefaultHeight = 300; + +const char kWebViewInfoKeyName[] = "web_view_info"; + +} // namespace web_view + +} // namespace atom diff --git a/atom/browser/web_view_constants.h b/atom/browser/web_view_constants.h new file mode 100644 index 000000000000..0831bdbdf1d4 --- /dev/null +++ b/atom/browser/web_view_constants.h @@ -0,0 +1,27 @@ +// Copyright (c) 2015 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_WEB_VIEW_CONSTANTS_H_ +#define ATOM_BROWSER_WEB_VIEW_CONSTANTS_H_ + +namespace atom { + +namespace web_view { + +extern const char kPreloadUrl[]; +extern const char kNodeIntegration[]; +extern const char kPlugins[]; +extern const char kDisableWebSecurity[]; +extern const char kPartitionId[]; + +extern const int kDefaultWidth; +extern const int kDefaultHeight; + +extern const char kWebViewInfoKeyName[]; + +} // namespace web_view + +} // namespace atom + +#endif // ATOM_BROWSER_WEB_VIEW_CONSTANTS_H_ diff --git a/atom/browser/web_view_guest_delegate.cc b/atom/browser/web_view_guest_delegate.cc index 8e1810c4a39b..a954cea8dc02 100644 --- a/atom/browser/web_view_guest_delegate.cc +++ b/atom/browser/web_view_guest_delegate.cc @@ -5,6 +5,7 @@ #include "atom/browser/web_view_guest_delegate.h" #include "atom/browser/api/atom_api_web_contents.h" +#include "atom/browser/web_view_constants.h" #include "atom/common/native_mate_converters/gurl_converter.h" #include "content/public/browser/guest_host.h" #include "content/public/browser/render_frame_host.h" @@ -13,13 +14,6 @@ namespace atom { -namespace { - -const int kDefaultWidth = 300; -const int kDefaultHeight = 300; - -} // namespace - WebViewGuestDelegate::WebViewGuestDelegate() : guest_opaque_(true), guest_host_(nullptr), @@ -178,7 +172,7 @@ gfx::Size WebViewGuestDelegate::GetDefaultSize() const { return embedder_web_contents_->GetRenderWidgetHostView() ->GetVisibleViewportSize(); } else { - return gfx::Size(kDefaultWidth, kDefaultHeight); + return gfx::Size(web_view::kDefaultWidth, web_view::kDefaultHeight); } } diff --git a/atom/browser/web_view_manager.cc b/atom/browser/web_view_manager.cc index 76915264c6fd..9d0b9337599f 100644 --- a/atom/browser/web_view_manager.cc +++ b/atom/browser/web_view_manager.cc @@ -11,22 +11,6 @@ namespace atom { -// static -bool WebViewManager::GetInfoForWebContents( - const content::WebContents* web_contents, WebViewInfo* info) { - // use embedders' browser context to retrieve WebViewManager. - auto manager = static_cast( - AtomBrowserMainParts::Get()->browser_context()->GetGuestManager()); - if (!manager) - return false; - base::AutoLock auto_lock(manager->lock_); - auto iter = manager->webview_info_map_.find(web_contents); - if (iter == manager->webview_info_map_.end()) - return false; - *info = iter->second; - return true; -} - WebViewManager::WebViewManager(content::BrowserContext* context) { } @@ -36,11 +20,9 @@ WebViewManager::~WebViewManager() { void WebViewManager::AddGuest(int guest_instance_id, int element_instance_id, content::WebContents* embedder, - content::WebContents* web_contents, - const WebViewInfo& info) { + content::WebContents* web_contents) { base::AutoLock auto_lock(lock_); web_contents_embedder_map_[guest_instance_id] = { web_contents, embedder }; - webview_info_map_[web_contents] = info; // Map the element in embedder to guest. int owner_process_id = embedder->GetRenderProcessHost()->GetID(); @@ -53,10 +35,7 @@ void WebViewManager::RemoveGuest(int guest_instance_id) { if (!ContainsKey(web_contents_embedder_map_, guest_instance_id)) return; - auto web_contents = - web_contents_embedder_map_[guest_instance_id].web_contents; web_contents_embedder_map_.erase(guest_instance_id); - webview_info_map_.erase(web_contents); // Remove the record of element in embedder too. for (const auto& element : element_instance_id_to_guest_map_) diff --git a/atom/browser/web_view_manager.h b/atom/browser/web_view_manager.h index d8ed857b444f..20c044849720 100644 --- a/atom/browser/web_view_manager.h +++ b/atom/browser/web_view_manager.h @@ -8,6 +8,7 @@ #include #include "base/files/file_path.h" +#include "base/supports_user_data.h" #include "base/synchronization/lock.h" #include "content/public/browser/browser_plugin_guest_manager.h" #include "content/public/browser/site_instance.h" @@ -31,10 +32,17 @@ class WebViewManager : public content::BrowserPluginGuestManager { GURL partition_id; }; - // Finds the WebViewManager attached with |web_contents| and returns the - // WebViewInfo of it. - static bool GetInfoForWebContents(const content::WebContents* web_contents, - WebViewInfo* info); + class WebViewInfoUserData : public base::SupportsUserData::Data { + public: + explicit WebViewInfoUserData(WebViewInfo info) + : web_view_info_(info) {} + ~WebViewInfoUserData() override {} + + WebViewInfo& web_view_info() { return web_view_info_; } + + private: + WebViewInfo web_view_info_; + }; explicit WebViewManager(content::BrowserContext* context); virtual ~WebViewManager(); @@ -42,8 +50,7 @@ class WebViewManager : public content::BrowserPluginGuestManager { void AddGuest(int guest_instance_id, int element_instance_id, content::WebContents* embedder, - content::WebContents* web_contents, - const WebViewInfo& info); + content::WebContents* web_contents); void RemoveGuest(int guest_instance_id); protected: @@ -83,10 +90,6 @@ class WebViewManager : public content::BrowserPluginGuestManager { // (embedder_process_id, element_instance_id) => guest_instance_id std::map element_instance_id_to_guest_map_; - typedef std::map WebViewInfoMap; - // web_contents => (guest_instance_id, embedder, ...) - WebViewInfoMap webview_info_map_; - base::Lock lock_; DISALLOW_COPY_AND_ASSIGN(WebViewManager); diff --git a/filenames.gypi b/filenames.gypi index 807ccd32bb66..2f97d01507e8 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -226,6 +226,8 @@ 'atom/browser/ui/x/window_state_watcher.h', 'atom/browser/ui/x/x_window_utils.cc', 'atom/browser/ui/x/x_window_utils.h', + 'atom/browser/web_view_constants.cc', + 'atom/browser/web_view_constants.h', 'atom/browser/web_view_guest_delegate.cc', 'atom/browser/web_view_guest_delegate.h', 'atom/browser/web_view_manager.cc', diff --git a/spec/webview-spec.coffee b/spec/webview-spec.coffee index 486efaa6ffb4..fe281510b40e 100644 --- a/spec/webview-spec.coffee +++ b/spec/webview-spec.coffee @@ -155,6 +155,23 @@ describe ' tag', -> document.body.appendChild webview describe 'partition attribute', -> + it 'inserts no node symbols when not set', (done) -> + webview.addEventListener 'console-message', (e) -> + assert.equal e.message, 'undefined undefined undefined undefined' + done() + webview.src = "file://#{fixtures}/pages/c.html" + webview.partition = "test" + document.body.appendChild webview + + it 'inserts node symbols when set', (done) -> + webview.addEventListener 'console-message', (e) -> + assert.equal e.message, 'function object object' + done() + webview.setAttribute 'nodeintegration', 'on' + webview.src = "file://#{fixtures}/pages/d.html" + webview.partition = "test" + document.body.appendChild webview + it 'isolates storage for different id', (done) -> listener = (e) -> assert.equal e.message, " 0"