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