OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef CHROME_FRAME_CHROME_FRAME_AUTOMATION_H_ | |
6 #define CHROME_FRAME_CHROME_FRAME_AUTOMATION_H_ | |
7 | |
8 #include <atlbase.h> | |
9 #include <atlwin.h> | |
10 #include <map> | |
11 #include <string> | |
12 #include <vector> | |
13 | |
14 #include "base/containers/stack_container.h" | |
15 #include "base/memory/ref_counted.h" | |
16 #include "base/memory/scoped_handle.h" | |
17 #include "base/synchronization/lock.h" | |
18 #include "base/threading/thread.h" | |
19 #include "base/timer/timer.h" | |
20 #include "chrome/test/automation/automation_proxy.h" | |
21 #include "chrome/test/automation/tab_proxy.h" | |
22 #include "chrome_frame/chrome_frame_delegate.h" | |
23 #include "chrome_frame/plugin_url_request.h" | |
24 #include "chrome_frame/sync_msg_reply_dispatcher.h" | |
25 #include "content/public/common/page_zoom.h" | |
26 | |
27 // By a convoluated route, this timeout also winds up being the sync automation | |
28 // message timeout. See the ChromeFrameAutomationProxyImpl ctor and the | |
29 // AutomationProxy ctor for details. | |
30 const unsigned long kCommandExecutionTimeout = 60000; // NOLINT, 60 seconds | |
31 | |
32 class ProxyFactory; | |
33 class NavigationConstraints; | |
34 enum AutomationPageFontSize; | |
35 | |
36 struct DECLSPEC_NOVTABLE ChromeFrameAutomationProxy { // NOLINT | |
37 virtual bool Send(IPC::Message* msg) = 0; | |
38 | |
39 virtual void SendAsAsync( | |
40 IPC::SyncMessage* msg, | |
41 SyncMessageReplyDispatcher::SyncMessageCallContext* context, | |
42 void* key) = 0; | |
43 virtual void CancelAsync(void* key) = 0; | |
44 virtual scoped_refptr<TabProxy> CreateTabProxy(int handle) = 0; | |
45 virtual void ReleaseTabProxy(AutomationHandle handle) = 0; | |
46 virtual std::string server_version() = 0; | |
47 | |
48 protected: | |
49 virtual ~ChromeFrameAutomationProxy() {} | |
50 }; | |
51 | |
52 // Forward declarations. | |
53 class ProxyFactory; | |
54 | |
55 // We extend the AutomationProxy class to handle our custom | |
56 // IPC messages | |
57 class ChromeFrameAutomationProxyImpl | |
58 : public ChromeFrameAutomationProxy, | |
59 // We have to derive from automationproxy since we want access to some | |
60 // members (tracker_ & channel_) - simple aggregation wont work; | |
61 // .. and non-public inheritance is verboten. | |
62 public AutomationProxy { | |
63 public: | |
64 ~ChromeFrameAutomationProxyImpl(); | |
65 virtual void SendAsAsync( | |
66 IPC::SyncMessage* msg, | |
67 SyncMessageReplyDispatcher::SyncMessageCallContext* context, | |
68 void* key); | |
69 | |
70 // Called on the worker thread. | |
71 virtual void OnChannelError(); | |
72 | |
73 virtual void CancelAsync(void* key); | |
74 | |
75 virtual scoped_refptr<TabProxy> CreateTabProxy(int handle); | |
76 virtual void ReleaseTabProxy(AutomationHandle handle); | |
77 | |
78 virtual std::string server_version() { | |
79 return AutomationProxy::server_version(); | |
80 } | |
81 | |
82 virtual bool Send(IPC::Message* msg) { | |
83 return AutomationProxy::Send(msg); | |
84 } | |
85 | |
86 protected: | |
87 friend class AutomationProxyCacheEntry; | |
88 ChromeFrameAutomationProxyImpl(AutomationProxyCacheEntry* entry, | |
89 std::string channel_id, | |
90 base::TimeDelta launch_timeout); | |
91 | |
92 class CFMsgDispatcher; | |
93 class TabProxyNotificationMessageFilter; | |
94 | |
95 scoped_refptr<CFMsgDispatcher> sync_; | |
96 scoped_refptr<TabProxyNotificationMessageFilter> message_filter_; | |
97 AutomationProxyCacheEntry* proxy_entry_; | |
98 }; | |
99 | |
100 // This class contains information used for launching chrome. | |
101 class ChromeFrameLaunchParams : // NOLINT | |
102 public base::RefCountedThreadSafe<ChromeFrameLaunchParams> { | |
103 public: | |
104 ChromeFrameLaunchParams(const GURL& url, const GURL& referrer, | |
105 const base::FilePath& profile_path, | |
106 const std::wstring& profile_name, | |
107 const std::wstring& language, | |
108 bool incognito, bool widget_mode, | |
109 bool route_all_top_level_navigations) | |
110 : launch_timeout_(kCommandExecutionTimeout), url_(url), | |
111 referrer_(referrer), profile_path_(profile_path), | |
112 profile_name_(profile_name), language_(language), | |
113 version_check_(true), incognito_mode_(incognito), | |
114 is_widget_mode_(widget_mode), | |
115 route_all_top_level_navigations_(route_all_top_level_navigations) { | |
116 } | |
117 | |
118 ~ChromeFrameLaunchParams() { | |
119 } | |
120 | |
121 void set_launch_timeout(int timeout) { | |
122 launch_timeout_ = timeout; | |
123 } | |
124 | |
125 int launch_timeout() const { | |
126 return launch_timeout_; | |
127 } | |
128 | |
129 const GURL& url() const { | |
130 return url_; | |
131 } | |
132 | |
133 void set_url(const GURL& url) { | |
134 url_ = url; | |
135 } | |
136 | |
137 const GURL& referrer() const { | |
138 return referrer_; | |
139 } | |
140 | |
141 void set_referrer(const GURL& referrer) { | |
142 referrer_ = referrer; | |
143 } | |
144 | |
145 const base::FilePath& profile_path() const { | |
146 return profile_path_; | |
147 } | |
148 | |
149 const std::wstring& profile_name() const { | |
150 return profile_name_; | |
151 } | |
152 | |
153 const std::wstring& language() const { | |
154 return language_; | |
155 } | |
156 | |
157 bool version_check() const { | |
158 return version_check_; | |
159 } | |
160 | |
161 void set_version_check(bool check) { | |
162 version_check_ = check; | |
163 } | |
164 | |
165 bool incognito() const { | |
166 return incognito_mode_; | |
167 } | |
168 | |
169 bool widget_mode() const { | |
170 return is_widget_mode_; | |
171 } | |
172 | |
173 void set_route_all_top_level_navigations( | |
174 bool route_all_top_level_navigations) { | |
175 route_all_top_level_navigations_ = route_all_top_level_navigations; | |
176 } | |
177 | |
178 bool route_all_top_level_navigations() const { | |
179 return route_all_top_level_navigations_; | |
180 } | |
181 | |
182 protected: | |
183 int launch_timeout_; | |
184 GURL url_; | |
185 GURL referrer_; | |
186 base::FilePath profile_path_; | |
187 std::wstring profile_name_; | |
188 std::wstring language_; | |
189 bool version_check_; | |
190 bool incognito_mode_; | |
191 bool is_widget_mode_; | |
192 bool route_all_top_level_navigations_; | |
193 | |
194 private: | |
195 DISALLOW_COPY_AND_ASSIGN(ChromeFrameLaunchParams); | |
196 }; | |
197 | |
198 // Callback when chrome process launch is complete and automation handshake | |
199 // (Hello message) is established. All methods are invoked on the automation | |
200 // proxy's worker thread. | |
201 struct DECLSPEC_NOVTABLE LaunchDelegate { // NOLINT | |
202 virtual void LaunchComplete(ChromeFrameAutomationProxy* proxy, | |
203 AutomationLaunchResult result) = 0; | |
204 virtual void AutomationServerDied() = 0; | |
205 }; // NOLINT | |
206 | |
207 // Manages a cached ChromeFrameAutomationProxyImpl entry and holds | |
208 // reference-less pointers to LaunchDelegate(s) to be notified in case | |
209 // of automation server process changes. | |
210 class AutomationProxyCacheEntry | |
211 : public base::RefCounted<AutomationProxyCacheEntry> { | |
212 public: | |
213 AutomationProxyCacheEntry(ChromeFrameLaunchParams* params, | |
214 LaunchDelegate* delegate); | |
215 | |
216 ~AutomationProxyCacheEntry(); | |
217 | |
218 void AddDelegate(LaunchDelegate* delegate); | |
219 void RemoveDelegate(LaunchDelegate* delegate, base::WaitableEvent* done, | |
220 bool* was_last_delegate); | |
221 | |
222 DWORD WaitForThread(DWORD timeout) { // NOLINT | |
223 DCHECK(thread_.get()); | |
224 return ::WaitForSingleObject(thread_->thread_handle().platform_handle(), | |
225 timeout); | |
226 } | |
227 | |
228 bool IsSameProfile(const std::wstring& name) const { | |
229 return lstrcmpiW(name.c_str(), profile_name.c_str()) == 0; | |
230 } | |
231 | |
232 base::Thread* thread() const { | |
233 return thread_.get(); | |
234 } | |
235 | |
236 base::MessageLoop* message_loop() const { | |
237 return thread_->message_loop(); | |
238 } | |
239 | |
240 bool IsSameThread(base::PlatformThreadId id) const { | |
241 return thread_->thread_id() == id; | |
242 } | |
243 | |
244 ChromeFrameAutomationProxyImpl* proxy() const { | |
245 DCHECK(IsSameThread(base::PlatformThread::CurrentId())); | |
246 return proxy_.get(); | |
247 } | |
248 | |
249 // Called by the proxy when the automation server has unexpectedly gone away. | |
250 void OnChannelError(); | |
251 | |
252 protected: | |
253 void CreateProxy(ChromeFrameLaunchParams* params, | |
254 LaunchDelegate* delegate); | |
255 | |
256 protected: | |
257 std::wstring profile_name; | |
258 scoped_ptr<base::Thread> thread_; | |
259 scoped_ptr<ChromeFrameAutomationProxyImpl> proxy_; | |
260 AutomationLaunchResult launch_result_; | |
261 typedef std::vector<LaunchDelegate*> LaunchDelegates; | |
262 LaunchDelegates launch_delegates_; | |
263 // Used for UMA histogram logging to measure the time for the chrome | |
264 // automation server to start; | |
265 base::TimeTicks automation_server_launch_start_time_; | |
266 }; | |
267 | |
268 // We must create and destroy automation proxy in a thread with a message loop. | |
269 // Hence thread cannot be a member of the proxy. | |
270 class ProxyFactory { | |
271 public: | |
272 ProxyFactory(); | |
273 virtual ~ProxyFactory(); | |
274 | |
275 // Fetches or creates a new automation server instance. | |
276 // delegate may be NULL. If non-null, a pointer to the delegate will | |
277 // be stored for the lifetime of the automation process or until | |
278 // ReleaseAutomationServer is called. | |
279 virtual void GetAutomationServer(LaunchDelegate* delegate, | |
280 ChromeFrameLaunchParams* params, | |
281 void** automation_server_id); | |
282 virtual bool ReleaseAutomationServer(void* server_id, | |
283 LaunchDelegate* delegate); | |
284 | |
285 private: | |
286 typedef base::StackVector<scoped_refptr<AutomationProxyCacheEntry>, 4> Vector; | |
287 Vector proxies_; | |
288 // Lock if we are going to call GetAutomationServer from more than one thread. | |
289 base::Lock lock_; | |
290 }; | |
291 | |
292 // Handles all automation requests initiated from the chrome frame objects. | |
293 // These include the chrome tab/chrome frame activex plugin objects. | |
294 class ChromeFrameAutomationClient | |
295 : public CWindowImpl<ChromeFrameAutomationClient>, | |
296 public TaskMarshallerThroughWindowsMessages<ChromeFrameAutomationClient>, | |
297 public base::RefCountedThreadSafe<ChromeFrameAutomationClient>, | |
298 public PluginUrlRequestDelegate, | |
299 public TabProxy::TabProxyDelegate, | |
300 public LaunchDelegate { | |
301 public: | |
302 ChromeFrameAutomationClient(); | |
303 ~ChromeFrameAutomationClient(); | |
304 | |
305 // Called from UI thread. | |
306 virtual bool Initialize(ChromeFrameDelegate* chrome_frame_delegate, | |
307 ChromeFrameLaunchParams* chrome_launch_params); | |
308 void Uninitialize(); | |
309 void NotifyAndUninitialize(); | |
310 | |
311 virtual bool InitiateNavigation( | |
312 const std::string& url, | |
313 const std::string& referrer, | |
314 NavigationConstraints* navigation_constraints); | |
315 | |
316 void FindInPage(const std::wstring& search_string, | |
317 FindInPageDirection forward, | |
318 FindInPageCase match_case, | |
319 bool find_next); | |
320 | |
321 TabProxy* tab() const { return tab_.get(); } | |
322 | |
323 BEGIN_MSG_MAP(ChromeFrameAutomationClient) | |
324 CHAIN_MSG_MAP( | |
325 TaskMarshallerThroughWindowsMessages<ChromeFrameAutomationClient>) | |
326 END_MSG_MAP() | |
327 | |
328 // Sets the passed in window as the parent of the external tab. | |
329 void SetParentWindow(HWND parent_window); | |
330 | |
331 HWND tab_window() const { | |
332 return tab_window_; | |
333 } | |
334 | |
335 void ReleaseAutomationServer(); | |
336 | |
337 // Returns the version number of plugin dll. | |
338 std::wstring GetVersion() const; | |
339 | |
340 // BitBlts the contents of the chrome window to the print dc. | |
341 void Print(HDC print_dc, const RECT& print_bounds); | |
342 | |
343 void set_use_chrome_network(bool use_chrome_network) { | |
344 use_chrome_network_ = use_chrome_network; | |
345 } | |
346 | |
347 bool use_chrome_network() const { | |
348 return use_chrome_network_; | |
349 } | |
350 | |
351 #ifdef UNIT_TEST | |
352 void set_proxy_factory(ProxyFactory* factory) { | |
353 proxy_factory_ = factory; | |
354 } | |
355 #endif | |
356 | |
357 void set_handle_top_level_requests(bool handle_top_level_requests) { | |
358 handle_top_level_requests_ = handle_top_level_requests; | |
359 } | |
360 | |
361 // Url request manager set up. | |
362 void SetUrlFetcher(PluginUrlRequestManager* url_fetcher); | |
363 | |
364 void SetPageFontSize(enum AutomationPageFontSize); | |
365 | |
366 // For IDeleteBrowsingHistorySupport | |
367 void RemoveBrowsingData(int remove_mask); | |
368 | |
369 protected: | |
370 // ChromeFrameAutomationProxy::LaunchDelegate implementation. | |
371 virtual void LaunchComplete(ChromeFrameAutomationProxy* proxy, | |
372 AutomationLaunchResult result); | |
373 virtual void AutomationServerDied(); | |
374 | |
375 // TabProxyDelegate implementation | |
376 virtual bool OnMessageReceived(TabProxy* tab, const IPC::Message& msg); | |
377 virtual void OnChannelError(TabProxy* tab); | |
378 | |
379 virtual void OnFinalMessage(HWND wnd) { | |
380 Release(); | |
381 } | |
382 | |
383 scoped_refptr<ChromeFrameLaunchParams> launch_params() { | |
384 return chrome_launch_params_; | |
385 } | |
386 | |
387 private: | |
388 void OnMessageReceivedUIThread(const IPC::Message& msg); | |
389 void OnChannelErrorUIThread(); | |
390 | |
391 HWND chrome_window() const { return chrome_window_; } | |
392 void BeginNavigateCompleted(AutomationMsg_NavigationResponseValues result); | |
393 | |
394 // Helpers | |
395 void ReportNavigationError(AutomationMsg_NavigationResponseValues error_code, | |
396 const std::string& url); | |
397 | |
398 bool is_initialized() const { | |
399 return init_state_ == INITIALIZED; | |
400 } | |
401 | |
402 HWND parent_window_; | |
403 base::PlatformThreadId ui_thread_id_; | |
404 | |
405 void* automation_server_id_; | |
406 ChromeFrameAutomationProxy* automation_server_; | |
407 | |
408 HWND chrome_window_; | |
409 scoped_refptr<TabProxy> tab_; | |
410 ChromeFrameDelegate* chrome_frame_delegate_; | |
411 | |
412 // Handle to the underlying chrome window. This is a child of the external | |
413 // tab window. | |
414 HWND tab_window_; | |
415 | |
416 // Keeps track of the version of Chrome we're talking to. | |
417 std::string automation_server_version_; | |
418 | |
419 typedef enum InitializationState { | |
420 UNINITIALIZED = 0, | |
421 INITIALIZING, | |
422 INITIALIZED, | |
423 UNINITIALIZING, | |
424 }; | |
425 | |
426 InitializationState init_state_; | |
427 bool use_chrome_network_; | |
428 bool handle_top_level_requests_; | |
429 ProxyFactory* proxy_factory_; | |
430 int tab_handle_; | |
431 // The SessionId used by Chrome as the id in the Javascript Tab object. | |
432 int session_id_; | |
433 | |
434 // Set to true if we received a navigation request prior to the automation | |
435 // server being initialized. | |
436 bool navigate_after_initialization_; | |
437 | |
438 scoped_refptr<ChromeFrameLaunchParams> chrome_launch_params_; | |
439 | |
440 // Cache security manager for URL zone checking | |
441 base::win::ScopedComPtr<IInternetSecurityManager> security_manager_; | |
442 | |
443 // When host network stack is used, this object is in charge of | |
444 // handling network requests. | |
445 PluginUrlRequestManager* url_fetcher_; | |
446 PluginUrlRequestManager::ThreadSafeFlags url_fetcher_flags_; | |
447 | |
448 // set to true if the host needs to get notified of all top level navigations | |
449 // in this page. This typically applies to hosts which would render the new | |
450 // page without chrome frame. Defaults to false. | |
451 bool route_all_top_level_navigations_; | |
452 | |
453 friend class BeginNavigateContext; | |
454 friend class CreateExternalTabContext; | |
455 }; | |
456 | |
457 #endif // CHROME_FRAME_CHROME_FRAME_AUTOMATION_H_ | |
OLD | NEW |