summaryrefslogtreecommitdiffstats
path: root/chrome_frame/cfproxy_support.cc
blob: 4e7d807089cbfc25de9bda9c15aab443fc316cc2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
// Copyright (c) 2011 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 <vector>
#include "base/atomic_sequence_num.h"
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "base/process_util.h"
#include "chrome/common/automation_messages.h"
#include "chrome/common/chrome_switches.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, 0, 0);
      break;
    case AutomationMsg_ConnectExternalTab::ID:
      delegate->Completed_ConnectToTab(false, NULL, NULL, 0, 0);
      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: {
      // Tuple4<HWND, HWND, int, 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, out.d);
      }
      return true;
    }

    case AutomationMsg_ConnectExternalTab::ID: {
      // Tuple4<HWND, HWND, int, 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, out.d);
      }
      return true;
    }
  }  // switch

  return false;
}
}  // namespace

// Itf2IPCMessage
// Converts and sends trivial messages.
void Interface2IPCMessage::RemoveBrowsingData(int mask) {
  sender_->Send(new AutomationMsg_RemoveBrowsingData(mask));
}

void Interface2IPCMessage::SetProxyConfig(
    const std::string& json_encoded_proxy_cfg) {
  sender_->Send(new AutomationMsg_SetProxyConfig(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(
      tab, message, origin, target));
}

void Interface2IPCMessage::Tab_Reload(int tab) {
  sender_->Send(new AutomationMsg_ReloadAsync(tab));
}

void Interface2IPCMessage::Tab_Stop(int tab) {
  sender_->Send(new AutomationMsg_StopAsync(tab));
}

void Interface2IPCMessage::Tab_SaveAs(int tab) {
  sender_->Send(new AutomationMsg_SaveAsAsync(tab));
}

void Interface2IPCMessage::Tab_Print(int tab) {
  sender_->Send(new AutomationMsg_PrintAsync(tab));
}

void Interface2IPCMessage::Tab_Cut(int tab) {
  sender_->Send(new AutomationMsg_Cut(tab));
}

void Interface2IPCMessage::Tab_Copy(int tab) {
  sender_->Send(new AutomationMsg_Copy(tab));
}

void Interface2IPCMessage::Tab_Paste(int tab) {
  sender_->Send(new AutomationMsg_Paste(tab));
}

void Interface2IPCMessage::Tab_SelectAll(int tab) {
  sender_->Send(new AutomationMsg_SelectAll(tab));
}

void Interface2IPCMessage::Tab_MenuCommand(int tab, int selected_command) {
  sender_->Send(new AutomationMsg_ForwardContextMenuCommandToChrome(
      tab, selected_command));
}

void Interface2IPCMessage::Tab_Zoom(int tab, PageZoom::Function zoom_level) {
  sender_->Send(new AutomationMsg_SetZoomLevel(tab, zoom_level));
}

void Interface2IPCMessage::Tab_FontSize(int tab,
                                        enum AutomationPageFontSize font_size) {
  sender_->Send(new AutomationMsg_SetPageFontSize(tab, font_size));
}

void Interface2IPCMessage::Tab_SetInitialFocus(int tab, bool reverse,
                                         bool restore_focus_to_view) {
  sender_->Send(new AutomationMsg_SetInitialFocus(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(tab, msg));
}

// Misc.
void Interface2IPCMessage::Tab_OnHostMoved(int tab) {
  sender_->Send(new AutomationMsg_BrowserMove(tab));
}

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.
    base::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);
  }
}

// Cancel all outgoing calls for this delegate.
void SyncMsgSender::Cancel(ChromeProxyDelegate* delegate) {
  std::vector<SingleSentMessage*> cancelled;
  {
    base::AutoLock lock(messages_lock_);
    SentMessages::iterator it = messages_.begin();
    for (; it != messages_.end(); ) {
      SingleSentMessage* origin = it->second;
      if (origin->delegate_ == delegate) {
        cancelled.push_back(origin);
        it = messages_.erase(it);
      } else {
        ++it;
      }
    }
  }

  for (std::vector<SingleSentMessage*>::iterator it = cancelled.begin();
       it != cancelled.end(); ++it) {
    SingleSentMessage* origin = *it;
    DispatchReplyFail(origin->type_, delegate, origin->ctx_);
    delete origin;
  }
}

SyncMsgSender::SingleSentMessage* SyncMsgSender::RemoveMessage(int id) {
  base::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
  {
    base::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->GetCommandLineString());
  if (!extra_args.empty()) {
    command_line_string.append(L" ");
    command_line_string.append(extra_args);
  }
  return command_line_string;
}