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.
5 #ifndef CHROME_FRAME_CHROME_FRAME_AUTOMATION_H_
6 #define CHROME_FRAME_CHROME_FRAME_AUTOMATION_H_
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/scoped_handle.h"
16 #include "base/stack_container.h"
17 #include "base/synchronization/lock.h"
18 #include "base/threading/thread.h"
19 #include "base/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"
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
33 class NavigationConstraints
;
34 enum AutomationPageFontSize
;
36 struct DECLSPEC_NOVTABLE ChromeFrameAutomationProxy
{ // NOLINT
37 virtual bool Send(IPC::Message
* msg
) = 0;
39 virtual void SendAsAsync(
40 IPC::SyncMessage
* msg
,
41 SyncMessageReplyDispatcher::SyncMessageCallContext
* context
,
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;
48 virtual void SendProxyConfig(const std::string
&) = 0;
50 virtual ~ChromeFrameAutomationProxy() {}
53 // Forward declarations.
56 // We extend the AutomationProxy class to handle our custom
58 class ChromeFrameAutomationProxyImpl
59 : public ChromeFrameAutomationProxy
,
60 // We have to derive from automationproxy since we want access to some
61 // members (tracker_ & channel_) - simple aggregation wont work;
62 // .. and non-public inheritance is verboten.
63 public AutomationProxy
{
65 ~ChromeFrameAutomationProxyImpl();
66 virtual void SendAsAsync(
67 IPC::SyncMessage
* msg
,
68 SyncMessageReplyDispatcher::SyncMessageCallContext
* context
,
71 // Called on the worker thread.
72 virtual void OnChannelError();
74 virtual void CancelAsync(void* key
);
76 virtual scoped_refptr
<TabProxy
> CreateTabProxy(int handle
);
77 virtual void ReleaseTabProxy(AutomationHandle handle
);
79 virtual std::string
server_version() {
80 return AutomationProxy::server_version();
83 virtual bool Send(IPC::Message
* msg
) {
84 return AutomationProxy::Send(msg
);
87 virtual void SendProxyConfig(const std::string
& p
) {
88 AutomationProxy::SendProxyConfig(p
);
92 friend class AutomationProxyCacheEntry
;
93 ChromeFrameAutomationProxyImpl(AutomationProxyCacheEntry
* entry
,
94 std::string channel_id
,
95 base::TimeDelta launch_timeout
);
97 class CFMsgDispatcher
;
98 class TabProxyNotificationMessageFilter
;
100 scoped_refptr
<CFMsgDispatcher
> sync_
;
101 scoped_refptr
<TabProxyNotificationMessageFilter
> message_filter_
;
102 AutomationProxyCacheEntry
* proxy_entry_
;
105 // This class contains information used for launching chrome.
106 class ChromeFrameLaunchParams
: // NOLINT
107 public base::RefCountedThreadSafe
<ChromeFrameLaunchParams
> {
109 ChromeFrameLaunchParams(const GURL
& url
, const GURL
& referrer
,
110 const FilePath
& profile_path
,
111 const std::wstring
& profile_name
,
112 const std::wstring
& language
,
113 bool incognito
, bool widget_mode
,
114 bool route_all_top_level_navigations
,
115 bool send_shutdown_delay_switch
)
116 : launch_timeout_(kCommandExecutionTimeout
), url_(url
),
117 referrer_(referrer
), profile_path_(profile_path
),
118 profile_name_(profile_name
), language_(language
),
119 version_check_(true), incognito_mode_(incognito
),
120 is_widget_mode_(widget_mode
),
121 route_all_top_level_navigations_(route_all_top_level_navigations
),
122 send_shutdown_delay_switch_(send_shutdown_delay_switch
) {
125 ~ChromeFrameLaunchParams() {
128 void set_launch_timeout(int timeout
) {
129 launch_timeout_
= timeout
;
132 int launch_timeout() const {
133 return launch_timeout_
;
136 const GURL
& url() const {
140 void set_url(const GURL
& url
) {
144 const GURL
& referrer() const {
148 void set_referrer(const GURL
& referrer
) {
149 referrer_
= referrer
;
152 const FilePath
& profile_path() const {
153 return profile_path_
;
156 const std::wstring
& profile_name() const {
157 return profile_name_
;
160 const std::wstring
& language() const {
164 bool version_check() const {
165 return version_check_
;
168 void set_version_check(bool check
) {
169 version_check_
= check
;
172 bool incognito() const {
173 return incognito_mode_
;
176 bool widget_mode() const {
177 return is_widget_mode_
;
180 void set_route_all_top_level_navigations(
181 bool route_all_top_level_navigations
) {
182 route_all_top_level_navigations_
= route_all_top_level_navigations
;
185 bool route_all_top_level_navigations() const {
186 return route_all_top_level_navigations_
;
189 bool send_shutdown_delay_switch() const {
190 return send_shutdown_delay_switch_
;
197 FilePath profile_path_
;
198 std::wstring profile_name_
;
199 std::wstring language_
;
201 bool incognito_mode_
;
202 bool is_widget_mode_
;
203 bool route_all_top_level_navigations_
;
204 bool send_shutdown_delay_switch_
;
207 DISALLOW_COPY_AND_ASSIGN(ChromeFrameLaunchParams
);
210 // Callback when chrome process launch is complete and automation handshake
211 // (Hello message) is established. All methods are invoked on the automation
212 // proxy's worker thread.
213 struct DECLSPEC_NOVTABLE LaunchDelegate
{ // NOLINT
214 virtual void LaunchComplete(ChromeFrameAutomationProxy
* proxy
,
215 AutomationLaunchResult result
) = 0;
216 virtual void AutomationServerDied() = 0;
219 // Manages a cached ChromeFrameAutomationProxyImpl entry and holds
220 // reference-less pointers to LaunchDelegate(s) to be notified in case
221 // of automation server process changes.
222 class AutomationProxyCacheEntry
223 : public base::RefCounted
<AutomationProxyCacheEntry
> {
225 AutomationProxyCacheEntry(ChromeFrameLaunchParams
* params
,
226 LaunchDelegate
* delegate
);
228 ~AutomationProxyCacheEntry();
230 void AddDelegate(LaunchDelegate
* delegate
);
231 void RemoveDelegate(LaunchDelegate
* delegate
, base::WaitableEvent
* done
,
232 bool* was_last_delegate
);
234 DWORD
WaitForThread(DWORD timeout
) { // NOLINT
235 DCHECK(thread_
.get());
236 return ::WaitForSingleObject(thread_
->thread_handle(), timeout
);
239 bool IsSameProfile(const std::wstring
& name
) const {
240 return lstrcmpiW(name
.c_str(), profile_name
.c_str()) == 0;
243 base::Thread
* thread() const {
244 return thread_
.get();
247 MessageLoop
* message_loop() const {
248 return thread_
->message_loop();
251 bool IsSameThread(base::PlatformThreadId id
) const {
252 return thread_
->thread_id() == id
;
255 ChromeFrameAutomationProxyImpl
* proxy() const {
256 DCHECK(IsSameThread(base::PlatformThread::CurrentId()));
260 // Called by the proxy when the automation server has unexpectedly gone away.
261 void OnChannelError();
264 void CreateProxy(ChromeFrameLaunchParams
* params
,
265 LaunchDelegate
* delegate
);
268 std::wstring profile_name
;
269 scoped_ptr
<base::Thread
> thread_
;
270 scoped_ptr
<ChromeFrameAutomationProxyImpl
> proxy_
;
271 AutomationLaunchResult launch_result_
;
272 typedef std::vector
<LaunchDelegate
*> LaunchDelegates
;
273 LaunchDelegates launch_delegates_
;
274 // Used for UMA histogram logging to measure the time for the chrome
275 // automation server to start;
276 base::TimeTicks automation_server_launch_start_time_
;
279 // We must create and destroy automation proxy in a thread with a message loop.
280 // Hence thread cannot be a member of the proxy.
284 virtual ~ProxyFactory();
286 // Fetches or creates a new automation server instance.
287 // delegate may be NULL. If non-null, a pointer to the delegate will
288 // be stored for the lifetime of the automation process or until
289 // ReleaseAutomationServer is called.
290 virtual void GetAutomationServer(LaunchDelegate
* delegate
,
291 ChromeFrameLaunchParams
* params
,
292 void** automation_server_id
);
293 virtual bool ReleaseAutomationServer(void* server_id
,
294 LaunchDelegate
* delegate
);
297 typedef StackVector
<scoped_refptr
<AutomationProxyCacheEntry
>, 4> Vector
;
299 // Lock if we are going to call GetAutomationServer from more than one thread.
303 // Handles all automation requests initiated from the chrome frame objects.
304 // These include the chrome tab/chrome frame activex plugin objects.
305 class ChromeFrameAutomationClient
306 : public CWindowImpl
<ChromeFrameAutomationClient
>,
307 public TaskMarshallerThroughWindowsMessages
<ChromeFrameAutomationClient
>,
308 public base::RefCountedThreadSafe
<ChromeFrameAutomationClient
>,
309 public PluginUrlRequestDelegate
,
310 public TabProxy::TabProxyDelegate
,
311 public LaunchDelegate
{
313 ChromeFrameAutomationClient();
314 ~ChromeFrameAutomationClient();
316 // Called from UI thread.
317 virtual bool Initialize(ChromeFrameDelegate
* chrome_frame_delegate
,
318 ChromeFrameLaunchParams
* chrome_launch_params
);
320 void NotifyAndUninitialize();
322 virtual bool InitiateNavigation(
323 const std::string
& url
,
324 const std::string
& referrer
,
325 NavigationConstraints
* navigation_constraints
);
327 virtual bool NavigateToIndex(int index
);
328 bool ForwardMessageFromExternalHost(const std::string
& message
,
329 const std::string
& origin
,
330 const std::string
& target
);
331 bool SetProxySettings(const std::string
& json_encoded_proxy_settings
);
333 void FindInPage(const std::wstring
& search_string
,
334 FindInPageDirection forward
,
335 FindInPageCase match_case
,
338 virtual void OnChromeFrameHostMoved();
340 TabProxy
* tab() const { return tab_
.get(); }
342 BEGIN_MSG_MAP(ChromeFrameAutomationClient
)
344 TaskMarshallerThroughWindowsMessages
<ChromeFrameAutomationClient
>)
347 // Resizes the hosted chrome window. This is brokered to the chrome
348 // automation instance as the host browser could be running under low IL,
349 // which would cause the SetWindowPos call to fail.
350 void Resize(int width
, int height
, int flags
);
352 // Sets the passed in window as the parent of the external tab.
353 void SetParentWindow(HWND parent_window
);
355 void SendContextMenuCommandToChromeFrame(int selected_command
);
357 HWND
tab_window() const {
361 void ReleaseAutomationServer();
363 // Returns the version number of plugin dll.
364 std::wstring
GetVersion() const;
366 // BitBlts the contents of the chrome window to the print dc.
367 void Print(HDC print_dc
, const RECT
& print_bounds
);
369 // Called in full tab mode and indicates a request to chrome to print
373 void set_use_chrome_network(bool use_chrome_network
) {
374 use_chrome_network_
= use_chrome_network
;
377 bool use_chrome_network() const {
378 return use_chrome_network_
;
381 bool send_shutdown_delay_switch() const {
382 return send_shutdown_delay_switch_
;
386 void set_proxy_factory(ProxyFactory
* factory
) {
387 proxy_factory_
= factory
;
391 void set_handle_top_level_requests(bool handle_top_level_requests
) {
392 handle_top_level_requests_
= handle_top_level_requests
;
395 // Url request manager set up.
396 void SetUrlFetcher(PluginUrlRequestManager
* url_fetcher
);
398 // Attaches an existing external tab to this automation client instance.
399 void AttachExternalTab(uint64 external_tab_cookie
);
400 void BlockExternalTab(uint64 cookie
);
402 void SetPageFontSize(enum AutomationPageFontSize
);
404 // For IDeleteBrowsingHistorySupport
405 void RemoveBrowsingData(int remove_mask
);
407 // Sets the current zoom level on the tab.
408 void SetZoomLevel(content::PageZoom zoom_level
);
410 // Fires before unload and unload handlers on the page if any. Allows the
411 // the website to put up a confirmation dialog on unload.
412 void OnUnload(bool* should_unload
);
415 // ChromeFrameAutomationProxy::LaunchDelegate implementation.
416 virtual void LaunchComplete(ChromeFrameAutomationProxy
* proxy
,
417 AutomationLaunchResult result
);
418 virtual void AutomationServerDied();
420 // TabProxyDelegate implementation
421 virtual bool OnMessageReceived(TabProxy
* tab
, const IPC::Message
& msg
);
422 virtual void OnChannelError(TabProxy
* tab
);
424 void CreateExternalTab();
425 AutomationLaunchResult
CreateExternalTabComplete(HWND chrome_window
,
429 // Called in UI thread. Here we fire event to the client notifying for
430 // the result of Initialize() method call.
431 void InitializeComplete(AutomationLaunchResult result
);
433 virtual void OnFinalMessage(HWND wnd
) {
437 scoped_refptr
<ChromeFrameLaunchParams
> launch_params() {
438 return chrome_launch_params_
;
442 void InitializeFieldTrials();
444 void OnMessageReceivedUIThread(const IPC::Message
& msg
);
445 void OnChannelErrorUIThread();
447 HWND
chrome_window() const { return chrome_window_
; }
448 void BeginNavigate();
449 void BeginNavigateCompleted(AutomationMsg_NavigationResponseValues result
);
452 void ReportNavigationError(AutomationMsg_NavigationResponseValues error_code
,
453 const std::string
& url
);
455 bool ProcessUrlRequestMessage(TabProxy
* tab
, const IPC::Message
& msg
,
458 // PluginUrlRequestDelegate implementation. Simply adds tab's handle
459 // as parameter and forwards to Chrome via IPC.
460 virtual void OnResponseStarted(int request_id
, const char* mime_type
,
461 const char* headers
, int size
, base::Time last_modified
,
462 const std::string
& redirect_url
, int redirect_status
,
463 const net::HostPortPair
& socket_address
);
464 virtual void OnReadComplete(int request_id
, const std::string
& data
);
465 virtual void OnResponseEnd(int request_id
,
466 const net::URLRequestStatus
& status
);
467 virtual void OnCookiesRetrieved(bool success
, const GURL
& url
,
468 const std::string
& cookie_string
, int cookie_id
);
470 bool is_initialized() const {
471 return init_state_
== INITIALIZED
;
475 base::PlatformThreadId ui_thread_id_
;
477 void* automation_server_id_
;
478 ChromeFrameAutomationProxy
* automation_server_
;
481 scoped_refptr
<TabProxy
> tab_
;
482 ChromeFrameDelegate
* chrome_frame_delegate_
;
484 // Handle to the underlying chrome window. This is a child of the external
488 // Keeps track of the version of Chrome we're talking to.
489 std::string automation_server_version_
;
491 typedef enum InitializationState
{
498 InitializationState init_state_
;
499 bool use_chrome_network_
;
500 bool handle_top_level_requests_
;
501 ProxyFactory
* proxy_factory_
;
503 // The SessionId used by Chrome as the id in the Javascript Tab object.
505 // Only used if we attach to an existing tab.
506 uint64 external_tab_cookie_
;
508 // Set to true if we received a navigation request prior to the automation
509 // server being initialized.
510 bool navigate_after_initialization_
;
512 scoped_refptr
<ChromeFrameLaunchParams
> chrome_launch_params_
;
514 // Cache security manager for URL zone checking
515 base::win::ScopedComPtr
<IInternetSecurityManager
> security_manager_
;
517 // When host network stack is used, this object is in charge of
518 // handling network requests.
519 PluginUrlRequestManager
* url_fetcher_
;
520 PluginUrlRequestManager::ThreadSafeFlags url_fetcher_flags_
;
522 // set to true if the host needs to get notified of all top level navigations
523 // in this page. This typically applies to hosts which would render the new
524 // page without chrome frame. Defaults to false.
525 bool route_all_top_level_navigations_
;
527 // Set to true if Chrome Frame should tell Chrome to delay shutdown after
528 // we break a connection. Currently used only as part of a field trial.
529 bool send_shutdown_delay_switch_
;
531 friend class BeginNavigateContext
;
532 friend class CreateExternalTabContext
;
535 #endif // CHROME_FRAME_CHROME_FRAME_AUTOMATION_H_