diff options
author | gbillock@chromium.org <gbillock@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-16 20:41:20 +0000 |
---|---|---|
committer | gbillock@chromium.org <gbillock@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-16 20:41:20 +0000 |
commit | 7a137c9deed67a943c21f82d0a9c71112da5d603 (patch) | |
tree | 776060f62eb90aebdbe304654d176772705f0922 /content | |
parent | 84a9361de5e11561f59becc0b38a707fff8da198 (diff) | |
download | chromium_src-7a137c9deed67a943c21f82d0a9c71112da5d603.zip chromium_src-7a137c9deed67a943c21f82d0a9c71112da5d603.tar.gz chromium_src-7a137c9deed67a943c21f82d0a9c71112da5d603.tar.bz2 |
Add API to construct new vector interchange MIME data type.
Add test for web intents host.
R=groby@chromium.org
BUG=153695
Review URL: https://chromiumcodereview.appspot.com/11026070
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@162239 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r-- | content/browser/intents/intent_injector.cc | 7 | ||||
-rw-r--r-- | content/content_tests.gypi | 1 | ||||
-rw-r--r-- | content/renderer/render_view_impl.cc | 3 | ||||
-rw-r--r-- | content/renderer/render_view_impl.h | 1 | ||||
-rw-r--r-- | content/renderer/web_intents_host.cc | 159 | ||||
-rw-r--r-- | content/renderer/web_intents_host.h | 34 | ||||
-rw-r--r-- | content/renderer/web_intents_host_browsertest.cc | 120 |
7 files changed, 248 insertions, 77 deletions
diff --git a/content/browser/intents/intent_injector.cc b/content/browser/intents/intent_injector.cc index 6645760..28cd1e2 100644 --- a/content/browser/intents/intent_injector.cc +++ b/content/browser/intents/intent_injector.cc @@ -82,8 +82,11 @@ void IntentInjector::RenderViewCreated(RenderViewHost* render_view_host) { return; } - if (source_intent_->data_type == webkit_glue::WebIntentData::BLOB) { - // Grant read permission on the blob file to the delivered context. + // If we're passing a browser-originated blob, either directly or as part of a + // payload, grant read permission on the blob file to the delivered context. + if (source_intent_->data_type == webkit_glue::WebIntentData::BLOB || + (source_intent_->data_type == webkit_glue::WebIntentData::MIME_TYPE && + !source_intent_->blob_file.empty())) { const int child_id = render_view_host->GetProcess()->GetID(); ChildProcessSecurityPolicy* policy = ChildProcessSecurityPolicy::GetInstance(); diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 19fd56c..5473342 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -699,6 +699,7 @@ 'renderer/render_view_browsertest_mac.mm', 'renderer/render_widget_browsertest.cc', 'renderer/renderer_accessibility_browsertest.cc', + 'renderer/web_intents_host_browsertest.cc', 'test/content_browser_test.h', 'test/content_browser_test.cc', 'test/content_browser_test_utils.cc', diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index b2eb191..e9dd481 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc @@ -3794,6 +3794,9 @@ void RenderViewImpl::didCreateScriptContext(WebFrame* frame, int world_id) { content::GetContentClient()->renderer()->DidCreateScriptContext( frame, context, extension_group, world_id); + + intents_host_->DidCreateScriptContext( + frame, context, extension_group, world_id); } void RenderViewImpl::willReleaseScriptContext(WebFrame* frame, diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h index 2219c97..b3a4f2b 100644 --- a/content/renderer/render_view_impl.h +++ b/content/renderer/render_view_impl.h @@ -802,6 +802,7 @@ class RenderViewImpl : public RenderWidget, friend class ExternalPopupMenuTest; friend class PepperDeviceTest; friend class RendererAccessibilityTest; + friend class WebIntentsHostTest; friend class content::RenderViewTest; FRIEND_TEST_ALL_PREFIXES(ExternalPopupMenuRemoveTest, RemoveOnChange); diff --git a/content/renderer/web_intents_host.cc b/content/renderer/web_intents_host.cc index 9c60da3..933f41a 100644 --- a/content/renderer/web_intents_host.cc +++ b/content/renderer/web_intents_host.cc @@ -8,6 +8,7 @@ #include "base/bind_helpers.h" #include "base/utf_string_conversions.h" #include "content/common/intents_messages.h" +#include "content/public/renderer/v8_value_converter.h" #include "content/renderer/render_view_impl.h" #include "ipc/ipc_message.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h" @@ -23,7 +24,6 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSerializedScriptValue.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h" -#include "v8/include/v8.h" #include "webkit/fileapi/file_system_util.h" #include "webkit/glue/cpp_bound_class.h" @@ -120,81 +120,110 @@ void WebIntentsHost::OnFailure(const WebKit::WebString& data) { // We set the intent payload into all top-level frame window objects. This // should persist the data through redirects, and not deliver it to any // sub-frames. -// TODO(gbillock): match to spec to double-check registration match before -// delivery. -void WebIntentsHost::DidClearWindowObject(WebFrame* frame) { +void WebIntentsHost::DidCreateScriptContext(WebKit::WebFrame* frame, + v8::Handle<v8::Context> ctx, + int extension_group, + int world_id) { if (intent_.get() == NULL || frame->top() != frame) return; + if (ctx != frame->mainWorldScriptContext()) + return; + if (!delivered_intent_client_.get()) { delivered_intent_client_.reset(new DeliveredIntentClientImpl(this)); } - WebVector<WebString> extras_keys(intent_->extra_data.size()); - WebVector<WebString> extras_values(intent_->extra_data.size()); - std::map<string16, string16>::iterator iter; - int i; - for (i = 0, iter = intent_->extra_data.begin(); - iter != intent_->extra_data.end(); - ++i, ++iter) { + WebIntent web_intent = CreateWebIntent(frame, *intent_); + + if (!web_intent.action().isEmpty()) + frame->deliverIntent(web_intent, NULL, delivered_intent_client_.get()); +} + +WebIntent WebIntentsHost::CreateWebIntent( + WebFrame* frame, const webkit_glue::WebIntentData& intent_data) { + // Must be called with v8 scope held. + DCHECK(v8::Context::InContext()); + + // TODO(gbillock): Remove this block when we get rid of |extras|. + WebVector<WebString> extras_keys(intent_data.extra_data.size()); + WebVector<WebString> extras_values(intent_data.extra_data.size()); + std::map<string16, string16>::const_iterator iter = + intent_data.extra_data.begin(); + for (size_t i = 0; iter != intent_data.extra_data.end(); ++i, ++iter) { extras_keys[i] = iter->first; extras_values[i] = iter->second; } - v8::HandleScope scope; - v8::Local<v8::Context> ctx = frame->mainWorldScriptContext(); - v8::Context::Scope cscope(ctx); - WebIntent web_intent; - - if (intent_->data_type == webkit_glue::WebIntentData::SERIALIZED) { - web_intent = WebIntent::create(intent_->action, intent_->type, - intent_->data, - extras_keys, extras_values); - } else if (intent_->data_type == webkit_glue::WebIntentData::UNSERIALIZED) { - v8::Local<v8::String> dataV8 = v8::String::New( - reinterpret_cast<const uint16_t*>(intent_->unserialized_data.data()), - static_cast<int>(intent_->unserialized_data.length())); - WebSerializedScriptValue serialized_data = - WebSerializedScriptValue::serialize(dataV8); - - web_intent = WebIntent::create(intent_->action, intent_->type, - serialized_data.toString(), - extras_keys, extras_values); - } else if (intent_->data_type == webkit_glue::WebIntentData::BLOB) { - DCHECK(intent_->data_type == webkit_glue::WebIntentData::BLOB); - web_blob_ = WebBlob::createFromFile( - WebString::fromUTF8(intent_->blob_file.AsUTF8Unsafe()), - intent_->blob_length); - WebSerializedScriptValue serialized_data = - WebSerializedScriptValue::serialize(web_blob_.toV8Value()); - web_intent = WebIntent::create(intent_->action, intent_->type, - serialized_data.toString(), - extras_keys, extras_values); - } else if (intent_->data_type == webkit_glue::WebIntentData::FILESYSTEM) { - const GURL origin = GURL(frame->document().securityOrigin().toString()); - const GURL root_url = - fileapi::GetFileSystemRootURI(origin, fileapi::kFileSystemTypeIsolated); - const std::string url = base::StringPrintf( - "%s%s/%s/", - root_url.spec().c_str(), - intent_->filesystem_id.c_str(), - intent_->root_name.c_str()); - // TODO(kmadhusu): This is a temporary hack to create a serializable file - // system. Once we have a better way to create a serializable file system, - // remove this hack. - v8::Handle<v8::Value> filesystem_V8 = frame->createSerializableFileSystem( - WebKit::WebFileSystem::TypeIsolated, - WebKit::WebString::fromUTF8(intent_->root_name), - WebKit::WebString::fromUTF8(url)); - WebSerializedScriptValue serialized_data = - WebSerializedScriptValue::serialize(filesystem_V8); - web_intent = WebIntent::create(intent_->action, intent_->type, - serialized_data.toString(), - extras_keys, extras_values); - } else { - NOTREACHED(); + switch (intent_data.data_type) { + case webkit_glue::WebIntentData::SERIALIZED: { + return WebIntent::create(intent_data.action, intent_data.type, + intent_data.data, + extras_keys, extras_values); + } + + case webkit_glue::WebIntentData::UNSERIALIZED: { + v8::Local<v8::String> dataV8 = v8::String::New( + reinterpret_cast<const uint16_t*>( + intent_data.unserialized_data.data()), + static_cast<int>(intent_data.unserialized_data.length())); + WebSerializedScriptValue serialized_data = + WebSerializedScriptValue::serialize(dataV8); + + return WebIntent::create(intent_data.action, intent_data.type, + serialized_data.toString(), + extras_keys, extras_values); + } + + case webkit_glue::WebIntentData::BLOB: { + web_blob_ = WebBlob::createFromFile( + WebString::fromUTF8(intent_data.blob_file.AsUTF8Unsafe()), + intent_data.blob_length); + WebSerializedScriptValue serialized_data = + WebSerializedScriptValue::serialize(web_blob_.toV8Value()); + return WebIntent::create(intent_data.action, intent_data.type, + serialized_data.toString(), + extras_keys, extras_values); + } + + case webkit_glue::WebIntentData::FILESYSTEM: { + const GURL origin = GURL(frame->document().securityOrigin().toString()); + const GURL root_url = + fileapi::GetFileSystemRootURI(origin, + fileapi::kFileSystemTypeIsolated); + const std::string url = base::StringPrintf( + "%s%s/%s/", + root_url.spec().c_str(), + intent_data.filesystem_id.c_str(), + intent_data.root_name.c_str()); + // TODO(kmadhusu): This is a temporary hack to create a serializable file + // system. Once we have a better way to create a serializable file system, + // remove this hack. + v8::Handle<v8::Value> filesystem_V8 = frame->createSerializableFileSystem( + WebKit::WebFileSystem::TypeIsolated, + WebKit::WebString::fromUTF8(intent_data.root_name), + WebKit::WebString::fromUTF8(url)); + WebSerializedScriptValue serialized_data = + WebSerializedScriptValue::serialize(filesystem_V8); + return WebIntent::create(intent_data.action, intent_data.type, + serialized_data.toString(), + extras_keys, extras_values); + } + + case webkit_glue::WebIntentData::MIME_TYPE: { + scoped_ptr<content::V8ValueConverter> converter( + content::V8ValueConverter::create()); + v8::Handle<v8::Value> valV8 = converter->ToV8Value( + &intent_data.mime_data, v8::Context::GetCurrent()); + + WebSerializedScriptValue serialized_data = + WebSerializedScriptValue::serialize(valV8); + return WebIntent::create(intent_data.action, intent_data.type, + serialized_data.toString(), + WebVector<WebString>(), WebVector<WebString>()); + } } - if (!web_intent.action().isEmpty()) - frame->deliverIntent(web_intent, NULL, delivered_intent_client_.get()); + NOTREACHED(); + return WebIntent(); } diff --git a/content/renderer/web_intents_host.h b/content/renderer/web_intents_host.h index 0116492..3556d76 100644 --- a/content/renderer/web_intents_host.h +++ b/content/renderer/web_intents_host.h @@ -10,7 +10,9 @@ #include "base/memory/scoped_ptr.h" #include "content/public/renderer/render_view_observer.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebBlob.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebIntent.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" +#include "v8/include/v8.h" #include "webkit/glue/web_intent_data.h" #include "webkit/glue/web_intent_reply_data.h" @@ -43,25 +45,27 @@ class WebIntentsHost : public content::RenderViewObserver { // Called into when the delivered intent object gets a postFailure call. void OnFailure(const WebKit::WebString& data); - private: - // A counter used to assign unique IDs to web intents invocations in this - // renderer. - int id_counter_; - - // Map tracking registered Web Intent requests by assigned ID numbers to - // correctly route any return data. - std::map<int, WebKit::WebIntentRequest> intent_requests_; + // Forwarded from RenderViewImpl. Notification that a new script context was + // created within webkit. + virtual void DidCreateScriptContext(WebKit::WebFrame* frame, + v8::Handle<v8::Context> ctx, + int extension_group, + int world_id); + private: // RenderView::Observer implementation. virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - virtual void DidClearWindowObject(WebKit::WebFrame* frame) OVERRIDE; + + // Converts incoming intent data to a WebIntent object. + WebKit::WebIntent CreateWebIntent( + WebKit::WebFrame* frame, const webkit_glue::WebIntentData& intent_data); // TODO(gbillock): Do we need various ***ClientRedirect methods to implement // intent cancelling policy? Figure this out. // On the service page, handler method for the IntentsMsg_SetWebIntent // message. - void OnSetIntent(const webkit_glue::WebIntentData& intent); + CONTENT_EXPORT void OnSetIntent(const webkit_glue::WebIntentData& intent); // On the client page, handler method for the IntentsMsg_WebIntentReply // message. Forwards the reply |data| to the registered WebIntentRequest @@ -70,6 +74,16 @@ class WebIntentsHost : public content::RenderViewObserver { const WebKit::WebString& data, int intent_id); + friend class WebIntentsHostTest; + + // A counter used to assign unique IDs to web intents invocations in this + // renderer. + int id_counter_; + + // Map tracking registered Web Intent requests by assigned ID numbers to + // correctly route any return data. + std::map<int, WebKit::WebIntentRequest> intent_requests_; + // Delivered intent data from the caller. scoped_ptr<webkit_glue::WebIntentData> intent_; diff --git a/content/renderer/web_intents_host_browsertest.cc b/content/renderer/web_intents_host_browsertest.cc new file mode 100644 index 0000000..9f2abc7 --- /dev/null +++ b/content/renderer/web_intents_host_browsertest.cc @@ -0,0 +1,120 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/gtest_prod_util.h" +#include "base/values.h" +#include "base/utf_string_conversions.h" +#include "content/common/intents_messages.h" +#include "content/public/renderer/v8_value_converter.h" +#include "content/public/test/render_view_test.h" +#include "content/renderer/render_view_impl.h" +#include "content/renderer/web_intents_host.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebDeliveredIntentClient.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSerializedScriptValue.h" +#include "webkit/glue/web_intent_data.h" + +class WebIntentsHostTest : public content::RenderViewTest { + protected: + RenderViewImpl* view() { return static_cast<RenderViewImpl*>(view_); } + WebIntentsHost* web_intents_host() { return view()->intents_host_; } + + void SetIntentData(const webkit_glue::WebIntentData& data) { + web_intents_host()->OnSetIntent(data); + } + + base::DictionaryValue* ParseValueFromReply(const IPC::Message* reply_msg) { + IntentsHostMsg_WebIntentReply::Param reply_params; + IntentsHostMsg_WebIntentReply::Read(reply_msg, &reply_params); + WebKit::WebSerializedScriptValue serialized_data = + WebKit::WebSerializedScriptValue::fromString(reply_params.b); + + v8::HandleScope scope; + v8::Local<v8::Context> ctx = GetMainFrame()->mainWorldScriptContext(); + v8::Context::Scope cscope(ctx); + v8::Handle<v8::Value> v8_val = serialized_data.deserialize(); + scoped_ptr<content::V8ValueConverter> converter( + content::V8ValueConverter::create()); + base::Value* reply = converter->FromV8Value(v8_val, ctx); + EXPECT_TRUE(reply->IsType(base::Value::TYPE_DICTIONARY)); + base::DictionaryValue* dict = NULL; + reply->GetAsDictionary(&dict); + return dict; + } +}; + +TEST_F(WebIntentsHostTest, TestUnserialized) { + webkit_glue::WebIntentData data(ASCIIToUTF16("action"), ASCIIToUTF16("type"), + ASCIIToUTF16("unserialized data")); + SetIntentData(data); + + LoadHTML("<html>" + "<head><script>\n" + "var d = {};\n" + "d.action = window.webkitIntent.action;\n" + "d.type = window.webkitIntent.type;\n" + "d.data = window.webkitIntent.data;\n" + "window.webkitIntent.postResult(d);\n" + "</script></head>" + "<body>body</body></html>"); + + const IPC::Message* reply_msg = + render_thread_->sink().GetUniqueMessageMatching( + IntentsHostMsg_WebIntentReply::ID); + ASSERT_TRUE(reply_msg); + scoped_ptr<base::DictionaryValue> dict(ParseValueFromReply(reply_msg)); + + std::string reply_action; + dict->GetStringASCII(std::string("action"), &reply_action); + EXPECT_EQ("action", reply_action); + std::string reply_type; + dict->GetStringASCII(std::string("type"), &reply_type); + EXPECT_EQ("type", reply_type); + std::string reply_data; + dict->GetStringASCII(std::string("data"), &reply_data); + EXPECT_EQ("unserialized data", reply_data); +} + +TEST_F(WebIntentsHostTest, TestVector) { + webkit_glue::WebIntentData data(ASCIIToUTF16("action"), ASCIIToUTF16("type")); + DictionaryValue* d1 = new DictionaryValue; + d1->SetString(std::string("key1"), std::string("val1")); + data.mime_data.Append(d1); + DictionaryValue* d2 = new DictionaryValue; + d2->SetString(std::string("key2"), std::string("val2")); + data.mime_data.Append(d2); + SetIntentData(data); + + LoadHTML("<html>" + "<head><script>\n" + "var d = {};\n" + "d.action = window.webkitIntent.action;\n" + "d.type = window.webkitIntent.type;\n" + "d.data = window.webkitIntent.data;\n" + "window.webkitIntent.postResult(d);\n" + "</script></head>" + "<body>body</body></html>"); + + const IPC::Message* reply_msg = + render_thread_->sink().GetUniqueMessageMatching( + IntentsHostMsg_WebIntentReply::ID); + ASSERT_TRUE(reply_msg); + scoped_ptr<base::DictionaryValue> dict(ParseValueFromReply(reply_msg)); + + base::ListValue* payload; + ASSERT_TRUE(dict->GetList("data", &payload)); + EXPECT_EQ(2U, payload->GetSize()); + + base::DictionaryValue* v1 = NULL; + ASSERT_TRUE(payload->GetDictionary(0, &v1)); + DCHECK(v1); + std::string val1; + ASSERT_TRUE(v1->GetStringASCII(std::string("key1"), &val1)); + EXPECT_EQ("val1", val1); + + base::DictionaryValue* v2 = NULL; + ASSERT_TRUE(payload->GetDictionary(1, &v2)); + std::string val2; + v2->GetStringASCII(std::string("key2"), &val2); + EXPECT_EQ("val2", val2); +} |