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

Side by Side Diff: chrome_frame/urlmon_moniker.cc

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 #include "chrome_frame/urlmon_moniker.h" 5 #include "chrome_frame/urlmon_moniker.h"
6 6
7 #include <shlguid.h> 7 #include <shlguid.h>
8 8
9 #include "base/string_util.h" 9 #include "base/string_util.h"
10 #include "chrome_frame/bho.h" 10 #include "chrome_frame/bho.h"
11 #include "chrome_frame/chrome_active_document.h"
11 #include "chrome_frame/urlmon_bind_status_callback.h" 12 #include "chrome_frame/urlmon_bind_status_callback.h"
12 #include "chrome_frame/vtable_patch_manager.h" 13 #include "chrome_frame/vtable_patch_manager.h"
13 #include "net/http/http_util.h" 14 #include "net/http/http_util.h"
14 15
15 static const int kMonikerBindToObject = 8; 16 static const int kMonikerBindToObject = 8;
16 static const int kMonikerBindToStorage = kMonikerBindToObject + 1; 17 static const int kMonikerBindToStorage = kMonikerBindToObject + 1;
18 static wchar_t kBindContextParamName[] = L"_CHROMEFRAME_PRECREATE_";
17 19
18 base::LazyInstance<base::ThreadLocalPointer<NavigationManager> > 20 base::LazyInstance<base::ThreadLocalPointer<NavigationManager> >
19 NavigationManager::thread_singleton_(base::LINKER_INITIALIZED); 21 NavigationManager::thread_singleton_(base::LINKER_INITIALIZED);
20 22
21 BEGIN_VTABLE_PATCHES(IMoniker) 23 BEGIN_VTABLE_PATCHES(IMoniker)
22 VTABLE_PATCH_ENTRY(kMonikerBindToObject, MonikerPatch::BindToObject) 24 VTABLE_PATCH_ENTRY(kMonikerBindToObject, MonikerPatch::BindToObject)
23 VTABLE_PATCH_ENTRY(kMonikerBindToStorage, MonikerPatch::BindToStorage) 25 VTABLE_PATCH_ENTRY(kMonikerBindToStorage, MonikerPatch::BindToStorage)
24 END_VTABLE_PATCHES() 26 END_VTABLE_PATCHES()
25 27
26 namespace { 28 namespace {
(...skipping 14 matching lines...) Expand all
41 break; 43 break;
42 } 44 }
43 } 45 }
44 } 46 }
45 47
46 return referrer; 48 return referrer;
47 } 49 }
48 50
49 } // end namespace 51 } // end namespace
50 52
51 void ReadStreamCache::RewindCache() const {
52 DCHECK(cache_);
53 RewindStream(cache_);
54 }
55
56 HRESULT ReadStreamCache::WriteToCache(const void* data, ULONG size,
57 ULONG* written) {
58 HRESULT hr = S_OK;
59 if (!cache_) {
60 hr = ::CreateStreamOnHGlobal(NULL, TRUE, cache_.Receive());
61 DCHECK(cache_);
62 }
63
64 if (SUCCEEDED(hr))
65 hr = cache_->Write(data, size, written);
66
67 return hr;
68 }
69
70 size_t ReadStreamCache::GetCacheSize() const {
71 size_t ret = 0;
72 if (cache_) {
73 STATSTG stg = {0};
74 cache_->Stat(&stg, STATFLAG_NONAME);
75 DCHECK_EQ(stg.cbSize.HighPart, 0);
76 ret = stg.cbSize.LowPart;
77 }
78
79 return ret;
80 }
81
82 HRESULT ReadStreamCache::Read(void* pv, ULONG cb, ULONG* read) {
83 DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i",
84 ::GetCurrentThreadId());
85 DCHECK(delegate_);
86 DWORD read_bytes = 0;
87 HRESULT hr = delegate_->Read(pv, cb, &read_bytes);
88 if (read)
89 *read = read_bytes;
90
91 // Note that Read() might return E_PENDING so we just check if anything
92 // was read rather than check hr.
93 if (read_bytes) {
94 DWORD written = 0;
95 WriteToCache(pv, read_bytes, &written);
96 DCHECK(read_bytes == written);
97 }
98
99 return hr;
100 }
101
102 /////////////////////////////
103
104 HRESULT SimpleBindingImpl::GetBindResult(CLSID* protocol, DWORD* result_code,
105 LPOLESTR* result, DWORD* reserved) {
106 DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i",
107 ::GetCurrentThreadId());
108
109 HRESULT hr = S_OK;
110
111 if (protocol)
112 *protocol = GUID_NULL;
113
114 if (result)
115 *result = NULL;
116
117 if (delegate_)
118 hr = delegate_->GetBindResult(protocol, result_code, result, reserved);
119
120 if (SUCCEEDED(hr) && bind_results_ != S_OK)
121 *result_code = bind_results_;
122
123 return hr;
124 }
125
126 HRESULT SimpleBindingImpl::DelegateQI(void* obj, REFIID iid, void** ret,
127 DWORD cookie) {
128 SimpleBindingImpl* me = reinterpret_cast<SimpleBindingImpl*>(obj);
129 HRESULT hr = E_NOINTERFACE;
130 if (me->delegate_)
131 hr = me->delegate_.QueryInterface(iid, ret);
132 DLOG(INFO) << __FUNCTION__ << " " << GuidToString(iid)
133 << StringPrintf(" 0x%08X", hr);
134 return hr;
135 }
136
137 ///////////////////////////////
138
139 void RequestHeaders::OnBeginningTransaction(const wchar_t* url,
140 const wchar_t* headers,
141 const wchar_t* additional_headers) {
142 if (url)
143 request_url_ = url;
144
145 if (headers)
146 begin_request_headers_ = headers;
147
148 if (additional_headers)
149 additional_request_headers_ = additional_headers;
150
151 DLOG(INFO) << __FUNCTION__ << "\n " << request_url_ << "\n "
152 << begin_request_headers_ << "\n "
153 << additional_request_headers_;
154
155 NavigationManager* mgr = NavigationManager::GetThreadInstance();
156 if (mgr) {
157 DCHECK(mgr->IsTopLevelUrl(request_url_.c_str()));
158 mgr->SetActiveRequestHeaders(this);
159 }
160 }
161
162 void RequestHeaders::OnResponse(DWORD response_code,
163 const wchar_t* response_headers,
164 const wchar_t* request_headers) {
165 response_code_ = response_code;
166
167 if (response_headers)
168 response_headers_ = response_headers;
169
170 if (request_headers)
171 request_headers_ = request_headers;
172
173 #ifndef NDEBUG
174 NavigationManager* mgr = NavigationManager::GetThreadInstance();
175 if (mgr) {
176 // For some reason we might not have gotten an OnBeginningTransaction call!
177 // DCHECK(mgr->IsTopLevelUrl(request_url_.c_str()));
178 // DCHECK(mgr->GetActiveRequestHeaders() == this);
179 mgr->SetActiveRequestHeaders(this);
180 }
181 #endif
182 }
183
184 std::string RequestHeaders::GetReferrer() {
185 std::string referrer = FindReferrerFromHeaders(begin_request_headers_.c_str(),
186 additional_request_headers_.c_str());
187 if (referrer.empty()) {
188 DLOG(INFO) << request_url_ << "\nbheaders: " << begin_request_headers_
189 << "\nadd:" << additional_request_headers_ << "\nreq: " << request_heade rs_;
190 }
191 return referrer;
192 }
193
194 HRESULT RequestHeaders::FireHttpNegotiateEvents(IHttpNegotiate* http) const {
195 DCHECK(http);
196
197 LPOLESTR additional_headers = NULL;
198 HRESULT hr = http->BeginningTransaction(request_url_.c_str(),
199 begin_request_headers_.c_str(), 0, &additional_headers);
200 DCHECK(SUCCEEDED(hr));
201 ::CoTaskMemFree(additional_headers);
202
203 // Also notify the navigation manager on this thread if one exists.
204 NavigationManager* mgr = NavigationManager::GetThreadInstance();
205 if (mgr) {
206 mgr->OnBeginningTransaction(true, request_url_.c_str(),
207 begin_request_headers_.c_str(), additional_request_headers_.c_str());
208 }
209
210 additional_headers = NULL;
211 hr = http->OnResponse(response_code_, response_headers_.c_str(),
212 request_headers_.c_str(), &additional_headers);
213 DCHECK(SUCCEEDED(hr));
214 if (additional_headers) {
215 ::CoTaskMemFree(additional_headers);
216 additional_headers = NULL;
217 }
218
219 return hr;
220 }
221
222 ///////////////////////////////
223
224 RequestData::RequestData() {
225 ZeroMemory(&format_, sizeof(format_));
226 format_.dwAspect = 1;
227 format_.lindex = -1;
228 format_.tymed = TYMED_ISTREAM;
229 CComObject<ReadStreamCache>* stream = NULL;
230 CComObject<ReadStreamCache>::CreateInstance(&stream);
231 DCHECK(stream);
232 stream_delegate_ = stream;
233 DCHECK_EQ(stream->m_dwRef, 1);
234 }
235
236 RequestData::~RequestData() {
237 }
238
239 void RequestData::Initialize(RequestHeaders* headers) {
240 if (headers) {
241 headers_ = headers;
242 } else {
243 headers_ = new RequestHeaders();
244 }
245 }
246
247 HRESULT RequestData::DelegateDataRead(IBindStatusCallback* callback,
248 DWORD flags, DWORD size,
249 FORMATETC* format, STGMEDIUM* storage,
250 size_t* bytes_read) {
251 DCHECK(callback);
252 DCHECK(storage);
253 if ((flags & BSCF_FIRSTDATANOTIFICATION) && format) {
254 format_ = *format;
255 }
256
257 IStream* original = storage->pstm;
258 DCHECK(original);
259 if (!original)
260 return E_POINTER;
261
262 size_t size_before = stream_delegate_->GetCacheSize();
263 stream_delegate_->SetDelegate(storage->pstm);
264 storage->pstm = stream_delegate_;
265 HRESULT hr = callback->OnDataAvailable(flags, size, format, storage);
266 storage->pstm = original;
267 if (bytes_read)
268 *bytes_read = stream_delegate_->GetCacheSize() - size_before;
269 return hr;
270 }
271
272 void RequestData::CacheAll(IStream* data) {
273 DCHECK(data);
274 char buffer[4096];
275 HRESULT hr = S_OK;
276 while (hr == S_OK) {
277 DWORD read = 0;
278 hr = data->Read(buffer, arraysize(buffer), &read);
279 if (read) {
280 DWORD written = 0;
281 stream_delegate_->WriteToCache(buffer, read, &written);
282 DCHECK(read == written);
283 } else {
284 // Just in case Read() completed with S_OK but zero bytes.
285 break;
286 }
287 }
288 }
289
290 HRESULT RequestData::GetResetCachedContentStream(IStream** clone) {
291 DCHECK(clone);
292 IStream* cache = stream_delegate_->cache();
293 if (!cache)
294 return HRESULT_FROM_WIN32(ERROR_EMPTY);
295 HRESULT hr = cache->Clone(clone);
296 if (SUCCEEDED(hr)) {
297 RewindStream(*clone);
298 } else {
299 NOTREACHED();
300 }
301 return hr;
302 }
303 53
304 //////////////////////////// 54 ////////////////////////////
305 55
306 HRESULT NavigationManager::NavigateToCurrentUrlInCF(IBrowserService* browser) { 56 HRESULT NavigationManager::NavigateToCurrentUrlInCF(IBrowserService* browser) {
307 DCHECK(browser); 57 DCHECK(browser);
308 DLOG(INFO) << __FUNCTION__ << " " << url(); 58 DLOG(INFO) << __FUNCTION__ << " " << url();
309 59
310 MarkBrowserOnThreadForCFNavigation(browser); 60 MarkBrowserOnThreadForCFNavigation(browser);
311 61
62 HRESULT hr = S_OK;
63 ScopedComPtr<IShellBrowser> shell_browser;
312 ScopedComPtr<IBindCtx> bind_context; 64 ScopedComPtr<IBindCtx> bind_context;
65 hr = ::CreateAsyncBindCtxEx(NULL, 0, NULL, NULL, bind_context.Receive(), 0);
66
313 ScopedComPtr<IMoniker> moniker; 67 ScopedComPtr<IMoniker> moniker;
314 HRESULT hr = ::CreateBindCtx(0, bind_context.Receive());
315 DCHECK(bind_context); 68 DCHECK(bind_context);
316 if (SUCCEEDED(hr) && 69 if (SUCCEEDED(hr) &&
317 SUCCEEDED(hr = ::CreateURLMonikerEx(NULL, url_.c_str(), moniker.Receive(), 70 SUCCEEDED(hr = ::CreateURLMonikerEx(NULL, url_.c_str(), moniker.Receive(),
318 URL_MK_UNIFORM))) { 71 URL_MK_UNIFORM))) {
319 if (SUCCEEDED(hr)) { 72 if (SUCCEEDED(hr)) {
320 // If there's a referrer, preserve it. 73 // If there's a referrer, preserve it.
321 std::wstring headers; 74 std::wstring headers;
322 if (!referrer_.empty()) { 75 if (!referrer_.empty()) {
323 headers = StringPrintf(L"Referer: %ls\r\n\r\n", 76 headers = StringPrintf(L"Referer: %ls\r\n\r\n",
324 ASCIIToWide(referrer_).c_str()); 77 ASCIIToWide(referrer_).c_str());
325 } 78 }
326 79
327 // Pass in URL fragments if applicable. 80 // Pass in URL fragments if applicable.
328 std::wstring fragment; 81 std::wstring fragment;
329 GURL parsed_moniker_url(url_); 82 GURL parsed_moniker_url(url_);
330 if (parsed_moniker_url.has_ref()) { 83 if (parsed_moniker_url.has_ref()) {
331 fragment = UTF8ToWide(parsed_moniker_url.ref()); 84 fragment = UTF8ToWide(parsed_moniker_url.ref());
332 set_original_url_with_fragment(url_.c_str()); 85 set_original_url_with_fragment(url_.c_str());
333 } 86 }
334 87
335 hr = NavigateBrowserToMoniker(browser, moniker, headers.c_str(), 88 hr = NavigateBrowserToMoniker(browser, moniker, headers.c_str(),
336 bind_context, fragment.c_str()); 89 bind_context, fragment.c_str());
337 DLOG(INFO) << StringPrintf("NavigateBrowserToMoniker: 0x%08X", hr); 90 DLOG(INFO) << StringPrintf("NavigateBrowserToMoniker: 0x%08X", hr);
338 } 91 }
339 } 92 }
340 93
341 return hr; 94 return hr;
342 } 95 }
343 96
344 void NavigationManager::SetActiveRequestData(RequestData* request_data) {
345 DLOG(INFO) << __FUNCTION__ << StringPrintf(" 0x%08X", request_data);
346 DCHECK(request_data_ == NULL || request_data == NULL);
347 DLOG_IF(ERROR, url_.empty() && request_data)
348 << "attempt to cache data after url has been cleared";
349 // Clear the current request headers as the request data must have the
350 // correct set of headers.
351 DCHECK(request_data == NULL || request_data->headers() != NULL);
352 request_headers_ = NULL;
353
354 if (request_data == NULL || !url_.empty()) {
355 request_data_ = request_data;
356 }
357 }
358
359 void NavigationManager::OnBeginningTransaction(bool is_top_level, 97 void NavigationManager::OnBeginningTransaction(bool is_top_level,
360 const wchar_t* url, const wchar_t* headers, 98 const wchar_t* url, const wchar_t* headers,
361 const wchar_t* additional_headers) { 99 const wchar_t* additional_headers) {
362 DCHECK(url != NULL); 100 DCHECK(url != NULL);
363 101
364 // We've seen this happen on the first page load in IE8 (it might also happen 102 // We've seen this happen on the first page load in IE8 (it might also happen
365 // in other versions of IE) and for some reason we did not get a call to 103 // in other versions of IE) and for some reason we did not get a call to
366 // BeginningTransaction the first time it happened and this time around we're 104 // BeginningTransaction the first time it happened and this time around we're
367 // using a cached data object that didn't get the request headers or URL. 105 // using a cached data object that didn't get the request headers or URL.
368 DLOG_IF(ERROR, lstrlenW(url) == 0) << __FUNCTION__ << "Invalid URL."; 106 DLOG_IF(ERROR, lstrlenW(url) == 0) << __FUNCTION__ << "Invalid URL.";
(...skipping 21 matching lines...) Expand all
390 void NavigationManager::RegisterThreadInstance() { 128 void NavigationManager::RegisterThreadInstance() {
391 DCHECK(GetThreadInstance() == NULL); 129 DCHECK(GetThreadInstance() == NULL);
392 thread_singleton_.Pointer()->Set(this); 130 thread_singleton_.Pointer()->Set(this);
393 } 131 }
394 132
395 void NavigationManager::UnregisterThreadInstance() { 133 void NavigationManager::UnregisterThreadInstance() {
396 DCHECK(GetThreadInstance() == this); 134 DCHECK(GetThreadInstance() == this);
397 thread_singleton_.Pointer()->Set(NULL); 135 thread_singleton_.Pointer()->Set(NULL);
398 } 136 }
399 137
138 // Mark a bind context for navigation by storing a bind context param.
139 HRESULT NavigationManager::AttachCFObject(IBindCtx* bind_context) {
140 if (!bind_context) {
141 NOTREACHED();
142 return E_INVALIDARG;
143 }
144
145 CComObject<ChromeActiveDocument>* cf_doc = NULL;
146 HRESULT hr = CComObject<ChromeActiveDocument>::CreateInstance(&cf_doc);
147 if (cf_doc) {
148 hr = bind_context->RegisterObjectParam(kBindContextParamName,
149 static_cast<IPersistMoniker*>(cf_doc));
150 if (FAILED(hr))
151 delete cf_doc;
152 }
153
154 return hr;
155 }
156
157 HRESULT NavigationManager::DetachCFObject(IMoniker* moniker,
158 IBindCtx* bind_context,
159 IUnknown** object) {
160 if (!bind_context || !moniker) {
161 NOTREACHED();
162 return E_INVALIDARG;
163 }
164
165 std::wstring url = GetActualUrlFromMoniker(moniker, bind_context,
166 std::wstring());
167 NavigationManager* mgr = GetThreadInstance();
168 if (mgr && !mgr->IsTopLevelUrl(url.c_str())) {
169 DLOG(WARNING) << "attempt to switch-in at non-top level.\n" <<
170 "Top level url: " << mgr->url() << "\nUrl being loaded: " << url;
171 return E_FAIL;
172 }
173
174 ScopedComPtr<IUnknown> cf_doc;
175 HRESULT hr = S_OK;
176 hr = bind_context->GetObjectParam(kBindContextParamName, cf_doc.Receive());
177 if (cf_doc) {
178 hr = bind_context->RevokeObjectParam(kBindContextParamName);
179 *object = cf_doc.Detach();
180 }
181
182 return hr;
183 }
184
400 ///////////////////////////////////////// 185 /////////////////////////////////////////
401 186
402 // static 187 // static
403 bool MonikerPatch::Initialize() { 188 bool MonikerPatch::Initialize() {
404 if (IS_PATCHED(IMoniker)) { 189 if (IS_PATCHED(IMoniker)) {
405 DLOG(WARNING) << __FUNCTION__ << " called more than once."; 190 DLOG(WARNING) << __FUNCTION__ << " called more than once.";
406 return true; 191 return true;
407 } 192 }
408 193
409 ScopedComPtr<IMoniker> moniker; 194 ScopedComPtr<IMoniker> moniker;
410 HRESULT hr = ::CreateURLMoniker(NULL, L"http://localhost/", 195 HRESULT hr = ::CreateURLMoniker(NULL, L"http://localhost/",
411 moniker.Receive()); 196 moniker.Receive());
412 DCHECK(SUCCEEDED(hr)); 197 DCHECK(SUCCEEDED(hr));
413 if (SUCCEEDED(hr)) { 198 if (SUCCEEDED(hr)) {
414 hr = vtable_patch::PatchInterfaceMethods(moniker, IMoniker_PatchInfo); 199 hr = vtable_patch::PatchInterfaceMethods(moniker, IMoniker_PatchInfo);
415 DLOG_IF(ERROR, FAILED(hr)) << StringPrintf("patch failed 0x%08X", hr); 200 DLOG_IF(ERROR, FAILED(hr)) << StringPrintf("patch failed 0x%08X", hr);
416 } 201 }
417 202
418 return SUCCEEDED(hr); 203 return SUCCEEDED(hr);
419 } 204 }
420 205
421 // static 206 // static
422 void MonikerPatch::Uninitialize() { 207 void MonikerPatch::Uninitialize() {
423 vtable_patch::UnpatchInterfaceMethods(IMoniker_PatchInfo); 208 vtable_patch::UnpatchInterfaceMethods(IMoniker_PatchInfo);
424 } 209 }
425 210
211 bool ShouldWrapCallback(IMoniker* moniker, IBindCtx* bind_context) {
212 NavigationManager* mgr = NavigationManager::GetThreadInstance();
213 if (!mgr) {
214 DLOG(INFO) << __FUNCTION__ << "No navitation manager to wrap";
215 return false;
216 }
217
218 CComHeapPtr<WCHAR> url;
219 HRESULT hr = moniker->GetDisplayName(bind_context, NULL, &url);
220 DCHECK(SUCCEEDED(hr));
221 bool should_wrap = mgr->IsTopLevelUrl(url);
222 return should_wrap;
223 }
224
426 // static 225 // static
427 HRESULT MonikerPatch::BindToObject(IMoniker_BindToObject_Fn original, 226 HRESULT MonikerPatch::BindToObject(IMoniker_BindToObject_Fn original,
428 IMoniker* me, IBindCtx* bind_ctx, 227 IMoniker* me, IBindCtx* bind_ctx,
429 IMoniker* to_left, REFIID iid, void** obj) { 228 IMoniker* to_left, REFIID iid, void** obj) {
430 DLOG(INFO) << __FUNCTION__; 229 DLOG(INFO) << __FUNCTION__;
431 DCHECK(to_left == NULL); 230 DCHECK(to_left == NULL);
432 CComHeapPtr<WCHAR> url; 231
433 HRESULT hr = me->GetDisplayName(bind_ctx, NULL, &url); 232 HRESULT hr = S_OK;
434 DCHECK(SUCCEEDED(hr)); 233 ScopedComPtr<IUnknown> cf_doc;
435 NavigationManager* mgr = NavigationManager::GetThreadInstance(); 234 NavigationManager::DetachCFObject(me, bind_ctx, cf_doc.Receive());
436 if (mgr) { 235 if (cf_doc) {
437 bool interest = mgr ? mgr->IsTopLevelUrl(url) : false; 236 ScopedComPtr<IPersistMoniker> persist_moniker;
438 if (interest) { 237 hr = persist_moniker.QueryFrom(cf_doc);
439 scoped_refptr<RequestData> request_data(mgr->GetActiveRequestData(url)); 238 if (persist_moniker) {
440 if (request_data) { 239 hr = persist_moniker->Load(TRUE, me, bind_ctx, STGM_READ);
441 DLOG(INFO) << " got cached content"; 240 if (SUCCEEDED(hr)) {
442 mgr->set_referrer(request_data->headers()->GetReferrer()); 241 return persist_moniker.QueryInterface(iid, obj);
443 DLOG(INFO) << "referrer is: " << mgr->referrer();
444 // Create a new CF document object and initialize it with
445 // the already cached data.
446 ScopedComPtr<IUnknown> cf_doc;
447 hr = cf_doc.CreateInstance(CLSID_ChromeActiveDocument);
448 if (FAILED(hr)) {
449 NOTREACHED() << "Failed to cocreate active document. Error:" << hr;
450 return original(me, bind_ctx, to_left, iid, obj);
451 }
452 ScopedComPtr<IPersistMoniker> persist_moniker;
453 hr = persist_moniker.QueryFrom(cf_doc);
454 DCHECK(SUCCEEDED(hr));
455 hr = persist_moniker->Load(TRUE, me, bind_ctx, STGM_READ);
456 if (SUCCEEDED(hr)) {
457 hr = persist_moniker.QueryInterface(iid, obj);
458 DCHECK(SUCCEEDED(hr));
459 }
460 } else { 242 } else {
461 DLOG(INFO) << " creating callback object"; 243 NOTREACHED() << StringPrintf("CF ActiveDoc::Load error: 0x%x", hr);
462 CComObject<CFUrlmonBindStatusCallback>* callback = NULL;
463 hr = CComObject<CFUrlmonBindStatusCallback>::CreateInstance(
464 &callback);
465 callback->AddRef();
466 hr = callback->Initialize(bind_ctx, mgr->GetActiveRequestHeaders());
467 DCHECK(SUCCEEDED(hr));
468 hr = original(me, bind_ctx, to_left, iid, obj);
469 callback->Release();
470 if (SUCCEEDED(hr) && (*obj) == NULL) {
471 DCHECK(hr == MK_S_ASYNCHRONOUS);
472 }
473 } 244 }
474 } else { 245 } else {
475 DLOG(INFO) << " -- calling original. (no interest)"; 246 NOTREACHED() << StringPrintf("CF IPersistMoniker QI failed: 0x%x", hr);
476 hr = original(me, bind_ctx, to_left, iid, obj);
477 } 247 }
478 } else {
479 // We don't have a NavigationManager instance for cases like View Source
480 // etc.
481 hr = original(me, bind_ctx, to_left, iid, obj);
482 } 248 }
483 249
250 hr = original(me, bind_ctx, to_left, iid, obj);
484 return hr; 251 return hr;
485 } 252 }
486 253
487 // static 254 // static
488 HRESULT MonikerPatch::BindToStorage(IMoniker_BindToStorage_Fn original, 255 HRESULT MonikerPatch::BindToStorage(IMoniker_BindToStorage_Fn original,
489 IMoniker* me, IBindCtx* bind_ctx, 256 IMoniker* me, IBindCtx* bind_ctx,
490 IMoniker* to_left, REFIID iid, void** obj) { 257 IMoniker* to_left, REFIID iid, void** obj) {
491 DLOG(INFO) << __FUNCTION__; 258 DLOG(INFO) << __FUNCTION__;
492 DCHECK(iid == IID_IStream || iid == IID_IUnknown);
493 DCHECK(to_left == NULL); 259 DCHECK(to_left == NULL);
494 260
495 HRESULT hr = E_UNEXPECTED; 261 HRESULT hr = S_OK;
496 NavigationManager* mgr = NavigationManager::GetThreadInstance(); 262 CComObject<BSCBStorageBind>* callback = NULL;
497 if (mgr) { 263 if ((IsEqualIID(IID_IStream, iid)) && ShouldWrapCallback(me, bind_ctx)) {
498 CComHeapPtr<WCHAR> url; 264 hr = CComObject<BSCBStorageBind>::CreateInstance(&callback);
499 hr = me->GetDisplayName(bind_ctx, NULL, &url); 265 callback->AddRef();
266 hr = callback->Initialize(me, bind_ctx);
500 DCHECK(SUCCEEDED(hr)); 267 DCHECK(SUCCEEDED(hr));
501 bool interest = mgr->IsTopLevelUrl(url);
502 DLOG(INFO) << "interest: " << interest << " url " << url;
503 if (interest) {
504 scoped_refptr<RequestData> request_data(mgr->GetActiveRequestData(url));
505 if (request_data) {
506 CComObject<SimpleBindingImpl>* binding = NULL;
507 CComObject<SimpleBindingImpl>::CreateInstance(&binding);
508 binding->OverrideBindResults(INET_E_TERMINATED_BIND);
509 binding->AddRef();
510 hr = BindToStorageFromCache(bind_ctx, kChromeMimeType, request_data,
511 binding, reinterpret_cast<IStream**>(obj));
512 binding->Release();
513 } else {
514 DLOG(INFO) << " creating callback object";
515 CComObject<CFUrlmonBindStatusCallback>* callback = NULL;
516 hr = CComObject<CFUrlmonBindStatusCallback>::CreateInstance(
517 &callback);
518 callback->AddRef();
519 hr = callback->Initialize(bind_ctx, mgr->GetActiveRequestHeaders());
520 DCHECK(SUCCEEDED(hr));
521 hr = original(me, bind_ctx, to_left, iid, obj);
522 callback->Release();
523 if (SUCCEEDED(hr) && (*obj) == NULL) {
524 DCHECK(hr == MK_S_ASYNCHRONOUS);
525 }
526 }
527 } else {
528 hr = original(me, bind_ctx, to_left, iid, obj);
529 }
530 } else {
531 // We usually only get here when we're issuing requests from our
532 // worker thread. However there are some exceptions such as when
533 // windows media player is issuing requests, so we don't DCHECK.
534 hr = original(me, bind_ctx, to_left, iid, obj);
535 } 268 }
536 269
537 return hr; 270 hr = original(me, bind_ctx, to_left, iid, obj);
538 }
539 271
540 HRESULT MonikerPatch::BindToStorageFromCache(IBindCtx* bind_ctx, 272 // If the binding terminates before the data could be played back
541 const wchar_t* mime_type, 273 // now is the chance. Sometimes OnStopBinding happens after this returns
542 RequestData* data, 274 // and then it's too late.
543 SimpleBindingImpl* binding, 275 if ((S_OK == hr) && callback)
544 IStream** cache_out) { 276 callback->MayPlayBack(BSCF_LASTDATANOTIFICATION);
545 DCHECK(bind_ctx);
546 // mime_type may be NULL
547 DCHECK(data);
548 DCHECK(binding);
549 // cache_out may be NULL
550
551 ScopedComPtr<IUnknown> holder;
552 HRESULT hr = bind_ctx->GetObjectParam(L"_BSCB_Holder_", holder.Receive());
553 DCHECK(holder);
554 ScopedComPtr<IBindStatusCallback> bscb;
555 ScopedComPtr<IHttpNegotiate> http_negotiate;
556 DoQueryService(IID_IBindStatusCallback, holder, bscb.Receive());
557 DoQueryService(IID_IHttpNegotiate, bscb, http_negotiate.Receive());
558 if (!bscb) {
559 NOTREACHED();
560 return E_NOINTERFACE;
561 }
562
563 hr = bscb->OnStartBinding(0, binding);
564 DCHECK(SUCCEEDED(hr));
565 if (SUCCEEDED(hr)) {
566 // Fire BeginningTransaction and OnResponse events.
567 if (http_negotiate)
568 data->headers()->FireHttpNegotiateEvents(http_negotiate);
569
570 FORMATETC format_etc = data->format();
571 if (mime_type) {
572 // If a non NULL mime type was specified, override the clipboard format.
573 format_etc.cfFormat = ::RegisterClipboardFormatW(mime_type);
574 DCHECK(format_etc.cfFormat);
575 }
576
577 const wchar_t* mime_type_available = mime_type;
578 wchar_t format_name[MAX_PATH] = {0};
579 if (!mime_type_available) {
580 ::GetClipboardFormatName(format_etc.cfFormat, format_name,
581 arraysize(format_name));
582 mime_type_available = format_name;
583 }
584 DCHECK(mime_type_available);
585 hr = bscb->OnProgress(0, 0, BINDSTATUS_MIMETYPEAVAILABLE,
586 mime_type_available);
587
588 ScopedComPtr<IStream> cache;
589 data->GetResetCachedContentStream(cache.Receive());
590
591 STGMEDIUM medium = {0};
592 medium.tymed = TYMED_ISTREAM;
593 medium.pstm = cache;
594 DLOG(INFO) << __FUNCTION__ << " total bytes available: "
595 << data->GetCachedContentSize();
596 hr = bscb->OnDataAvailable(
597 BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION |
598 BSCF_DATAFULLYAVAILABLE, data->GetCachedContentSize(), &format_etc,
599 &medium);
600
601 // OnDataAvailable might report a failure such as INET_E_TERMINATED_BIND
602 // when mshtml decides not to handle the request.
603 // We ignore the return value from OnStopBinding and return whatever
604 // OnDataAvailable gave us.
605 if (FAILED(hr)) {
606 binding->OverrideBindResults(hr);
607 } else if (cache_out) {
608 *cache_out = cache.Detach();
609 }
610
611 bscb->OnStopBinding(hr, NULL);
612 }
613 277
614 return hr; 278 return hr;
615 } 279 }
616
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698