| // Copyright 2017 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 "extensions/renderer/messaging_util.h" |
| |
| #include <memory> |
| |
| #include "base/strings/stringprintf.h" |
| #include "extensions/common/api/messaging/message.h" |
| #include "extensions/common/extension_builder.h" |
| #include "extensions/renderer/bindings/api_binding_test.h" |
| #include "extensions/renderer/bindings/api_binding_test_util.h" |
| #include "extensions/renderer/native_extension_bindings_system_test_base.h" |
| #include "extensions/renderer/script_context.h" |
| #include "gin/converter.h" |
| #include "v8/include/v8.h" |
| |
| namespace extensions { |
| |
| using MessagingUtilTest = APIBindingTest; |
| |
| TEST_F(MessagingUtilTest, TestMaximumMessageSize) { |
| v8::HandleScope handle_scope(isolate()); |
| v8::Local<v8::Context> context = MainContext(); |
| |
| constexpr char kMessageTooLongError[] = |
| "Message length exceeded maximum allowed length."; |
| |
| { |
| v8::Local<v8::Value> long_message = |
| V8ValueFromScriptSource(context, "'a'.repeat(1024 *1024 * 65)"); |
| std::string error; |
| std::unique_ptr<Message> message = |
| messaging_util::MessageFromV8(context, long_message, &error); |
| EXPECT_FALSE(message); |
| EXPECT_EQ(kMessageTooLongError, error); |
| } |
| |
| { |
| v8::Local<v8::Value> long_json_message = V8ValueFromScriptSource( |
| context, "(JSON.stringify('a'.repeat(1024 *1024 * 65)))"); |
| ASSERT_TRUE(long_json_message->IsString()); |
| std::string error; |
| std::unique_ptr<Message> message = messaging_util::MessageFromV8( |
| context, long_json_message.As<v8::String>(), &error); |
| EXPECT_FALSE(message); |
| EXPECT_EQ(kMessageTooLongError, error); |
| } |
| } |
| |
| TEST_F(MessagingUtilTest, TestParseMessageOptionsFrameId) { |
| v8::HandleScope handle_scope(isolate()); |
| v8::Local<v8::Context> context = MainContext(); |
| |
| struct { |
| int expected_frame_id; |
| const char* string_options; |
| } test_cases[] = { |
| {messaging_util::kNoFrameId, "({})"}, |
| {messaging_util::kNoFrameId, "({frameId: undefined})"}, |
| // Note: we don't test null here, because the argument parsing code |
| // ensures we would never pass undefined to ParseMessageOptions (and |
| // there's a DCHECK to validate it). The null case is tested in the tabs' |
| // API hooks delegate test. |
| {0, "({frameId: 0})"}, |
| {2, "({frameId: 2})"}, |
| }; |
| |
| for (const auto& test_case : test_cases) { |
| SCOPED_TRACE(test_case.string_options); |
| v8::Local<v8::Value> value = |
| V8ValueFromScriptSource(context, test_case.string_options); |
| ASSERT_FALSE(value.IsEmpty()); |
| ASSERT_TRUE(value->IsObject()); |
| messaging_util::MessageOptions options = |
| messaging_util::ParseMessageOptions(context, value.As<v8::Object>(), |
| messaging_util::PARSE_FRAME_ID); |
| EXPECT_EQ(test_case.expected_frame_id, options.frame_id); |
| } |
| } |
| |
| using MessagingUtilWithSystemTest = NativeExtensionBindingsSystemUnittest; |
| |
| TEST_F(MessagingUtilWithSystemTest, TestGetTargetIdFromExtensionContext) { |
| v8::HandleScope handle_scope(isolate()); |
| v8::Local<v8::Context> context = MainContext(); |
| |
| scoped_refptr<const Extension> extension = ExtensionBuilder("foo").Build(); |
| RegisterExtension(extension); |
| |
| ScriptContext* script_context = CreateScriptContext( |
| context, extension.get(), Feature::BLESSED_EXTENSION_CONTEXT); |
| script_context->set_url(extension->url()); |
| |
| std::string other_id(32, 'a'); |
| struct { |
| v8::Local<v8::Value> passed_id; |
| base::StringPiece expected_id; |
| bool should_pass; |
| } test_cases[] = { |
| // If the extension ID is not provided, the bindings use the calling |
| // extension's. |
| {v8::Null(isolate()), extension->id(), true}, |
| // We treat the empty string to be the same as null, even though it's |
| // somewhat unfortunate. |
| // See https://crbug.com/823577. |
| {gin::StringToV8(isolate(), ""), extension->id(), true}, |
| {gin::StringToV8(isolate(), extension->id()), extension->id(), true}, |
| {gin::StringToV8(isolate(), other_id), other_id, true}, |
| {gin::StringToV8(isolate(), "invalid id"), base::StringPiece(), false}, |
| }; |
| |
| for (size_t i = 0; i < arraysize(test_cases); ++i) { |
| SCOPED_TRACE(base::StringPrintf("Test Case: %d", static_cast<int>(i))); |
| const auto& test_case = test_cases[i]; |
| std::string target; |
| std::string error; |
| EXPECT_EQ(test_case.should_pass, |
| messaging_util::GetTargetExtensionId( |
| script_context, test_case.passed_id, "runtime.sendMessage", |
| &target, &error)); |
| EXPECT_EQ(test_case.expected_id, target); |
| EXPECT_EQ(test_case.should_pass, error.empty()) << error; |
| } |
| } |
| |
| TEST_F(MessagingUtilWithSystemTest, TestGetTargetIdFromWebContext) { |
| v8::HandleScope handle_scope(isolate()); |
| v8::Local<v8::Context> context = MainContext(); |
| |
| ScriptContext* script_context = |
| CreateScriptContext(context, nullptr, Feature::WEB_PAGE_CONTEXT); |
| script_context->set_url(GURL("https://example.com")); |
| |
| std::string other_id(32, 'a'); |
| struct { |
| v8::Local<v8::Value> passed_id; |
| base::StringPiece expected_id; |
| bool should_pass; |
| } test_cases[] = { |
| // A web page should always have to specify the extension id. |
| {gin::StringToV8(isolate(), other_id), other_id, true}, |
| {v8::Null(isolate()), base::StringPiece(), false}, |
| {gin::StringToV8(isolate(), ""), base::StringPiece(), false}, |
| {gin::StringToV8(isolate(), "invalid id"), base::StringPiece(), false}, |
| }; |
| |
| for (size_t i = 0; i < arraysize(test_cases); ++i) { |
| SCOPED_TRACE(base::StringPrintf("Test Case: %d", static_cast<int>(i))); |
| const auto& test_case = test_cases[i]; |
| std::string target; |
| std::string error; |
| EXPECT_EQ(test_case.should_pass, |
| messaging_util::GetTargetExtensionId( |
| script_context, test_case.passed_id, "runtime.sendMessage", |
| &target, &error)); |
| EXPECT_EQ(test_case.expected_id, target); |
| EXPECT_EQ(test_case.should_pass, error.empty()) << error; |
| } |
| } |
| |
| } // namespace extensions |