• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   virtual void SendProxyConfig(const std::string&) = 0;
49  protected:
~ChromeFrameAutomationProxyChromeFrameAutomationProxy50   virtual ~ChromeFrameAutomationProxy() {}
51 };
52 
53 // Forward declarations.
54 class ProxyFactory;
55 
56 // We extend the AutomationProxy class to handle our custom
57 // IPC messages
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 {
64  public:
65   ~ChromeFrameAutomationProxyImpl();
66   virtual void SendAsAsync(
67       IPC::SyncMessage* msg,
68       SyncMessageReplyDispatcher::SyncMessageCallContext* context,
69       void* key);
70 
71   // Called on the worker thread.
72   virtual void OnChannelError();
73 
74   virtual void CancelAsync(void* key);
75 
76   virtual scoped_refptr<TabProxy> CreateTabProxy(int handle);
77   virtual void ReleaseTabProxy(AutomationHandle handle);
78 
server_version()79   virtual std::string server_version() {
80     return AutomationProxy::server_version();
81   }
82 
Send(IPC::Message * msg)83   virtual bool Send(IPC::Message* msg) {
84     return AutomationProxy::Send(msg);
85   }
86 
SendProxyConfig(const std::string & p)87   virtual void SendProxyConfig(const std::string& p) {
88     AutomationProxy::SendProxyConfig(p);
89   }
90 
91  protected:
92   friend class AutomationProxyCacheEntry;
93   ChromeFrameAutomationProxyImpl(AutomationProxyCacheEntry* entry,
94                                  std::string channel_id,
95                                  base::TimeDelta launch_timeout);
96 
97   class CFMsgDispatcher;
98   class TabProxyNotificationMessageFilter;
99 
100   scoped_refptr<CFMsgDispatcher> sync_;
101   scoped_refptr<TabProxyNotificationMessageFilter> message_filter_;
102   AutomationProxyCacheEntry* proxy_entry_;
103 };
104 
105 // This class contains information used for launching chrome.
106 class ChromeFrameLaunchParams :  // NOLINT
107     public base::RefCountedThreadSafe<ChromeFrameLaunchParams> {
108  public:
ChromeFrameLaunchParams(const GURL & url,const GURL & referrer,const base::FilePath & profile_path,const std::wstring & profile_name,const std::wstring & language,bool incognito,bool widget_mode,bool route_all_top_level_navigations)109   ChromeFrameLaunchParams(const GURL& url, const GURL& referrer,
110                           const base::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     : launch_timeout_(kCommandExecutionTimeout), url_(url),
116       referrer_(referrer), profile_path_(profile_path),
117       profile_name_(profile_name), language_(language),
118       version_check_(true), incognito_mode_(incognito),
119       is_widget_mode_(widget_mode),
120       route_all_top_level_navigations_(route_all_top_level_navigations) {
121   }
122 
~ChromeFrameLaunchParams()123   ~ChromeFrameLaunchParams() {
124   }
125 
set_launch_timeout(int timeout)126   void set_launch_timeout(int timeout) {
127     launch_timeout_ = timeout;
128   }
129 
launch_timeout()130   int launch_timeout() const {
131     return launch_timeout_;
132   }
133 
url()134   const GURL& url() const {
135     return url_;
136   }
137 
set_url(const GURL & url)138   void set_url(const GURL& url) {
139     url_ = url;
140   }
141 
referrer()142   const GURL& referrer() const {
143     return referrer_;
144   }
145 
set_referrer(const GURL & referrer)146   void set_referrer(const GURL& referrer) {
147     referrer_ = referrer;
148   }
149 
profile_path()150   const base::FilePath& profile_path() const {
151     return profile_path_;
152   }
153 
profile_name()154   const std::wstring& profile_name() const {
155     return profile_name_;
156   }
157 
language()158   const std::wstring& language() const {
159     return language_;
160   }
161 
version_check()162   bool version_check() const {
163     return version_check_;
164   }
165 
set_version_check(bool check)166   void set_version_check(bool check) {
167     version_check_ = check;
168   }
169 
incognito()170   bool incognito() const {
171     return incognito_mode_;
172   }
173 
widget_mode()174   bool widget_mode() const {
175     return is_widget_mode_;
176   }
177 
set_route_all_top_level_navigations(bool route_all_top_level_navigations)178   void set_route_all_top_level_navigations(
179       bool route_all_top_level_navigations) {
180     route_all_top_level_navigations_ = route_all_top_level_navigations;
181   }
182 
route_all_top_level_navigations()183   bool route_all_top_level_navigations() const {
184     return route_all_top_level_navigations_;
185   }
186 
187  protected:
188   int launch_timeout_;
189   GURL url_;
190   GURL referrer_;
191   base::FilePath profile_path_;
192   std::wstring profile_name_;
193   std::wstring language_;
194   bool version_check_;
195   bool incognito_mode_;
196   bool is_widget_mode_;
197   bool route_all_top_level_navigations_;
198 
199  private:
200   DISALLOW_COPY_AND_ASSIGN(ChromeFrameLaunchParams);
201 };
202 
203 // Callback when chrome process launch is complete and automation handshake
204 // (Hello message) is established.  All methods are invoked on the automation
205 // proxy's worker thread.
206 struct DECLSPEC_NOVTABLE LaunchDelegate {  // NOLINT
207   virtual void LaunchComplete(ChromeFrameAutomationProxy* proxy,
208                               AutomationLaunchResult result) = 0;
209   virtual void AutomationServerDied() = 0;
210 };  // NOLINT
211 
212 // Manages a cached ChromeFrameAutomationProxyImpl entry and holds
213 // reference-less pointers to LaunchDelegate(s) to be notified in case
214 // of automation server process changes.
215 class AutomationProxyCacheEntry
216     : public base::RefCounted<AutomationProxyCacheEntry> {
217  public:
218   AutomationProxyCacheEntry(ChromeFrameLaunchParams* params,
219                             LaunchDelegate* delegate);
220 
221   ~AutomationProxyCacheEntry();
222 
223   void AddDelegate(LaunchDelegate* delegate);
224   void RemoveDelegate(LaunchDelegate* delegate, base::WaitableEvent* done,
225                       bool* was_last_delegate);
226 
WaitForThread(DWORD timeout)227   DWORD WaitForThread(DWORD timeout) {  // NOLINT
228     DCHECK(thread_.get());
229     return ::WaitForSingleObject(thread_->thread_handle().platform_handle(),
230                                  timeout);
231   }
232 
IsSameProfile(const std::wstring & name)233   bool IsSameProfile(const std::wstring& name) const {
234     return lstrcmpiW(name.c_str(), profile_name.c_str()) == 0;
235   }
236 
thread()237   base::Thread* thread() const {
238     return thread_.get();
239   }
240 
message_loop()241   base::MessageLoop* message_loop() const {
242     return thread_->message_loop();
243   }
244 
IsSameThread(base::PlatformThreadId id)245   bool IsSameThread(base::PlatformThreadId id) const {
246     return thread_->thread_id() == id;
247   }
248 
proxy()249   ChromeFrameAutomationProxyImpl* proxy() const {
250     DCHECK(IsSameThread(base::PlatformThread::CurrentId()));
251     return proxy_.get();
252   }
253 
254   // Called by the proxy when the automation server has unexpectedly gone away.
255   void OnChannelError();
256 
257  protected:
258   void CreateProxy(ChromeFrameLaunchParams* params,
259                    LaunchDelegate* delegate);
260 
261  protected:
262   std::wstring profile_name;
263   scoped_ptr<base::Thread> thread_;
264   scoped_ptr<ChromeFrameAutomationProxyImpl> proxy_;
265   AutomationLaunchResult launch_result_;
266   typedef std::vector<LaunchDelegate*> LaunchDelegates;
267   LaunchDelegates launch_delegates_;
268   // Used for UMA histogram logging to measure the time for the chrome
269   // automation server to start;
270   base::TimeTicks automation_server_launch_start_time_;
271 };
272 
273 // We must create and destroy automation proxy in a thread with a message loop.
274 // Hence thread cannot be a member of the proxy.
275 class ProxyFactory {
276  public:
277   ProxyFactory();
278   virtual ~ProxyFactory();
279 
280   // Fetches or creates a new automation server instance.
281   // delegate may be NULL.  If non-null, a pointer to the delegate will
282   // be stored for the lifetime of the automation process or until
283   // ReleaseAutomationServer is called.
284   virtual void GetAutomationServer(LaunchDelegate* delegate,
285                                    ChromeFrameLaunchParams* params,
286                                    void** automation_server_id);
287   virtual bool ReleaseAutomationServer(void* server_id,
288                                        LaunchDelegate* delegate);
289 
290  private:
291   typedef base::StackVector<scoped_refptr<AutomationProxyCacheEntry>, 4> Vector;
292   Vector proxies_;
293   // Lock if we are going to call GetAutomationServer from more than one thread.
294   base::Lock lock_;
295 };
296 
297 // Handles all automation requests initiated from the chrome frame objects.
298 // These include the chrome tab/chrome frame activex plugin objects.
299 class ChromeFrameAutomationClient
300     : public CWindowImpl<ChromeFrameAutomationClient>,
301       public TaskMarshallerThroughWindowsMessages<ChromeFrameAutomationClient>,
302       public base::RefCountedThreadSafe<ChromeFrameAutomationClient>,
303       public PluginUrlRequestDelegate,
304       public TabProxy::TabProxyDelegate,
305       public LaunchDelegate {
306  public:
307   ChromeFrameAutomationClient();
308   ~ChromeFrameAutomationClient();
309 
310   // Called from UI thread.
311   virtual bool Initialize(ChromeFrameDelegate* chrome_frame_delegate,
312                           ChromeFrameLaunchParams* chrome_launch_params);
313   void Uninitialize();
314   void NotifyAndUninitialize();
315 
316   virtual bool InitiateNavigation(
317       const std::string& url,
318       const std::string& referrer,
319       NavigationConstraints* navigation_constraints);
320 
321   virtual bool NavigateToIndex(int index);
322   bool ForwardMessageFromExternalHost(const std::string& message,
323                                       const std::string& origin,
324                                       const std::string& target);
325   bool SetProxySettings(const std::string& json_encoded_proxy_settings);
326 
327   void FindInPage(const std::wstring& search_string,
328                   FindInPageDirection forward,
329                   FindInPageCase match_case,
330                   bool find_next);
331 
332   virtual void OnChromeFrameHostMoved();
333 
tab()334   TabProxy* tab() const { return tab_.get(); }
335 
336   BEGIN_MSG_MAP(ChromeFrameAutomationClient)
337     CHAIN_MSG_MAP(
338         TaskMarshallerThroughWindowsMessages<ChromeFrameAutomationClient>)
339   END_MSG_MAP()
340 
341   // Resizes the hosted chrome window. This is brokered to the chrome
342   // automation instance as the host browser could be running under low IL,
343   // which would cause the SetWindowPos call to fail.
344   void Resize(int width, int height, int flags);
345 
346   // Sets the passed in window as the parent of the external tab.
347   void SetParentWindow(HWND parent_window);
348 
349   void SendContextMenuCommandToChromeFrame(int selected_command);
350 
tab_window()351   HWND tab_window() const {
352     return tab_window_;
353   }
354 
355   void ReleaseAutomationServer();
356 
357   // Returns the version number of plugin dll.
358   std::wstring GetVersion() const;
359 
360   // BitBlts the contents of the chrome window to the print dc.
361   void Print(HDC print_dc, const RECT& print_bounds);
362 
363   // Called in full tab mode and indicates a request to chrome to print
364   // the whole tab.
365   void PrintTab();
366 
set_use_chrome_network(bool use_chrome_network)367   void set_use_chrome_network(bool use_chrome_network) {
368     use_chrome_network_ = use_chrome_network;
369   }
370 
use_chrome_network()371   bool use_chrome_network() const {
372     return use_chrome_network_;
373   }
374 
375 #ifdef UNIT_TEST
set_proxy_factory(ProxyFactory * factory)376   void set_proxy_factory(ProxyFactory* factory) {
377     proxy_factory_ = factory;
378   }
379 #endif
380 
set_handle_top_level_requests(bool handle_top_level_requests)381   void set_handle_top_level_requests(bool handle_top_level_requests) {
382     handle_top_level_requests_ = handle_top_level_requests;
383   }
384 
385   // Url request manager set up.
386   void SetUrlFetcher(PluginUrlRequestManager* url_fetcher);
387 
388   // Attaches an existing external tab to this automation client instance.
389   void AttachExternalTab(uint64 external_tab_cookie);
390   void BlockExternalTab(uint64 cookie);
391 
392   void SetPageFontSize(enum AutomationPageFontSize);
393 
394   // For IDeleteBrowsingHistorySupport
395   void RemoveBrowsingData(int remove_mask);
396 
397   // Sets the current zoom level on the tab.
398   void SetZoomLevel(content::PageZoom zoom_level);
399 
400   // Fires before unload and unload handlers on the page if any. Allows the
401   // the website to put up a confirmation dialog on unload.
402   void OnUnload(bool* should_unload);
403 
404  protected:
405   // ChromeFrameAutomationProxy::LaunchDelegate implementation.
406   virtual void LaunchComplete(ChromeFrameAutomationProxy* proxy,
407                               AutomationLaunchResult result);
408   virtual void AutomationServerDied();
409 
410   // TabProxyDelegate implementation
411   virtual bool OnMessageReceived(TabProxy* tab, const IPC::Message& msg);
412   virtual void OnChannelError(TabProxy* tab);
413 
414   void CreateExternalTab();
415   AutomationLaunchResult CreateExternalTabComplete(HWND chrome_window,
416                                                    HWND tab_window,
417                                                    int tab_handle,
418                                                    int session_id);
419   // Called in UI thread. Here we fire event to the client notifying for
420   // the result of Initialize() method call.
421   void InitializeComplete(AutomationLaunchResult result);
422 
OnFinalMessage(HWND wnd)423   virtual void OnFinalMessage(HWND wnd) {
424     Release();
425   }
426 
launch_params()427   scoped_refptr<ChromeFrameLaunchParams> launch_params() {
428     return chrome_launch_params_;
429   }
430 
431  private:
432   void OnMessageReceivedUIThread(const IPC::Message& msg);
433   void OnChannelErrorUIThread();
434 
chrome_window()435   HWND chrome_window() const { return chrome_window_; }
436   void BeginNavigate();
437   void BeginNavigateCompleted(AutomationMsg_NavigationResponseValues result);
438 
439   // Helpers
440   void ReportNavigationError(AutomationMsg_NavigationResponseValues error_code,
441                              const std::string& url);
442 
443   bool ProcessUrlRequestMessage(TabProxy* tab, const IPC::Message& msg,
444                                 bool ui_thread);
445 
446   // PluginUrlRequestDelegate implementation. Simply adds tab's handle
447   // as parameter and forwards to Chrome via IPC.
448   virtual void OnResponseStarted(
449       int request_id, const char* mime_type, const char* headers, int size,
450       base::Time last_modified, const std::string& redirect_url,
451       int redirect_status, const net::HostPortPair& socket_address,
452       uint64 upload_size);
453   virtual void OnReadComplete(int request_id, const std::string& data);
454   virtual void OnResponseEnd(int request_id,
455                              const net::URLRequestStatus& status);
456 
is_initialized()457   bool is_initialized() const {
458     return init_state_ == INITIALIZED;
459   }
460 
461   HWND parent_window_;
462   base::PlatformThreadId ui_thread_id_;
463 
464   void* automation_server_id_;
465   ChromeFrameAutomationProxy* automation_server_;
466 
467   HWND chrome_window_;
468   scoped_refptr<TabProxy> tab_;
469   ChromeFrameDelegate* chrome_frame_delegate_;
470 
471   // Handle to the underlying chrome window. This is a child of the external
472   // tab window.
473   HWND tab_window_;
474 
475   // Keeps track of the version of Chrome we're talking to.
476   std::string automation_server_version_;
477 
478   typedef enum InitializationState {
479     UNINITIALIZED = 0,
480     INITIALIZING,
481     INITIALIZED,
482     UNINITIALIZING,
483   };
484 
485   InitializationState init_state_;
486   bool use_chrome_network_;
487   bool handle_top_level_requests_;
488   ProxyFactory* proxy_factory_;
489   int tab_handle_;
490   // The SessionId used by Chrome as the id in the Javascript Tab object.
491   int session_id_;
492   // Only used if we attach to an existing tab.
493   uint64 external_tab_cookie_;
494 
495   // Set to true if we received a navigation request prior to the automation
496   // server being initialized.
497   bool navigate_after_initialization_;
498 
499   scoped_refptr<ChromeFrameLaunchParams> chrome_launch_params_;
500 
501   // Cache security manager for URL zone checking
502   base::win::ScopedComPtr<IInternetSecurityManager> security_manager_;
503 
504   // When host network stack is used, this object is in charge of
505   // handling network requests.
506   PluginUrlRequestManager* url_fetcher_;
507   PluginUrlRequestManager::ThreadSafeFlags url_fetcher_flags_;
508 
509   // set to true if the host needs to get notified of all top level navigations
510   // in this page. This typically applies to hosts which would render the new
511   // page without chrome frame. Defaults to false.
512   bool route_all_top_level_navigations_;
513 
514   friend class BeginNavigateContext;
515   friend class CreateExternalTabContext;
516 };
517 
518 #endif  // CHROME_FRAME_CHROME_FRAME_AUTOMATION_H_
519