Home | History | Annotate | Download | only in chrome_frame
      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_ACTIVEX_BASE_H_
      6 #define CHROME_FRAME_CHROME_FRAME_ACTIVEX_BASE_H_
      7 
      8 #include <atlbase.h>
      9 #include <atlcom.h>
     10 #include <atlctl.h>
     11 #include <exdisp.h>
     12 #include <wininet.h>
     13 #include <shdeprecated.h>  // for IBrowserService2
     14 #include <shlguid.h>
     15 
     16 #include <set>
     17 #include <string>
     18 #include <vector>
     19 
     20 #include "base/metrics/histogram.h"
     21 #include "base/strings/string_util.h"
     22 #include "base/strings/stringprintf.h"
     23 #include "base/strings/utf_string_conversions.h"
     24 #include "base/win/scoped_bstr.h"
     25 #include "base/win/scoped_comptr.h"
     26 #include "base/win/scoped_variant.h"
     27 #include "chrome/app/chrome_command_ids.h"
     28 #include "chrome/common/url_constants.h"
     29 #include "chrome_frame/chrome_frame_plugin.h"
     30 #include "chrome_frame/chrome_tab.h"
     31 #include "chrome_frame/com_message_event.h"
     32 #include "chrome_frame/com_type_info_holder.h"
     33 #include "chrome_frame/simple_resource_loader.h"
     34 #include "chrome_frame/urlmon_url_request.h"
     35 #include "chrome_frame/urlmon_url_request_private.h"
     36 #include "chrome_frame/utils.h"
     37 #include "grit/chrome_frame_resources.h"
     38 #include "grit/generated_resources.h"
     39 #include "net/cookies/cookie_monster.h"
     40 
     41 // Connection point class to support firing IChromeFrameEvents (dispinterface).
     42 template<class T>
     43 class ATL_NO_VTABLE ProxyDIChromeFrameEvents
     44     : public IConnectionPointImpl<T, &DIID_DIChromeFrameEvents> {
     45  public:
     46   void FireMethodWithParams(ChromeFrameEventDispId dispid,
     47                             const VARIANT* params, size_t num_params) {
     48     T* me = static_cast<T*>(this);
     49     // We need to copy the whole vector and AddRef the sinks in case
     50     // some would get disconnected as we fire methods. Note that this is not
     51     // a threading issue, but a re-entrance issue, because the connection
     52     // can be affected by the implementation of the sinks receiving the event.
     53     me->Lock();
     54     std::vector< base::win::ScopedComPtr<IUnknown> > sink_array(
     55         m_vec.GetSize());
     56     for (int connection = 0; connection < m_vec.GetSize(); ++connection)
     57       sink_array[connection] = m_vec.GetAt(connection);
     58     me->Unlock();
     59 
     60     for (size_t sink = 0; sink < sink_array.size(); ++sink) {
     61       DIChromeFrameEvents* events =
     62           static_cast<DIChromeFrameEvents*>(sink_array[sink].get());
     63       if (events) {
     64         DISPPARAMS disp_params = {
     65             const_cast<VARIANT*>(params),
     66             NULL,
     67             num_params,
     68             0};
     69         HRESULT hr = events->Invoke(static_cast<DISPID>(dispid),
     70                                     DIID_DIChromeFrameEvents,
     71                                     LOCALE_USER_DEFAULT, DISPATCH_METHOD,
     72                                     &disp_params, NULL, NULL, NULL);
     73         DLOG_IF(ERROR, FAILED(hr)) << "invoke(" << dispid << ") failed" <<
     74             base::StringPrintf("0x%08X", hr);
     75       }
     76     }
     77   }
     78 
     79   void FireMethodWithParam(ChromeFrameEventDispId dispid,
     80                            const VARIANT& param) {
     81     FireMethodWithParams(dispid, &param, 1);
     82   }
     83 
     84   void Fire_onload(IDispatch* event) {
     85     VARIANT var = { VT_DISPATCH };
     86     var.pdispVal = event;
     87     FireMethodWithParam(CF_EVENT_DISPID_ONLOAD, var);
     88   }
     89 
     90   void Fire_onloaderror(IDispatch* event) {
     91     VARIANT var = { VT_DISPATCH };
     92     var.pdispVal = event;
     93     FireMethodWithParam(CF_EVENT_DISPID_ONLOADERROR, var);
     94   }
     95 
     96   void Fire_onmessage(IDispatch* event) {
     97     VARIANT var = { VT_DISPATCH };
     98     var.pdispVal = event;
     99     FireMethodWithParam(CF_EVENT_DISPID_ONMESSAGE, var);
    100   }
    101 
    102   void Fire_onreadystatechanged(long readystate) {  // NOLINT
    103     VARIANT var = { VT_I4 };
    104     var.lVal = readystate;
    105     FireMethodWithParam(CF_EVENT_DISPID_ONREADYSTATECHANGED, var);
    106   }
    107 
    108   void Fire_onprivatemessage(IDispatch* event, BSTR target) {
    109     // Arguments in reverse order to the function declaration, because
    110     // that's what DISPPARAMS requires.
    111     VARIANT args[2] = { { VT_BSTR, }, {VT_DISPATCH, } };
    112     args[0].bstrVal = target;
    113     args[1].pdispVal = event;
    114 
    115     FireMethodWithParams(CF_EVENT_DISPID_ONPRIVATEMESSAGE,
    116                          args,
    117                          arraysize(args));
    118   }
    119 
    120   void Fire_onchannelerror() {  // NOLINT
    121     FireMethodWithParams(CF_EVENT_DISPID_ONCHANNELERROR, NULL, 0);
    122   }
    123 
    124   void Fire_onclose() {  // NOLINT
    125     FireMethodWithParams(CF_EVENT_DISPID_ONCLOSE, NULL, 0);
    126   }
    127 };
    128 
    129 extern bool g_first_launch_by_process_;
    130 
    131 namespace chrome_frame {
    132 // Implemented outside this file so that the header doesn't include
    133 // automation_messages.h.
    134 std::string ActiveXCreateUrl(const GURL& parsed_url,
    135                              const AttachExternalTabParams& params);
    136 int GetDisposition(const AttachExternalTabParams& params);
    137 void GetMiniContextMenuData(UINT cmd,
    138                             const MiniContextMenuParams& params,
    139                             GURL* referrer,
    140                             GURL* url);
    141 }  // namespace chrome_frame
    142 
    143 // Common implementation for ActiveX and Active Document
    144 template <class T, const CLSID& class_id>
    145 class ATL_NO_VTABLE ChromeFrameActivexBase :  // NOLINT
    146   public CComObjectRootEx<CComMultiThreadModel>,
    147   public IOleControlImpl<T>,
    148   public IOleObjectImpl<T>,
    149   public IOleInPlaceActiveObjectImpl<T>,
    150   public IViewObjectExImpl<T>,
    151   public IOleInPlaceObjectWindowlessImpl<T>,
    152   public ISupportErrorInfo,
    153   public IQuickActivateImpl<T>,
    154   public com_util::IProvideClassInfo2Impl<class_id,
    155                                           DIID_DIChromeFrameEvents>,
    156   public com_util::IDispatchImpl<IChromeFrame>,
    157   public IConnectionPointContainerImpl<T>,
    158   public ProxyDIChromeFrameEvents<T>,
    159   public IPropertyNotifySinkCP<T>,
    160   public CComCoClass<T, &class_id>,
    161   public CComControl<T>,
    162   public ChromeFramePlugin<T> {
    163  protected:
    164   typedef std::set<base::win::ScopedComPtr<IDispatch> > EventHandlers;
    165   typedef ChromeFrameActivexBase<T, class_id> BasePlugin;
    166 
    167  public:
    168   ChromeFrameActivexBase()
    169       : ready_state_(READYSTATE_UNINITIALIZED),
    170       url_fetcher_(new UrlmonUrlRequestManager()),
    171       failed_to_fetch_in_place_frame_(false),
    172       draw_sad_tab_(false) {
    173     m_bWindowOnly = TRUE;
    174     url_fetcher_->set_container(static_cast<IDispatch*>(this));
    175   }
    176 
    177   ~ChromeFrameActivexBase() {
    178     url_fetcher_->set_container(NULL);
    179   }
    180 
    181 DECLARE_OLEMISC_STATUS(OLEMISC_RECOMPOSEONRESIZE | OLEMISC_CANTLINKINSIDE |
    182                        OLEMISC_INSIDEOUT | OLEMISC_ACTIVATEWHENVISIBLE |
    183                        OLEMISC_SETCLIENTSITEFIRST)
    184 
    185 DECLARE_NOT_AGGREGATABLE(T)
    186 
    187 BEGIN_COM_MAP(ChromeFrameActivexBase)
    188   COM_INTERFACE_ENTRY(IChromeFrame)
    189   COM_INTERFACE_ENTRY(IDispatch)
    190   COM_INTERFACE_ENTRY(IViewObjectEx)
    191   COM_INTERFACE_ENTRY(IViewObject2)
    192   COM_INTERFACE_ENTRY(IViewObject)
    193   COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless)
    194   COM_INTERFACE_ENTRY(IOleInPlaceObject)
    195   COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless)
    196   COM_INTERFACE_ENTRY(IOleInPlaceActiveObject)
    197   COM_INTERFACE_ENTRY(IOleControl)
    198   COM_INTERFACE_ENTRY(IOleObject)
    199   COM_INTERFACE_ENTRY(ISupportErrorInfo)
    200   COM_INTERFACE_ENTRY(IQuickActivate)
    201   COM_INTERFACE_ENTRY(IProvideClassInfo)
    202   COM_INTERFACE_ENTRY(IProvideClassInfo2)
    203   COM_INTERFACE_ENTRY(IConnectionPointContainer)
    204   COM_INTERFACE_ENTRY_FUNC_BLIND(0, InterfaceNotSupported)
    205 END_COM_MAP()
    206 
    207 BEGIN_CONNECTION_POINT_MAP(T)
    208   CONNECTION_POINT_ENTRY(IID_IPropertyNotifySink)
    209   CONNECTION_POINT_ENTRY(DIID_DIChromeFrameEvents)
    210 END_CONNECTION_POINT_MAP()
    211 
    212 BEGIN_MSG_MAP(ChromeFrameActivexBase)
    213   MESSAGE_HANDLER(WM_CREATE, OnCreate)
    214   MESSAGE_HANDLER(WM_DOWNLOAD_IN_HOST, OnDownloadRequestInHost)
    215   MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
    216   CHAIN_MSG_MAP(ChromeFramePlugin<T>)
    217   CHAIN_MSG_MAP(CComControl<T>)
    218   DEFAULT_REFLECTION_HANDLER()
    219 END_MSG_MAP()
    220 
    221   // IViewObjectEx
    222   DECLARE_VIEW_STATUS(VIEWSTATUS_SOLIDBKGND | VIEWSTATUS_OPAQUE)
    223 
    224   inline HRESULT IViewObject_Draw(DWORD draw_aspect, LONG index,
    225       void* aspect_info, DVTARGETDEVICE* ptd, HDC info_dc, HDC dc,
    226       LPCRECTL bounds, LPCRECTL win_bounds) {
    227     // ATL ASSERTs if dwDrawAspect is DVASPECT_DOCPRINT, so we cheat.
    228     DWORD aspect = draw_aspect;
    229     if (aspect == DVASPECT_DOCPRINT)
    230       aspect = DVASPECT_CONTENT;
    231 
    232     return CComControl<T>::IViewObject_Draw(aspect, index, aspect_info, ptd,
    233         info_dc, dc, bounds, win_bounds);
    234   }
    235 
    236   DECLARE_PROTECT_FINAL_CONSTRUCT()
    237 
    238   void SetResourceModule() {
    239     SimpleResourceLoader* loader_instance = SimpleResourceLoader::GetInstance();
    240     DCHECK(loader_instance);
    241     HMODULE res_dll = loader_instance->GetResourceModuleHandle();
    242     _AtlBaseModule.SetResourceInstance(res_dll);
    243   }
    244 
    245   HRESULT FinalConstruct() {
    246     SetResourceModule();
    247 
    248     if (!Initialize())
    249       return E_OUTOFMEMORY;
    250 
    251     // Set to true if this is the first launch by this process.
    252     // Used to perform one time tasks.
    253     if (g_first_launch_by_process_) {
    254       g_first_launch_by_process_ = false;
    255       UMA_HISTOGRAM_CUSTOM_COUNTS("ChromeFrame.IEVersion",
    256                                   GetIEVersion(),
    257                                   IE_INVALID,
    258                                   IE_10,
    259                                   IE_10 + 1);
    260     }
    261 
    262     return S_OK;
    263   }
    264 
    265   void FinalRelease() {
    266     Uninitialize();
    267   }
    268 
    269   void ResetUrlRequestManager() {
    270     url_fetcher_.reset(new UrlmonUrlRequestManager());
    271   }
    272 
    273   static HRESULT WINAPI InterfaceNotSupported(void* pv, REFIID riid, void** ppv,
    274                                               DWORD dw) {
    275 #ifndef NDEBUG
    276     wchar_t buffer[64] = {0};
    277     ::StringFromGUID2(riid, buffer, arraysize(buffer));
    278     DVLOG(1) << "E_NOINTERFACE: " << buffer;
    279 #endif
    280     return E_NOINTERFACE;
    281   }
    282 
    283   // ISupportsErrorInfo
    284   STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid) {
    285     static const IID* interfaces[] = {
    286       &IID_IChromeFrame,
    287       &IID_IDispatch
    288     };
    289 
    290     for (int i = 0; i < arraysize(interfaces); ++i) {
    291       if (InlineIsEqualGUID(*interfaces[i], riid))
    292         return S_OK;
    293     }
    294     return S_FALSE;
    295   }
    296 
    297   // Called to draw our control when chrome hasn't been initialized.
    298   virtual HRESULT OnDraw(ATL_DRAWINFO& draw_info) {  // NOLINT
    299     if (NULL == draw_info.prcBounds) {
    300       NOTREACHED();
    301       return E_FAIL;
    302     }
    303 
    304     if (draw_sad_tab_) {
    305       // TODO(tommi): Draw a proper sad tab.
    306       RECT rc = {0};
    307       if (draw_info.prcBounds) {
    308         rc.top = draw_info.prcBounds->top;
    309         rc.bottom = draw_info.prcBounds->bottom;
    310         rc.left = draw_info.prcBounds->left;
    311         rc.right = draw_info.prcBounds->right;
    312       } else {
    313         GetClientRect(&rc);
    314       }
    315       ::DrawTextA(draw_info.hdcDraw, ":-(", -1, &rc,
    316           DT_CENTER | DT_VCENTER | DT_SINGLELINE);
    317     } else {
    318       // Don't draw anything.
    319     }
    320     return S_OK;
    321   }
    322 
    323   // Used to setup the document_url_ member needed for completing navigation.
    324   // Create external tab (possibly in incognito mode).
    325   HRESULT IOleObject_SetClientSite(IOleClientSite* client_site) {
    326     // If we currently have a document site pointer, release it.
    327     doc_site_.Release();
    328     if (client_site) {
    329       doc_site_.QueryFrom(client_site);
    330     }
    331 
    332     if (client_site == NULL) {
    333       in_place_frame_.Release();
    334     }
    335 
    336     return CComControlBase::IOleObject_SetClientSite(client_site);
    337   }
    338 
    339   bool HandleContextMenuCommand(UINT cmd, const MiniContextMenuParams& params) {
    340     if (cmd == IDC_ABOUT_CHROME_FRAME) {
    341       int tab_handle = automation_client_->tab()->handle();
    342       HostNavigate(GURL("about:version"), GURL(), NEW_WINDOW);
    343       return true;
    344     } else {
    345       switch (cmd) {
    346         case IDS_CONTENT_CONTEXT_SAVEAUDIOAS:
    347         case IDS_CONTENT_CONTEXT_SAVEVIDEOAS:
    348         case IDS_CONTENT_CONTEXT_SAVEIMAGEAS:
    349         case IDS_CONTENT_CONTEXT_SAVELINKAS: {
    350           GURL referrer, url;
    351           chrome_frame::GetMiniContextMenuData(cmd, params, &referrer, &url);
    352           DoFileDownloadInIE(UTF8ToWide(url.spec()).c_str());
    353           return true;
    354         }
    355 
    356         case IDC_PRINT: {
    357           automation_client_->PrintTab();
    358           return true;
    359         }
    360       }
    361     }
    362 
    363     return false;
    364   }
    365 
    366   // Should connections initiated by this class try to block
    367   // responses served with the X-Frame-Options header?
    368   // ActiveX controls genereally will want to do this,
    369   // returning true, while true top-level documents
    370   // (ActiveDocument servers) will not. Your specialization
    371   // of this template should implement this method based on how
    372   // it "feels" from a security perspective. If it's hosted in another
    373   // scriptable document, return true, else false.
    374   //
    375   // The base implementation returns true unless we are in privileged
    376   // mode, in which case we always trust our container so we return false.
    377   bool is_frame_busting_enabled() const {
    378     return !is_privileged();
    379   }
    380 
    381   static void BringWebBrowserWindowToTop(IWebBrowser2* web_browser2) {
    382     DCHECK(web_browser2);
    383     if (web_browser2) {
    384       web_browser2->put_Visible(VARIANT_TRUE);
    385       HWND ie_window = NULL;
    386       web_browser2->get_HWND(reinterpret_cast<long*>(&ie_window));
    387       ::BringWindowToTop(ie_window);
    388     }
    389   }
    390 
    391  protected:
    392   virtual void GetProfilePath(const std::wstring& profile_name,
    393                               base::FilePath* profile_path) {
    394     bool is_IE = (lstrcmpi(profile_name.c_str(), kIexploreProfileName) == 0) ||
    395                  (lstrcmpi(profile_name.c_str(), kRundllProfileName) == 0);
    396     // Browsers without IDeleteBrowsingHistory in non-priv mode
    397     // have their profiles moved into "Temporary Internet Files".
    398     if (is_IE && GetIEVersion() < IE_8) {
    399       *profile_path = GetIETemporaryFilesFolder();
    400       *profile_path = profile_path->Append(L"Google Chrome Frame");
    401     } else {
    402       ChromeFramePlugin::GetProfilePath(profile_name, profile_path);
    403     }
    404     DVLOG(1) << __FUNCTION__ << ": " << profile_path->value();
    405   }
    406 
    407   void OnLoad(const GURL& url) {
    408     if (ready_state_ < READYSTATE_COMPLETE) {
    409       ready_state_ = READYSTATE_COMPLETE;
    410       FireOnChanged(DISPID_READYSTATE);
    411     }
    412 
    413     HRESULT hr = InvokeScriptFunction(onload_handler_, url.spec());
    414   }
    415 
    416   void OnLoadFailed(int error_code, const std::string& url) {
    417     HRESULT hr = InvokeScriptFunction(onerror_handler_, url);
    418   }
    419 
    420   void OnMessageFromChromeFrame(const std::string& message,
    421                                 const std::string& origin,
    422                                 const std::string& target) {
    423     base::win::ScopedComPtr<IDispatch> message_event;
    424     if (SUCCEEDED(CreateDomEvent("message", message, origin,
    425                                  message_event.Receive()))) {
    426       base::win::ScopedVariant event_var;
    427       event_var.Set(static_cast<IDispatch*>(message_event));
    428       InvokeScriptFunction(onmessage_handler_, event_var.AsInput());
    429     }
    430   }
    431 
    432   virtual void OnTabbedOut(bool reverse) {
    433     DCHECK(m_bInPlaceActive);
    434 
    435     HWND parent = ::GetParent(m_hWnd);
    436     ::SetFocus(parent);
    437     base::win::ScopedComPtr<IOleControlSite> control_site;
    438     control_site.QueryFrom(m_spClientSite);
    439     if (control_site)
    440       control_site->OnFocus(FALSE);
    441   }
    442 
    443   virtual void OnOpenURL(const GURL& url_to_open,
    444                          const GURL& referrer, int open_disposition) {
    445     HostNavigate(url_to_open, referrer, open_disposition);
    446   }
    447 
    448   // Called when Chrome has decided that a request needs to be treated as a
    449   // download.  The caller will be the UrlRequest worker thread.
    450   // The worker thread will block while we process the request and take
    451   // ownership of the request object.
    452   // There's room for improvement here and also see todo below.
    453   LPARAM OnDownloadRequestInHost(UINT message, WPARAM wparam, LPARAM lparam,
    454                                  BOOL& handled) {
    455     ChromeFrameUrl cf_url;
    456     cf_url.Parse(UTF8ToWide(GetDocumentUrl()));
    457 
    458     // Always issue the download request in a new window to ensure that the
    459     // currently loaded ChromeFrame document does not inadvartently see an
    460     // unload request. This runs javascript unload handlers on the page which
    461     // renders the page non functional.
    462     VARIANT flags = { VT_I4 };
    463     V_I4(&flags) = navNoHistory;
    464     if (!cf_url.attach_to_external_tab())
    465       V_I4(&flags) |= navOpenInNewWindow;
    466 
    467     DownloadInHostParams* download_params =
    468         reinterpret_cast<DownloadInHostParams*>(wparam);
    469     DCHECK(download_params);
    470     // TODO(tommi): It looks like we might have to switch the request object
    471     // into a pass-through request object and serve up any thus far received
    472     // content and headers to IE in order to prevent what can currently happen
    473     // which is reissuing requests and turning POST into GET.
    474     if (download_params->moniker) {
    475       NavigateBrowserToMoniker(
    476           doc_site_, download_params->moniker,
    477           UTF8ToWide(download_params->request_headers).c_str(),
    478           download_params->bind_ctx, NULL, download_params->post_data,
    479           &flags);
    480     }
    481     delete download_params;
    482     return TRUE;
    483   }
    484 
    485   virtual void OnAttachExternalTab(const AttachExternalTabParams& params) {
    486     GURL current_url(static_cast<BSTR>(url_));
    487     std::string url = chrome_frame::ActiveXCreateUrl(current_url, params);
    488     // Pass the current document url as the referrer for the new navigation.
    489     HostNavigate(GURL(url), current_url, chrome_frame::GetDisposition(params));
    490   }
    491 
    492   virtual void OnHandleContextMenu(const ContextMenuModel& menu_model,
    493                                    int align_flags,
    494                                    const MiniContextMenuParams& params) {
    495     scoped_refptr<BasePlugin> ref(this);
    496     ChromeFramePlugin<T>::OnHandleContextMenu(menu_model, align_flags, params);
    497   }
    498 
    499   LRESULT OnCreate(UINT message, WPARAM wparam, LPARAM lparam,
    500                    BOOL& handled) {  // NO_LINT
    501     ModifyStyle(0, WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0);
    502     url_fetcher_->put_notification_window(m_hWnd);
    503     if (automation_client_.get()) {
    504       automation_client_->SetParentWindow(m_hWnd);
    505     } else {
    506       NOTREACHED() << "No automation server";
    507       return -1;
    508     }
    509     // Only fire the 'interactive' ready state if we aren't there already.
    510     if (ready_state_ < READYSTATE_INTERACTIVE) {
    511       ready_state_ = READYSTATE_INTERACTIVE;
    512       FireOnChanged(DISPID_READYSTATE);
    513     }
    514     return 0;
    515   }
    516 
    517   LRESULT OnDestroy(UINT message, WPARAM wparam, LPARAM lparam,
    518                     BOOL& handled) {  // NO_LINT
    519     DVLOG(1) << __FUNCTION__;
    520     return 0;
    521   }
    522 
    523   // ChromeFrameDelegate override
    524   virtual void OnAutomationServerReady() {
    525     draw_sad_tab_ = false;
    526     ChromeFramePlugin<T>::OnAutomationServerReady();
    527 
    528     ready_state_ = READYSTATE_COMPLETE;
    529     FireOnChanged(DISPID_READYSTATE);
    530   }
    531 
    532   // ChromeFrameDelegate override
    533   virtual void OnAutomationServerLaunchFailed(
    534       AutomationLaunchResult reason, const std::string& server_version) {
    535     DVLOG(1) << __FUNCTION__;
    536     if (reason == AUTOMATION_SERVER_CRASHED)
    537       draw_sad_tab_ = true;
    538 
    539     ready_state_ = READYSTATE_UNINITIALIZED;
    540     FireOnChanged(DISPID_READYSTATE);
    541   }
    542 
    543   virtual void OnCloseTab() {
    544     Fire_onclose();
    545   }
    546 
    547   // Overridden to take advantage of readystate prop changes and send those
    548   // to potential listeners.
    549   HRESULT FireOnChanged(DISPID dispid) {
    550     if (dispid == DISPID_READYSTATE) {
    551       Fire_onreadystatechanged(ready_state_);
    552     }
    553     return __super::FireOnChanged(dispid);
    554   }
    555 
    556   // IChromeFrame
    557   // Property getter/setters for the src attribute, which contains a URL.
    558   // The ChromeFrameActivex control initiates navigation to this URL
    559   // when instantiated.
    560   STDMETHOD(get_src)(BSTR* src) {
    561     if (NULL == src) {
    562       return E_POINTER;
    563     }
    564 
    565     *src = SysAllocString(url_);
    566     return S_OK;
    567   }
    568 
    569   STDMETHOD(put_src)(BSTR src) {
    570     if (src == NULL)
    571       return E_INVALIDARG;
    572 
    573     // Switch the src to UTF8 and try to expand to full URL
    574     std::string src_utf8;
    575     WideToUTF8(src, SysStringLen(src), &src_utf8);
    576     std::string full_url = ResolveURL(GetDocumentUrl(), src_utf8);
    577 
    578     // We can initiate navigation here even if ready_state is not complete.
    579     // We do not have to set proxy, and AutomationClient will take care
    580     // of navigation just after CreateExternalTab is done.
    581     if (!automation_client_->InitiateNavigation(full_url,
    582                                                 GetDocumentUrl(),
    583                                                 this)) {
    584       // TODO(robertshield): Make InitiateNavigation return more useful
    585       // error information.
    586       return E_INVALIDARG;
    587     }
    588 
    589     // Save full URL in BSTR member
    590     url_.Reset(::SysAllocString(UTF8ToWide(full_url).c_str()));
    591 
    592     return S_OK;
    593   }
    594 
    595   STDMETHOD(get_onload)(VARIANT* onload_handler) {
    596     if (NULL == onload_handler)
    597       return E_INVALIDARG;
    598 
    599     *onload_handler = onload_handler_.Copy();
    600 
    601     return S_OK;
    602   }
    603 
    604   // Property setter for the onload attribute, which contains a
    605   // javascript function to be invoked on successful navigation.
    606   STDMETHOD(put_onload)(VARIANT onload_handler) {
    607     if (V_VT(&onload_handler) != VT_DISPATCH) {
    608       DLOG(WARNING) << "Invalid onload handler type: "
    609                     << onload_handler.vt
    610                     << " specified";
    611       return E_INVALIDARG;
    612     }
    613 
    614     onload_handler_ = onload_handler;
    615 
    616     return S_OK;
    617   }
    618 
    619   // Property getter/setters for the onloaderror attribute, which contains a
    620   // javascript function to be invoked on navigation failure.
    621   STDMETHOD(get_onloaderror)(VARIANT* onerror_handler) {
    622     if (NULL == onerror_handler)
    623       return E_INVALIDARG;
    624 
    625     *onerror_handler = onerror_handler_.Copy();
    626 
    627     return S_OK;
    628   }
    629 
    630   STDMETHOD(put_onloaderror)(VARIANT onerror_handler) {
    631     if (V_VT(&onerror_handler) != VT_DISPATCH) {
    632       DLOG(WARNING) << "Invalid onloaderror handler type: "
    633                     << onerror_handler.vt
    634                     << " specified";
    635       return E_INVALIDARG;
    636     }
    637 
    638     onerror_handler_ = onerror_handler;
    639 
    640     return S_OK;
    641   }
    642 
    643   // Property getter/setters for the onmessage attribute, which contains a
    644   // javascript function to be invoked when we receive a message from the
    645   // chrome frame.
    646   STDMETHOD(put_onmessage)(VARIANT onmessage_handler) {
    647     if (V_VT(&onmessage_handler) != VT_DISPATCH) {
    648       DLOG(WARNING) << "Invalid onmessage handler type: "
    649                     << onmessage_handler.vt
    650                     << " specified";
    651       return E_INVALIDARG;
    652     }
    653 
    654     onmessage_handler_ = onmessage_handler;
    655 
    656     return S_OK;
    657   }
    658 
    659   STDMETHOD(get_onmessage)(VARIANT* onmessage_handler) {
    660     if (NULL == onmessage_handler)
    661       return E_INVALIDARG;
    662 
    663     *onmessage_handler = onmessage_handler_.Copy();
    664 
    665     return S_OK;
    666   }
    667 
    668   STDMETHOD(get_readyState)(long* ready_state) {  // NOLINT
    669     DVLOG(1) << __FUNCTION__;
    670     DCHECK(ready_state);
    671 
    672     if (!ready_state)
    673       return E_INVALIDARG;
    674 
    675     *ready_state = ready_state_;
    676 
    677     return S_OK;
    678   }
    679 
    680   // Property getter/setters for use_chrome_network flag. This flag
    681   // indicates if chrome network stack is to be used for fetching
    682   // network requests.
    683   STDMETHOD(get_useChromeNetwork)(VARIANT_BOOL* use_chrome_network) {
    684     if (!use_chrome_network)
    685       return E_INVALIDARG;
    686 
    687     *use_chrome_network =
    688         automation_client_->use_chrome_network() ? VARIANT_TRUE : VARIANT_FALSE;
    689     return S_OK;
    690   }
    691 
    692   STDMETHOD(put_useChromeNetwork)(VARIANT_BOOL use_chrome_network) {
    693     if (!is_privileged()) {
    694       DLOG(ERROR) << "Attempt to set useChromeNetwork in non-privileged mode";
    695       return E_ACCESSDENIED;
    696     }
    697 
    698     automation_client_->set_use_chrome_network(
    699         (VARIANT_FALSE != use_chrome_network));
    700     return S_OK;
    701   }
    702 
    703   // Posts a message to the chrome frame.
    704   STDMETHOD(postMessage)(BSTR message, VARIANT target) {
    705     if (NULL == message) {
    706       return E_INVALIDARG;
    707     }
    708 
    709     if (!automation_client_.get())
    710       return E_FAIL;
    711 
    712     std::string utf8_target;
    713     if (target.vt == VT_BSTR) {
    714       int len = ::SysStringLen(target.bstrVal);
    715       if (len == 1 && target.bstrVal[0] == L'*') {
    716         utf8_target = "*";
    717       } else {
    718         GURL resolved(target.bstrVal);
    719         if (!resolved.is_valid()) {
    720           Error(L"Unable to parse the specified target URL.");
    721           return E_INVALIDARG;
    722         }
    723 
    724         utf8_target = resolved.spec();
    725       }
    726     } else {
    727       utf8_target = "*";
    728     }
    729 
    730     std::string utf8_message;
    731     WideToUTF8(message, ::SysStringLen(message), &utf8_message);
    732 
    733     GURL url(GURL(document_url_).GetOrigin());
    734     std::string origin(url.is_empty() ? "null" : url.spec());
    735     if (!automation_client_->ForwardMessageFromExternalHost(utf8_message,
    736                                                             origin,
    737                                                             utf8_target)) {
    738       Error(L"Failed to post message to chrome frame");
    739       return E_FAIL;
    740     }
    741 
    742     return S_OK;
    743   }
    744 
    745   STDMETHOD(addEventListener)(BSTR event_type, IDispatch* listener,
    746                               VARIANT use_capture) {
    747     EventHandlers* handlers = NULL;
    748     HRESULT hr = GetHandlersForEvent(event_type, &handlers);
    749     if (FAILED(hr))
    750       return hr;
    751 
    752     DCHECK(handlers != NULL);
    753 
    754     handlers->insert(base::win::ScopedComPtr<IDispatch>(listener));
    755 
    756     return hr;
    757   }
    758 
    759   STDMETHOD(removeEventListener)(BSTR event_type, IDispatch* listener,
    760                                  VARIANT use_capture) {
    761     EventHandlers* handlers = NULL;
    762     HRESULT hr = GetHandlersForEvent(event_type, &handlers);
    763     if (FAILED(hr))
    764       return hr;
    765 
    766     DCHECK(handlers != NULL);
    767     handlers->erase(base::win::ScopedComPtr<IDispatch>(listener));
    768 
    769     return hr;
    770   }
    771 
    772   STDMETHOD(get_version)(BSTR* version) {
    773     if (!automation_client_.get()) {
    774       NOTREACHED();
    775       return E_FAIL;
    776     }
    777 
    778     if (version == NULL) {
    779       return E_INVALIDARG;
    780     }
    781 
    782     *version = SysAllocString(automation_client_->GetVersion().c_str());
    783     return S_OK;
    784   }
    785 
    786   STDMETHOD(postPrivateMessage)(BSTR message, BSTR origin, BSTR target) {
    787     if (NULL == message)
    788       return E_INVALIDARG;
    789 
    790     if (!is_privileged()) {
    791       DLOG(ERROR) << "Attempt to postPrivateMessage in non-privileged mode";
    792       return E_ACCESSDENIED;
    793     }
    794 
    795     DCHECK(automation_client_.get());
    796     std::string utf8_message, utf8_origin, utf8_target;
    797     WideToUTF8(message, ::SysStringLen(message), &utf8_message);
    798     WideToUTF8(origin, ::SysStringLen(origin), &utf8_origin);
    799     WideToUTF8(target, ::SysStringLen(target), &utf8_target);
    800 
    801     if (!automation_client_->ForwardMessageFromExternalHost(utf8_message,
    802                                                             utf8_origin,
    803                                                             utf8_target)) {
    804       Error(L"Failed to post message to chrome frame");
    805       return E_FAIL;
    806     }
    807 
    808     return S_OK;
    809   }
    810 
    811   STDMETHOD(installExtension)(BSTR crx_path) {
    812     NOTREACHED();  // Deprecated.
    813     return E_NOTIMPL;
    814   }
    815 
    816   STDMETHOD(loadExtension)(BSTR path) {
    817     NOTREACHED();  // Deprecated.
    818     return E_NOTIMPL;
    819   }
    820 
    821   STDMETHOD(getEnabledExtensions)() {
    822     NOTREACHED();  // Deprecated.
    823     return E_NOTIMPL;
    824   }
    825 
    826   STDMETHOD(registerBhoIfNeeded)() {
    827     return E_NOTIMPL;
    828   }
    829 
    830   // Returns the vector of event handlers for a given event (e.g. "load").
    831   // If the event type isn't recognized, the function fills in a descriptive
    832   // error (IErrorInfo) and returns E_INVALIDARG.
    833   HRESULT GetHandlersForEvent(BSTR event_type, EventHandlers** handlers) {
    834     DCHECK(handlers != NULL);
    835 
    836     // TODO(tommi): make these if() statements data-driven.
    837     HRESULT hr = S_OK;
    838     const wchar_t* event_type_end = event_type + ::SysStringLen(event_type);
    839     if (LowerCaseEqualsASCII(event_type, event_type_end, "message")) {
    840       *handlers = &onmessage_;
    841     } else if (LowerCaseEqualsASCII(event_type, event_type_end, "load")) {
    842       *handlers = &onload_;
    843     } else if (LowerCaseEqualsASCII(event_type, event_type_end, "loaderror")) {
    844       *handlers = &onloaderror_;
    845     } else if (LowerCaseEqualsASCII(event_type, event_type_end,
    846                                     "readystatechanged")) {
    847       *handlers = &onreadystatechanged_;
    848     } else if (LowerCaseEqualsASCII(event_type, event_type_end,
    849                                     "privatemessage")) {
    850       // This event handler is only available in privileged mode.
    851       if (is_privileged()) {
    852         *handlers = &onprivatemessage_;
    853       } else {
    854         Error("Event type 'privatemessage' is privileged");
    855         hr = E_ACCESSDENIED;
    856       }
    857     } else if (LowerCaseEqualsASCII(event_type, event_type_end,
    858                                     "extensionready")) {
    859       // This event handler is only available in privileged mode.
    860       if (is_privileged()) {
    861         *handlers = &onextensionready_;
    862       } else {
    863         Error("Event type 'extensionready' is privileged");
    864         hr = E_ACCESSDENIED;
    865       }
    866     } else {
    867       Error(base::StringPrintf(
    868           "Event type '%ls' not found", event_type).c_str());
    869       hr = E_INVALIDARG;
    870     }
    871 
    872     return hr;
    873   }
    874 
    875   // Creates a new event object that supports the |data| property.
    876   // Note: you should supply an empty string for |origin| unless you're
    877   // creating a "message" event.
    878   HRESULT CreateDomEvent(const std::string& event_type, const std::string& data,
    879                          const std::string& origin, IDispatch** event) {
    880     DCHECK(event_type.length() > 0);  // NOLINT
    881     DCHECK(event != NULL);
    882 
    883     CComObject<ComMessageEvent>* ev = NULL;
    884     HRESULT hr = CComObject<ComMessageEvent>::CreateInstance(&ev);
    885     if (SUCCEEDED(hr)) {
    886       ev->AddRef();
    887 
    888       base::win::ScopedComPtr<IOleContainer> container;
    889       m_spClientSite->GetContainer(container.Receive());
    890       if (ev->Initialize(container, data, origin, event_type)) {
    891         *event = ev;
    892       } else {
    893         NOTREACHED() << "event->Initialize";
    894         ev->Release();
    895         hr = E_UNEXPECTED;
    896       }
    897     }
    898 
    899     return hr;
    900   }
    901 
    902   // Helper function to execute a function on a script IDispatch interface.
    903   HRESULT InvokeScriptFunction(const VARIANT& script_object,
    904                                const std::string& param) {
    905     base::win::ScopedVariant script_arg(UTF8ToWide(param.c_str()).c_str());
    906     return InvokeScriptFunction(script_object, script_arg.AsInput());
    907   }
    908 
    909   HRESULT InvokeScriptFunction(const VARIANT& script_object, VARIANT* param) {
    910     return InvokeScriptFunction(script_object, param, 1);
    911   }
    912 
    913   HRESULT InvokeScriptFunction(const VARIANT& script_object, VARIANT* params,
    914                                int param_count) {
    915     DCHECK_GE(param_count, 0);
    916     DCHECK(params);
    917 
    918     if (V_VT(&script_object) != VT_DISPATCH ||
    919         script_object.pdispVal == NULL) {
    920       return S_FALSE;
    921     }
    922 
    923     CComPtr<IDispatch> script(script_object.pdispVal);
    924     HRESULT hr = script.InvokeN(static_cast<DISPID>(DISPID_VALUE),
    925                                 params,
    926                                 param_count);
    927     // 0x80020101 == SCRIPT_E_REPORTED.
    928     // When the script we're invoking has an error, we get this error back.
    929     DLOG_IF(ERROR, FAILED(hr) && hr != 0x80020101) << "Failed to invoke script";
    930     return hr;
    931   }
    932 
    933   // Gives the browser a chance to handle an accelerator that was
    934   // sent to the out of proc chromium instance.
    935   // Returns S_OK iff the accelerator was handled by the browser.
    936   HRESULT AllowFrameToTranslateAccelerator(const MSG& msg) {
    937     static const int kMayTranslateAcceleratorOffset = 0x5c;
    938     // Although IBrowserService2 is officially deprecated, it's still alive
    939     // and well in IE7 and earlier.  We have to use it here to correctly give
    940     // the browser a chance to handle keyboard shortcuts.
    941     // This happens automatically for activex components that have windows that
    942     // belong to the current thread.  In that circumstance IE owns the message
    943     // loop and can walk the line of components allowing each participant the
    944     // chance to handle the keystroke and eventually falls back to
    945     // v_MayTranslateAccelerator.  However in our case, the message loop is
    946     // owned by the out-of-proc chromium instance so IE doesn't have a chance to
    947     // fall back on its default behavior.  Instead we give IE a chance to
    948     // handle the shortcut here.
    949     MSG accel_message = msg;
    950     accel_message.hwnd = ::GetParent(m_hWnd);
    951     HRESULT hr = S_FALSE;
    952     base::win::ScopedComPtr<IBrowserService2> bs2;
    953 
    954     // For non-IE containers, we use the standard IOleInPlaceFrame contract
    955     // (which IE does not support). For IE, we try to use IBrowserService2,
    956     // but need special handling for IE8 (see below).
    957     //
    958     // We try to cache an IOleInPlaceFrame for our site.  If we fail, we don't
    959     // retry, and we fall back to the IBrowserService2 and PostMessage
    960     // approaches below.
    961     if (!in_place_frame_ && !failed_to_fetch_in_place_frame_) {
    962       base::win::ScopedComPtr<IOleInPlaceUIWindow> dummy_ui_window;
    963       RECT dummy_pos_rect = {0};
    964       RECT dummy_clip_rect = {0};
    965       OLEINPLACEFRAMEINFO dummy_frame_info = {0};
    966       if (!m_spInPlaceSite ||
    967           FAILED(m_spInPlaceSite->GetWindowContext(in_place_frame_.Receive(),
    968                                                    dummy_ui_window.Receive(),
    969                                                    &dummy_pos_rect,
    970                                                    &dummy_clip_rect,
    971                                                    &dummy_frame_info))) {
    972         failed_to_fetch_in_place_frame_ = true;
    973       }
    974     }
    975 
    976     // The IBrowserService2 code below (second conditional) explicitly checks
    977     // for whether the IBrowserService2::v_MayTranslateAccelerator function is
    978     // valid. On IE8 there is one vtable ieframe!c_ImpostorBrowserService2Vtbl
    979     // where this function entry is NULL which leads to a crash. We don't know
    980     // under what circumstances this vtable is actually used though.
    981     if (in_place_frame_) {
    982       hr = in_place_frame_->TranslateAccelerator(&accel_message, 0);
    983     } else if (S_OK == DoQueryService(
    984         SID_STopLevelBrowser, m_spInPlaceSite,
    985         bs2.Receive()) && bs2.get() &&
    986         *(*(reinterpret_cast<void***>(bs2.get())) +
    987         kMayTranslateAcceleratorOffset)) {
    988       hr = bs2->v_MayTranslateAccelerator(&accel_message);
    989     } else {
    990       // IE8 doesn't support IBrowserService2 unless you enable a special,
    991       // undocumented flag with CoInternetSetFeatureEnabled and even then,
    992       // the object you get back implements only a couple of methods of
    993       // that interface... all the other entries in the vtable are NULL.
    994       // In addition, the class that implements it is called
    995       // ImpostorBrowserService2 :)
    996       // IE8 does have a new interface though, presumably called
    997       // ITabBrowserService or something that can be abbreviated to TBS.
    998       // That interface has a method, TranslateAcceleratorTBS that does
    999       // call the root MayTranslateAccelerator function, but alas the
   1000       // first argument to MayTranslateAccelerator is hard coded to FALSE
   1001       // which means that global accelerators are not handled and we're
   1002       // out of luck.
   1003       // A third thing that's notable with regards to IE8 is that
   1004       // none of the *MayTranslate* functions exist in a vtable inside
   1005       // ieframe.dll.  I checked this by scanning for the address of
   1006       // those functions inside the dll and found none, which means that
   1007       // all calls to those functions are relative.
   1008       // So, for IE8 in certain cases, and for other containers that may
   1009       // support neither IOleInPlaceFrame or IBrowserService2 our approach
   1010       // is very simple.  Just post the message to our parent window and IE
   1011       // will pick it up if it's an accelerator. We won't know for sure if
   1012       // the browser handled the keystroke or not.
   1013       ::PostMessage(accel_message.hwnd, accel_message.message,
   1014                     accel_message.wParam, accel_message.lParam);
   1015     }
   1016 
   1017     return hr;
   1018   }
   1019 
   1020   virtual void OnAcceleratorPressed(const MSG& accel_message) {
   1021     DCHECK(m_spInPlaceSite != NULL);
   1022     // Allow our host a chance to handle the accelerator.
   1023     // This catches things like Ctrl+F, Ctrl+O etc, but not browser
   1024     // accelerators such as F11, Ctrl+T etc.
   1025     // (see AllowFrameToTranslateAccelerator for those).
   1026     HRESULT hr = TranslateAccelerator(const_cast<MSG*>(&accel_message));
   1027     if (hr != S_OK)
   1028       hr = AllowFrameToTranslateAccelerator(accel_message);
   1029 
   1030     DVLOG(1) << __FUNCTION__ << " browser response: "
   1031              << base::StringPrintf("0x%08x", hr);
   1032 
   1033     if (hr != S_OK) {
   1034       // The WM_SYSKEYDOWN/WM_SYSKEYUP messages are not processed by the
   1035       // IOleControlSite and IBrowserService2::v_MayTranslateAccelerator
   1036       // implementations. We need to understand this better. That is for
   1037       // another day. For now we just post these messages back to the parent
   1038       // which forwards it off to the frame. This should not cause major
   1039       // grief for Chrome as it does not need to handle WM_SYSKEY* messages in
   1040       // in ChromeFrame mode.
   1041       // TODO(iyengar)
   1042       // Understand and fix WM_SYSCHAR handling
   1043       // We should probably unify the accelerator handling for the active
   1044       // document and the activex.
   1045       if (accel_message.message == WM_SYSCHAR ||
   1046           accel_message.message == WM_SYSKEYDOWN ||
   1047           accel_message.message == WM_SYSKEYUP) {
   1048         ::PostMessage(GetParent(), accel_message.message, accel_message.wParam,
   1049                       accel_message.lParam);
   1050         return;
   1051       }
   1052     }
   1053     // Last chance to handle the keystroke is to pass it to chromium.
   1054     // We do this last partially because there's no way for us to tell if
   1055     // chromium actually handled the keystroke, but also since the browser
   1056     // should have first dibs anyway.
   1057     if (hr != S_OK && automation_client_.get()) {
   1058       TabProxy* tab = automation_client_->tab();
   1059       if (tab) {
   1060         tab->ProcessUnhandledAccelerator(accel_message);
   1061       }
   1062     }
   1063   }
   1064 
   1065  protected:
   1066   void HostNavigate(const GURL& url_to_open,
   1067                     const GURL& referrer, int open_disposition) {
   1068     base::win::ScopedComPtr<IWebBrowser2> web_browser2;
   1069     DoQueryService(SID_SWebBrowserApp, m_spClientSite, web_browser2.Receive());
   1070     if (!web_browser2) {
   1071       NOTREACHED() << "Failed to retrieve IWebBrowser2 interface";
   1072       return;
   1073     }
   1074     base::win::ScopedVariant url;
   1075     // Check to see if the URL uses a "view-source:" prefix, if so, open it
   1076     // using chrome frame full tab mode by using 'cf:' protocol handler.
   1077     // Also change the disposition to NEW_WINDOW since IE6 doesn't have tabs.
   1078     if (url_to_open.has_scheme() &&
   1079         (url_to_open.SchemeIs(content::kViewSourceScheme) ||
   1080         url_to_open.SchemeIs(chrome::kAboutScheme))) {
   1081       std::wstring chrome_url;
   1082       chrome_url.append(kChromeProtocolPrefix);
   1083       chrome_url.append(UTF8ToWide(url_to_open.spec()));
   1084       url.Set(chrome_url.c_str());
   1085       open_disposition = NEW_WINDOW;
   1086     } else {
   1087       url.Set(UTF8ToWide(url_to_open.spec()).c_str());
   1088     }
   1089 
   1090     VARIANT flags = { VT_I4 };
   1091     V_I4(&flags) = 0;
   1092 
   1093     IEVersion ie_version = GetIEVersion();
   1094     DCHECK(ie_version != NON_IE && ie_version != IE_UNSUPPORTED);
   1095     // Since IE6 doesn't support tabs, so we just use window instead.
   1096     if (ie_version == IE_6) {
   1097       if (open_disposition == NEW_FOREGROUND_TAB ||
   1098           open_disposition == NEW_BACKGROUND_TAB ||
   1099           open_disposition == NEW_WINDOW ||
   1100           open_disposition == NEW_POPUP) {
   1101         V_I4(&flags) = navOpenInNewWindow;
   1102       } else if (open_disposition != CURRENT_TAB) {
   1103         NOTREACHED() << "Unsupported open disposition in IE6";
   1104       }
   1105     } else {
   1106       switch (open_disposition) {
   1107         case NEW_FOREGROUND_TAB:
   1108           V_I4(&flags) = navOpenInNewTab;
   1109           break;
   1110         case NEW_BACKGROUND_TAB:
   1111           V_I4(&flags) = navOpenInBackgroundTab;
   1112           break;
   1113         case NEW_WINDOW:
   1114         case NEW_POPUP:
   1115           V_I4(&flags) = navOpenInNewWindow;
   1116           break;
   1117         default:
   1118           break;
   1119       }
   1120     }
   1121 
   1122     // TODO(sanjeevr): The navOpenInNewWindow flag causes IE to open this
   1123     // in a new window ONLY if the user has specified
   1124     // "Always open popups in a new window". Otherwise it opens in a new tab.
   1125     // We need to investigate more and see if we can force IE to display the
   1126     // link in a new window. MSHTML uses the below code to force an open in a
   1127     // new window. But this logic also fails for us. Perhaps this flag is not
   1128     // honoured if the ActiveDoc is not MSHTML.
   1129     // Even the HLNF_DISABLEWINDOWRESTRICTIONS flag did not work.
   1130     // Start of MSHTML-like logic.
   1131     // CComQIPtr<ITargetFramePriv2> target_frame = web_browser2;
   1132     // if (target_frame) {
   1133     //   CComPtr<IUri> uri;
   1134     //   CreateUri(UTF8ToWide(open_url_command->url_.spec()).c_str(),
   1135     //             Uri_CREATE_IE_SETTINGS, 0, &uri);
   1136     //   CComPtr<IBindCtx> bind_ctx;
   1137     //   CreateBindCtx(0, &bind_ctx);
   1138     //   target_frame->AggregatedNavigation2(
   1139     //       HLNF_TRUSTFIRSTDOWNLOAD|HLNF_OPENINNEWWINDOW, bind_ctx, NULL,
   1140     //       L"No_Name", uri, L"");
   1141     // }
   1142     // End of MSHTML-like logic
   1143     VARIANT empty = base::win::ScopedVariant::kEmptyVariant;
   1144     base::win::ScopedVariant http_headers;
   1145 
   1146     if (referrer.is_valid()) {
   1147       std::wstring referrer_header = L"Referer: ";
   1148       referrer_header += UTF8ToWide(referrer.spec());
   1149       referrer_header += L"\r\n\r\n";
   1150       http_headers.Set(referrer_header.c_str());
   1151     }
   1152 
   1153     // IE6 does not support tabs. If Chrome sent us a window open request
   1154     // indicating that the navigation needs to occur in a foreground tab or
   1155     // a popup window, then we need to ensure that the new window in IE6 is
   1156     // brought to the foreground.
   1157     if (ie_version == IE_6) {
   1158       ChromeFrameUrl cf_url;
   1159       cf_url.Parse(static_cast<BSTR>(url_));
   1160 
   1161       if (cf_url.attach_to_external_tab() &&
   1162           (cf_url.disposition() == NEW_FOREGROUND_TAB ||
   1163            cf_url.disposition() == NEW_POPUP)) {
   1164         BringWebBrowserWindowToTop(web_browser2);
   1165       }
   1166     }
   1167 
   1168     HRESULT hr = web_browser2->Navigate2(url.AsInput(), &flags, &empty, &empty,
   1169                                          http_headers.AsInput());
   1170     // If the current window is a popup window then attempting to open a new
   1171     // tab for the navigation will fail. We attempt to issue the navigation in
   1172     // a new window in this case.
   1173     // http://msdn.microsoft.com/en-us/library/aa752133(v=vs.85).aspx
   1174     if (FAILED(hr) && V_I4(&flags) != navOpenInNewWindow) {
   1175       V_I4(&flags) = navOpenInNewWindow;
   1176       hr = web_browser2->Navigate2(url.AsInput(), &flags, &empty, &empty,
   1177                                    http_headers.AsInput());
   1178       DLOG_IF(ERROR, FAILED(hr))
   1179           << "Navigate2 failed with error: "
   1180           << base::StringPrintf("0x%08X", hr);
   1181     }
   1182   }
   1183 
   1184   void InitializeAutomationSettings() {
   1185     static const wchar_t kHandleTopLevelRequests[] = L"HandleTopLevelRequests";
   1186     static const wchar_t kUseChromeNetworking[] = L"UseChromeNetworking";
   1187 
   1188     // Query and assign the top-level-request routing, and host networking
   1189     // settings from the registry.
   1190     bool top_level_requests = GetConfigBool(true, kHandleTopLevelRequests);
   1191     bool chrome_network = GetConfigBool(false, kUseChromeNetworking);
   1192     automation_client_->set_handle_top_level_requests(top_level_requests);
   1193     automation_client_->set_use_chrome_network(chrome_network);
   1194   }
   1195 
   1196   base::win::ScopedBstr url_;
   1197   base::win::ScopedComPtr<IOleDocumentSite> doc_site_;
   1198 
   1199   // If false, we tried but failed to fetch an IOleInPlaceFrame from our host.
   1200   // Cached here so we don't try to fetch it every time if we keep failing.
   1201   bool failed_to_fetch_in_place_frame_;
   1202   bool draw_sad_tab_;
   1203 
   1204   base::win::ScopedComPtr<IOleInPlaceFrame> in_place_frame_;
   1205 
   1206   // For more information on the ready_state_ property see:
   1207   // http://msdn.microsoft.com/en-us/library/aa768179(VS.85).aspx#
   1208   READYSTATE ready_state_;
   1209 
   1210   // The following members contain IDispatch interfaces representing the
   1211   // onload/onerror/onmessage handlers on the page.
   1212   base::win::ScopedVariant onload_handler_;
   1213   base::win::ScopedVariant onerror_handler_;
   1214   base::win::ScopedVariant onmessage_handler_;
   1215 
   1216   EventHandlers onmessage_;
   1217   EventHandlers onloaderror_;
   1218   EventHandlers onload_;
   1219   EventHandlers onreadystatechanged_;
   1220   EventHandlers onprivatemessage_;
   1221   EventHandlers onextensionready_;
   1222 
   1223   // Handle network requests when host network stack is used. Passed to the
   1224   // automation client on initialization.
   1225   scoped_ptr<UrlmonUrlRequestManager> url_fetcher_;
   1226 };
   1227 
   1228 #endif  // CHROME_FRAME_CHROME_FRAME_ACTIVEX_BASE_H_
   1229