summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authornasko@chromium.org <nasko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-24 18:38:53 +0000
committernasko@chromium.org <nasko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-24 18:38:53 +0000
commit74f45dda73cf3707524942508474e7b37fe6e711 (patch)
tree5ec758157f146d27c7870d049b0201a01a47fc13 /content
parent5ba45b1430bdb0358c541426bda5cf83cf4c0806 (diff)
downloadchromium_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')
-rw-r--r--content/renderer/browser_plugin/browser_plugin.cc72
-rw-r--r--content/renderer/browser_plugin/browser_plugin.h16
-rw-r--r--content/renderer/browser_plugin/browser_plugin_bindings.cc49
-rw-r--r--content/renderer/browser_plugin/browser_plugin_browsertest.cc111
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