Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(175)

Side by Side Diff: chrome_frame/urlmon_moniker.h

Issue 1589013: Switch renderer in Moniker patch... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 10 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef CHROME_FRAME_URLMON_MONIKER_H_ 5 #ifndef CHROME_FRAME_URLMON_MONIKER_H_
6 #define CHROME_FRAME_URLMON_MONIKER_H_ 6 #define CHROME_FRAME_URLMON_MONIKER_H_
7 7
8 #include <atlbase.h> 8 #include <atlbase.h>
9 #include <atlcom.h> 9 #include <atlcom.h>
10 #include <urlmon.h> 10 #include <urlmon.h>
11 #include <string> 11 #include <string>
12 12
13 #include "base/lazy_instance.h" 13 #include "base/lazy_instance.h"
14 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "base/scoped_comptr_win.h" 15 #include "base/scoped_comptr_win.h"
16 #include "base/thread_local.h" 16 #include "base/thread_local.h"
17
18 #include "chrome_frame/urlmon_moniker_base.h"
19 #include "chrome_frame/utils.h" 17 #include "chrome_frame/utils.h"
20 18
21 // This file contains classes that are used to cache the contents of a top-level 19 // This file contains classes that are used to cache the contents of a top-level
22 // http request (not for sub frames) while that request is parsed for the 20 // http request (not for sub frames) while that request is parsed for the
23 // presence of a meta tag indicating that the page should be rendered in CF. 21 // presence of a meta tag indicating that the page should be rendered in CF.
24 22
25 // Here are a few scenarios we handle and how the classes come to play. 23 // Here are a few scenarios we handle and how the classes come to play.
26 24
27 // 25 //
28 // Scenario 1: Non CF url navigation through address bar (www.msn.com) 26 // Scenario 1: Non CF url navigation through address bar (www.msn.com)
29 // - Bho::BeforeNavigate - top level url = www.msn.com 27 // - Bho::BeforeNavigate - top level url = www.msn.com
30 // - MSHTML -> MonikerPatch::BindToStorage. 28 // - MSHTML -> MonikerPatch::BindToStorage.
31 // (IEFrame starts this by calling mshtml!*SuperNavigate*) 29 // (IEFrame starts this by calling mshtml!*SuperNavigate*)
32 // - request_data is NULL
33 // - check if the url is a top level url 30 // - check if the url is a top level url
34 // - iff the url is a top level url, we switch in our own callback object 31 // - iff the url is a top level url, we switch in our own callback object
35 // and hook it up to the bind context (CFUrlmonBindStatusCallback) 32 // and hook it up to the bind context (BSCBStorageBind)
36 // The callback object caches the document in memory.
37 // - otherwise just call the original 33 // - otherwise just call the original
38 // - Bho::OnHttpEquiv is called with done == TRUE. At this point we determine 34 // - BSCBStorageBind::OnDataAvailable - sniffs data and determines that the
39 // that the page did not have the CF meta tag in it and we delete the cache. 35 // renderer is not chrome. Goes into pass through mode.
40 // - The page loads in mshtml. 36 // - The page loads in mshtml.
41 // 37 //
42 38
43 // 39 //
44 // Scenario 2: CF navigation through address bar URL 40 // Scenario 2: CF navigation through address bar URL
45 // - Bho::BeforeNavigate - top level url = http://wave.google.com/ 41 // - Bho::BeforeNavigate - top level url = http://wave.google.com/
46 // - MSHTML -> MonikerPatch::BindToStorage. 42 // - MSHTML -> MonikerPatch::BindToStorage.
47 // (IEFrame starts this by calling mshtml!*SuperNavigate*) 43 // (IEFrame starts this by calling mshtml!*SuperNavigate*)
48 // - request_data is NULL 44 // - request_data is NULL
49 // - check if the url is a top level url 45 // - check if the url is a top level url
50 // - iff the url is a top level url (in this case, yes), we switch in our own 46 // - iff the url is a top level url, we switch in our own callback object
51 // callback object and hook it up to the bind context 47 // and hook it up to the bind context (BSCBStorageBind)
52 // (CFUrlmonBindStatusCallback) 48 // - BSCBStorageBind::OnDataAvailable - sniffs data and determines that the
53 // - As the document is fetched, the callback object caches the 49 // renderer is chrome. It then registers a special bind context param and
54 // document in memory. 50 // sets a magic clip format in the format_etc. Then goes into pass through
55 // - Bho::OnHttpEquiv (done == FALSE) 51 // mode.
56 // - mgr->NavigateToCurrentUrlInCF 52 // - mshtml looks at the clip format and re-issues the navigation with the
57 // - Set TLS (MarkBrowserOnThreadForCFNavigation) 53 // same bind context. Also returns INET_E_TERMINATED_BIND so that same
58 // - Create new bind context, moniker for the URL 54 // underlying transaction objects are used.
59 // - NavigateBrowserToMoniker with new moniker, bind context
60 // - Our callback _may_ get an error from mshtml indicating that mshtml
61 // isn't interested in the data anymore (since we started a new
62 // navigation). If that happens, our callback class
63 // (CFUrlmonBindStatusCallback) will continue to cache the document
64 // until all of it has been retrieved successfully. When the data
65 // is all read, we report INET_E_TERMINATE_BIND (see SimpleBindingImpl)
66 // as the end result.
67 // - In the case where all of the data has been downloaded before
68 // - OnHttpEquiv is called, we will already have the cache but the
69 // end bind status in the callback will be S_OK.
70 // - Bho::BeforeNavigate2 - top level url = http://wave.google.com/
71 // - IEFrame -> MonikerPatch::BindToStorage 55 // - IEFrame -> MonikerPatch::BindToStorage
72 // - request_data is not NULL since we now have a cached copy of the content. 56 // - We check for the special bind context param and instantiate and
73 // - We call BindToStorageFromCache. 57 // return our ActiveDoc
74 // - HttpNegotiatePatch::ReportProgress
75 // - Check TLS (CheckForCFNavigation) and report chrome mime type
76 // - IEFrame does the following:
77 // - Creates a new moniker
78 // - Calls MonikerPatch::BindToObject
79 // - We create an instance of ChromeActiveDocument and initialize it
80 // with the cached document.
81 // - ChromeActiveDocument gives the UrlmonUrlRequestManager the cached
82 // contents (RequestData) which the manager will use as the content
83 // when serving up content for the CF document.
84 //
85 58
86 // 59 //
87 // Scenario 3: CF navigation through mshtml link 60 // Scenario 3: CF navigation through mshtml link
88 // Same as scenario #2. 61 // Same as scenario #2.
89 // 62 //
90 63
91 // 64 //
92 // Scenario 4: CF navigation through link click in chrome loads non CF page 65 // Scenario 4: CF navigation through link click in chrome loads non CF page
93 // - Link click comes to ChromeActiveDocument::OnOpenURL 66 // - Link click comes to ChromeActiveDocument::OnOpenURL
94 // - web_browser->Navigate with URL 67 // - web_browser->Navigate with URL
95 // - [Scenario 1] 68 // - [Scenario 1]
96 // 69 //
97 70
98 // 71 //
99 // Scenario 5: CF navigation through link click in chrome loads CF page 72 // Scenario 5: CF navigation through link click in chrome loads CF page
100 // - Link click comes to ChromeActiveDocument::OnOpenURL 73 // - Link click comes to ChromeActiveDocument::OnOpenURL
101 // - web_browser->Navigate with URL 74 // - web_browser->Navigate with URL
102 // - [Scenario 2] 75 // - [Scenario 2]
103 // 76 //
104 77
105 // An implementation of IStream that delegates to another source
106 // but caches all data that is read from the source.
107 class ReadStreamCache
108 : public CComObjectRootEx<CComSingleThreadModel>,
109 public DelegatingReadStream {
110 public:
111 ReadStreamCache() {
112 DLOG(INFO) << __FUNCTION__;
113 }
114
115 ~ReadStreamCache() {
116 DLOG(INFO) << __FUNCTION__ << " cache: " << GetCacheSize();
117 }
118
119 BEGIN_COM_MAP(ReadStreamCache)
120 COM_INTERFACE_ENTRY(IStream)
121 COM_INTERFACE_ENTRY(ISequentialStream)
122 END_COM_MAP()
123
124 IStream* cache() const {
125 return cache_;
126 }
127
128 void RewindCache() const;
129
130 HRESULT WriteToCache(const void* data, ULONG size, ULONG* written);
131
132 // Returns how many bytes we've cached. Used for logging.
133 size_t GetCacheSize() const;
134
135 // ISequentialStream.
136 STDMETHOD(Read)(void* pv, ULONG cb, ULONG* read);
137
138 protected:
139 ScopedComPtr<IStream> cache_;
140
141 private:
142 DISALLOW_COPY_AND_ASSIGN(ReadStreamCache);
143 };
144
145 // Basic implementation of IBinding with the option of offering a way
146 // to override the bind result error value.
147 class SimpleBindingImpl
148 : public CComObjectRootEx<CComSingleThreadModel>,
149 public DelegatingBinding {
150 public:
151 SimpleBindingImpl() : bind_results_(S_OK) {
152 }
153
154 ~SimpleBindingImpl() {
155 }
156
157 BEGIN_COM_MAP(SimpleBindingImpl)
158 COM_INTERFACE_ENTRY(IBinding)
159 COM_INTERFACE_ENTRY_FUNC_BLIND(0, DelegateQI)
160 END_COM_MAP()
161
162 static STDMETHODIMP DelegateQI(void* obj, REFIID iid, void** ret,
163 DWORD cookie);
164
165 STDMETHOD(GetBindResult)(CLSID* protocol, DWORD* result_code,
166 LPOLESTR* result, DWORD* reserved);
167
168 void OverrideBindResults(HRESULT results) {
169 bind_results_ = results;
170 }
171
172 protected:
173 HRESULT bind_results_;
174
175 private:
176 DISALLOW_COPY_AND_ASSIGN(SimpleBindingImpl);
177 };
178
179 class RequestHeaders
180 : public base::RefCountedThreadSafe<RequestHeaders> {
181 public:
182 RequestHeaders() : response_code_(-1) {
183 }
184
185 ~RequestHeaders() {
186 }
187
188 void OnBeginningTransaction(const wchar_t* url, const wchar_t* headers,
189 const wchar_t* additional_headers);
190
191 void OnResponse(DWORD response_code, const wchar_t* response_headers,
192 const wchar_t* request_headers);
193
194 const std::wstring& request_url() const {
195 return request_url_;
196 }
197
198 // Invokes BeginningTransaction and OnResponse on the |http| object
199 // providing already cached headers and status values.
200 // Any additional headers returned from either of the two methods are ignored.
201 HRESULT FireHttpNegotiateEvents(IHttpNegotiate* http) const;
202
203 std::string GetReferrer();
204
205 protected:
206 std::wstring request_url_;
207 std::wstring begin_request_headers_;
208 std::wstring additional_request_headers_;
209 std::wstring request_headers_;
210 std::wstring response_headers_;
211 DWORD response_code_;
212
213 private:
214 DISALLOW_COPY_AND_ASSIGN(RequestHeaders);
215 };
216
217 // Holds cached data for a urlmon request.
218 class RequestData
219 : public base::RefCountedThreadSafe<RequestData> {
220 public:
221 RequestData();
222 ~RequestData();
223
224 void Initialize(RequestHeaders* headers);
225
226 // Calls IBindStatusCallback::OnDataAvailable and caches any data that is
227 // read during that operation.
228 // We also cache the format of the data stream if available during the first
229 // call to this method.
230 HRESULT DelegateDataRead(IBindStatusCallback* callback, DWORD flags,
231 DWORD size, FORMATETC* format, STGMEDIUM* storage,
232 size_t* bytes_read);
233
234 // Reads everything that's available from |data| into a cached stream.
235 void CacheAll(IStream* data);
236
237 // Returns a new stream object to read the cache.
238 // The returned stream object's seek pointer is at pos 0.
239 HRESULT GetResetCachedContentStream(IStream** clone);
240
241 size_t GetCachedContentSize() const {
242 return stream_delegate_->GetCacheSize();
243 }
244
245 const FORMATETC& format() const {
246 return format_;
247 }
248
249 RequestHeaders* headers() const {
250 return headers_;
251 }
252
253 void set_headers(RequestHeaders* headers) {
254 DCHECK(headers);
255 DCHECK(headers_ == NULL);
256 headers_ = headers;
257 }
258
259 protected:
260 ScopedComPtr<ReadStreamCache, &GUID_NULL> stream_delegate_;
261 FORMATETC format_;
262 scoped_refptr<RequestHeaders> headers_;
263
264 private:
265 DISALLOW_COPY_AND_ASSIGN(RequestData);
266 };
267
268 // This class is the link between a few static, moniker related functions to 78 // This class is the link between a few static, moniker related functions to
269 // the bho. The specific services needed by those functions are abstracted into 79 // the bho. The specific services needed by those functions are abstracted into
270 // this interface for easier testability. 80 // this interface for easier testability.
271 class NavigationManager { 81 class NavigationManager {
272 public: 82 public:
273 NavigationManager() { 83 NavigationManager() {
274 } 84 }
275 85
276 // Returns the Bho instance for the current thread. This is returned from 86 // Returns the Bho instance for the current thread. This is returned from
277 // TLS. Returns NULL if no instance exists on the current thread. 87 // TLS. Returns NULL if no instance exists on the current thread.
278 static NavigationManager* GetThreadInstance(); 88 static NavigationManager* GetThreadInstance();
279 89
90 // Mark a bind context for navigation by storing a bind context param.
91 static HRESULT AttachCFObject(IBindCtx* bind_context);
92 static HRESULT DetachCFObject(IMoniker* moniker, IBindCtx* bind_context,
93 IUnknown** object);
94
280 void RegisterThreadInstance(); 95 void RegisterThreadInstance();
281 void UnregisterThreadInstance(); 96 void UnregisterThreadInstance();
282 97
283 virtual ~NavigationManager() { 98 virtual ~NavigationManager() {
284 DCHECK(GetThreadInstance() != this); 99 DCHECK(GetThreadInstance() != this);
285 } 100 }
286 101
287 // Returns the url of the current top level navigation. 102 // Returns the url of the current top level navigation.
288 const std::wstring& url() const { 103 const std::wstring& url() const {
289 return url_; 104 return url_;
(...skipping 16 matching lines...) Expand all
306 121
307 // Returns the referrer header value of the current top level navigation. 122 // Returns the referrer header value of the current top level navigation.
308 const std::string& referrer() const { 123 const std::string& referrer() const {
309 return referrer_; 124 return referrer_;
310 } 125 }
311 126
312 void set_referrer(const std::string& referrer) { 127 void set_referrer(const std::string& referrer) {
313 referrer_ = referrer; 128 referrer_ = referrer;
314 } 129 }
315 130
316 // Called when a top level navigation has finished and we don't need to
317 // keep the cached content around anymore.
318 virtual void ReleaseRequestData() {
319 DLOG(INFO) << __FUNCTION__;
320 url_.clear();
321 SetActiveRequestData(NULL);
322 }
323
324 // Return true if this is a URL that represents a top-level 131 // Return true if this is a URL that represents a top-level
325 // document that might have to be rendered in CF. 132 // document that might have to be rendered in CF.
326 virtual bool IsTopLevelUrl(const wchar_t* url) { 133 virtual bool IsTopLevelUrl(const wchar_t* url) {
327 return lstrcmpiW(url_.c_str(), url) == 0; 134 return lstrcmpiW(url_.c_str(), url) == 0;
328 } 135 }
329 136
330 // Called from HttpNegotiatePatch::BeginningTransaction when a request is 137 // Called from HttpNegotiatePatch::BeginningTransaction when a request is
331 // being issued. We check the url and headers and see if there is a referrer 138 // being issued. We check the url and headers and see if there is a referrer
332 // header that we need to cache. 139 // header that we need to cache.
333 virtual void OnBeginningTransaction(bool is_top_level, const wchar_t* url, 140 virtual void OnBeginningTransaction(bool is_top_level, const wchar_t* url,
334 const wchar_t* headers, 141 const wchar_t* headers,
335 const wchar_t* additional_headers); 142 const wchar_t* additional_headers);
336 143
337 // Called when we've detected the http-equiv meta tag in the current page 144 // Called when we've detected the http-equiv meta tag in the current page
338 // and need to switch over from mshtml to CF. 145 // and need to switch over from mshtml to CF.
339 virtual HRESULT NavigateToCurrentUrlInCF(IBrowserService* browser); 146 virtual HRESULT NavigateToCurrentUrlInCF(IBrowserService* browser);
340 147
341 virtual void SetActiveRequestData(RequestData* request_data);
342
343 // When BindToObject is called on a URL before BindToStorage is called,
344 // the request and response headers are reported on that moniker.
345 // Later BindToStorage is called to fetch the content. We use the
346 // RequestHeaders class to carry over the headers to the RequestData object
347 // that will be created to hold the content.
348 virtual void SetActiveRequestHeaders(RequestHeaders* request_headers) {
349 request_headers_ = request_headers;
350 }
351
352 virtual RequestHeaders* GetActiveRequestHeaders() {
353 return request_headers_;
354 }
355
356 virtual RequestData* GetActiveRequestData(const wchar_t* url) {
357 return IsTopLevelUrl(url) ? request_data_.get() : NULL;
358 }
359
360 protected: 148 protected:
361 std::string referrer_; 149 std::string referrer_;
362 std::wstring url_; 150 std::wstring url_;
363 scoped_refptr<RequestData> request_data_; 151
364 scoped_refptr<RequestHeaders> request_headers_;
365 static base::LazyInstance<base::ThreadLocalPointer<NavigationManager> > 152 static base::LazyInstance<base::ThreadLocalPointer<NavigationManager> >
366 thread_singleton_; 153 thread_singleton_;
367 154
368 // If the url being navigated to within ChromeFrame has a fragment, this 155 // If the url being navigated to within ChromeFrame has a fragment, this
369 // member contains this URL. This member is cleared when the Chrome active 156 // member contains this URL. This member is cleared when the Chrome active
370 // document is loaded. 157 // document is loaded.
371 std::wstring original_url_with_fragment_; 158 std::wstring original_url_with_fragment_;
372 159
373 private: 160 private:
374 DISALLOW_COPY_AND_ASSIGN(NavigationManager); 161 DISALLOW_COPY_AND_ASSIGN(NavigationManager);
(...skipping 22 matching lines...) Expand all
397 IBindCtx* bind_ctx, IMoniker* to_left, REFIID iid, void** obj); 184 IBindCtx* bind_ctx, IMoniker* to_left, REFIID iid, void** obj);
398 185
399 static STDMETHODIMP BindToObject(IMoniker_BindToObject_Fn original, 186 static STDMETHODIMP BindToObject(IMoniker_BindToObject_Fn original,
400 IMoniker* me, IBindCtx* bind_ctx, 187 IMoniker* me, IBindCtx* bind_ctx,
401 IMoniker* to_left, REFIID iid, void** obj); 188 IMoniker* to_left, REFIID iid, void** obj);
402 189
403 static STDMETHODIMP BindToStorage(IMoniker_BindToStorage_Fn original, 190 static STDMETHODIMP BindToStorage(IMoniker_BindToStorage_Fn original,
404 IMoniker* me, IBindCtx* bind_ctx, 191 IMoniker* me, IBindCtx* bind_ctx,
405 IMoniker* to_left, REFIID iid, void** obj); 192 IMoniker* to_left, REFIID iid, void** obj);
406 193
407 // Reads content from cache (owned by RequestData) and simulates a regular
408 // binding by calling the expected methods on the callback object bound to
409 // the bind context.
410 static HRESULT BindToStorageFromCache(IBindCtx* bind_ctx,
411 const wchar_t* mime_type,
412 RequestData* data,
413 SimpleBindingImpl* binding,
414 IStream** cache_out);
415 }; 194 };
416 195
417 #endif // CHROME_FRAME_URLMON_MONIKER_H_ 196 #endif // CHROME_FRAME_URLMON_MONIKER_H_
418 197
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698