| OLD | NEW |
| 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_bind_status_callback.h" | 5 #include "chrome_frame/urlmon_bind_status_callback.h" |
| 6 | 6 |
| 7 #include <mshtml.h> |
| 7 #include <shlguid.h> | 8 #include <shlguid.h> |
| 8 | 9 |
| 9 #include "base/logging.h" | 10 #include "base/logging.h" |
| 10 #include "base/string_util.h" | 11 #include "base/string_util.h" |
| 11 | 12 #include "base/utf_string_conversions.h" |
| 12 CFUrlmonBindStatusCallback::CFUrlmonBindStatusCallback() | 13 |
| 13 : only_buffer_(false), data_(new RequestData()) { | 14 #include "chrome_frame/urlmon_moniker.h" |
| 14 DLOG(INFO) << __FUNCTION__ << me(); | 15 #include "chrome_tab.h" // NOLINT |
| 15 } | 16 |
| 16 | 17 |
| 17 CFUrlmonBindStatusCallback::~CFUrlmonBindStatusCallback() { | 18 // A helper to given feed data to the specified |bscb| using |
| 18 DLOG(INFO) << __FUNCTION__ << me(); | 19 // CacheStream instance. |
| 19 } | 20 HRESULT CacheStream::BSCBFeedData(IBindStatusCallback* bscb, const char* data, |
| 20 | 21 size_t size, CLIPFORMAT clip_format, |
| 21 std::string CFUrlmonBindStatusCallback::me() { | 22 size_t flags) { |
| 22 return StringPrintf(" obj=0x%08X", | 23 if (!bscb) { |
| 23 static_cast<CFUrlmonBindStatusCallback*>(this)); | 24 NOTREACHED() << "invalid IBindStatusCallback"; |
| 24 } | 25 return E_INVALIDARG; |
| 25 | 26 } |
| 26 HRESULT CFUrlmonBindStatusCallback::DelegateQI(void* obj, REFIID iid, | 27 |
| 27 void** ret, DWORD cookie) { | 28 // We can't use a CComObjectStackEx here since mshtml will hold |
| 28 CFUrlmonBindStatusCallback* me = | 29 // onto the stream pointer. |
| 29 reinterpret_cast<CFUrlmonBindStatusCallback*>(obj); | 30 CComObject<CacheStream>* cache_stream = NULL; |
| 30 HRESULT hr = me->delegate_.QueryInterface(iid, ret); | 31 HRESULT hr = CComObject<CacheStream>::CreateInstance(&cache_stream); |
| 31 return hr; | |
| 32 } | |
| 33 | |
| 34 HRESULT CFUrlmonBindStatusCallback::Initialize(IBindCtx* bind_ctx, | |
| 35 RequestHeaders* headers) { | |
| 36 DLOG(INFO) << __FUNCTION__ << me(); | |
| 37 DCHECK(bind_ctx); | |
| 38 DCHECK(!binding_delegate_.get()); | |
| 39 // headers may be NULL. | |
| 40 | |
| 41 data_->Initialize(headers); | |
| 42 | |
| 43 bind_ctx_ = bind_ctx; | |
| 44 | |
| 45 // Replace the bind context callback with ours. | |
| 46 HRESULT hr = ::RegisterBindStatusCallback(bind_ctx, this, | |
| 47 delegate_.Receive(), 0); | |
| 48 if (!delegate_) { | |
| 49 NOTREACHED() << "Failed to find registered bind status callback"; | |
| 50 ::RevokeBindStatusCallback(bind_ctx_, this); | |
| 51 bind_ctx_.Release(); | |
| 52 hr = E_UNEXPECTED; | |
| 53 } | |
| 54 | |
| 55 return hr; | |
| 56 } | |
| 57 | |
| 58 HRESULT CFUrlmonBindStatusCallback::QueryService(REFGUID service, REFIID iid, | |
| 59 void** object) { | |
| 60 HRESULT hr = E_NOINTERFACE; | |
| 61 if (delegate_) { | |
| 62 ScopedComPtr<IServiceProvider> svc; | |
| 63 svc.QueryFrom(delegate_); | |
| 64 if (svc) { | |
| 65 hr = svc->QueryService(service, iid, object); | |
| 66 } | |
| 67 } | |
| 68 return hr; | |
| 69 } | |
| 70 | |
| 71 // IBindStatusCallback | |
| 72 HRESULT CFUrlmonBindStatusCallback::OnStartBinding(DWORD reserved, | |
| 73 IBinding* binding) { | |
| 74 DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i", | |
| 75 PlatformThread::CurrentId()); | |
| 76 DCHECK(!binding_delegate_.get()); | |
| 77 | |
| 78 CComObject<SimpleBindingImpl>* binding_delegate; | |
| 79 HRESULT hr = CComObject<SimpleBindingImpl>::CreateInstance(&binding_delegate); | |
| 80 if (FAILED(hr)) { | 32 if (FAILED(hr)) { |
| 81 NOTREACHED(); | 33 NOTREACHED(); |
| 82 return hr; | 34 return hr; |
| 83 } | 35 } |
| 84 | 36 |
| 85 binding_delegate_ = binding_delegate; | 37 cache_stream->AddRef(); |
| 86 DCHECK_EQ(binding_delegate->m_dwRef, 1); | 38 cache_stream->Initialize(data, size); |
| 87 binding_delegate_->SetDelegate(binding); | 39 |
| 88 | 40 FORMATETC format_etc = { clip_format, NULL, DVASPECT_CONTENT, -1, |
| 89 return delegate_->OnStartBinding(reserved, binding_delegate_); | 41 TYMED_ISTREAM }; |
| 90 } | 42 STGMEDIUM medium = {0}; |
| 91 | 43 medium.tymed = TYMED_ISTREAM; |
| 92 HRESULT CFUrlmonBindStatusCallback::GetPriority(LONG* priority) { | 44 medium.pstm = cache_stream; |
| 45 |
| 46 hr = bscb->OnDataAvailable(flags, size, &format_etc, &medium); |
| 47 |
| 48 cache_stream->Release(); |
| 49 return hr; |
| 50 } |
| 51 |
| 52 void CacheStream::Initialize(const char* cache, size_t size) { |
| 53 cache_ = cache; |
| 54 size_ = size; |
| 55 position_ = 0; |
| 56 } |
| 57 |
| 58 // Read is the only call that we expect. Return E_PENDING if there |
| 59 // is no more data to serve. Otherwise this will result in a |
| 60 // read with 0 bytes indicating that no more data is available. |
| 61 STDMETHODIMP CacheStream::Read(void* pv, ULONG cb, ULONG* read) { |
| 62 if (!pv || !read) |
| 63 return E_INVALIDARG; |
| 64 |
| 65 // Default to E_PENDING to signal that this is a partial data. |
| 66 HRESULT hr = E_PENDING; |
| 67 if (position_ < size_) { |
| 68 *read = std::min(size_ - position_, size_t(cb)); |
| 69 memcpy(pv, cache_ + position_, *read); |
| 70 position_ += *read; |
| 71 hr = S_OK; |
| 72 } |
| 73 |
| 74 return hr; |
| 75 } |
| 76 |
| 77 |
| 78 ///////////////////////////////////////////////////////////////////// |
| 79 |
| 80 bool SniffData::InitializeCache(const std::wstring& url) { |
| 81 url_ = url; |
| 82 renderer_type_ = UNDETERMINED; |
| 83 |
| 84 const int kAllocationSize = 32 * 1024; |
| 85 HGLOBAL memory = GlobalAlloc(0, kAllocationSize); |
| 86 HRESULT hr = CreateStreamOnHGlobal(memory, TRUE, cache_.Receive()); |
| 87 if (FAILED(hr)) { |
| 88 GlobalFree(memory); |
| 89 NOTREACHED(); |
| 90 return false; |
| 91 } |
| 92 |
| 93 return true; |
| 94 } |
| 95 |
| 96 HRESULT SniffData::ReadIntoCache(IStream* stream, bool force_determination) { |
| 97 if (!stream) { |
| 98 NOTREACHED(); |
| 99 return E_INVALIDARG; |
| 100 } |
| 101 |
| 102 HRESULT hr = S_OK; |
| 103 while (SUCCEEDED(hr)) { |
| 104 const size_t kChunkSize = 4 * 1024; |
| 105 char buffer[kChunkSize]; |
| 106 DWORD read = 0; |
| 107 hr = stream->Read(buffer, sizeof(buffer), &read); |
| 108 if (read) { |
| 109 DWORD written = 0; |
| 110 cache_->Write(buffer, read, &written); |
| 111 size_ += written; |
| 112 } |
| 113 |
| 114 if ((S_FALSE == hr) || !read) |
| 115 break; |
| 116 } |
| 117 |
| 118 if (force_determination || (size() >= kMaxSniffSize)) { |
| 119 DetermineRendererType(); |
| 120 } |
| 121 |
| 122 return hr; |
| 123 } |
| 124 |
| 125 HRESULT SniffData::DrainCache(IBindStatusCallback* bscb, DWORD bscf, |
| 126 CLIPFORMAT clip_format) { |
| 127 if (!is_cache_valid()) { |
| 128 return S_OK; |
| 129 } |
| 130 |
| 131 // Ideally we could just use the cache_ IStream implementation but |
| 132 // can't use it here since we have to return E_PENDING for the |
| 133 // last call |
| 134 HGLOBAL memory = NULL; |
| 135 HRESULT hr = GetHGlobalFromStream(cache_, &memory); |
| 136 if (SUCCEEDED(hr) && memory) { |
| 137 char* buffer = reinterpret_cast<char*>(GlobalLock(memory)); |
| 138 hr = CacheStream::BSCBFeedData(bscb, buffer, size_, clip_format, bscf); |
| 139 GlobalUnlock(memory); |
| 140 } |
| 141 |
| 142 size_ = 0; |
| 143 cache_.Release(); |
| 144 return hr; |
| 145 } |
| 146 |
| 147 // Scan the buffer or OptIn URL list and decide if the renderer is |
| 148 // to be switched |
| 149 void SniffData::DetermineRendererType() { |
| 150 if (is_undetermined()) { |
| 151 if (IsOptInUrl(url_.c_str())) { |
| 152 renderer_type_ = CHROME; |
| 153 } else { |
| 154 renderer_type_ = OTHER; |
| 155 if (is_cache_valid() && cache_) { |
| 156 HGLOBAL memory = NULL; |
| 157 GetHGlobalFromStream(cache_, &memory); |
| 158 char* buffer = reinterpret_cast<char*>(GlobalLock(memory)); |
| 159 |
| 160 std::wstring html_contents; |
| 161 // TODO(joshia): detect and handle different content encodings |
| 162 if (buffer && size_) { |
| 163 UTF8ToWide(buffer, size_, &html_contents); |
| 164 GlobalUnlock(memory); |
| 165 } |
| 166 |
| 167 // Note that document_contents_ may have NULL characters in it. While |
| 168 // browsers may handle this properly, we don't and will stop scanning |
| 169 // for the XUACompat content value if we encounter one. |
| 170 std::wstring xua_compat_content; |
| 171 UtilGetXUACompatContentValue(html_contents, &xua_compat_content); |
| 172 if (StrStrI(xua_compat_content.c_str(), kChromeContentPrefix)) { |
| 173 renderer_type_ = CHROME; |
| 174 } |
| 175 } |
| 176 } |
| 177 } |
| 178 } |
| 179 |
| 180 ///////////////////////////////////////////////////////////////////// |
| 181 |
| 182 HRESULT BSCBStorageBind::Initialize(IMoniker* moniker, IBindCtx* bind_ctx) { |
| 183 DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i", |
| 184 PlatformThread::CurrentId()); |
| 185 |
| 186 HRESULT hr = AttachToBind(bind_ctx); |
| 187 if (FAILED(hr)) { |
| 188 NOTREACHED() << __FUNCTION__ << me() << "AttachToBind error: " << hr; |
| 189 return hr; |
| 190 } |
| 191 |
| 192 if (!delegate()) { |
| 193 NOTREACHED() << __FUNCTION__ << me() << "No existing callback: " << hr; |
| 194 return E_FAIL; |
| 195 } |
| 196 |
| 197 std::wstring url = GetActualUrlFromMoniker(moniker, bind_ctx, |
| 198 std::wstring()); |
| 199 data_sniffer_.InitializeCache(url); |
| 200 return hr; |
| 201 } |
| 202 |
| 203 STDMETHODIMP BSCBStorageBind::OnProgress(ULONG progress, ULONG progress_max, |
| 204 ULONG status_code, LPCWSTR status_text) { |
| 205 DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" status=%i tid=%i %ls", |
| 206 status_code, PlatformThread::CurrentId(), status_text); |
| 207 |
| 208 HRESULT hr = S_OK; |
| 209 if (data_sniffer_.is_undetermined()) { |
| 210 Progress new_progress = { progress, progress_max, status_code, |
| 211 status_text ? status_text : std::wstring() }; |
| 212 saved_progress_.push_back(new_progress); |
| 213 } else { |
| 214 hr = CallbackImpl::OnProgress(progress, progress_max, status_code, |
| 215 status_text); |
| 216 } |
| 217 |
| 218 return hr; |
| 219 } |
| 220 |
| 221 // Refer to urlmon_moniker.h for explanation of how things work. |
| 222 STDMETHODIMP BSCBStorageBind::OnDataAvailable(DWORD flags, DWORD size, |
| 223 FORMATETC* format_etc, |
| 224 STGMEDIUM* stgmed) { |
| 93 DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i", | 225 DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i", |
| 94 PlatformThread::CurrentId()); | 226 PlatformThread::CurrentId()); |
| 95 return delegate_->GetPriority(priority); | 227 if (!stgmed || !format_etc) { |
| 96 } | 228 DLOG(INFO) << __FUNCTION__ << me() << "Invalid stgmed or format_etc"; |
| 97 | 229 return CallbackImpl::OnDataAvailable(flags, size, format_etc, stgmed); |
| 98 HRESULT CFUrlmonBindStatusCallback::OnLowResource(DWORD reserved) { | 230 } |
| 231 |
| 232 if ((stgmed->tymed != TYMED_ISTREAM) || !stgmed->pstm) { |
| 233 DLOG(INFO) << __FUNCTION__ << me() << "stgmedium is not a valid stream"; |
| 234 return CallbackImpl::OnDataAvailable(flags, size, format_etc, stgmed); |
| 235 } |
| 236 |
| 237 HRESULT hr = S_OK; |
| 238 if (!clip_format_) |
| 239 clip_format_ = format_etc->cfFormat; |
| 240 |
| 241 if (data_sniffer_.is_undetermined()) { |
| 242 bool force_determination = !!(flags & |
| 243 (BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE)); |
| 244 hr = data_sniffer_.ReadIntoCache(stgmed->pstm, force_determination); |
| 245 // If we don't have sufficient data to determine renderer type |
| 246 // wait for the next data notification. |
| 247 if (data_sniffer_.is_undetermined()) |
| 248 return S_OK; |
| 249 } |
| 250 |
| 251 DCHECK(!data_sniffer_.is_undetermined()); |
| 252 |
| 253 if (data_sniffer_.is_cache_valid()) { |
| 254 hr = MayPlayBack(flags); |
| 255 DCHECK(!data_sniffer_.is_cache_valid()); |
| 256 } else { |
| 257 hr = CallbackImpl::OnDataAvailable(flags, size, format_etc, stgmed); |
| 258 } |
| 259 |
| 260 return hr; |
| 261 } |
| 262 |
| 263 STDMETHODIMP BSCBStorageBind::OnStopBinding(HRESULT hresult, LPCWSTR error) { |
| 99 DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i", | 264 DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i", |
| 100 PlatformThread::CurrentId()); | 265 PlatformThread::CurrentId()); |
| 101 return delegate_->OnLowResource(reserved); | 266 HRESULT hr = MayPlayBack(BSCF_LASTDATANOTIFICATION); |
| 102 } | 267 return CallbackImpl::OnStopBinding(hresult, error); |
| 103 | 268 } |
| 104 HRESULT CFUrlmonBindStatusCallback::OnProgress(ULONG progress, | 269 |
| 105 ULONG progress_max, | 270 // Play back the cached data to the delegate. Normally this would happen |
| 106 ULONG status_code, | 271 // when we have read enough data to determine the renderer. In this case |
| 107 LPCWSTR status_text) { | 272 // we first play back the data from the cache and then go into a 'pass |
| 108 DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" status=%i tid=%i %ls", | 273 // through' mode. In some cases we may end up getting OnStopBinding |
| 109 status_code, PlatformThread::CurrentId(), status_text); | 274 // before we get a chance to determine. Also it's possible that the |
| 110 if (status_code == BINDSTATUS_REDIRECTING && status_text) { | 275 // BindToStorage call will return before OnStopBinding is sent. Hence |
| 111 redirected_url_ = status_text; | 276 // This is called from 3 places and it's important to maintain the |
| 112 } | 277 // exact sequence of calls. |
| 113 return delegate_->OnProgress(progress, progress_max, status_code, | 278 // Once the data is played back, calling this again is a no op. |
| 114 status_text); | 279 HRESULT BSCBStorageBind::MayPlayBack(DWORD flags) { |
| 115 } | 280 // Force renderer type determination if not already done since |
| 116 | 281 // we want to play back data now. |
| 117 HRESULT CFUrlmonBindStatusCallback::OnStopBinding(HRESULT hresult, | 282 data_sniffer_.DetermineRendererType(); |
| 118 LPCWSTR error) { | 283 DCHECK(!data_sniffer_.is_undetermined()); |
| 119 DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" hr=0x%08X '%ls' tid=%i", | 284 |
| 120 hresult, error, PlatformThread::CurrentId()); | 285 HRESULT hr = S_OK; |
| 121 if (SUCCEEDED(hresult)) { | 286 if (data_sniffer_.is_chrome()) { |
| 122 // Notify the BHO that this is the one and only RequestData object. | 287 // Remember clip format. If we are switching to chrome, then in order |
| 123 NavigationManager* mgr = NavigationManager::GetThreadInstance(); | 288 // to make mshtml return INET_E_TERMINATED_BIND and reissue navigation |
| 124 DCHECK(mgr); | 289 // with the same bind context, we have to return a mime type that is |
| 125 if (mgr && data_->GetCachedContentSize()) { | 290 // special cased by mshtml. |
| 126 mgr->SetActiveRequestData(data_); | 291 static const CLIPFORMAT kMagicClipFormat = |
| 127 if (!redirected_url_.empty()) { | 292 RegisterClipboardFormat(CFSTR_MIME_MPEG); |
| 128 mgr->set_url(redirected_url_.c_str()); | 293 clip_format_ = kMagicClipFormat; |
| 294 } else { |
| 295 if (!saved_progress_.empty()) { |
| 296 for (std::vector<Progress>::iterator i = saved_progress_.begin(); |
| 297 i != saved_progress_.end(); i++) { |
| 298 const wchar_t* status_text = i->status_text_.empty() ? |
| 299 NULL : i->status_text_.c_str(); |
| 300 CallbackImpl::OnProgress(i->progress_, i->progress_max_, |
| 301 i->status_code_, status_text); |
| 129 } | 302 } |
| 303 saved_progress_.clear(); |
| 130 } | 304 } |
| 131 | 305 } |
| 132 if (only_buffer_) { | 306 |
| 133 hresult = INET_E_TERMINATED_BIND; | 307 if (data_sniffer_.is_cache_valid()) { |
| 134 DLOG(INFO) << " - changed to INET_E_TERMINATED_BIND"; | 308 hr = data_sniffer_.DrainCache(delegate(), |
| 135 } | 309 flags | BSCF_FIRSTDATANOTIFICATION, clip_format_); |
| 136 } | 310 if (data_sniffer_.is_chrome()) |
| 137 | 311 NavigationManager::AttachCFObject(bind_ctx_); |
| 138 // Hold a reference to ourselves while we release the bind context | 312 } |
| 139 // and disconnect the callback. | 313 |
| 140 AddRef(); | 314 return hr; |
| 141 | 315 } |
| 142 HRESULT hr = delegate_->OnStopBinding(hresult, error); | |
| 143 | |
| 144 if (bind_ctx_) { | |
| 145 ::RevokeBindStatusCallback(bind_ctx_, this); | |
| 146 bind_ctx_.Release(); | |
| 147 } | |
| 148 | |
| 149 binding_delegate_.Release(); | |
| 150 | |
| 151 // After this call, this object might be gone. | |
| 152 Release(); | |
| 153 | |
| 154 return hr; | |
| 155 } | |
| 156 | |
| 157 HRESULT CFUrlmonBindStatusCallback::GetBindInfo(DWORD* bindf, | |
| 158 BINDINFO* bind_info) { | |
| 159 DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i", | |
| 160 PlatformThread::CurrentId()); | |
| 161 return delegate_->GetBindInfo(bindf, bind_info); | |
| 162 } | |
| 163 | |
| 164 HRESULT CFUrlmonBindStatusCallback::OnDataAvailable(DWORD bscf, DWORD size, | |
| 165 FORMATETC* format_etc, | |
| 166 STGMEDIUM* stgmed) { | |
| 167 DCHECK(format_etc); | |
| 168 #ifndef NDEBUG | |
| 169 wchar_t clip_fmt_name[MAX_PATH] = {0}; | |
| 170 if (format_etc) { | |
| 171 ::GetClipboardFormatNameW(format_etc->cfFormat, clip_fmt_name, | |
| 172 arraysize(clip_fmt_name)); | |
| 173 } | |
| 174 DLOG(INFO) << __FUNCTION__ << me() | |
| 175 << StringPrintf(" tid=%i original fmt=%ls", | |
| 176 PlatformThread::CurrentId(), clip_fmt_name); | |
| 177 | |
| 178 if (!stgmed) { | |
| 179 NOTREACHED() << "Invalid STGMEDIUM received"; | |
| 180 return delegate_->OnDataAvailable(bscf, size, format_etc, stgmed); | |
| 181 } | |
| 182 | |
| 183 if (stgmed->tymed != TYMED_ISTREAM) { | |
| 184 DLOG(INFO) << "Not handling medium:" << stgmed->tymed; | |
| 185 return delegate_->OnDataAvailable(bscf, size, format_etc, stgmed); | |
| 186 } | |
| 187 | |
| 188 if (bscf & BSCF_FIRSTDATANOTIFICATION) { | |
| 189 DLOG(INFO) << "first data notification"; | |
| 190 } | |
| 191 #endif | |
| 192 | |
| 193 HRESULT hr = S_OK; | |
| 194 size_t bytes_read = 0; | |
| 195 if (!only_buffer_) { | |
| 196 hr = data_->DelegateDataRead(delegate_, bscf, size, format_etc, stgmed, | |
| 197 &bytes_read); | |
| 198 } | |
| 199 | |
| 200 DLOG(INFO) << __FUNCTION__ << StringPrintf(" - 0x%08x", hr); | |
| 201 if (hr == INET_E_TERMINATED_BIND) { | |
| 202 // Check if the content type is CF's mime type. | |
| 203 UINT cf_format = ::RegisterClipboardFormatW(kChromeMimeType); | |
| 204 bool override_bind_results = (format_etc->cfFormat == cf_format); | |
| 205 if (!override_bind_results) { | |
| 206 ScopedComPtr<IBrowserService> browser_service; | |
| 207 DoQueryService(SID_SShellBrowser, delegate_, browser_service.Receive()); | |
| 208 override_bind_results = (browser_service != NULL) && | |
| 209 CheckForCFNavigation(browser_service, false); | |
| 210 } | |
| 211 | |
| 212 if (override_bind_results) { | |
| 213 // We want to complete fetching the entire document even though the | |
| 214 // delegate isn't interested in continuing. | |
| 215 // This happens when we switch from mshtml to CF. | |
| 216 // We take over and buffer the document and once we're done, we report | |
| 217 // INET_E_TERMINATED to mshtml so that it will continue as usual. | |
| 218 hr = S_OK; | |
| 219 only_buffer_ = true; | |
| 220 binding_delegate_->OverrideBindResults(INET_E_TERMINATED_BIND); | |
| 221 } | |
| 222 } | |
| 223 | |
| 224 if (only_buffer_) { | |
| 225 data_->CacheAll(stgmed->pstm); | |
| 226 DCHECK(hr == S_OK); | |
| 227 } | |
| 228 | |
| 229 return hr; | |
| 230 } | |
| 231 | |
| 232 HRESULT CFUrlmonBindStatusCallback::OnObjectAvailable(REFIID iid, | |
| 233 IUnknown* unk) { | |
| 234 DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i", | |
| 235 PlatformThread::CurrentId()); | |
| 236 return delegate_->OnObjectAvailable(iid, unk); | |
| 237 } | |
| 238 | |
| 239 // IBindStatusCallbackEx | |
| 240 HRESULT CFUrlmonBindStatusCallback::GetBindInfoEx(DWORD* bindf, | |
| 241 BINDINFO* bind_info, | |
| 242 DWORD* bindf2, | |
| 243 DWORD* reserved) { | |
| 244 DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i", | |
| 245 PlatformThread::CurrentId()); | |
| 246 ScopedComPtr<IBindStatusCallbackEx> bscbex; | |
| 247 bscbex.QueryFrom(delegate_); | |
| 248 return bscbex->GetBindInfoEx(bindf, bind_info, bindf2, reserved); | |
| 249 } | |
| 250 | |
| 251 HRESULT CFUrlmonBindStatusCallback::BeginningTransaction(LPCWSTR url, | |
| 252 LPCWSTR headers, | |
| 253 DWORD reserved, | |
| 254 LPWSTR* additional_headers) { | |
| 255 DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i", | |
| 256 PlatformThread::CurrentId()); | |
| 257 | |
| 258 ScopedComPtr<IHttpNegotiate> http_negotiate; | |
| 259 HRESULT hr = http_negotiate.QueryFrom(delegate_); | |
| 260 if (SUCCEEDED(hr)) { | |
| 261 hr = http_negotiate->BeginningTransaction(url, headers, reserved, | |
| 262 additional_headers); | |
| 263 } else { | |
| 264 hr = S_OK; | |
| 265 } | |
| 266 | |
| 267 data_->headers()->OnBeginningTransaction(url, headers, | |
| 268 additional_headers && *additional_headers ? *additional_headers : NULL); | |
| 269 | |
| 270 DLOG_IF(ERROR, FAILED(hr)) << __FUNCTION__; | |
| 271 return hr; | |
| 272 } | |
| 273 | |
| 274 HRESULT CFUrlmonBindStatusCallback::OnResponse(DWORD response_code, | |
| 275 LPCWSTR response_headers, | |
| 276 LPCWSTR request_headers, | |
| 277 LPWSTR* additional_headers) { | |
| 278 DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i", | |
| 279 PlatformThread::CurrentId()); | |
| 280 | |
| 281 data_->headers()->OnResponse(response_code, response_headers, | |
| 282 request_headers); | |
| 283 | |
| 284 ScopedComPtr<IHttpNegotiate> http_negotiate; | |
| 285 HRESULT hr = http_negotiate.QueryFrom(delegate_); | |
| 286 if (SUCCEEDED(hr)) { | |
| 287 hr = http_negotiate->OnResponse(response_code, response_headers, | |
| 288 request_headers, additional_headers); | |
| 289 } else { | |
| 290 hr = S_OK; | |
| 291 } | |
| 292 return hr; | |
| 293 } | |
| 294 | |
| 295 HRESULT CFUrlmonBindStatusCallback::GetRootSecurityId(BYTE* security_id, | |
| 296 DWORD* security_id_size, | |
| 297 DWORD_PTR reserved) { | |
| 298 ScopedComPtr<IHttpNegotiate2> http_negotiate; | |
| 299 http_negotiate.QueryFrom(delegate_); | |
| 300 return http_negotiate->GetRootSecurityId(security_id, security_id_size, | |
| 301 reserved); | |
| 302 } | |
| 303 | |
| 304 HRESULT CFUrlmonBindStatusCallback::GetSerializedClientCertContext( | |
| 305 BYTE** cert, | |
| 306 DWORD* cert_size) { | |
| 307 ScopedComPtr<IHttpNegotiate3> http_negotiate; | |
| 308 http_negotiate.QueryFrom(delegate_); | |
| 309 return http_negotiate->GetSerializedClientCertContext(cert, cert_size); | |
| 310 } | |
| OLD | NEW |