summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-21 02:56:02 +0000
committerkalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-21 02:56:02 +0000
commit5322973d577a1064bb32eb19bd01c6aa5e7c51a5 (patch)
tree43f6b82ae3b489cbf90473b180200e0120791b8c
parent768c0ff262cb7af622df394e9f2c1dbfe53e0162 (diff)
downloadchromium_src-5322973d577a1064bb32eb19bd01c6aa5e7c51a5.zip
chromium_src-5322973d577a1064bb32eb19bd01c6aa5e7c51a5.tar.gz
chromium_src-5322973d577a1064bb32eb19bd01c6aa5e7c51a5.tar.bz2
Go back to JSON serialization of extension messages. base::Value pickling was
causing OOMs on the browser, and V8ValueConverter has bugs. This is effectively a revert of both r204067 and r204496, except the json library replaced by the new safe $JSON, and it's eagerly included via our small-footprint v8::Extension. BUG=247530,248019,249419 R=mpcomplete@chromium.org TBR=cdn@chromium.org Review URL: https://chromiumcodereview.appspot.com/17144003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@207675 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/extensions/api/messaging/extension_message_port.cc10
-rw-r--r--chrome/browser/extensions/api/messaging/extension_message_port.h6
-rw-r--r--chrome/browser/extensions/api/messaging/message_service.cc16
-rw-r--r--chrome/browser/extensions/api/messaging/message_service.h11
-rw-r--r--chrome/browser/extensions/api/messaging/native_message_port.cc14
-rw-r--r--chrome/browser/extensions/api/messaging/native_message_port.h2
-rw-r--r--chrome/browser/extensions/api/messaging/native_message_process_host.cc31
-rw-r--r--chrome/browser/extensions/api/messaging/native_message_process_host.h11
-rw-r--r--chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc53
-rw-r--r--chrome/browser/extensions/message_handler.cc5
-rw-r--r--chrome/browser/extensions/message_handler.h6
-rw-r--r--chrome/chrome_tests_unit.gypi1
-rw-r--r--chrome/common/extensions/extension_messages.h4
-rw-r--r--chrome/renderer/extensions/dispatcher.cc2
-rw-r--r--chrome/renderer/extensions/dispatcher.h2
-rw-r--r--chrome/renderer/extensions/extension_helper.cc5
-rw-r--r--chrome/renderer/extensions/extension_helper.h2
-rw-r--r--chrome/renderer/extensions/miscellaneous_bindings.cc38
-rw-r--r--chrome/renderer/extensions/miscellaneous_bindings.h5
-rw-r--r--chrome/renderer/extensions/module_system.cc3
-rw-r--r--chrome/renderer/extensions/safe_builtins.cc63
-rw-r--r--chrome/renderer/extensions/safe_builtins.h1
-rw-r--r--chrome/renderer/extensions/safe_builtins_unittest.cc68
-rw-r--r--chrome/renderer/resources/extensions/miscellaneous_bindings.js10
-rw-r--r--chrome/test/data/devtools/extensions/devtools_messaging/devtools.js2
25 files changed, 208 insertions, 163 deletions
diff --git a/chrome/browser/extensions/api/messaging/extension_message_port.cc b/chrome/browser/extensions/api/messaging/extension_message_port.cc
index a3bba97..e4782c7 100644
--- a/chrome/browser/extensions/api/messaging/extension_message_port.cc
+++ b/chrome/browser/extensions/api/messaging/extension_message_port.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/extensions/api/messaging/extension_message_port.h"
-#include "base/values.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_system.h"
@@ -46,11 +45,10 @@ void ExtensionMessagePort::DispatchOnDisconnect(
routing_id_, source_port_id, error_message));
}
-void ExtensionMessagePort::DispatchOnMessage(
- scoped_ptr<base::ListValue> message,
- int target_port_id) {
- process_->Send(new ExtensionMsg_DeliverMessage(
- routing_id_, target_port_id, *message));
+void ExtensionMessagePort::DispatchOnMessage(const std::string& message,
+ int target_port_id) {
+ process_->Send(new ExtensionMsg_DeliverMessage(
+ routing_id_, target_port_id, message));
}
void ExtensionMessagePort::IncrementLazyKeepaliveCount() {
diff --git a/chrome/browser/extensions/api/messaging/extension_message_port.h b/chrome/browser/extensions/api/messaging/extension_message_port.h
index 7cc386a..ccf9b69 100644
--- a/chrome/browser/extensions/api/messaging/extension_message_port.h
+++ b/chrome/browser/extensions/api/messaging/extension_message_port.h
@@ -9,10 +9,6 @@
class GURL;
-namespace base {
-class ListValue;
-}
-
namespace content {
class RenderProcessHost;
} // namespace content
@@ -34,7 +30,7 @@ class ExtensionMessagePort : public MessageService::MessagePort {
const GURL& source_url) OVERRIDE;
virtual void DispatchOnDisconnect(int source_port_id,
const std::string& error_message) OVERRIDE;
- virtual void DispatchOnMessage(scoped_ptr<base::ListValue> message,
+ virtual void DispatchOnMessage(const std::string& message,
int target_port_id) OVERRIDE;
virtual void IncrementLazyKeepaliveCount() OVERRIDE;
virtual void DecrementLazyKeepaliveCount() OVERRIDE;
diff --git a/chrome/browser/extensions/api/messaging/message_service.cc b/chrome/browser/extensions/api/messaging/message_service.cc
index 3188a7f..3d05766 100644
--- a/chrome/browser/extensions/api/messaging/message_service.cc
+++ b/chrome/browser/extensions/api/messaging/message_service.cc
@@ -6,7 +6,6 @@
#include "base/atomic_sequence_num.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/json/json_writer.h"
#include "base/lazy_instance.h"
@@ -458,7 +457,7 @@ void MessageService::CloseChannelImpl(
}
void MessageService::PostMessage(
- int source_port_id, scoped_ptr<base::ListValue> message) {
+ int source_port_id, const std::string& message) {
int channel_id = GET_CHANNEL_ID(source_port_id);
MessageChannelMap::iterator iter = channels_.find(channel_id);
if (iter == channels_.end()) {
@@ -469,9 +468,7 @@ void MessageService::PostMessage(
lazy_background_task_queue_->AddPendingTask(
pending->second.first, pending->second.second,
base::Bind(&MessageService::PendingPostMessage,
- weak_factory_.GetWeakPtr(),
- source_port_id,
- base::Passed(&message)));
+ weak_factory_.GetWeakPtr(), source_port_id, message));
}
return;
}
@@ -481,13 +478,12 @@ void MessageService::PostMessage(
MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ?
iter->second->opener.get() : iter->second->receiver.get();
- port->DispatchOnMessage(message.Pass(), dest_port_id);
+ port->DispatchOnMessage(message, dest_port_id);
}
-void MessageService::PostMessageFromNativeProcess(
- int port_id,
- scoped_ptr<base::ListValue> message) {
- PostMessage(port_id, message.Pass());
+void MessageService::PostMessageFromNativeProcess(int port_id,
+ const std::string& message) {
+ PostMessage(port_id, message);
}
void MessageService::Observe(int type,
diff --git a/chrome/browser/extensions/api/messaging/message_service.h b/chrome/browser/extensions/api/messaging/message_service.h
index 59ba6ff..6de5a74 100644
--- a/chrome/browser/extensions/api/messaging/message_service.h
+++ b/chrome/browser/extensions/api/messaging/message_service.h
@@ -22,7 +22,6 @@ class Profile;
namespace base {
class DictionaryValue;
-class ListValue;
}
namespace content {
@@ -83,7 +82,7 @@ class MessageService : public ProfileKeyedAPI,
const std::string& error_message) {}
// Dispatch a message to this end of the communication.
- virtual void DispatchOnMessage(scoped_ptr<base::ListValue> message,
+ virtual void DispatchOnMessage(const std::string& message,
int target_port_id) = 0;
// MessagPorts that target extensions will need to adjust their keepalive
@@ -145,12 +144,12 @@ class MessageService : public ProfileKeyedAPI,
const std::string& error_message) OVERRIDE;
// Sends a message to the given port.
- void PostMessage(int port_id, scoped_ptr<base::ListValue> message);
+ void PostMessage(int port_id, const std::string& message);
// NativeMessageProcessHost::Client
virtual void PostMessageFromNativeProcess(
int port_id,
- scoped_ptr<base::ListValue> message) OVERRIDE;
+ const std::string& message) OVERRIDE;
private:
friend class MockMessageService;
@@ -206,10 +205,10 @@ class MessageService : public ProfileKeyedAPI,
CloseChannel(port_id, error_message);
}
void PendingPostMessage(int port_id,
- scoped_ptr<base::ListValue> message,
+ const std::string& message,
extensions::ExtensionHost* host) {
if (host)
- PostMessage(port_id, message.Pass());
+ PostMessage(port_id, message);
}
// Immediate dispatches a disconnect to |source| for |port_id|. Sets source's
diff --git a/chrome/browser/extensions/api/messaging/native_message_port.cc b/chrome/browser/extensions/api/messaging/native_message_port.cc
index 7ca7bea..e746e29 100644
--- a/chrome/browser/extensions/api/messaging/native_message_port.cc
+++ b/chrome/browser/extensions/api/messaging/native_message_port.cc
@@ -5,8 +5,6 @@
#include "chrome/browser/extensions/api/messaging/native_message_port.h"
#include "base/bind.h"
-#include "base/json/json_writer.h"
-#include "base/values.h"
#include "chrome/browser/extensions/api/messaging/native_message_process_host.h"
#include "content/public/browser/browser_thread.h"
@@ -21,20 +19,12 @@ NativeMessagePort::~NativeMessagePort() {
content::BrowserThread::IO, FROM_HERE, native_process_);
}
-void NativeMessagePort::DispatchOnMessage(scoped_ptr<base::ListValue> message,
+void NativeMessagePort::DispatchOnMessage(const std::string& message,
int target_port_id) {
- std::string message_as_json;
- if (!message->empty()) {
- DCHECK_EQ(1u, message->GetSize());
- base::Value* value = NULL;
- message->Get(0, &value);
- base::JSONWriter::Write(value, &message_as_json);
- }
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&NativeMessageProcessHost::Send,
- base::Unretained(native_process_),
- message_as_json));
+ base::Unretained(native_process_), message));
}
} // namespace extensions
diff --git a/chrome/browser/extensions/api/messaging/native_message_port.h b/chrome/browser/extensions/api/messaging/native_message_port.h
index 4c88445..6afce8a 100644
--- a/chrome/browser/extensions/api/messaging/native_message_port.h
+++ b/chrome/browser/extensions/api/messaging/native_message_port.h
@@ -16,7 +16,7 @@ class NativeMessagePort : public MessageService::MessagePort {
// Takes ownership of |native_process|.
explicit NativeMessagePort(NativeMessageProcessHost* native_process);
virtual ~NativeMessagePort();
- virtual void DispatchOnMessage(scoped_ptr<base::ListValue> message,
+ virtual void DispatchOnMessage(const std::string& message,
int target_port_id) OVERRIDE;
private:
diff --git a/chrome/browser/extensions/api/messaging/native_message_process_host.cc b/chrome/browser/extensions/api/messaging/native_message_process_host.cc
index 9f8c50b..9187a08 100644
--- a/chrome/browser/extensions/api/messaging/native_message_process_host.cc
+++ b/chrome/browser/extensions/api/messaging/native_message_process_host.cc
@@ -5,9 +5,7 @@
#include "chrome/browser/extensions/api/messaging/native_message_process_host.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/files/file_path.h"
-#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/platform_file.h"
#include "base/process_util.h"
@@ -44,8 +42,6 @@ const char kForbiddenError[] =
"Access to the specified native messaging host is forbidden.";
const char kHostInputOuputError[] =
"Error when communicating with the native messaging host.";
-const char kInvalidJsonError[] =
- "Message must be valid JSON";
} // namespace
@@ -272,35 +268,10 @@ void NativeMessageProcessHost::ProcessIncomingData(
if (incoming_data_.size() < message_size + kMessageHeaderSize)
return;
- scoped_ptr<base::ListValue> message(new base::ListValue());
- {
- std::string message_as_json =
- incoming_data_.substr(kMessageHeaderSize, message_size);
- int error_code;
- std::string error_message;
- scoped_ptr<base::Value> message_as_value(
- base::JSONReader::ReadAndReturnError(message_as_json,
- 0, // no flags
- &error_code,
- &error_message));
- if (!message_as_value) {
- base::JSONReader::JsonParseError parse_error =
- static_cast<base::JSONReader::JsonParseError>(error_code);
- LOG(ERROR) << "Native Messaging host sent message with invalid JSON \""
- << message_as_json << "\": " << error_message << " ("
- << base::JSONReader::ErrorCodeToString(parse_error) << "), "
- << "message size " << message_size << ", "
- << "incoming data size " << incoming_data_.size() << ".";
- Close(kInvalidJsonError);
- return;
- }
- message->Append(message_as_value.release());
- }
-
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
base::Bind(&Client::PostMessageFromNativeProcess, weak_client_ui_,
destination_port_,
- base::Passed(&message)));
+ incoming_data_.substr(kMessageHeaderSize, message_size)));
incoming_data_.erase(0, kMessageHeaderSize + message_size);
}
diff --git a/chrome/browser/extensions/api/messaging/native_message_process_host.h b/chrome/browser/extensions/api/messaging/native_message_process_host.h
index ef339b2..987055f 100644
--- a/chrome/browser/extensions/api/messaging/native_message_process_host.h
+++ b/chrome/browser/extensions/api/messaging/native_message_process_host.h
@@ -15,15 +15,13 @@
#include "chrome/browser/extensions/api/messaging/native_process_launcher.h"
#include "content/public/browser/browser_thread.h"
-namespace base {
-class ListValue;
-}
-
namespace net {
+
class DrainableIOBuffer;
class FileStream;
class IOBuffer;
class IOBufferWithSize;
+
} // namespace net
namespace extensions {
@@ -45,9 +43,8 @@ class NativeMessageProcessHost
public:
virtual ~Client() {}
// Called on the UI thread.
- virtual void PostMessageFromNativeProcess(
- int port_id,
- scoped_ptr<base::ListValue> message) = 0;
+ virtual void PostMessageFromNativeProcess(int port_id,
+ const std::string& message) = 0;
virtual void CloseChannel(int port_id,
const std::string& error_message) = 0;
};
diff --git a/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc b/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc
index d8fe2c4..6fc7d3a 100644
--- a/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc
+++ b/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc
@@ -104,15 +104,19 @@ class NativeMessagingTest : public ::testing::Test,
virtual void PostMessageFromNativeProcess(
int port_id,
- scoped_ptr<base::ListValue> message_as_list) OVERRIDE {
- // |message_as_list| should contain a single DictionaryValue. Extract it
- // into |last_message_|.
- ASSERT_EQ(1u, message_as_list->GetSize());
- base::Value* last_message_value = NULL;
- message_as_list->Remove(0, &last_message_value);
- ASSERT_EQ(base::Value::TYPE_DICTIONARY, last_message_value->GetType());
- last_message_.reset(
- static_cast<base::DictionaryValue*>(last_message_value));
+ const std::string& message) OVERRIDE {
+ last_message_ = message;
+
+ // Parse the message.
+ base::Value* parsed = base::JSONReader::Read(message);
+ base::DictionaryValue* dict_value;
+ if (parsed && parsed->GetAsDictionary(&dict_value)) {
+ last_message_parsed_.reset(dict_value);
+ } else {
+ LOG(ERROR) << "Failed to parse " << message;
+ last_message_parsed_.reset();
+ delete parsed;
+ }
if (read_message_run_loop_)
read_message_run_loop_->Quit();
@@ -146,7 +150,8 @@ class NativeMessagingTest : public ::testing::Test,
base::FilePath user_data_dir_;
scoped_ptr<base::RunLoop> read_message_run_loop_;
content::TestBrowserThreadBundle thread_bundle_;
- scoped_ptr<DictionaryValue> last_message_;
+ std::string last_message_;
+ scoped_ptr<base::DictionaryValue> last_message_parsed_;
};
// Read a single message from a local file.
@@ -163,26 +168,19 @@ TEST_F(NativeMessagingTest, SingleSendMessageRead) {
read_message_run_loop_.reset(new base::RunLoop());
read_message_run_loop_->RunUntilIdle();
- if (!last_message_) {
+ if (last_message_.empty()) {
read_message_run_loop_.reset(new base::RunLoop());
native_message_process_host_->ReadNowForTesting();
read_message_run_loop_->Run();
}
- ASSERT_TRUE(last_message_);
-
- scoped_ptr<base::Value> kTestMessageAsValue(
- base::JSONReader::Read(kTestMessage));
- ASSERT_TRUE(kTestMessageAsValue);
- EXPECT_TRUE(base::Value::Equals(kTestMessageAsValue.get(),
- last_message_.get()))
- << "Expected " << *kTestMessageAsValue << " got " << *last_message_;
+ EXPECT_EQ(kTestMessage, last_message_);
}
// Tests sending a single message. The message should get written to
// |temp_file| and should match the contents of single_message_request.msg.
TEST_F(NativeMessagingTest, SingleSendMessageWrite) {
base::FilePath temp_output_file = temp_dir_.path().AppendASCII("output");
- base::FilePath temp_input_file = CreateTempFileWithMessage("{}");
+ base::FilePath temp_input_file = CreateTempFileWithMessage(std::string());
scoped_ptr<NativeProcessLauncher> launcher(
new FakeLauncher(temp_input_file, temp_output_file));
@@ -228,29 +226,30 @@ TEST_F(NativeMessagingTest, EchoConnect) {
native_message_process_host_->Send("{\"text\": \"Hello.\"}");
read_message_run_loop_.reset(new base::RunLoop());
read_message_run_loop_->Run();
- ASSERT_TRUE(last_message_);
+ ASSERT_FALSE(last_message_.empty());
+ ASSERT_TRUE(last_message_parsed_);
std::string expected_url = std::string("chrome-extension://") +
kTestNativeMessagingExtensionId + "/";
int id;
- EXPECT_TRUE(last_message_->GetInteger("id", &id));
+ EXPECT_TRUE(last_message_parsed_->GetInteger("id", &id));
EXPECT_EQ(1, id);
std::string text;
- EXPECT_TRUE(last_message_->GetString("echo.text", &text));
+ EXPECT_TRUE(last_message_parsed_->GetString("echo.text", &text));
EXPECT_EQ("Hello.", text);
std::string url;
- EXPECT_TRUE(last_message_->GetString("caller_url", &url));
+ EXPECT_TRUE(last_message_parsed_->GetString("caller_url", &url));
EXPECT_EQ(expected_url, url);
native_message_process_host_->Send("{\"foo\": \"bar\"}");
read_message_run_loop_.reset(new base::RunLoop());
read_message_run_loop_->Run();
- EXPECT_TRUE(last_message_->GetInteger("id", &id));
+ EXPECT_TRUE(last_message_parsed_->GetInteger("id", &id));
EXPECT_EQ(2, id);
- EXPECT_TRUE(last_message_->GetString("echo.foo", &text));
+ EXPECT_TRUE(last_message_parsed_->GetString("echo.foo", &text));
EXPECT_EQ("bar", text);
- EXPECT_TRUE(last_message_->GetString("caller_url", &url));
+ EXPECT_TRUE(last_message_parsed_->GetString("caller_url", &url));
EXPECT_EQ(expected_url, url);
}
diff --git a/chrome/browser/extensions/message_handler.cc b/chrome/browser/extensions/message_handler.cc
index f0576e5..8389b9a 100644
--- a/chrome/browser/extensions/message_handler.cc
+++ b/chrome/browser/extensions/message_handler.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/extensions/message_handler.h"
-#include "base/values.h"
#include "chrome/browser/extensions/api/messaging/message_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/profiles/profile.h"
@@ -44,12 +43,12 @@ void MessageHandler::RenderViewHostInitialized() {
}
void MessageHandler::OnPostMessage(int port_id,
- const base::ListValue& message) {
+ const std::string& message) {
Profile* profile = Profile::FromBrowserContext(
render_view_host()->GetProcess()->GetBrowserContext());
MessageService* message_service = MessageService::Get(profile);
if (message_service) {
- message_service->PostMessage(port_id, make_scoped_ptr(message.DeepCopy()));
+ message_service->PostMessage(port_id, message);
}
}
diff --git a/chrome/browser/extensions/message_handler.h b/chrome/browser/extensions/message_handler.h
index 7142682..140105d 100644
--- a/chrome/browser/extensions/message_handler.h
+++ b/chrome/browser/extensions/message_handler.h
@@ -9,10 +9,6 @@
#include "content/public/browser/render_view_host_observer.h"
-namespace base {
-class ListValue;
-}
-
namespace extensions {
// Filters and dispatches extension-related IPC messages that arrive from
@@ -37,7 +33,7 @@ class MessageHandler : public content::RenderViewHostObserver {
private:
// Message handlers.
- void OnPostMessage(int port_id, const base::ListValue& message);
+ void OnPostMessage(int port_id, const std::string& message);
DISALLOW_COPY_AND_ASSIGN(MessageHandler);
};
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 6c3cbf1..eb1de60 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -1710,6 +1710,7 @@
'renderer/extensions/json_schema_unittest.cc',
'renderer/extensions/module_system_unittest.cc',
'renderer/extensions/renderer_permissions_policy_delegate_unittest.cc',
+ 'renderer/extensions/safe_builtins_unittest.cc',
'renderer/media/webrtc_logging_handler_impl_unittest.cc',
'renderer/net/predictor_queue_unittest.cc',
'renderer/net/renderer_predictor_unittest.cc',
diff --git a/chrome/common/extensions/extension_messages.h b/chrome/common/extensions/extension_messages.h
index 708f0f6..a49359b 100644
--- a/chrome/common/extensions/extension_messages.h
+++ b/chrome/common/extensions/extension_messages.h
@@ -426,7 +426,7 @@ IPC_MESSAGE_ROUTED4(ExtensionMsg_DispatchOnConnect,
// Deliver a message sent with ExtensionHostMsg_PostMessage.
IPC_MESSAGE_ROUTED2(ExtensionMsg_DeliverMessage,
int /* target_port_id */,
- base::ListValue /* message args, a 0-or-1 length list */)
+ std::string /* message */)
// Dispatch the Port.onDisconnect event for message channels.
IPC_MESSAGE_ROUTED2(ExtensionMsg_DispatchOnDisconnect,
@@ -536,7 +536,7 @@ IPC_SYNC_MESSAGE_CONTROL4_1(ExtensionHostMsg_OpenChannelToTab,
// by ViewHostMsg_OpenChannelTo*.
IPC_MESSAGE_ROUTED2(ExtensionHostMsg_PostMessage,
int /* port_id */,
- base::ListValue /* message args, a 0-or-1 length list */)
+ std::string /* message */)
// Send a message to an extension process. The handle is the value returned
// by ViewHostMsg_OpenChannelTo*.
diff --git a/chrome/renderer/extensions/dispatcher.cc b/chrome/renderer/extensions/dispatcher.cc
index ec1b055..50348c3 100644
--- a/chrome/renderer/extensions/dispatcher.cc
+++ b/chrome/renderer/extensions/dispatcher.cc
@@ -510,7 +510,7 @@ void Dispatcher::OnDispatchOnConnect(
}
void Dispatcher::OnDeliverMessage(int target_port_id,
- const base::ListValue& message) {
+ const std::string& message) {
MiscellaneousBindings::DeliverMessage(
v8_context_set_.GetAll(),
target_port_id,
diff --git a/chrome/renderer/extensions/dispatcher.h b/chrome/renderer/extensions/dispatcher.h
index 2d81dff..80cd0ee 100644
--- a/chrome/renderer/extensions/dispatcher.h
+++ b/chrome/renderer/extensions/dispatcher.h
@@ -164,7 +164,7 @@ class Dispatcher : public content::RenderProcessObserver {
const std::string& channel_name,
const base::DictionaryValue& source_tab,
const ExtensionMsg_ExternalConnectionInfo& info);
- void OnDeliverMessage(int target_port_id, const base::ListValue& message);
+ void OnDeliverMessage(int target_port_id, const std::string& message);
void OnDispatchOnDisconnect(int port_id, const std::string& error_message);
void OnSetFunctionNames(const std::vector<std::string>& names);
void OnSetSystemFont(const std::string& font_family,
diff --git a/chrome/renderer/extensions/extension_helper.cc b/chrome/renderer/extensions/extension_helper.cc
index a0b651a..2dc8dc6 100644
--- a/chrome/renderer/extensions/extension_helper.cc
+++ b/chrome/renderer/extensions/extension_helper.cc
@@ -271,9 +271,8 @@ void ExtensionHelper::OnExtensionDispatchOnConnect(
render_view());
}
-void ExtensionHelper::OnExtensionDeliverMessage(
- int target_id,
- const base::ListValue& message) {
+void ExtensionHelper::OnExtensionDeliverMessage(int target_id,
+ const std::string& message) {
MiscellaneousBindings::DeliverMessage(dispatcher_->v8_context_set().GetAll(),
target_id,
message,
diff --git a/chrome/renderer/extensions/extension_helper.h b/chrome/renderer/extensions/extension_helper.h
index 0d4f8b5..07a9b59 100644
--- a/chrome/renderer/extensions/extension_helper.h
+++ b/chrome/renderer/extensions/extension_helper.h
@@ -81,7 +81,7 @@ class ExtensionHelper
const base::DictionaryValue& source_tab,
const ExtensionMsg_ExternalConnectionInfo& info);
void OnExtensionDeliverMessage(int target_port_id,
- const base::ListValue& message);
+ const std::string& message);
void OnExtensionDispatchOnDisconnect(int port_id,
const std::string& error_message);
void OnExecuteCode(const ExtensionMsg_ExecuteCode_Params& params);
diff --git a/chrome/renderer/extensions/miscellaneous_bindings.cc b/chrome/renderer/extensions/miscellaneous_bindings.cc
index 753c9bb..8921d77 100644
--- a/chrome/renderer/extensions/miscellaneous_bindings.cc
+++ b/chrome/renderer/extensions/miscellaneous_bindings.cc
@@ -95,9 +95,10 @@ class ExtensionImpl : public extensions::ChromeV8Extension {
if (!renderview)
return;
- // Arguments are (int32 port_id, object message).
- CHECK_EQ(2, args.Length());
- CHECK(args[0]->IsInt32());
+ // Arguments are (int32 port_id, string message).
+ CHECK(args.Length() == 2 &&
+ args[0]->IsInt32() &&
+ args[1]->IsString());
int port_id = args[0]->Int32Value();
if (!HasPortData(port_id)) {
@@ -106,18 +107,8 @@ class ExtensionImpl : public extensions::ChromeV8Extension {
return;
}
- // The message can be any base::Value but IPC can't serialize that, so we
- // give it a singleton base::ListValue instead, or an empty list if the
- // argument was undefined (v8 value converter will return NULL for this).
- scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
- scoped_ptr<base::Value> message(
- converter->FromV8Value(args[1], context()->v8_context()));
- ListValue message_as_list;
- if (message)
- message_as_list.Append(message.release());
-
renderview->Send(new ExtensionHostMsg_PostMessage(
- renderview->GetRoutingID(), port_id, message_as_list));
+ renderview->GetRoutingID(), port_id, *v8::String::AsciiValue(args[1])));
}
// Forcefully disconnects a port.
@@ -284,7 +275,7 @@ void MiscellaneousBindings::DispatchOnConnect(
void MiscellaneousBindings::DeliverMessage(
const ChromeV8ContextSet::ContextSet& contexts,
int target_port_id,
- const base::ListValue& message,
+ const std::string& message,
content::RenderView* restrict_to_render_view) {
v8::HandleScope handle_scope;
@@ -300,9 +291,6 @@ void MiscellaneousBindings::DeliverMessage(
if ((*it)->v8_context().IsEmpty())
continue;
- v8::Handle<v8::Context> context = (*it)->v8_context();
- v8::Context::Scope context_scope(context);
-
// Check to see whether the context has this port before bothering to create
// the message.
v8::Handle<v8::Value> port_id_handle = v8::Integer::New(target_port_id);
@@ -316,19 +304,7 @@ void MiscellaneousBindings::DeliverMessage(
continue;
std::vector<v8::Handle<v8::Value> > arguments;
-
- // Convert the message to a v8 object; either a value or undefined.
- // See PostMessage for more details.
- if (message.empty()) {
- arguments.push_back(v8::Undefined());
- } else {
- CHECK_EQ(1u, message.GetSize());
- const base::Value* message_value = NULL;
- message.Get(0, &message_value);
- scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
- arguments.push_back(converter->ToV8Value(message_value, context));
- }
-
+ arguments.push_back(v8::String::New(message.c_str(), message.size()));
arguments.push_back(port_id_handle);
(*it)->module_system()->CallModuleMethod("miscellaneous_bindings",
"dispatchOnMessage",
diff --git a/chrome/renderer/extensions/miscellaneous_bindings.h b/chrome/renderer/extensions/miscellaneous_bindings.h
index 95d0733..79dfeb7 100644
--- a/chrome/renderer/extensions/miscellaneous_bindings.h
+++ b/chrome/renderer/extensions/miscellaneous_bindings.h
@@ -11,7 +11,6 @@
namespace base {
class DictionaryValue;
-class ListValue;
}
namespace content {
@@ -56,7 +55,7 @@ class MiscellaneousBindings {
static void DeliverMessage(
const ChromeV8ContextSet::ContextSet& context_set,
int target_port_id,
- const base::ListValue& message,
+ const std::string& message,
content::RenderView* restrict_to_render_view);
// Dispatches the onDisconnect event in response to the channel being closed.
@@ -67,6 +66,6 @@ class MiscellaneousBindings {
content::RenderView* restrict_to_render_view);
};
-} // namespace
+} // namespace extensions
#endif // CHROME_RENDERER_EXTENSIONS_MISCELLANEOUS_BINDINGS_H_
diff --git a/chrome/renderer/extensions/module_system.cc b/chrome/renderer/extensions/module_system.cc
index c29b440..29575b2 100644
--- a/chrome/renderer/extensions/module_system.cc
+++ b/chrome/renderer/extensions/module_system.cc
@@ -198,6 +198,7 @@ v8::Handle<v8::Value> ModuleSystem::RequireForJsInner(
// Each safe builtin. Keep in order with the arguments in WrapSource.
context_->safe_builtins()->GetArray(),
context_->safe_builtins()->GetFunction(),
+ context_->safe_builtins()->GetJSON(),
context_->safe_builtins()->GetObjekt(),
};
{
@@ -482,7 +483,7 @@ v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) {
// Keep in order with the arguments in RequireForJsInner.
v8::Handle<v8::String> left = v8::String::New(
"(function(require, requireNative, exports,"
- "$Array, $Function, $Object) {"
+ "$Array, $Function, $JSON, $Object) {"
"'use strict';");
v8::Handle<v8::String> right = v8::String::New("\n})");
return handle_scope.Close(
diff --git a/chrome/renderer/extensions/safe_builtins.cc b/chrome/renderer/extensions/safe_builtins.cc
index c28b077..05f67fc 100644
--- a/chrome/renderer/extensions/safe_builtins.cc
+++ b/chrome/renderer/extensions/safe_builtins.cc
@@ -28,6 +28,7 @@ const char kClassName[] = "extensions::SafeBuiltins";
// This is a convenient way to save functions that user scripts may clobber.\n"
const char kScript[] =
"(function() {\n"
+ "'use strict';\n"
"native function Apply();\n"
"native function Save();\n"
"\n"
@@ -52,16 +53,64 @@ const char kScript[] =
" });\n"
"}\n"
"\n"
- "function getSafeBuiltin(builtin) {\n"
- " var safe = {};\n"
+ "function getSafeBuiltin(builtin, includePrototype) {\n"
+ " var safe = function() {\n"
+ " throw 'Safe objects cannot be called nor constructed. ' +\n"
+ " 'Use $Foo.self() or new $Foo.self() instead.';\n"
+ " };\n"
+ " safe.self = builtin;\n"
" makeCallable(builtin, safe, true);\n"
- " makeCallable(builtin.prototype, safe, false);\n"
+ " if (includePrototype)\n"
+ " makeCallable(builtin.prototype, safe, false);\n"
" return safe;\n"
"}\n"
"\n"
- "[Array, Function, Object].forEach(function(builtin) {\n"
- " Save(builtin.name, getSafeBuiltin(builtin));\n"
+ "// Built-in types taken from the ECMAScript spec. The spec may change,\n"
+ "// though. It would be nice to generate this somehow.\n"
+ "// Note: no JSON, it needs to handle toJSON being overriden so is\n"
+ "// implemented by hand.\n"
+ "var builtinTypes = [Object, Function, Array, String, Boolean, Number,\n"
+ " /*Math,*/ Date, RegExp, /*JSON,*/ Error, EvalError,\n"
+ " ReferenceError, SyntaxError, TypeError, URIError];\n"
+ "builtinTypes.forEach(function(builtin) {\n"
+ " Save(builtin.name, getSafeBuiltin(builtin, true));\n"
"});\n"
+ "Save('Math', getSafeBuiltin(Math, false));\n"
+ "// Save JSON. This is trickier because extensions can override toJSON in\n"
+ "// incompatible ways, and we need to prevent that.\n"
+ "var builtinToJSONs = builtinTypes.map(function(t) {\n"
+ " return t.toJSON;\n"
+ "});\n"
+ "var builtinArray = Array;\n"
+ "var builtinJSONStringify = JSON.stringify;\n"
+ "Save('JSON', {\n"
+ " parse: JSON.parse,\n"
+ " stringify: function(obj) {\n"
+ " var savedToJSONs = new builtinArray(builtinTypes.length);\n"
+ " try {\n"
+ " for (var i = 0; i < builtinTypes.length; ++i) {\n"
+ " try {\n"
+ " if (builtinTypes[i].prototype.toJSON !==\n"
+ " builtinToJSONs[i]) {\n"
+ " savedToJSONs[i] = builtinTypes[i].prototype.toJSON;\n"
+ " builtinTypes[i].prototype.toJSON = builtinToJSONs[i];\n"
+ " }\n"
+ " } catch (e) {}\n"
+ " }\n"
+ " } catch (e) {}\n"
+ " try {\n"
+ " return builtinJSONStringify(obj);\n"
+ " } finally {\n"
+ " for (var i = 0; i < builtinTypes.length; ++i) {\n"
+ " try {\n"
+ " if (i in savedToJSONs)\n"
+ " builtinTypes[i].prototype.toJSON = savedToJSONs[i];\n"
+ " } catch (e) {}\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "});\n"
+ "\n"
"}());\n";
v8::Local<v8::String> MakeKey(const char* name) {
@@ -157,6 +206,10 @@ v8::Local<v8::Object> SafeBuiltins::GetFunction() const {
return Load("Function", context_->v8_context());
}
+v8::Local<v8::Object> SafeBuiltins::GetJSON() const {
+ return Load("JSON", context_->v8_context());
+}
+
v8::Local<v8::Object> SafeBuiltins::GetObjekt() const {
return Load("Object", context_->v8_context());
}
diff --git a/chrome/renderer/extensions/safe_builtins.h b/chrome/renderer/extensions/safe_builtins.h
index c2dcb4d..3be54c1 100644
--- a/chrome/renderer/extensions/safe_builtins.h
+++ b/chrome/renderer/extensions/safe_builtins.h
@@ -30,6 +30,7 @@ class SafeBuiltins {
// Object.keys.call(...) becomes Object.keys(...)
v8::Local<v8::Object> GetArray() const;
v8::Local<v8::Object> GetFunction() const;
+ v8::Local<v8::Object> GetJSON() const;
// NOTE(kalman): VS2010 won't compile "GetObject", it mysteriously renames it
// to "GetObjectW" - hence GetObjekt. Sorry.
v8::Local<v8::Object> GetObjekt() const;
diff --git a/chrome/renderer/extensions/safe_builtins_unittest.cc b/chrome/renderer/extensions/safe_builtins_unittest.cc
new file mode 100644
index 0000000..effc087
--- /dev/null
+++ b/chrome/renderer/extensions/safe_builtins_unittest.cc
@@ -0,0 +1,68 @@
+// Copyright 2013 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 "chrome/test/base/module_system_test.h"
+
+#include "grit/renderer_resources.h"
+
+namespace extensions {
+namespace {
+
+class SafeBuiltinsUnittest : public ModuleSystemTest {
+};
+
+TEST_F(SafeBuiltinsUnittest, TestNotOriginalObject) {
+ ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get());
+ RegisterModule("test",
+ "var assert = requireNative('assert');\n"
+ "Array.foo = 10;\n"
+ "assert.AssertTrue(!$Array.hasOwnProperty('foo'));\n"
+ );
+ module_system_->Require("test");
+}
+
+TEST_F(SafeBuiltinsUnittest, TestSelf) {
+ ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get());
+ RegisterModule("test",
+ "var assert = requireNative('assert');\n"
+ "Array.foo = 10;\n"
+ "assert.AssertTrue($Array.self.foo == 10);\n"
+ "var arr = $Array.self(1);\n"
+ "assert.AssertTrue(arr.length == 1);\n"
+ "assert.AssertTrue(arr[0] === undefined);\n"
+ );
+ module_system_->Require("test");
+}
+
+TEST_F(SafeBuiltinsUnittest, TestStaticFunction) {
+ ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get());
+ RegisterModule("test",
+ "var assert = requireNative('assert');\n"
+ "Object.getOwnPropertyNames = function() {throw new Error()};\n"
+ "var obj = {a: 10};\n"
+ "var propertyNames = $Object.getOwnPropertyNames(obj);\n"
+ "assert.AssertTrue(propertyNames.length == 1);\n"
+ "assert.AssertTrue(propertyNames[0] == 'a');\n"
+ );
+ module_system_->Require("test");
+}
+
+TEST_F(SafeBuiltinsUnittest, TestInstanceMethod) {
+ ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get());
+ RegisterModule("test",
+ "var assert = requireNative('assert');\n"
+ "Array.prototype.push = function() {throw new Error();}\n"
+ "var arr = []\n"
+ "$Array.push(arr, 1);\n"
+ "assert.AssertTrue(arr.length == 1);\n"
+ "assert.AssertTrue(arr[0] == 1);\n"
+ );
+ module_system_->Require("test");
+}
+
+// NOTE: JSON is already tested in ExtensionApiTest.Messaging, via
+// chrome/test/data/extensions/api_test/messaging/connect/page.js.
+
+} // namespace
+} // namespace extensions
diff --git a/chrome/renderer/resources/extensions/miscellaneous_bindings.js b/chrome/renderer/resources/extensions/miscellaneous_bindings.js
index 32f4c85b..52a7550 100644
--- a/chrome/renderer/resources/extensions/miscellaneous_bindings.js
+++ b/chrome/renderer/resources/extensions/miscellaneous_bindings.js
@@ -45,7 +45,10 @@
// Sends a message asynchronously to the context on the other end of this
// port.
Port.prototype.postMessage = function(msg) {
- miscNatives.PostMessage(this.portId_, msg);
+ // JSON.stringify doesn't support a root object which is undefined.
+ if (msg === undefined)
+ msg = null;
+ miscNatives.PostMessage(this.portId_, $JSON.stringify(msg));
};
// Disconnects the port from the other end.
@@ -266,8 +269,11 @@
// Called by native code when a message has been sent to the given port.
function dispatchOnMessage(msg, portId) {
var port = ports[portId];
- if (port)
+ if (port) {
+ if (msg)
+ msg = $JSON.parse(msg);
port.onMessage.dispatch(msg, port);
+ }
};
// Shared implementation used by tabs.sendMessage and runtime.sendMessage.
diff --git a/chrome/test/data/devtools/extensions/devtools_messaging/devtools.js b/chrome/test/data/devtools/extensions/devtools_messaging/devtools.js
index 915273b..56c2f14 100644
--- a/chrome/test/data/devtools/extensions/devtools_messaging/devtools.js
+++ b/chrome/test/data/devtools/extensions/devtools_messaging/devtools.js
@@ -30,7 +30,7 @@ function step1() {
}
function step2() {
- var object = [{"string": "foo"}, {"number": 42}];
+ var object = { "string": "foo", "number": 42 };
chrome.extension.sendRequest(object, function(response) {
assertEquals('onRequest callback: ' + JSON.stringify(object), response);
step3();