Home | History | Annotate | Download | only in chrome_frame
      1 // Copyright (c) 2010 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_URLMON_MONIKER_H_
      6 #define CHROME_FRAME_URLMON_MONIKER_H_
      7 
      8 #include <atlbase.h>
      9 #include <atlcom.h>
     10 #include <urlmon.h>
     11 #include <string>
     12 
     13 #include "base/lazy_instance.h"
     14 #include "base/logging.h"
     15 #include "base/threading/thread_local.h"
     16 #include "base/win/scoped_variant.h"
     17 #include "chrome_frame/utils.h"
     18 
     19 // This file contains classes that are used to cache the contents of a top-level
     20 // http request (not for sub frames) while that request is parsed for the
     21 // presence of a meta tag indicating that the page should be rendered in CF.
     22 
     23 // Here are a few scenarios we handle and how the classes come to play.
     24 
     25 //
     26 // Scenario 1: Non CF url navigation through address bar (www.msn.com)
     27 // - Bho::BeforeNavigate - top level url = www.msn.com
     28 // - MSHTML -> MonikerPatch::BindToStorage.
     29 //   (IEFrame starts this by calling mshtml!*SuperNavigate*)
     30 //    - check if the url is a top level url
     31 //    - iff the url is a top level url, we switch in our own callback object
     32 //      and hook it up to the bind context (BSCBStorageBind)
     33 //    - otherwise just call the original
     34 // - BSCBStorageBind::OnDataAvailable - sniffs data and determines that the
     35 //   renderer is not chrome. Goes into pass through mode.
     36 // -  The page loads in mshtml.
     37 //
     38 
     39 //
     40 // Scenario 2: CF navigation through address bar URL
     41 // - Bho::BeforeNavigate - top level url = http://wave.google.com/
     42 // - MSHTML -> MonikerPatch::BindToStorage.
     43 //   (IEFrame starts this by calling mshtml!*SuperNavigate*)
     44 //    - request_data is NULL
     45 //    - check if the url is a top level url
     46 //    - iff the url is a top level url, we switch in our own callback object
     47 //      and hook it up to the bind context (BSCBStorageBind)
     48 // - BSCBStorageBind::OnDataAvailable - sniffs data and determines that the
     49 //   renderer is chrome. It then registers a special bind context param and
     50 //   sets a magic clip format in the format_etc. Then goes into pass through
     51 //   mode.
     52 // - mshtml looks at the clip format and re-issues the navigation with the
     53 //   same bind context. Also returns INET_E_TERMINATED_BIND so that same
     54 //   underlying transaction objects are used.
     55 // - IEFrame -> MonikerPatch::BindToStorage
     56 //    - We check for the special bind context param and instantiate and
     57 //      return our ActiveDoc
     58 
     59 //
     60 // Scenario 3: CF navigation through mshtml link
     61 //  Same as scenario #2.
     62 //
     63 
     64 //
     65 // Scenario 4: CF navigation through link click in chrome loads non CF page
     66 // - Link click comes to ChromeActiveDocument::OnOpenURL
     67 //    - web_browser->Navigate with URL
     68 // - [Scenario 1]
     69 //
     70 
     71 //
     72 // Scenario 5: CF navigation through link click in chrome loads CF page
     73 // - Link click comes to ChromeActiveDocument::OnOpenURL
     74 //    - web_browser->Navigate with URL
     75 // - [Scenario 2]
     76 //
     77 
     78 // This class is the link between a few static, moniker related functions to
     79 // the bho.  The specific services needed by those functions are abstracted into
     80 // this interface for easier testability.
     81 class NavigationManager {
     82  public:
     83   NavigationManager() {
     84   }
     85 
     86   // Returns the Bho instance for the current thread. This is returned from
     87   // TLS.  Returns NULL if no instance exists on the current thread.
     88   static NavigationManager* GetThreadInstance();
     89 
     90   void RegisterThreadInstance();
     91   void UnregisterThreadInstance();
     92 
     93   virtual ~NavigationManager() {
     94     DCHECK(GetThreadInstance() != this);
     95   }
     96 
     97   // Returns the url of the current top level navigation.
     98   const std::wstring& url() const {
     99     return url_;
    100   }
    101 
    102   // Called to set the current top level URL that's being navigated to.
    103   void set_url(const wchar_t* url) {
    104     DVLOG(1) << __FUNCTION__ << " " << url;
    105     url_ = url;
    106   }
    107 
    108   // Returns the referrer header value of the current top level navigation.
    109   const std::string& referrer() const {
    110     return referrer_;
    111   }
    112 
    113   void set_referrer(const std::string& referrer) {
    114     referrer_ = referrer;
    115   }
    116 
    117   // Return true if this is a URL that represents a top-level
    118   // document that might have to be rendered in CF.
    119   virtual bool IsTopLevelUrl(const wchar_t* url);
    120 
    121   // Called when we've detected the http-equiv meta tag in the current page
    122   // and need to switch over from mshtml to CF.
    123   virtual HRESULT NavigateToCurrentUrlInCF(IBrowserService* browser);
    124 
    125   void set_post_data(VARIANT* post_data) {
    126     post_data_.Reset();
    127     if (post_data) {
    128       if (V_VT(post_data) == (VT_BYREF | VT_VARIANT)) {
    129         post_data_.Set(*post_data->pvarVal);
    130       } else {
    131         NOTREACHED() << "unexpected type for post_data: "
    132             << std::hex << post_data->vt;
    133       }
    134     }
    135   }
    136 
    137   const base::win::ScopedVariant& post_data() const {
    138     return post_data_;
    139   }
    140 
    141   void set_headers(VARIANT* headers) {
    142     headers_.Reset();
    143     if (headers) {
    144       headers_ = *headers;
    145     }
    146   }
    147 
    148   const base::win::ScopedVariant& headers() const {
    149     return headers_;
    150   }
    151 
    152  protected:
    153   std::string referrer_;
    154   std::wstring url_;
    155   base::win::ScopedVariant post_data_;
    156   base::win::ScopedVariant headers_;
    157 
    158   static base::LazyInstance<base::ThreadLocalPointer<NavigationManager> >
    159       thread_singleton_;
    160 
    161  private:
    162   DISALLOW_COPY_AND_ASSIGN(NavigationManager);
    163 };
    164 
    165 // static-only class that manages an IMoniker patch.
    166 // We need this patch to stay in the loop when top-level HTML content is
    167 // downloaded that might have the CF http-equiv meta tag.
    168 // When we detect candidates for those requests, we add our own callback
    169 // object (as explained at the top of this file) and use it to cache the
    170 // original document contents in order to avoid multiple network trips
    171 // if we need to switch the renderer over to CF.
    172 class MonikerPatch {
    173   MonikerPatch() {}  // no instances should be created of this class.
    174  public:
    175   // Patches two IMoniker methods, BindToObject and BindToStorage.
    176   static bool Initialize();
    177 
    178   // Nullifies the IMoniker patches.
    179   static void Uninitialize();
    180 
    181   // Typedefs for IMoniker methods.
    182   typedef HRESULT (STDMETHODCALLTYPE* IMoniker_BindToObject_Fn)(IMoniker* me,
    183       IBindCtx* bind_ctx, IMoniker* to_left, REFIID iid, void** obj);
    184   typedef HRESULT (STDMETHODCALLTYPE* IMoniker_BindToStorage_Fn)(IMoniker* me,
    185       IBindCtx* bind_ctx, IMoniker* to_left, REFIID iid, void** obj);
    186 
    187   static STDMETHODIMP BindToObject(IMoniker_BindToObject_Fn original,
    188                                    IMoniker* me, IBindCtx* bind_ctx,
    189                                    IMoniker* to_left, REFIID iid, void** obj);
    190 
    191   static STDMETHODIMP BindToStorage(IMoniker_BindToStorage_Fn original,
    192                                     IMoniker* me, IBindCtx* bind_ctx,
    193                                     IMoniker* to_left, REFIID iid, void** obj);
    194 };
    195 
    196 extern wchar_t* kChromeRequestParam;
    197 
    198 #endif  // CHROME_FRAME_URLMON_MONIKER_H_
    199