diff options
author | mpcomplete@google.com <mpcomplete@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-19 18:52:50 +0000 |
---|---|---|
committer | mpcomplete@google.com <mpcomplete@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-19 18:52:50 +0000 |
commit | f44265b0b203289b76b7d28b46bbfed1708829ea (patch) | |
tree | f4cd4bb88f20825863c90ec281bf48cb02cf8bd5 /chrome/browser/automation/extension_port_container.cc | |
parent | 0b7b45d3b8642aa9d3acb422ae7ed7efd3c18f73 (diff) | |
download | chromium_src-f44265b0b203289b76b7d28b46bbfed1708829ea.zip chromium_src-f44265b0b203289b76b7d28b46bbfed1708829ea.tar.gz chromium_src-f44265b0b203289b76b7d28b46bbfed1708829ea.tar.bz2 |
Allow connecting and messaging with extension ports by funneling external
ports through the automation postMessage interface.
See original review at: http://codereview.chromium.org/113461
Patch by Siggi Asgeirsson <sigurdur.asgeirsson@gmail.com>
Review URL: http://codereview.chromium.org/113538
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16396 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/automation/extension_port_container.cc')
-rw-r--r-- | chrome/browser/automation/extension_port_container.cc | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/chrome/browser/automation/extension_port_container.cc b/chrome/browser/automation/extension_port_container.cc new file mode 100644 index 0000000..cb56865 --- /dev/null +++ b/chrome/browser/automation/extension_port_container.cc @@ -0,0 +1,203 @@ +// Copyright (c) 2009 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/browser/automation/extension_port_container.h" + +#include "base/logging.h" +#include "base/json_reader.h" +#include "base/json_writer.h" +#include "chrome/common/render_messages.h" +#include "chrome/browser/automation/automation_provider.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/extensions/extension_message_service.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/renderer_host/render_view_host.h" + +// TODO(siggi): Find a more structured way to read and write JSON messages. +// TODO(siggi): move these constants to +// chrome/test/automation/extension_automation_constants.cc +const char ExtensionPortContainer::kAutomationOrigin[] = "__priv_xtapi"; +const char ExtensionPortContainer::kAutomationRequestTarget[] = + "__priv_prtreq"; +const char ExtensionPortContainer::kAutomationResponseTarget[] = + "__priv_prtres"; + +const wchar_t ExtensionPortContainer::kAutomationRequestIdKey[] = L"rqid"; +const wchar_t ExtensionPortContainer::kAutomationConnectionIdKey[] = L"connid"; +const wchar_t ExtensionPortContainer::kAutomationExtensionIdKey[] = L"extid"; +const wchar_t ExtensionPortContainer::kAutomationPortIdKey[] = L"portid"; +const wchar_t ExtensionPortContainer::kAutomationMessageDataKey[] = L"data"; + + +ExtensionPortContainer::ExtensionPortContainer(AutomationProvider* automation, + int tab_handle) : + automation_(automation), service_(NULL), port_id_(-1), + tab_handle_(tab_handle) { + URLRequestContext* context = automation_->profile()->GetRequestContext(); + service_ = ExtensionMessageService::GetInstance(context); + DCHECK(service_); +} + +ExtensionPortContainer::~ExtensionPortContainer() { + DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); + + if (port_id_ != -1) + service_->CloseAutomationChannel(port_id_); +} + +bool ExtensionPortContainer::PostResponseToExternalPort( + const std::string& message) { + return automation_->Send( + new AutomationMsg_ForwardMessageToExternalHost( + 0, tab_handle_, message, kAutomationOrigin, + kAutomationResponseTarget)); +} + +bool ExtensionPortContainer::PostMessageToExternalPort( + const std::string& message) { + return automation_->Send( + new AutomationMsg_ForwardMessageToExternalHost(0, + tab_handle_, + message, + kAutomationOrigin, + kAutomationRequestTarget)); +} + +void ExtensionPortContainer::PostMessageFromExternalPort( + const std::string &message) { + service_->PostMessageFromRenderer(port_id_, message); +} + +bool ExtensionPortContainer::Connect(const std::string &extension_id, + int process_id, + int routing_id, + int connection_id) { + DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); + + port_id_ = service_->OpenAutomationChannelToExtension(process_id, + routing_id, + extension_id, + this); + + SendConnectionResponse(connection_id, port_id_); + return port_id_ != -1; +} + +void ExtensionPortContainer::SendConnectionResponse(int connection_id, + int port_id) { + // Compose the reply message. + scoped_ptr<DictionaryValue> msg_dict(new DictionaryValue()); + msg_dict->SetInteger(kAutomationRequestIdKey, CHANNEL_OPENED); + msg_dict->SetInteger(kAutomationConnectionIdKey, connection_id); + msg_dict->SetInteger(kAutomationPortIdKey, port_id); + + std::string msg_json; + JSONWriter::Write(msg_dict.get(), false, &msg_json); + + PostResponseToExternalPort(msg_json); +} + +bool ExtensionPortContainer::Send(IPC::Message *message) { + DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); + + IPC_BEGIN_MESSAGE_MAP(ExtensionPortContainer, *message) + IPC_MESSAGE_HANDLER(ViewMsg_ExtensionHandleMessage, + OnExtensionHandleMessage) + IPC_MESSAGE_UNHANDLED_ERROR() + IPC_END_MESSAGE_MAP() + + delete message; + return true; +} + +void ExtensionPortContainer::OnExtensionHandleMessage( + const std::string& message, int source_port_id) { + // Compose the reply message and fire it away. + scoped_ptr<DictionaryValue> msg_dict(new DictionaryValue()); + msg_dict->SetInteger(kAutomationRequestIdKey, POST_MESSAGE); + msg_dict->SetInteger(kAutomationPortIdKey, port_id_); + msg_dict->SetString(kAutomationMessageDataKey, message); + + std::string msg_json; + JSONWriter::Write(msg_dict.get(), false, &msg_json); + + PostMessageToExternalPort(msg_json); +} + +bool ExtensionPortContainer::InterceptMessageFromExternalHost( + const std::string& message, const std::string& origin, + const std::string& target, AutomationProvider* automation, + RenderViewHost *view_host, int tab_handle) { + if (target != kAutomationRequestTarget) + return false; + + if (origin != kAutomationOrigin) { + // TODO(siggi): Should we block the message on wrong origin? + LOG(WARNING) << "Wrong origin on automation port message " << origin; + } + + scoped_ptr<Value> message_value(JSONReader::Read(message, false)); + DCHECK(message_value->IsType(Value::TYPE_DICTIONARY)); + if (!message_value->IsType(Value::TYPE_DICTIONARY)) + return true; + + DictionaryValue* message_dict = + reinterpret_cast<DictionaryValue*>(message_value.get()); + + int command = -1; + bool got_value = message_dict->GetInteger(kAutomationRequestIdKey, &command); + DCHECK(got_value); + if (!got_value) + return true; + + if (command == OPEN_CHANNEL) { + // Extract the "extension_id" and "connection_id" parameters. + std::string extension_id; + got_value = message_dict->GetString(kAutomationExtensionIdKey, + &extension_id); + DCHECK(got_value); + if (!got_value) + return true; + + int connection_id; + got_value = message_dict->GetInteger(kAutomationConnectionIdKey, + &connection_id); + DCHECK(got_value); + if (!got_value) + return true; + + int routing_id = view_host->routing_id(); + // Create the extension port and connect it. + scoped_ptr<ExtensionPortContainer> port( + new ExtensionPortContainer(automation, tab_handle)); + + int process_id = view_host->process()->pid(); + if (port->Connect(extension_id, process_id, routing_id, connection_id)) { + // We have a successful connection. + automation->AddPortContainer(port.release()); + } + } else if (command == POST_MESSAGE) { + int port_id = -1; + got_value = message_dict->GetInteger(kAutomationPortIdKey, &port_id); + DCHECK(got_value); + if (!got_value) + return true; + + std::string data; + got_value = message_dict->GetString(kAutomationMessageDataKey, &data); + DCHECK(got_value); + if (!got_value) + return true; + + ExtensionPortContainer* port = automation->GetPortContainer(port_id); + DCHECK(port); + if (port) + port->PostMessageFromExternalPort(data); + } else { + // We don't expect other messages here. + NOTREACHED(); + } + + return true; +} |