[email protected] | 3b63f8f4 | 2011-03-28 01:54:15 | [diff] [blame] | 1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "chrome_frame/cfproxy_private.h" |
| 6 | |
[email protected] | 314a0696 | 2010-10-20 21:32:32 | [diff] [blame] | 7 | #include <vector> |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 8 | #include "base/atomic_sequence_num.h" |
| 9 | #include "base/command_line.h" |
[email protected] | 3b63f8f4 | 2011-03-28 01:54:15 | [diff] [blame] | 10 | #include "base/memory/scoped_ptr.h" |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 11 | #include "base/process_util.h" |
[email protected] | a8ba636 | 2010-11-10 20:02:25 | [diff] [blame] | 12 | #include "chrome/common/automation_messages.h" |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 13 | #include "chrome/common/chrome_switches.h" |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 14 | #include "chrome_frame/chrome_launcher_utils.h" |
| 15 | #include "chrome_frame/utils.h" // for IsHeadlessMode(); |
| 16 | |
| 17 | |
| 18 | namespace { |
| 19 | void DispatchReplyFail(uint32 type, |
| 20 | ChromeProxyDelegate* delegate, |
| 21 | SyncMessageContext* ctx) { |
| 22 | switch (type) { |
| 23 | case AutomationMsg_CreateExternalTab::ID: |
[email protected] | 751bf4b | 2010-11-05 22:06:31 | [diff] [blame] | 24 | delegate->Completed_CreateTab(false, NULL, NULL, 0, 0); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 25 | break; |
| 26 | case AutomationMsg_ConnectExternalTab::ID: |
[email protected] | 751bf4b | 2010-11-05 22:06:31 | [diff] [blame] | 27 | delegate->Completed_ConnectToTab(false, NULL, NULL, 0, 0); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 28 | break; |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 29 | } |
| 30 | } |
| 31 | |
| 32 | bool DispatchReplyOk(const IPC::Message* reply_msg, uint32 type, |
| 33 | ChromeProxyDelegate* delegate, SyncMessageContext* ctx, |
| 34 | TabsMap* tab2delegate) { |
| 35 | void* iter = IPC::SyncMessage::GetDataIterator(reply_msg); |
| 36 | switch (type) { |
| 37 | case AutomationMsg_CreateExternalTab::ID: { |
[email protected] | 751bf4b | 2010-11-05 22:06:31 | [diff] [blame] | 38 | // Tuple4<HWND, HWND, int, int> out; |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 39 | TupleTypes<AutomationMsg_CreateExternalTab::ReplyParam>::ValueTuple out; |
| 40 | if (ReadParam(reply_msg, &iter, &out)) { |
| 41 | DCHECK(tab2delegate->find(out.c) == tab2delegate->end()); |
| 42 | (*tab2delegate)[out.c] = delegate; |
[email protected] | 751bf4b | 2010-11-05 22:06:31 | [diff] [blame] | 43 | delegate->Completed_CreateTab(true, out.a, out.b, out.c, out.d); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 44 | } |
| 45 | return true; |
| 46 | } |
| 47 | |
| 48 | case AutomationMsg_ConnectExternalTab::ID: { |
[email protected] | 751bf4b | 2010-11-05 22:06:31 | [diff] [blame] | 49 | // Tuple4<HWND, HWND, int, int> out; |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 50 | TupleTypes<AutomationMsg_ConnectExternalTab::ReplyParam>::ValueTuple out; |
| 51 | if (ReadParam(reply_msg, &iter, &out)) { |
| 52 | DCHECK(tab2delegate->find(out.c) == tab2delegate->end()); |
| 53 | (*tab2delegate)[out.c] = delegate; |
[email protected] | 751bf4b | 2010-11-05 22:06:31 | [diff] [blame] | 54 | delegate->Completed_ConnectToTab(true, out.a, out.b, out.c, out.d); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 55 | } |
| 56 | return true; |
| 57 | } |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 58 | } // switch |
| 59 | |
| 60 | return false; |
| 61 | } |
| 62 | } // namespace |
| 63 | |
| 64 | // Itf2IPCMessage |
| 65 | // Converts and sends trivial messages. |
| 66 | void Interface2IPCMessage::RemoveBrowsingData(int mask) { |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 67 | sender_->Send(new AutomationMsg_RemoveBrowsingData(mask)); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 68 | } |
| 69 | |
| 70 | void Interface2IPCMessage::SetProxyConfig( |
| 71 | const std::string& json_encoded_proxy_cfg) { |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 72 | sender_->Send(new AutomationMsg_SetProxyConfig(json_encoded_proxy_cfg)); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 73 | } |
| 74 | |
| 75 | // Tab related. |
| 76 | void Interface2IPCMessage::Tab_PostMessage(int tab, const std::string& message, |
| 77 | const std::string& origin, const std::string& target) { |
| 78 | sender_->Send(new AutomationMsg_HandleMessageFromExternalHost( |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 79 | tab, message, origin, target)); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 80 | } |
| 81 | |
| 82 | void Interface2IPCMessage::Tab_Reload(int tab) { |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 83 | sender_->Send(new AutomationMsg_ReloadAsync(tab)); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 84 | } |
| 85 | |
| 86 | void Interface2IPCMessage::Tab_Stop(int tab) { |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 87 | sender_->Send(new AutomationMsg_StopAsync(tab)); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 88 | } |
| 89 | |
| 90 | void Interface2IPCMessage::Tab_SaveAs(int tab) { |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 91 | sender_->Send(new AutomationMsg_SaveAsAsync(tab)); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 92 | } |
| 93 | |
| 94 | void Interface2IPCMessage::Tab_Print(int tab) { |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 95 | sender_->Send(new AutomationMsg_PrintAsync(tab)); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 96 | } |
| 97 | |
| 98 | void Interface2IPCMessage::Tab_Cut(int tab) { |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 99 | sender_->Send(new AutomationMsg_Cut(tab)); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 100 | } |
| 101 | |
| 102 | void Interface2IPCMessage::Tab_Copy(int tab) { |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 103 | sender_->Send(new AutomationMsg_Copy(tab)); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 104 | } |
| 105 | |
| 106 | void Interface2IPCMessage::Tab_Paste(int tab) { |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 107 | sender_->Send(new AutomationMsg_Paste(tab)); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 108 | } |
| 109 | |
| 110 | void Interface2IPCMessage::Tab_SelectAll(int tab) { |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 111 | sender_->Send(new AutomationMsg_SelectAll(tab)); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 112 | } |
| 113 | |
| 114 | void Interface2IPCMessage::Tab_MenuCommand(int tab, int selected_command) { |
| 115 | sender_->Send(new AutomationMsg_ForwardContextMenuCommandToChrome( |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 116 | tab, selected_command)); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 117 | } |
| 118 | |
| 119 | void Interface2IPCMessage::Tab_Zoom(int tab, PageZoom::Function zoom_level) { |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 120 | sender_->Send(new AutomationMsg_SetZoomLevel(tab, zoom_level)); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 121 | } |
| 122 | |
| 123 | void Interface2IPCMessage::Tab_FontSize(int tab, |
| 124 | enum AutomationPageFontSize font_size) { |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 125 | sender_->Send(new AutomationMsg_SetPageFontSize(tab, font_size)); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 126 | } |
| 127 | |
| 128 | void Interface2IPCMessage::Tab_SetInitialFocus(int tab, bool reverse, |
| 129 | bool restore_focus_to_view) { |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 130 | sender_->Send(new AutomationMsg_SetInitialFocus(tab, reverse, |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 131 | restore_focus_to_view)); |
| 132 | } |
| 133 | |
| 134 | void Interface2IPCMessage::Tab_SetParentWindow(int tab) { |
| 135 | CHECK(0) << "Implement me"; |
| 136 | // AutomationMsg_TabReposition |
| 137 | } |
| 138 | |
| 139 | void Interface2IPCMessage::Tab_Resize(int tab) { |
| 140 | CHECK(0) << "Implement me"; |
| 141 | // AutomationMsg_TabReposition |
| 142 | } |
| 143 | |
| 144 | void Interface2IPCMessage::Tab_ProcessAccelerator(int tab, const MSG& msg) { |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 145 | sender_->Send(new AutomationMsg_ProcessUnhandledAccelerator(tab, msg)); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 146 | } |
| 147 | |
| 148 | // Misc. |
| 149 | void Interface2IPCMessage::Tab_OnHostMoved(int tab) { |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 150 | sender_->Send(new AutomationMsg_BrowserMove(tab)); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 151 | } |
| 152 | |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 153 | void DelegateHolder::AddDelegate(ChromeProxyDelegate* p) { |
| 154 | delegate_list_.insert(p); |
| 155 | } |
| 156 | |
| 157 | void DelegateHolder::RemoveDelegate(ChromeProxyDelegate* p) { |
| 158 | // DCHECK(CalledOnValidThread()); |
| 159 | int tab_handle = p->tab_handle(); // Could be 0. |
| 160 | delegate_list_.erase(p); |
| 161 | tab2delegate_.erase(tab_handle); |
| 162 | } |
| 163 | |
| 164 | ChromeProxyDelegate* DelegateHolder::Tab2Delegate(int tab_handle) { |
| 165 | TabsMap::const_iterator iter = tab2delegate_.find(tab_handle); |
| 166 | if (iter != tab2delegate_.end()) |
| 167 | return iter->second; |
| 168 | return NULL; |
| 169 | } |
| 170 | |
| 171 | SyncMsgSender::SyncMsgSender(TabsMap* tab2delegate) |
| 172 | : tab2delegate_(tab2delegate) { |
| 173 | } |
| 174 | |
| 175 | // The outgoing queue of sync messages must be locked. |
| 176 | // Case: ui thread is sending message and waits for event, that is going to be |
| 177 | // signaled by completion handler in ipc_thread. |
| 178 | // We must append the message to the outgoing queue in UI thread, |
| 179 | // otherwise if channel is disconnected before having a chance to |
| 180 | // send the message, the ChromeProxyDelegate::_Disconnect implementation |
| 181 | // shall know how to unblock arbitrary sync call. Instead |
| 182 | // ChromeProxyDelgate::Completed_XXXX knows how to unblock a specific one. |
| 183 | void SyncMsgSender::QueueSyncMessage(const IPC::SyncMessage* msg, |
| 184 | ChromeProxyDelegate* delegate, |
| 185 | SyncMessageContext* ctx) { |
| 186 | if (delegate) { |
| 187 | // We are interested of the result. |
[email protected] | 20305ec | 2011-01-21 04:55:52 | [diff] [blame] | 188 | base::AutoLock lock(messages_lock_); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 189 | int id = IPC::SyncMessage::GetMessageId(*msg); |
| 190 | // A message can be sent only once. |
| 191 | DCHECK(messages_.end() == messages_.find(id)); |
| 192 | messages_[id] = new SingleSentMessage(msg->type(), delegate, ctx); |
| 193 | } |
| 194 | } |
| 195 | |
[email protected] | 314a0696 | 2010-10-20 21:32:32 | [diff] [blame] | 196 | // Cancel all outgoing calls for this delegate. |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 197 | void SyncMsgSender::Cancel(ChromeProxyDelegate* delegate) { |
[email protected] | 314a0696 | 2010-10-20 21:32:32 | [diff] [blame] | 198 | std::vector<SingleSentMessage*> cancelled; |
| 199 | { |
[email protected] | 20305ec | 2011-01-21 04:55:52 | [diff] [blame] | 200 | base::AutoLock lock(messages_lock_); |
[email protected] | 314a0696 | 2010-10-20 21:32:32 | [diff] [blame] | 201 | SentMessages::iterator it = messages_.begin(); |
| 202 | for (; it != messages_.end(); ) { |
| 203 | SingleSentMessage* origin = it->second; |
| 204 | if (origin->delegate_ == delegate) { |
| 205 | cancelled.push_back(origin); |
| 206 | it = messages_.erase(it); |
| 207 | } else { |
| 208 | ++it; |
| 209 | } |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | for (std::vector<SingleSentMessage*>::iterator it = cancelled.begin(); |
| 214 | it != cancelled.end(); ++it) { |
| 215 | SingleSentMessage* origin = *it; |
| 216 | DispatchReplyFail(origin->type_, delegate, origin->ctx_); |
| 217 | delete origin; |
| 218 | } |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 219 | } |
| 220 | |
| 221 | SyncMsgSender::SingleSentMessage* SyncMsgSender::RemoveMessage(int id) { |
[email protected] | 20305ec | 2011-01-21 04:55:52 | [diff] [blame] | 222 | base::AutoLock lock(messages_lock_); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 223 | SentMessages::iterator it = messages_.find(id); |
| 224 | if (it == messages_.end()) { |
| 225 | // Delegate is not interested in this sync message response. |
| 226 | return NULL; |
| 227 | } |
| 228 | |
| 229 | // See what message is this. |
| 230 | SingleSentMessage* origin = it->second; |
| 231 | messages_.erase(it); |
| 232 | return origin; |
| 233 | } |
| 234 | |
| 235 | bool SyncMsgSender::OnReplyReceived(const IPC::Message* reply_msg) { |
| 236 | if (!reply_msg->is_reply()) |
| 237 | return false; // Not a reply to sync message. |
| 238 | |
| 239 | // Find message by id. |
| 240 | int id = IPC::SyncMessage::GetMessageId(*reply_msg); |
| 241 | SingleSentMessage* origin = RemoveMessage(id); |
| 242 | if (origin) { |
| 243 | DispatchReplyOk(reply_msg, origin->type_, origin->delegate_, origin->ctx_, |
| 244 | tab2delegate_); |
| 245 | delete origin; |
| 246 | } |
| 247 | |
| 248 | return true; |
| 249 | } |
| 250 | |
| 251 | void SyncMsgSender::OnChannelClosed() { |
| 252 | SentMessages messages_sent; |
| 253 | // Make a copy of the messages queue |
| 254 | { |
[email protected] | 20305ec | 2011-01-21 04:55:52 | [diff] [blame] | 255 | base::AutoLock lock(messages_lock_); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 256 | messages_.swap(messages_sent); |
| 257 | } |
| 258 | |
| 259 | |
| 260 | SentMessages::reverse_iterator it = messages_sent.rbegin(); |
| 261 | for (; it != messages_sent.rend(); ++it) { |
| 262 | SingleSentMessage* origin = it->second; |
| 263 | DispatchReplyFail(origin->type_, origin->delegate_, origin->ctx_); |
| 264 | delete origin; |
| 265 | } |
| 266 | messages_sent.clear(); |
| 267 | } |
| 268 | |
| 269 | static base::AtomicSequenceNumber g_proxy_channel_id(base::LINKER_INITIALIZED); |
| 270 | std::string GenerateChannelId() { |
| 271 | return StringPrintf("ChromeTestingInterface:%u.%d", |
| 272 | base::GetCurrentProcId(), g_proxy_channel_id.GetNext() + 0xC000); |
| 273 | } |
| 274 | |
| 275 | std::wstring BuildCmdLine(const std::string& channel_id, |
| 276 | const FilePath& profile_path, |
| 277 | const std::wstring& extra_args) { |
| 278 | scoped_ptr<CommandLine> command_line( |
| 279 | chrome_launcher::CreateLaunchCommandLine()); |
| 280 | command_line->AppendSwitchASCII(switches::kAutomationClientChannelID, |
| 281 | channel_id); |
| 282 | // Run Chrome in Chrome Frame mode. In practice, this modifies the paths |
| 283 | // and registry keys that Chrome looks in via the BrowserDistribution |
| 284 | // mechanism. |
| 285 | command_line->AppendSwitch(switches::kChromeFrame); |
| 286 | // Chrome Frame never wants Chrome to start up with a First Run UI. |
| 287 | command_line->AppendSwitch(switches::kNoFirstRun); |
| 288 | command_line->AppendSwitch(switches::kDisablePopupBlocking); |
| 289 | |
| 290 | #ifndef NDEBUG |
| 291 | // Disable the "Whoa! Chrome has crashed." dialog, because that isn't very |
| 292 | // useful for Chrome Frame users. |
| 293 | command_line->AppendSwitch(switches::kNoErrorDialogs); |
| 294 | #endif |
| 295 | |
| 296 | // In headless mode runs like reliability test runs we want full crash dumps |
| 297 | // from chrome. |
| 298 | if (IsHeadlessMode()) |
| 299 | command_line->AppendSwitch(switches::kFullMemoryCrashReport); |
| 300 | |
| 301 | command_line->AppendSwitchPath(switches::kUserDataDir, profile_path); |
| 302 | |
[email protected] | 61a4c6f | 2011-07-20 04:54:52 | [diff] [blame] | 303 | std::wstring command_line_string(command_line->GetCommandLineString()); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 304 | if (!extra_args.empty()) { |
| 305 | command_line_string.append(L" "); |
| 306 | command_line_string.append(extra_args); |
| 307 | } |
| 308 | return command_line_string; |
| 309 | } |