diff options
author | nasko@chromium.org <nasko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-24 18:38:53 +0000 |
---|---|---|
committer | nasko@chromium.org <nasko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-24 18:38:53 +0000 |
commit | 74f45dda73cf3707524942508474e7b37fe6e711 (patch) | |
tree | 5ec758157f146d27c7870d049b0201a01a47fc13 /content | |
parent | 5ba45b1430bdb0358c541426bda5cf83cf4c0806 (diff) | |
download | chromium_src-74f45dda73cf3707524942508474e7b37fe6e711.zip chromium_src-74f45dda73cf3707524942508474e7b37fe6e711.tar.gz chromium_src-74f45dda73cf3707524942508474e7b37fe6e711.tar.bz2 |
Add support for parsing a 'partition' attribute on the <browser> tag.
BUG=145500
Review URL: https://chromiumcodereview.appspot.com/10928237
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@158329 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
4 files changed, 227 insertions, 21 deletions
diff --git a/content/renderer/browser_plugin/browser_plugin.cc b/content/renderer/browser_plugin/browser_plugin.cc index ebcbd3a..1a81d23 100644 --- a/content/renderer/browser_plugin/browser_plugin.cc +++ b/content/renderer/browser_plugin/browser_plugin.cc @@ -9,6 +9,7 @@ #if defined (OS_WIN) #include "base/sys_info.h" #endif +#include "base/utf_string_conversions.h" #include "content/common/browser_plugin_messages.h" #include "content/public/common/content_client.h" #include "content/public/renderer/content_renderer_client.h" @@ -42,7 +43,10 @@ namespace content { namespace { const char kCrashEventName[] = "crash"; const char kNavigationEventName[] = "navigation"; +const char* kPartitionAttribute = "partition"; +const char* kPersistPrefix = "persist:"; const char* kSrcAttribute = "src"; + } BrowserPlugin::BrowserPlugin( @@ -59,13 +63,12 @@ BrowserPlugin::BrowserPlugin( resize_pending_(false), navigate_src_sent_(false), parent_frame_(frame->identifier()), - process_id_(-1) { + process_id_(-1), + persist_storage_(false) { BrowserPluginManager::Get()->AddBrowserPlugin(instance_id, this); bindings_.reset(new BrowserPluginBindings(this)); - std::string src; - if (ParseSrcAttribute(params, &src)) - SetSrcAttribute(src); + ParseAttributes(params); } BrowserPlugin::~BrowserPlugin() { @@ -109,24 +112,73 @@ void BrowserPlugin::SetSrcAttribute(const std::string& src) { // resize works correctly for all cases (e.g. The embedder can reset the // guest's |src| to empty value, resize and then set the |src| to a // non-empty value). + // Additionally, once this instance has navigated, the storage partition + // cannot be changed, so this value is used for enforcing this. navigate_src_sent_ = true; } src_ = src; guest_crashed_ = false; } -bool BrowserPlugin::ParseSrcAttribute( - const WebKit::WebPluginParams& params, - std::string* src) { +std::string BrowserPlugin::GetPartitionAttribute() const { + std::string value; + if (persist_storage_) + value.append(kPersistPrefix); + + value.append(storage_partition_id_); + return value; +} + +bool BrowserPlugin::SetPartitionAttribute(const std::string& partition_id, + std::string& error_message) { + if (navigate_src_sent_) { + error_message = + "The object has already navigated, so its partition cannot be changed."; + return false; + } + + std::string input = partition_id; + + // Since the "persist:" prefix is in ASCII, StartsWith will work fine on + // UTF-8 encoded |partition_id|. If the prefix is a match, we can safely + // remove the prefix without splicing in the middle of a multi-byte codepoint. + // We can use the rest of the string as UTF-8 encoded one. + if (StartsWithASCII(input, kPersistPrefix, true)) { + size_t index = input.find(":"); + CHECK(index != std::string::npos); + // It is safe to do index + 1, since we tested for the full prefix above. + input = input.substr(index + 1); + if (input.empty()) { + error_message = "Invalid empty partition attribute."; + return false; + } + persist_storage_ = true; + } else { + persist_storage_ = false; + } + + storage_partition_id_ = input; + return true; +} + +void BrowserPlugin::ParseAttributes(const WebKit::WebPluginParams& params) { + std::string src; + // Get the src attribute from the attributes vector for (unsigned i = 0; i < params.attributeNames.size(); ++i) { std::string attributeName = params.attributeNames[i].utf8(); if (LowerCaseEqualsASCII(attributeName, kSrcAttribute)) { - *src = params.attributeValues[i].utf8(); - return true; + src = params.attributeValues[i].utf8(); + } else if (LowerCaseEqualsASCII(attributeName, kPartitionAttribute)) { + std::string error; + SetPartitionAttribute(params.attributeValues[i].utf8(), error); } } - return false; + + // Set the 'src' attribute last, as it will set the has_navigated_ flag to + // true, which prevents changing the 'partition' attribute. + if (!src.empty()) + SetSrcAttribute(src); } float BrowserPlugin::GetDeviceScaleFactor() const { diff --git a/content/renderer/browser_plugin/browser_plugin.h b/content/renderer/browser_plugin/browser_plugin.h index 54a03eb..d48b39f 100644 --- a/content/renderer/browser_plugin/browser_plugin.h +++ b/content/renderer/browser_plugin/browser_plugin.h @@ -37,6 +37,13 @@ class CONTENT_EXPORT BrowserPlugin : void SetSrcAttribute(const std::string& src); // Returns Chrome's process ID for the current guest. int process_id() const { return process_id_; } + // The partition identifier string is stored as UTF-8. + std::string GetPartitionAttribute() const; + // This method can be successfully called only before the first navigation for + // this instance of BrowserPlugin. If an error occurs, the |error_message| is + // set appropriately to indicate the failure reason. + bool SetPartitionAttribute(const std::string& partition_id, + std::string& error_message); // Inform the BrowserPlugin to update its backing store with the pixels in // its damage buffer. @@ -126,10 +133,9 @@ class CONTENT_EXPORT BrowserPlugin : // Virtual to allow for mocking in tests. virtual float GetDeviceScaleFactor() const; - // Parses the source URL of the browser plugin from the element's attributes - // and outputs them. - bool ParseSrcAttribute(const WebKit::WebPluginParams& params, - std::string* src); + // Parses the attributes of the browser plugin from the element's attributes + // and sets them appropriately. + void ParseAttributes(const WebKit::WebPluginParams& params); // Cleanup event listener state to free v8 resources when a BrowserPlugin // is destroyed. @@ -151,6 +157,8 @@ class CONTENT_EXPORT BrowserPlugin : int64 parent_frame_; std::string src_; int process_id_; + std::string storage_partition_id_; + bool persist_storage_; typedef std::vector<v8::Persistent<v8::Function> > EventListeners; typedef std::map<std::string, EventListeners> EventListenerMap; EventListenerMap event_listener_map_; diff --git a/content/renderer/browser_plugin/browser_plugin_bindings.cc b/content/renderer/browser_plugin/browser_plugin_bindings.cc index aaa7ba9..67a0552 100644 --- a/content/renderer/browser_plugin/browser_plugin_bindings.cc +++ b/content/renderer/browser_plugin/browser_plugin_bindings.cc @@ -40,6 +40,7 @@ namespace { const char kAddEventListener[] = "addEventListener"; const char kGetProcessId[] = "getProcessId"; +const char kPartitionAttribute[] = "partition"; const char kReloadMethod[] = "reload"; const char kRemoveEventListener[] = "removeEventListener"; const char kSrcAttribute[] = "src"; @@ -74,6 +75,10 @@ bool IdentifierIsSrcAttribute(NPIdentifier identifier) { return WebBindings::getStringIdentifier(kSrcAttribute) == identifier; } +bool IdentifierIsPartitionAttribute(NPIdentifier identifier) { + return WebBindings::getStringIdentifier(kPartitionAttribute) == identifier; +} + std::string StringFromNPVariant(const NPVariant& variant) { if (!NPVARIANT_IS_STRING(variant)) return std::string(); @@ -207,7 +212,8 @@ bool BrowserPluginBindingsInvokeDefault(NPObject* np_obj, } bool BrowserPluginBindingsHasProperty(NPObject* np_obj, NPIdentifier name) { - return IdentifierIsSrcAttribute(name); + return IdentifierIsSrcAttribute(name) || + IdentifierIsPartitionAttribute(name); } bool BrowserPluginBindingsGetProperty(NPObject* np_obj, NPIdentifier name, @@ -215,18 +221,29 @@ bool BrowserPluginBindingsGetProperty(NPObject* np_obj, NPIdentifier name, if (!np_obj) return false; + if (!result) + return false; + if (IdentifierIsAddEventListener(name) || IdentifierIsRemoveEventListener(name)) return false; + // All attributes from here on rely on the bindings, so retrieve it once and + // return on failure. + BrowserPluginBindings* bindings = GetBindings(np_obj); + if (!bindings) + return false; + if (IdentifierIsSrcAttribute(name)) { - BrowserPluginBindings* bindings = GetBindings(np_obj); - if (!bindings) - return false; std::string src = bindings->instance()->GetSrcAttribute(); return StringToNPVariant(src, result); } + if (IdentifierIsPartitionAttribute(name)) { + std::string partition_id = bindings->instance()->GetPartitionAttribute(); + return StringToNPVariant(partition_id, result); + } + return false; } @@ -234,15 +251,33 @@ bool BrowserPluginBindingsSetProperty(NPObject* np_obj, NPIdentifier name, const NPVariant* variant) { if (!np_obj) return false; + if (!variant) + return false; + + // All attributes from here on rely on the bindings, so retrieve it once and + // return on failure. + BrowserPluginBindings* bindings = GetBindings(np_obj); + if (!bindings) + return false; if (IdentifierIsSrcAttribute(name)) { std::string src = StringFromNPVariant(*variant); - BrowserPluginBindings* bindings = GetBindings(np_obj); - if (!bindings) - return false; bindings->instance()->SetSrcAttribute(src); return true; } + + if (IdentifierIsPartitionAttribute(name)) { + std::string partition_id = StringFromNPVariant(*variant); + std::string error_message; + if (!bindings->instance()->SetPartitionAttribute(partition_id, + error_message)) { + WebBindings::setException( + np_obj, static_cast<const NPUTF8 *>(error_message.c_str())); + return false; + } + return true; + } + return false; } diff --git a/content/renderer/browser_plugin/browser_plugin_browsertest.cc b/content/renderer/browser_plugin/browser_plugin_browsertest.cc index 6cfcd3e..66a24c96 100644 --- a/content/renderer/browser_plugin/browser_plugin_browsertest.cc +++ b/content/renderer/browser_plugin/browser_plugin_browsertest.cc @@ -25,6 +25,17 @@ const char kHTMLForBrowserPluginObject[] = "<object id='browserplugin' width='640px' height='480px'" " src='foo' type='%s'>"; +const char kHTMLForSourcelessPluginObject[] = + "<object id='browserplugin' width='640px' height='480px' type='%s'>"; + +const char kHTMLForPartitionedPluginObject[] = + "<object id='browserplugin' width='640px' height='480px'" + " src='foo' type='%s' partition='someid'>"; + +const char kHTMLForPartitionedPersistedPluginObject[] = + "<object id='browserplugin' width='640px' height='480px'" + " src='foo' type='%s' partition='persist:someid'>"; + std::string GetHTMLForBrowserPluginObject() { return StringPrintf(kHTMLForBrowserPluginObject, content::kBrowserPluginNewMimeType); @@ -355,4 +366,104 @@ TEST_F(BrowserPluginTest, ReloadMethod) { BrowserPluginHostMsg_Reload::ID)); } + +// Verify that the 'partition' attribute on the browser plugin is parsed +// correctly. +TEST_F(BrowserPluginTest, PartitionAttribute) { + std::string html = StringPrintf(kHTMLForPartitionedPluginObject, + content::kBrowserPluginNewMimeType); + LoadHTML(html.c_str()); + std::string partition_value = ExecuteScriptAndReturnString( + "document.getElementById('browserplugin').partition"); + EXPECT_STREQ("someid", partition_value.c_str()); + + html = StringPrintf(kHTMLForPartitionedPersistedPluginObject, + content::kBrowserPluginNewMimeType); + LoadHTML(html.c_str()); + partition_value = ExecuteScriptAndReturnString( + "document.getElementById('browserplugin').partition"); + EXPECT_STREQ("persist:someid", partition_value.c_str()); + + // Verify that once HTML has defined a source and partition, we cannot change + // the partition anymore. + ExecuteJavaScript( + "try {" + " document.getElementById('browserplugin').partition = 'foo';" + " document.title = 'success';" + "} catch (e) { document.title = e.message; }"); + std::string title = ExecuteScriptAndReturnString("document.title"); + EXPECT_STREQ( + "The object has already navigated, so its partition cannot be changed.", + title.c_str()); + + // Load a browser tag without 'src' defined. + html = StringPrintf(kHTMLForSourcelessPluginObject, + content::kBrowserPluginNewMimeType); + LoadHTML(html.c_str()); + + // Ensure we don't parse just "persist:" string and return exception. + ExecuteJavaScript( + "try {" + " document.getElementById('browserplugin').partition = 'persist:';" + " document.title = 'success';" + "} catch (e) { document.title = e.message; }"); + title = ExecuteScriptAndReturnString("document.title"); + EXPECT_STREQ("Invalid empty partition attribute.", title.c_str()); +} + +// Test to verify that after the first navigation, the partition attribute +// cannot be modified. +TEST_F(BrowserPluginTest, ImmutableAttributesAfterNavigation) { + std::string html = StringPrintf(kHTMLForSourcelessPluginObject, + content::kBrowserPluginNewMimeType); + LoadHTML(html.c_str()); + + ExecuteJavaScript( + "document.getElementById('browserplugin').partition = 'storage'"); + std::string partition_value = ExecuteScriptAndReturnString( + "document.getElementById('browserplugin').partition"); + EXPECT_STREQ("storage", partition_value.c_str()); + + std::string src_value = ExecuteScriptAndReturnString( + "document.getElementById('browserplugin').src"); + EXPECT_STREQ("", src_value.c_str()); + + ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'"); + { + const IPC::Message* msg = + browser_plugin_manager()->sink().GetUniqueMessageMatching( + BrowserPluginHostMsg_NavigateGuest::ID); + ASSERT_TRUE(msg); + + int instance_id; + long long frame_id; + std::string src; + gfx::Size size; + BrowserPluginHostMsg_NavigateGuest::Read( + msg, + &instance_id, + &frame_id, + &src, + &size); + EXPECT_STREQ("bar", src.c_str()); + } + + // Setting the partition should throw an exception and the value should not + // change. + ExecuteJavaScript( + "try {" + " document.getElementById('browserplugin').partition = 'someid';" + " document.title = 'success';" + "} catch (e) { document.title = e.message; }"); + + std::string title = ExecuteScriptAndReturnString("document.title"); + EXPECT_STREQ( + "The object has already navigated, so its partition cannot be changed.", + title.c_str()); + + partition_value = ExecuteScriptAndReturnString( + "document.getElementById('browserplugin').partition"); + EXPECT_STREQ("storage", partition_value.c_str()); +} + } // namespace content |