blob: 4e7d807089cbfc25de9bda9c15aab443fc316cc2 [file] [log] [blame]
[email protected]3b63f8f42011-03-28 01:54:151// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]5a8db802010-10-06 17:34:432// 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]314a06962010-10-20 21:32:327#include <vector>
[email protected]5a8db802010-10-06 17:34:438#include "base/atomic_sequence_num.h"
9#include "base/command_line.h"
[email protected]3b63f8f42011-03-28 01:54:1510#include "base/memory/scoped_ptr.h"
[email protected]5a8db802010-10-06 17:34:4311#include "base/process_util.h"
[email protected]a8ba6362010-11-10 20:02:2512#include "chrome/common/automation_messages.h"
[email protected]5a8db802010-10-06 17:34:4313#include "chrome/common/chrome_switches.h"
[email protected]5a8db802010-10-06 17:34:4314#include "chrome_frame/chrome_launcher_utils.h"
15#include "chrome_frame/utils.h" // for IsHeadlessMode();
16
17
18namespace {
19void DispatchReplyFail(uint32 type,
20 ChromeProxyDelegate* delegate,
21 SyncMessageContext* ctx) {
22 switch (type) {
23 case AutomationMsg_CreateExternalTab::ID:
[email protected]751bf4b2010-11-05 22:06:3124 delegate->Completed_CreateTab(false, NULL, NULL, 0, 0);
[email protected]5a8db802010-10-06 17:34:4325 break;
26 case AutomationMsg_ConnectExternalTab::ID:
[email protected]751bf4b2010-11-05 22:06:3127 delegate->Completed_ConnectToTab(false, NULL, NULL, 0, 0);
[email protected]5a8db802010-10-06 17:34:4328 break;
[email protected]5a8db802010-10-06 17:34:4329 }
30}
31
32bool 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]751bf4b2010-11-05 22:06:3138 // Tuple4<HWND, HWND, int, int> out;
[email protected]5a8db802010-10-06 17:34:4339 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]751bf4b2010-11-05 22:06:3143 delegate->Completed_CreateTab(true, out.a, out.b, out.c, out.d);
[email protected]5a8db802010-10-06 17:34:4344 }
45 return true;
46 }
47
48 case AutomationMsg_ConnectExternalTab::ID: {
[email protected]751bf4b2010-11-05 22:06:3149 // Tuple4<HWND, HWND, int, int> out;
[email protected]5a8db802010-10-06 17:34:4350 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]751bf4b2010-11-05 22:06:3154 delegate->Completed_ConnectToTab(true, out.a, out.b, out.c, out.d);
[email protected]5a8db802010-10-06 17:34:4355 }
56 return true;
57 }
[email protected]5a8db802010-10-06 17:34:4358 } // switch
59
60 return false;
61}
62} // namespace
63
64// Itf2IPCMessage
65// Converts and sends trivial messages.
66void Interface2IPCMessage::RemoveBrowsingData(int mask) {
[email protected]f5494d42010-12-23 22:15:3467 sender_->Send(new AutomationMsg_RemoveBrowsingData(mask));
[email protected]5a8db802010-10-06 17:34:4368}
69
70void Interface2IPCMessage::SetProxyConfig(
71 const std::string& json_encoded_proxy_cfg) {
[email protected]f5494d42010-12-23 22:15:3472 sender_->Send(new AutomationMsg_SetProxyConfig(json_encoded_proxy_cfg));
[email protected]5a8db802010-10-06 17:34:4373}
74
75// Tab related.
76void 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]f5494d42010-12-23 22:15:3479 tab, message, origin, target));
[email protected]5a8db802010-10-06 17:34:4380}
81
82void Interface2IPCMessage::Tab_Reload(int tab) {
[email protected]f5494d42010-12-23 22:15:3483 sender_->Send(new AutomationMsg_ReloadAsync(tab));
[email protected]5a8db802010-10-06 17:34:4384}
85
86void Interface2IPCMessage::Tab_Stop(int tab) {
[email protected]f5494d42010-12-23 22:15:3487 sender_->Send(new AutomationMsg_StopAsync(tab));
[email protected]5a8db802010-10-06 17:34:4388}
89
90void Interface2IPCMessage::Tab_SaveAs(int tab) {
[email protected]f5494d42010-12-23 22:15:3491 sender_->Send(new AutomationMsg_SaveAsAsync(tab));
[email protected]5a8db802010-10-06 17:34:4392}
93
94void Interface2IPCMessage::Tab_Print(int tab) {
[email protected]f5494d42010-12-23 22:15:3495 sender_->Send(new AutomationMsg_PrintAsync(tab));
[email protected]5a8db802010-10-06 17:34:4396}
97
98void Interface2IPCMessage::Tab_Cut(int tab) {
[email protected]f5494d42010-12-23 22:15:3499 sender_->Send(new AutomationMsg_Cut(tab));
[email protected]5a8db802010-10-06 17:34:43100}
101
102void Interface2IPCMessage::Tab_Copy(int tab) {
[email protected]f5494d42010-12-23 22:15:34103 sender_->Send(new AutomationMsg_Copy(tab));
[email protected]5a8db802010-10-06 17:34:43104}
105
106void Interface2IPCMessage::Tab_Paste(int tab) {
[email protected]f5494d42010-12-23 22:15:34107 sender_->Send(new AutomationMsg_Paste(tab));
[email protected]5a8db802010-10-06 17:34:43108}
109
110void Interface2IPCMessage::Tab_SelectAll(int tab) {
[email protected]f5494d42010-12-23 22:15:34111 sender_->Send(new AutomationMsg_SelectAll(tab));
[email protected]5a8db802010-10-06 17:34:43112}
113
114void Interface2IPCMessage::Tab_MenuCommand(int tab, int selected_command) {
115 sender_->Send(new AutomationMsg_ForwardContextMenuCommandToChrome(
[email protected]f5494d42010-12-23 22:15:34116 tab, selected_command));
[email protected]5a8db802010-10-06 17:34:43117}
118
119void Interface2IPCMessage::Tab_Zoom(int tab, PageZoom::Function zoom_level) {
[email protected]f5494d42010-12-23 22:15:34120 sender_->Send(new AutomationMsg_SetZoomLevel(tab, zoom_level));
[email protected]5a8db802010-10-06 17:34:43121}
122
123void Interface2IPCMessage::Tab_FontSize(int tab,
124 enum AutomationPageFontSize font_size) {
[email protected]f5494d42010-12-23 22:15:34125 sender_->Send(new AutomationMsg_SetPageFontSize(tab, font_size));
[email protected]5a8db802010-10-06 17:34:43126}
127
128void Interface2IPCMessage::Tab_SetInitialFocus(int tab, bool reverse,
129 bool restore_focus_to_view) {
[email protected]f5494d42010-12-23 22:15:34130 sender_->Send(new AutomationMsg_SetInitialFocus(tab, reverse,
[email protected]5a8db802010-10-06 17:34:43131 restore_focus_to_view));
132}
133
134void Interface2IPCMessage::Tab_SetParentWindow(int tab) {
135 CHECK(0) << "Implement me";
136 // AutomationMsg_TabReposition
137}
138
139void Interface2IPCMessage::Tab_Resize(int tab) {
140 CHECK(0) << "Implement me";
141 // AutomationMsg_TabReposition
142}
143
144void Interface2IPCMessage::Tab_ProcessAccelerator(int tab, const MSG& msg) {
[email protected]f5494d42010-12-23 22:15:34145 sender_->Send(new AutomationMsg_ProcessUnhandledAccelerator(tab, msg));
[email protected]5a8db802010-10-06 17:34:43146}
147
148// Misc.
149void Interface2IPCMessage::Tab_OnHostMoved(int tab) {
[email protected]f5494d42010-12-23 22:15:34150 sender_->Send(new AutomationMsg_BrowserMove(tab));
[email protected]5a8db802010-10-06 17:34:43151}
152
[email protected]5a8db802010-10-06 17:34:43153void DelegateHolder::AddDelegate(ChromeProxyDelegate* p) {
154 delegate_list_.insert(p);
155}
156
157void 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
164ChromeProxyDelegate* 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
171SyncMsgSender::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.
183void SyncMsgSender::QueueSyncMessage(const IPC::SyncMessage* msg,
184 ChromeProxyDelegate* delegate,
185 SyncMessageContext* ctx) {
186 if (delegate) {
187 // We are interested of the result.
[email protected]20305ec2011-01-21 04:55:52188 base::AutoLock lock(messages_lock_);
[email protected]5a8db802010-10-06 17:34:43189 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]314a06962010-10-20 21:32:32196// Cancel all outgoing calls for this delegate.
[email protected]5a8db802010-10-06 17:34:43197void SyncMsgSender::Cancel(ChromeProxyDelegate* delegate) {
[email protected]314a06962010-10-20 21:32:32198 std::vector<SingleSentMessage*> cancelled;
199 {
[email protected]20305ec2011-01-21 04:55:52200 base::AutoLock lock(messages_lock_);
[email protected]314a06962010-10-20 21:32:32201 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]5a8db802010-10-06 17:34:43219}
220
221SyncMsgSender::SingleSentMessage* SyncMsgSender::RemoveMessage(int id) {
[email protected]20305ec2011-01-21 04:55:52222 base::AutoLock lock(messages_lock_);
[email protected]5a8db802010-10-06 17:34:43223 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
235bool 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
251void SyncMsgSender::OnChannelClosed() {
252 SentMessages messages_sent;
253 // Make a copy of the messages queue
254 {
[email protected]20305ec2011-01-21 04:55:52255 base::AutoLock lock(messages_lock_);
[email protected]5a8db802010-10-06 17:34:43256 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
269static base::AtomicSequenceNumber g_proxy_channel_id(base::LINKER_INITIALIZED);
270std::string GenerateChannelId() {
271 return StringPrintf("ChromeTestingInterface:%u.%d",
272 base::GetCurrentProcId(), g_proxy_channel_id.GetNext() + 0xC000);
273}
274
275std::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]61a4c6f2011-07-20 04:54:52303 std::wstring command_line_string(command_line->GetCommandLineString());
[email protected]5a8db802010-10-06 17:34:43304 if (!extra_args.empty()) {
305 command_line_string.append(L" ");
306 command_line_string.append(extra_args);
307 }
308 return command_line_string;
309}