diff options
author | stoyan@chromium.org <stoyan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-05 23:38:55 +0000 |
---|---|---|
committer | stoyan@chromium.org <stoyan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-05 23:38:55 +0000 |
commit | 23f5ee3f8b0c9f854c080db48b1f97603576d865 (patch) | |
tree | 0b244a27b3a84e61fcea00316b5ff578b38d4ed4 /chrome_frame/cfproxy_support.cc | |
parent | 06552c1abc14f20e5dcc374a44c17e2cd29d9746 (diff) | |
download | chromium_src-23f5ee3f8b0c9f854c080db48b1f97603576d865.zip chromium_src-23f5ee3f8b0c9f854c080db48b1f97603576d865.tar.gz chromium_src-23f5ee3f8b0c9f854c080db48b1f97603576d865.tar.bz2 |
Initial skeleton for refactored ChromeFrameAutomationClient and AutomationProxy for the needs of ChromeFrame.
CFProxy is ready to some extent, while CFAC is mostly structure-only.
Review URL: http://codereview.chromium.org/3528004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@61583 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame/cfproxy_support.cc')
-rw-r--r-- | chrome_frame/cfproxy_support.cc | 450 |
1 files changed, 450 insertions, 0 deletions
diff --git a/chrome_frame/cfproxy_support.cc b/chrome_frame/cfproxy_support.cc new file mode 100644 index 0000000..72454c0 --- /dev/null +++ b/chrome_frame/cfproxy_support.cc @@ -0,0 +1,450 @@ +// Copyright (c) 2010 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_frame/cfproxy_private.h" + +#include "base/atomic_sequence_num.h" +#include "base/command_line.h" +#include "base/process_util.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/test/automation/automation_messages.h" +#include "chrome_frame/chrome_launcher_utils.h" +#include "chrome_frame/utils.h" // for IsHeadlessMode(); + + +namespace { +void DispatchReplyFail(uint32 type, + ChromeProxyDelegate* delegate, + SyncMessageContext* ctx) { + switch (type) { + case AutomationMsg_CreateExternalTab::ID: + delegate->Completed_CreateTab(false, NULL, NULL, NULL); + break; + case AutomationMsg_ConnectExternalTab::ID: + delegate->Completed_ConnectToTab(false, NULL, NULL, NULL); + break; + case AutomationMsg_InstallExtension::ID: + delegate->Completed_InstallExtension(false, + AUTOMATION_MSG_EXTENSION_INSTALL_FAILED, ctx); + break; + } +} + +bool DispatchReplyOk(const IPC::Message* reply_msg, uint32 type, + ChromeProxyDelegate* delegate, SyncMessageContext* ctx, + TabsMap* tab2delegate) { + void* iter = IPC::SyncMessage::GetDataIterator(reply_msg); + switch (type) { + case AutomationMsg_CreateExternalTab::ID: { + // Tuple3<HWND, HWND, int> out; + TupleTypes<AutomationMsg_CreateExternalTab::ReplyParam>::ValueTuple out; + if (ReadParam(reply_msg, &iter, &out)) { + DCHECK(tab2delegate->find(out.c) == tab2delegate->end()); + (*tab2delegate)[out.c] = delegate; + delegate->Completed_CreateTab(true, out.a, out.b, out.c); + } + return true; + } + + case AutomationMsg_ConnectExternalTab::ID: { + // Tuple3<HWND, HWND, int> out; + TupleTypes<AutomationMsg_ConnectExternalTab::ReplyParam>::ValueTuple out; + if (ReadParam(reply_msg, &iter, &out)) { + DCHECK(tab2delegate->find(out.c) == tab2delegate->end()); + (*tab2delegate)[out.c] = delegate; + delegate->Completed_ConnectToTab(true, out.a, out.b, out.c); + } + return true; + } + + case AutomationMsg_InstallExtension::ID: { + // Tuple1<AutomationMsg_ExtensionResponseValues> out; + TupleTypes<AutomationMsg_InstallExtension::ReplyParam>::ValueTuple out; + if (ReadParam(reply_msg, &iter, &out)) + delegate->Completed_InstallExtension(true, out.a, ctx); + return true; + } + + case AutomationMsg_LoadExpandedExtension::ID: { + // Tuple1<AutomationMsg_ExtensionResponseValues> out; + TupleTypes<AutomationMsg_LoadExpandedExtension::ReplyParam>::ValueTuple + out; + if (ReadParam(reply_msg, &iter, &out)) + delegate->Completed_LoadExpandedExtension(true, out.a, ctx); + break; + } + + case AutomationMsg_GetEnabledExtensions::ID: { + // Tuple1<std::vector<FilePath> > + TupleTypes<AutomationMsg_GetEnabledExtensions::ReplyParam>::ValueTuple + out; + if (ReadParam(reply_msg, &iter, &out)) + delegate->Completed_GetEnabledExtensions(true, &out.a); + break; + } + } // switch + + return false; +} +} // namespace + +// Itf2IPCMessage +// Converts and sends trivial messages. +void Interface2IPCMessage::RemoveBrowsingData(int mask) { + sender_->Send(new AutomationMsg_RemoveBrowsingData(0, mask)); +} + +void Interface2IPCMessage::SetProxyConfig( + const std::string& json_encoded_proxy_cfg) { + sender_->Send(new AutomationMsg_SetProxyConfig(0, json_encoded_proxy_cfg)); +} + +// Tab related. +void Interface2IPCMessage::Tab_PostMessage(int tab, const std::string& message, + const std::string& origin, const std::string& target) { + sender_->Send(new AutomationMsg_HandleMessageFromExternalHost( + 0, tab, message, origin, target)); +} + +void Interface2IPCMessage::Tab_Reload(int tab) { + sender_->Send(new AutomationMsg_ReloadAsync(0, tab)); +} + +void Interface2IPCMessage::Tab_Stop(int tab) { + sender_->Send(new AutomationMsg_StopAsync(0, tab)); +} + +void Interface2IPCMessage::Tab_SaveAs(int tab) { + sender_->Send(new AutomationMsg_SaveAsAsync(0, tab)); +} + +void Interface2IPCMessage::Tab_Print(int tab) { + sender_->Send(new AutomationMsg_PrintAsync(0, tab)); +} + +void Interface2IPCMessage::Tab_Cut(int tab) { + sender_->Send(new AutomationMsg_Cut(0, tab)); +} + +void Interface2IPCMessage::Tab_Copy(int tab) { + sender_->Send(new AutomationMsg_Copy(0, tab)); +} + +void Interface2IPCMessage::Tab_Paste(int tab) { + sender_->Send(new AutomationMsg_Paste(0, tab)); +} + +void Interface2IPCMessage::Tab_SelectAll(int tab) { + sender_->Send(new AutomationMsg_SelectAll(0, tab)); +} + +void Interface2IPCMessage::Tab_MenuCommand(int tab, int selected_command) { + sender_->Send(new AutomationMsg_ForwardContextMenuCommandToChrome( + 0, tab, selected_command)); +} + +void Interface2IPCMessage::Tab_Zoom(int tab, PageZoom::Function zoom_level) { + sender_->Send(new AutomationMsg_SetZoomLevel(0, tab, zoom_level)); +} + +void Interface2IPCMessage::Tab_FontSize(int tab, + enum AutomationPageFontSize font_size) { + sender_->Send(new AutomationMsg_SetPageFontSize(0, tab, font_size)); +} + +void Interface2IPCMessage::Tab_SetInitialFocus(int tab, bool reverse, + bool restore_focus_to_view) { + sender_->Send(new AutomationMsg_SetInitialFocus(0, tab, reverse, + restore_focus_to_view)); +} + +void Interface2IPCMessage::Tab_SetParentWindow(int tab) { + CHECK(0) << "Implement me"; + // AutomationMsg_TabReposition +} + +void Interface2IPCMessage::Tab_Resize(int tab) { + CHECK(0) << "Implement me"; + // AutomationMsg_TabReposition +} + +void Interface2IPCMessage::Tab_ProcessAccelerator(int tab, const MSG& msg) { + sender_->Send(new AutomationMsg_ProcessUnhandledAccelerator(0, tab, msg)); +} + +// Misc. +void Interface2IPCMessage::Tab_OnHostMoved(int tab) { + sender_->Send(new AutomationMsg_BrowserMove(0, tab)); +} + +void Interface2IPCMessage::Tab_SetEnableExtensionAutomation(int tab, + const std::vector<std::string>& functions_enabled) { + sender_->Send(new AutomationMsg_SetEnableExtensionAutomation(0, tab, + functions_enabled)); +} + +void DelegateHolder::AddDelegate(ChromeProxyDelegate* p) { + delegate_list_.insert(p); +} + +void DelegateHolder::RemoveDelegate(ChromeProxyDelegate* p) { + // DCHECK(CalledOnValidThread()); + int tab_handle = p->tab_handle(); // Could be 0. + delegate_list_.erase(p); + tab2delegate_.erase(tab_handle); +} + +ChromeProxyDelegate* DelegateHolder::Tab2Delegate(int tab_handle) { + TabsMap::const_iterator iter = tab2delegate_.find(tab_handle); + if (iter != tab2delegate_.end()) + return iter->second; + return NULL; +} + +SyncMsgSender::SyncMsgSender(TabsMap* tab2delegate) + : tab2delegate_(tab2delegate) { +} + +// The outgoing queue of sync messages must be locked. +// Case: ui thread is sending message and waits for event, that is going to be +// signaled by completion handler in ipc_thread. +// We must append the message to the outgoing queue in UI thread, +// otherwise if channel is disconnected before having a chance to +// send the message, the ChromeProxyDelegate::_Disconnect implementation +// shall know how to unblock arbitrary sync call. Instead +// ChromeProxyDelgate::Completed_XXXX knows how to unblock a specific one. +void SyncMsgSender::QueueSyncMessage(const IPC::SyncMessage* msg, + ChromeProxyDelegate* delegate, + SyncMessageContext* ctx) { + if (delegate) { + // We are interested of the result. + AutoLock lock(messages_lock_); + int id = IPC::SyncMessage::GetMessageId(*msg); + // A message can be sent only once. + DCHECK(messages_.end() == messages_.find(id)); + messages_[id] = new SingleSentMessage(msg->type(), delegate, ctx); + } +} + +void SyncMsgSender::Cancel(ChromeProxyDelegate* delegate) { + // TODO(stoyan): Cancel all outgoing calls for this delegate + // We may not need this. :) +} + +SyncMsgSender::SingleSentMessage* SyncMsgSender::RemoveMessage(int id) { + AutoLock lock(messages_lock_); + SentMessages::iterator it = messages_.find(id); + if (it == messages_.end()) { + // Delegate is not interested in this sync message response. + return NULL; + } + + // See what message is this. + SingleSentMessage* origin = it->second; + messages_.erase(it); + return origin; +} + +bool SyncMsgSender::OnReplyReceived(const IPC::Message* reply_msg) { + if (!reply_msg->is_reply()) + return false; // Not a reply to sync message. + + // Find message by id. + int id = IPC::SyncMessage::GetMessageId(*reply_msg); + SingleSentMessage* origin = RemoveMessage(id); + if (origin) { + DispatchReplyOk(reply_msg, origin->type_, origin->delegate_, origin->ctx_, + tab2delegate_); + delete origin; + } + + return true; +} + +void SyncMsgSender::OnChannelClosed() { + SentMessages messages_sent; + // Make a copy of the messages queue + { + AutoLock lock(messages_lock_); + messages_.swap(messages_sent); + } + + + SentMessages::reverse_iterator it = messages_sent.rbegin(); + for (; it != messages_sent.rend(); ++it) { + SingleSentMessage* origin = it->second; + DispatchReplyFail(origin->type_, origin->delegate_, origin->ctx_); + delete origin; + } + messages_sent.clear(); +} + +static base::AtomicSequenceNumber g_proxy_channel_id(base::LINKER_INITIALIZED); +std::string GenerateChannelId() { + return StringPrintf("ChromeTestingInterface:%u.%d", + base::GetCurrentProcId(), g_proxy_channel_id.GetNext() + 0xC000); +} + +std::wstring BuildCmdLine(const std::string& channel_id, + const FilePath& profile_path, + const std::wstring& extra_args) { + scoped_ptr<CommandLine> command_line( + chrome_launcher::CreateLaunchCommandLine()); + command_line->AppendSwitchASCII(switches::kAutomationClientChannelID, + channel_id); + // Run Chrome in Chrome Frame mode. In practice, this modifies the paths + // and registry keys that Chrome looks in via the BrowserDistribution + // mechanism. + command_line->AppendSwitch(switches::kChromeFrame); + // Chrome Frame never wants Chrome to start up with a First Run UI. + command_line->AppendSwitch(switches::kNoFirstRun); + command_line->AppendSwitch(switches::kDisablePopupBlocking); + +#ifndef NDEBUG + // Disable the "Whoa! Chrome has crashed." dialog, because that isn't very + // useful for Chrome Frame users. + command_line->AppendSwitch(switches::kNoErrorDialogs); +#endif + + // In headless mode runs like reliability test runs we want full crash dumps + // from chrome. + if (IsHeadlessMode()) + command_line->AppendSwitch(switches::kFullMemoryCrashReport); + + command_line->AppendSwitchPath(switches::kUserDataDir, profile_path); + + std::wstring command_line_string(command_line->command_line_string()); + if (!extra_args.empty()) { + command_line_string.append(L" "); + command_line_string.append(extra_args); + } + return command_line_string; +} + +int IsTabMessage(const IPC::Message& message) { + switch (message.type()) { + case AutomationMsg_NavigationStateChanged__ID: + case AutomationMsg_UpdateTargetUrl__ID: + case AutomationMsg_HandleAccelerator__ID: + case AutomationMsg_TabbedOut__ID: + case AutomationMsg_OpenURL__ID: + case AutomationMsg_NavigationFailed__ID: + case AutomationMsg_DidNavigate__ID: + case AutomationMsg_TabLoaded__ID: + case AutomationMsg_ForwardMessageToExternalHost__ID: + case AutomationMsg_ForwardContextMenuToExternalHost__ID: + case AutomationMsg_RequestStart__ID: + case AutomationMsg_RequestRead__ID: + case AutomationMsg_RequestEnd__ID: + case AutomationMsg_DownloadRequestInHost__ID: + case AutomationMsg_SetCookieAsync__ID: + case AutomationMsg_AttachExternalTab__ID: + case AutomationMsg_RequestGoToHistoryEntryOffset__ID: + case AutomationMsg_GetCookiesFromHost__ID: + case AutomationMsg_CloseExternalTab__ID: { + // Read tab handle from the message. + void* iter = NULL; + int tab_handle = 0; + message.ReadInt(&iter, &tab_handle); + return tab_handle; + } + } + + return 0; +} + +bool DispatchTabMessageToDelegate(ChromeProxyDelegate* delegate, + const IPC::Message& m) { + void* iter = 0; + switch (m.type()) { + case AutomationMsg_NavigationStateChanged__ID: { + // Tuple3<int, int, IPC::NavigationInfo> + AutomationMsg_NavigationStateChanged::Param params; + if (ReadParam(&m, &iter, ¶ms)) + delegate->NavigationStateChanged(params.b, params.c); + return true; + } + + case AutomationMsg_UpdateTargetUrl__ID: { + // Tuple2<int, std::wstring> + AutomationMsg_UpdateTargetUrl::Param params; + if (ReadParam(&m, &iter, ¶ms)) + delegate->UpdateTargetUrl(params.b); + return true; + } + + case AutomationMsg_HandleAccelerator__ID: { + AutomationMsg_HandleAccelerator::Param params; + return true; + } + + case AutomationMsg_TabbedOut__ID: { + AutomationMsg_TabbedOut::Param params; + return true; + } + + case AutomationMsg_OpenURL__ID: { + AutomationMsg_OpenURL::Param params; + return true; + } + + case AutomationMsg_NavigationFailed__ID: { + AutomationMsg_NavigationFailed::Param params; + return true; + } + + case AutomationMsg_DidNavigate__ID: { + AutomationMsg_DidNavigate::Param params; + return true; + } + + case AutomationMsg_TabLoaded__ID: { + return true; + } + case AutomationMsg_ForwardMessageToExternalHost__ID: { + return true; + } + + case AutomationMsg_ForwardContextMenuToExternalHost__ID: { + return true; + } + + case AutomationMsg_RequestStart__ID: { + return true; + } + + case AutomationMsg_RequestRead__ID: { + return true; + } + + case AutomationMsg_RequestEnd__ID: { + return true; + } + + case AutomationMsg_DownloadRequestInHost__ID: { + return true; + } + + case AutomationMsg_SetCookieAsync__ID: { + return true; + } + + case AutomationMsg_AttachExternalTab__ID: { + return true; + } + + case AutomationMsg_RequestGoToHistoryEntryOffset__ID: { + return true; + } + + case AutomationMsg_GetCookiesFromHost__ID: { + return true; + } + + case AutomationMsg_CloseExternalTab__ID: { + return true; + } + } + return true; +} |