| Index: chrome_frame/urlmon_moniker.cc
|
| ===================================================================
|
| --- chrome_frame/urlmon_moniker.cc (revision 43957)
|
| +++ chrome_frame/urlmon_moniker.cc (working copy)
|
| @@ -8,12 +8,14 @@
|
|
|
| #include "base/string_util.h"
|
| #include "chrome_frame/bho.h"
|
| +#include "chrome_frame/chrome_active_document.h"
|
| #include "chrome_frame/urlmon_bind_status_callback.h"
|
| #include "chrome_frame/vtable_patch_manager.h"
|
| #include "net/http/http_util.h"
|
|
|
| static const int kMonikerBindToObject = 8;
|
| static const int kMonikerBindToStorage = kMonikerBindToObject + 1;
|
| +static wchar_t kBindContextParamName[] = L"_CHROMEFRAME_PRECREATE_";
|
|
|
| base::LazyInstance<base::ThreadLocalPointer<NavigationManager> >
|
| NavigationManager::thread_singleton_(base::LINKER_INITIALIZED);
|
| @@ -48,259 +50,7 @@
|
|
|
| } // end namespace
|
|
|
| -void ReadStreamCache::RewindCache() const {
|
| - DCHECK(cache_);
|
| - RewindStream(cache_);
|
| -}
|
|
|
| -HRESULT ReadStreamCache::WriteToCache(const void* data, ULONG size,
|
| - ULONG* written) {
|
| - HRESULT hr = S_OK;
|
| - if (!cache_) {
|
| - hr = ::CreateStreamOnHGlobal(NULL, TRUE, cache_.Receive());
|
| - DCHECK(cache_);
|
| - }
|
| -
|
| - if (SUCCEEDED(hr))
|
| - hr = cache_->Write(data, size, written);
|
| -
|
| - return hr;
|
| -}
|
| -
|
| -size_t ReadStreamCache::GetCacheSize() const {
|
| - size_t ret = 0;
|
| - if (cache_) {
|
| - STATSTG stg = {0};
|
| - cache_->Stat(&stg, STATFLAG_NONAME);
|
| - DCHECK_EQ(stg.cbSize.HighPart, 0);
|
| - ret = stg.cbSize.LowPart;
|
| - }
|
| -
|
| - return ret;
|
| -}
|
| -
|
| -HRESULT ReadStreamCache::Read(void* pv, ULONG cb, ULONG* read) {
|
| - DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i",
|
| - ::GetCurrentThreadId());
|
| - DCHECK(delegate_);
|
| - DWORD read_bytes = 0;
|
| - HRESULT hr = delegate_->Read(pv, cb, &read_bytes);
|
| - if (read)
|
| - *read = read_bytes;
|
| -
|
| - // Note that Read() might return E_PENDING so we just check if anything
|
| - // was read rather than check hr.
|
| - if (read_bytes) {
|
| - DWORD written = 0;
|
| - WriteToCache(pv, read_bytes, &written);
|
| - DCHECK(read_bytes == written);
|
| - }
|
| -
|
| - return hr;
|
| -}
|
| -
|
| -/////////////////////////////
|
| -
|
| -HRESULT SimpleBindingImpl::GetBindResult(CLSID* protocol, DWORD* result_code,
|
| - LPOLESTR* result, DWORD* reserved) {
|
| - DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i",
|
| - ::GetCurrentThreadId());
|
| -
|
| - HRESULT hr = S_OK;
|
| -
|
| - if (protocol)
|
| - *protocol = GUID_NULL;
|
| -
|
| - if (result)
|
| - *result = NULL;
|
| -
|
| - if (delegate_)
|
| - hr = delegate_->GetBindResult(protocol, result_code, result, reserved);
|
| -
|
| - if (SUCCEEDED(hr) && bind_results_ != S_OK)
|
| - *result_code = bind_results_;
|
| -
|
| - return hr;
|
| -}
|
| -
|
| -HRESULT SimpleBindingImpl::DelegateQI(void* obj, REFIID iid, void** ret,
|
| - DWORD cookie) {
|
| - SimpleBindingImpl* me = reinterpret_cast<SimpleBindingImpl*>(obj);
|
| - HRESULT hr = E_NOINTERFACE;
|
| - if (me->delegate_)
|
| - hr = me->delegate_.QueryInterface(iid, ret);
|
| - DLOG(INFO) << __FUNCTION__ << " " << GuidToString(iid)
|
| - << StringPrintf(" 0x%08X", hr);
|
| - return hr;
|
| -}
|
| -
|
| -///////////////////////////////
|
| -
|
| -void RequestHeaders::OnBeginningTransaction(const wchar_t* url,
|
| - const wchar_t* headers,
|
| - const wchar_t* additional_headers) {
|
| - if (url)
|
| - request_url_ = url;
|
| -
|
| - if (headers)
|
| - begin_request_headers_ = headers;
|
| -
|
| - if (additional_headers)
|
| - additional_request_headers_ = additional_headers;
|
| -
|
| - DLOG(INFO) << __FUNCTION__ << "\n " << request_url_ << "\n "
|
| - << begin_request_headers_ << "\n "
|
| - << additional_request_headers_;
|
| -
|
| - NavigationManager* mgr = NavigationManager::GetThreadInstance();
|
| - if (mgr) {
|
| - DCHECK(mgr->IsTopLevelUrl(request_url_.c_str()));
|
| - mgr->SetActiveRequestHeaders(this);
|
| - }
|
| -}
|
| -
|
| -void RequestHeaders::OnResponse(DWORD response_code,
|
| - const wchar_t* response_headers,
|
| - const wchar_t* request_headers) {
|
| - response_code_ = response_code;
|
| -
|
| - if (response_headers)
|
| - response_headers_ = response_headers;
|
| -
|
| - if (request_headers)
|
| - request_headers_ = request_headers;
|
| -
|
| -#ifndef NDEBUG
|
| - NavigationManager* mgr = NavigationManager::GetThreadInstance();
|
| - if (mgr) {
|
| - // For some reason we might not have gotten an OnBeginningTransaction call!
|
| - // DCHECK(mgr->IsTopLevelUrl(request_url_.c_str()));
|
| - // DCHECK(mgr->GetActiveRequestHeaders() == this);
|
| - mgr->SetActiveRequestHeaders(this);
|
| - }
|
| -#endif
|
| -}
|
| -
|
| -std::string RequestHeaders::GetReferrer() {
|
| - std::string referrer = FindReferrerFromHeaders(begin_request_headers_.c_str(),
|
| - additional_request_headers_.c_str());
|
| - if (referrer.empty()) {
|
| - DLOG(INFO) << request_url_ << "\nbheaders: " << begin_request_headers_
|
| - << "\nadd:" << additional_request_headers_ << "\nreq: " << request_headers_;
|
| - }
|
| - return referrer;
|
| -}
|
| -
|
| -HRESULT RequestHeaders::FireHttpNegotiateEvents(IHttpNegotiate* http) const {
|
| - DCHECK(http);
|
| -
|
| - LPOLESTR additional_headers = NULL;
|
| - HRESULT hr = http->BeginningTransaction(request_url_.c_str(),
|
| - begin_request_headers_.c_str(), 0, &additional_headers);
|
| - DCHECK(SUCCEEDED(hr));
|
| - ::CoTaskMemFree(additional_headers);
|
| -
|
| - // Also notify the navigation manager on this thread if one exists.
|
| - NavigationManager* mgr = NavigationManager::GetThreadInstance();
|
| - if (mgr) {
|
| - mgr->OnBeginningTransaction(true, request_url_.c_str(),
|
| - begin_request_headers_.c_str(), additional_request_headers_.c_str());
|
| - }
|
| -
|
| - additional_headers = NULL;
|
| - hr = http->OnResponse(response_code_, response_headers_.c_str(),
|
| - request_headers_.c_str(), &additional_headers);
|
| - DCHECK(SUCCEEDED(hr));
|
| - if (additional_headers) {
|
| - ::CoTaskMemFree(additional_headers);
|
| - additional_headers = NULL;
|
| - }
|
| -
|
| - return hr;
|
| -}
|
| -
|
| -///////////////////////////////
|
| -
|
| -RequestData::RequestData() {
|
| - ZeroMemory(&format_, sizeof(format_));
|
| - format_.dwAspect = 1;
|
| - format_.lindex = -1;
|
| - format_.tymed = TYMED_ISTREAM;
|
| - CComObject<ReadStreamCache>* stream = NULL;
|
| - CComObject<ReadStreamCache>::CreateInstance(&stream);
|
| - DCHECK(stream);
|
| - stream_delegate_ = stream;
|
| - DCHECK_EQ(stream->m_dwRef, 1);
|
| -}
|
| -
|
| -RequestData::~RequestData() {
|
| -}
|
| -
|
| -void RequestData::Initialize(RequestHeaders* headers) {
|
| - if (headers) {
|
| - headers_ = headers;
|
| - } else {
|
| - headers_ = new RequestHeaders();
|
| - }
|
| -}
|
| -
|
| -HRESULT RequestData::DelegateDataRead(IBindStatusCallback* callback,
|
| - DWORD flags, DWORD size,
|
| - FORMATETC* format, STGMEDIUM* storage,
|
| - size_t* bytes_read) {
|
| - DCHECK(callback);
|
| - DCHECK(storage);
|
| - if ((flags & BSCF_FIRSTDATANOTIFICATION) && format) {
|
| - format_ = *format;
|
| - }
|
| -
|
| - IStream* original = storage->pstm;
|
| - DCHECK(original);
|
| - if (!original)
|
| - return E_POINTER;
|
| -
|
| - size_t size_before = stream_delegate_->GetCacheSize();
|
| - stream_delegate_->SetDelegate(storage->pstm);
|
| - storage->pstm = stream_delegate_;
|
| - HRESULT hr = callback->OnDataAvailable(flags, size, format, storage);
|
| - storage->pstm = original;
|
| - if (bytes_read)
|
| - *bytes_read = stream_delegate_->GetCacheSize() - size_before;
|
| - return hr;
|
| -}
|
| -
|
| -void RequestData::CacheAll(IStream* data) {
|
| - DCHECK(data);
|
| - char buffer[4096];
|
| - HRESULT hr = S_OK;
|
| - while (hr == S_OK) {
|
| - DWORD read = 0;
|
| - hr = data->Read(buffer, arraysize(buffer), &read);
|
| - if (read) {
|
| - DWORD written = 0;
|
| - stream_delegate_->WriteToCache(buffer, read, &written);
|
| - DCHECK(read == written);
|
| - } else {
|
| - // Just in case Read() completed with S_OK but zero bytes.
|
| - break;
|
| - }
|
| - }
|
| -}
|
| -
|
| -HRESULT RequestData::GetResetCachedContentStream(IStream** clone) {
|
| - DCHECK(clone);
|
| - IStream* cache = stream_delegate_->cache();
|
| - if (!cache)
|
| - return HRESULT_FROM_WIN32(ERROR_EMPTY);
|
| - HRESULT hr = cache->Clone(clone);
|
| - if (SUCCEEDED(hr)) {
|
| - RewindStream(*clone);
|
| - } else {
|
| - NOTREACHED();
|
| - }
|
| - return hr;
|
| -}
|
| -
|
| ////////////////////////////
|
|
|
| HRESULT NavigationManager::NavigateToCurrentUrlInCF(IBrowserService* browser) {
|
| @@ -309,9 +59,12 @@
|
|
|
| MarkBrowserOnThreadForCFNavigation(browser);
|
|
|
| + HRESULT hr = S_OK;
|
| + ScopedComPtr<IShellBrowser> shell_browser;
|
| ScopedComPtr<IBindCtx> bind_context;
|
| + hr = ::CreateAsyncBindCtxEx(NULL, 0, NULL, NULL, bind_context.Receive(), 0);
|
| +
|
| ScopedComPtr<IMoniker> moniker;
|
| - HRESULT hr = ::CreateBindCtx(0, bind_context.Receive());
|
| DCHECK(bind_context);
|
| if (SUCCEEDED(hr) &&
|
| SUCCEEDED(hr = ::CreateURLMonikerEx(NULL, url_.c_str(), moniker.Receive(),
|
| @@ -341,21 +94,6 @@
|
| return hr;
|
| }
|
|
|
| -void NavigationManager::SetActiveRequestData(RequestData* request_data) {
|
| - DLOG(INFO) << __FUNCTION__ << StringPrintf(" 0x%08X", request_data);
|
| - DCHECK(request_data_ == NULL || request_data == NULL);
|
| - DLOG_IF(ERROR, url_.empty() && request_data)
|
| - << "attempt to cache data after url has been cleared";
|
| - // Clear the current request headers as the request data must have the
|
| - // correct set of headers.
|
| - DCHECK(request_data == NULL || request_data->headers() != NULL);
|
| - request_headers_ = NULL;
|
| -
|
| - if (request_data == NULL || !url_.empty()) {
|
| - request_data_ = request_data;
|
| - }
|
| -}
|
| -
|
| void NavigationManager::OnBeginningTransaction(bool is_top_level,
|
| const wchar_t* url, const wchar_t* headers,
|
| const wchar_t* additional_headers) {
|
| @@ -397,6 +135,53 @@
|
| thread_singleton_.Pointer()->Set(NULL);
|
| }
|
|
|
| +// Mark a bind context for navigation by storing a bind context param.
|
| +HRESULT NavigationManager::AttachCFObject(IBindCtx* bind_context) {
|
| + if (!bind_context) {
|
| + NOTREACHED();
|
| + return E_INVALIDARG;
|
| + }
|
| +
|
| + CComObject<ChromeActiveDocument>* cf_doc = NULL;
|
| + HRESULT hr = CComObject<ChromeActiveDocument>::CreateInstance(&cf_doc);
|
| + if (cf_doc) {
|
| + hr = bind_context->RegisterObjectParam(kBindContextParamName,
|
| + static_cast<IPersistMoniker*>(cf_doc));
|
| + if (FAILED(hr))
|
| + delete cf_doc;
|
| + }
|
| +
|
| + return hr;
|
| +}
|
| +
|
| +HRESULT NavigationManager::DetachCFObject(IMoniker* moniker,
|
| + IBindCtx* bind_context,
|
| + IUnknown** object) {
|
| + if (!bind_context || !moniker) {
|
| + NOTREACHED();
|
| + return E_INVALIDARG;
|
| + }
|
| +
|
| + std::wstring url = GetActualUrlFromMoniker(moniker, bind_context,
|
| + std::wstring());
|
| + NavigationManager* mgr = GetThreadInstance();
|
| + if (mgr && !mgr->IsTopLevelUrl(url.c_str())) {
|
| + DLOG(WARNING) << "attempt to switch-in at non-top level.\n" <<
|
| + "Top level url: " << mgr->url() << "\nUrl being loaded: " << url;
|
| + return E_FAIL;
|
| + }
|
| +
|
| + ScopedComPtr<IUnknown> cf_doc;
|
| + HRESULT hr = S_OK;
|
| + hr = bind_context->GetObjectParam(kBindContextParamName, cf_doc.Receive());
|
| + if (cf_doc) {
|
| + hr = bind_context->RevokeObjectParam(kBindContextParamName);
|
| + *object = cf_doc.Detach();
|
| + }
|
| +
|
| + return hr;
|
| +}
|
| +
|
| /////////////////////////////////////////
|
|
|
| // static
|
| @@ -423,64 +208,46 @@
|
| vtable_patch::UnpatchInterfaceMethods(IMoniker_PatchInfo);
|
| }
|
|
|
| +bool ShouldWrapCallback(IMoniker* moniker, IBindCtx* bind_context) {
|
| + NavigationManager* mgr = NavigationManager::GetThreadInstance();
|
| + if (!mgr) {
|
| + DLOG(INFO) << __FUNCTION__ << "No navitation manager to wrap";
|
| + return false;
|
| + }
|
| +
|
| + CComHeapPtr<WCHAR> url;
|
| + HRESULT hr = moniker->GetDisplayName(bind_context, NULL, &url);
|
| + DCHECK(SUCCEEDED(hr));
|
| + bool should_wrap = mgr->IsTopLevelUrl(url);
|
| + return should_wrap;
|
| +}
|
| +
|
| // static
|
| HRESULT MonikerPatch::BindToObject(IMoniker_BindToObject_Fn original,
|
| IMoniker* me, IBindCtx* bind_ctx,
|
| IMoniker* to_left, REFIID iid, void** obj) {
|
| DLOG(INFO) << __FUNCTION__;
|
| DCHECK(to_left == NULL);
|
| - CComHeapPtr<WCHAR> url;
|
| - HRESULT hr = me->GetDisplayName(bind_ctx, NULL, &url);
|
| - DCHECK(SUCCEEDED(hr));
|
| - NavigationManager* mgr = NavigationManager::GetThreadInstance();
|
| - if (mgr) {
|
| - bool interest = mgr ? mgr->IsTopLevelUrl(url) : false;
|
| - if (interest) {
|
| - scoped_refptr<RequestData> request_data(mgr->GetActiveRequestData(url));
|
| - if (request_data) {
|
| - DLOG(INFO) << " got cached content";
|
| - mgr->set_referrer(request_data->headers()->GetReferrer());
|
| - DLOG(INFO) << "referrer is: " << mgr->referrer();
|
| - // Create a new CF document object and initialize it with
|
| - // the already cached data.
|
| - ScopedComPtr<IUnknown> cf_doc;
|
| - hr = cf_doc.CreateInstance(CLSID_ChromeActiveDocument);
|
| - if (FAILED(hr)) {
|
| - NOTREACHED() << "Failed to cocreate active document. Error:" << hr;
|
| - return original(me, bind_ctx, to_left, iid, obj);
|
| - }
|
| - ScopedComPtr<IPersistMoniker> persist_moniker;
|
| - hr = persist_moniker.QueryFrom(cf_doc);
|
| - DCHECK(SUCCEEDED(hr));
|
| - hr = persist_moniker->Load(TRUE, me, bind_ctx, STGM_READ);
|
| - if (SUCCEEDED(hr)) {
|
| - hr = persist_moniker.QueryInterface(iid, obj);
|
| - DCHECK(SUCCEEDED(hr));
|
| - }
|
| +
|
| + HRESULT hr = S_OK;
|
| + ScopedComPtr<IUnknown> cf_doc;
|
| + NavigationManager::DetachCFObject(me, bind_ctx, cf_doc.Receive());
|
| + if (cf_doc) {
|
| + ScopedComPtr<IPersistMoniker> persist_moniker;
|
| + hr = persist_moniker.QueryFrom(cf_doc);
|
| + if (persist_moniker) {
|
| + hr = persist_moniker->Load(TRUE, me, bind_ctx, STGM_READ);
|
| + if (SUCCEEDED(hr)) {
|
| + return persist_moniker.QueryInterface(iid, obj);
|
| } else {
|
| - DLOG(INFO) << " creating callback object";
|
| - CComObject<CFUrlmonBindStatusCallback>* callback = NULL;
|
| - hr = CComObject<CFUrlmonBindStatusCallback>::CreateInstance(
|
| - &callback);
|
| - callback->AddRef();
|
| - hr = callback->Initialize(bind_ctx, mgr->GetActiveRequestHeaders());
|
| - DCHECK(SUCCEEDED(hr));
|
| - hr = original(me, bind_ctx, to_left, iid, obj);
|
| - callback->Release();
|
| - if (SUCCEEDED(hr) && (*obj) == NULL) {
|
| - DCHECK(hr == MK_S_ASYNCHRONOUS);
|
| - }
|
| + NOTREACHED() << StringPrintf("CF ActiveDoc::Load error: 0x%x", hr);
|
| }
|
| } else {
|
| - DLOG(INFO) << " -- calling original. (no interest)";
|
| - hr = original(me, bind_ctx, to_left, iid, obj);
|
| + NOTREACHED() << StringPrintf("CF IPersistMoniker QI failed: 0x%x", hr);
|
| }
|
| - } else {
|
| - // We don't have a NavigationManager instance for cases like View Source
|
| - // etc.
|
| - hr = original(me, bind_ctx, to_left, iid, obj);
|
| }
|
|
|
| + hr = original(me, bind_ctx, to_left, iid, obj);
|
| return hr;
|
| }
|
|
|
| @@ -489,128 +256,24 @@
|
| IMoniker* me, IBindCtx* bind_ctx,
|
| IMoniker* to_left, REFIID iid, void** obj) {
|
| DLOG(INFO) << __FUNCTION__;
|
| - DCHECK(iid == IID_IStream || iid == IID_IUnknown);
|
| DCHECK(to_left == NULL);
|
|
|
| - HRESULT hr = E_UNEXPECTED;
|
| - NavigationManager* mgr = NavigationManager::GetThreadInstance();
|
| - if (mgr) {
|
| - CComHeapPtr<WCHAR> url;
|
| - hr = me->GetDisplayName(bind_ctx, NULL, &url);
|
| + HRESULT hr = S_OK;
|
| + CComObject<BSCBStorageBind>* callback = NULL;
|
| + if ((IsEqualIID(IID_IStream, iid)) && ShouldWrapCallback(me, bind_ctx)) {
|
| + hr = CComObject<BSCBStorageBind>::CreateInstance(&callback);
|
| + callback->AddRef();
|
| + hr = callback->Initialize(me, bind_ctx);
|
| DCHECK(SUCCEEDED(hr));
|
| - bool interest = mgr->IsTopLevelUrl(url);
|
| - DLOG(INFO) << "interest: " << interest << " url " << url;
|
| - if (interest) {
|
| - scoped_refptr<RequestData> request_data(mgr->GetActiveRequestData(url));
|
| - if (request_data) {
|
| - CComObject<SimpleBindingImpl>* binding = NULL;
|
| - CComObject<SimpleBindingImpl>::CreateInstance(&binding);
|
| - binding->OverrideBindResults(INET_E_TERMINATED_BIND);
|
| - binding->AddRef();
|
| - hr = BindToStorageFromCache(bind_ctx, kChromeMimeType, request_data,
|
| - binding, reinterpret_cast<IStream**>(obj));
|
| - binding->Release();
|
| - } else {
|
| - DLOG(INFO) << " creating callback object";
|
| - CComObject<CFUrlmonBindStatusCallback>* callback = NULL;
|
| - hr = CComObject<CFUrlmonBindStatusCallback>::CreateInstance(
|
| - &callback);
|
| - callback->AddRef();
|
| - hr = callback->Initialize(bind_ctx, mgr->GetActiveRequestHeaders());
|
| - DCHECK(SUCCEEDED(hr));
|
| - hr = original(me, bind_ctx, to_left, iid, obj);
|
| - callback->Release();
|
| - if (SUCCEEDED(hr) && (*obj) == NULL) {
|
| - DCHECK(hr == MK_S_ASYNCHRONOUS);
|
| - }
|
| - }
|
| - } else {
|
| - hr = original(me, bind_ctx, to_left, iid, obj);
|
| - }
|
| - } else {
|
| - // We usually only get here when we're issuing requests from our
|
| - // worker thread. However there are some exceptions such as when
|
| - // windows media player is issuing requests, so we don't DCHECK.
|
| - hr = original(me, bind_ctx, to_left, iid, obj);
|
| }
|
|
|
| - return hr;
|
| -}
|
| + hr = original(me, bind_ctx, to_left, iid, obj);
|
|
|
| -HRESULT MonikerPatch::BindToStorageFromCache(IBindCtx* bind_ctx,
|
| - const wchar_t* mime_type,
|
| - RequestData* data,
|
| - SimpleBindingImpl* binding,
|
| - IStream** cache_out) {
|
| - DCHECK(bind_ctx);
|
| - // mime_type may be NULL
|
| - DCHECK(data);
|
| - DCHECK(binding);
|
| - // cache_out may be NULL
|
| + // If the binding terminates before the data could be played back
|
| + // now is the chance. Sometimes OnStopBinding happens after this returns
|
| + // and then it's too late.
|
| + if ((S_OK == hr) && callback)
|
| + callback->MayPlayBack(BSCF_LASTDATANOTIFICATION);
|
|
|
| - ScopedComPtr<IUnknown> holder;
|
| - HRESULT hr = bind_ctx->GetObjectParam(L"_BSCB_Holder_", holder.Receive());
|
| - DCHECK(holder);
|
| - ScopedComPtr<IBindStatusCallback> bscb;
|
| - ScopedComPtr<IHttpNegotiate> http_negotiate;
|
| - DoQueryService(IID_IBindStatusCallback, holder, bscb.Receive());
|
| - DoQueryService(IID_IHttpNegotiate, bscb, http_negotiate.Receive());
|
| - if (!bscb) {
|
| - NOTREACHED();
|
| - return E_NOINTERFACE;
|
| - }
|
| -
|
| - hr = bscb->OnStartBinding(0, binding);
|
| - DCHECK(SUCCEEDED(hr));
|
| - if (SUCCEEDED(hr)) {
|
| - // Fire BeginningTransaction and OnResponse events.
|
| - if (http_negotiate)
|
| - data->headers()->FireHttpNegotiateEvents(http_negotiate);
|
| -
|
| - FORMATETC format_etc = data->format();
|
| - if (mime_type) {
|
| - // If a non NULL mime type was specified, override the clipboard format.
|
| - format_etc.cfFormat = ::RegisterClipboardFormatW(mime_type);
|
| - DCHECK(format_etc.cfFormat);
|
| - }
|
| -
|
| - const wchar_t* mime_type_available = mime_type;
|
| - wchar_t format_name[MAX_PATH] = {0};
|
| - if (!mime_type_available) {
|
| - ::GetClipboardFormatName(format_etc.cfFormat, format_name,
|
| - arraysize(format_name));
|
| - mime_type_available = format_name;
|
| - }
|
| - DCHECK(mime_type_available);
|
| - hr = bscb->OnProgress(0, 0, BINDSTATUS_MIMETYPEAVAILABLE,
|
| - mime_type_available);
|
| -
|
| - ScopedComPtr<IStream> cache;
|
| - data->GetResetCachedContentStream(cache.Receive());
|
| -
|
| - STGMEDIUM medium = {0};
|
| - medium.tymed = TYMED_ISTREAM;
|
| - medium.pstm = cache;
|
| - DLOG(INFO) << __FUNCTION__ << " total bytes available: "
|
| - << data->GetCachedContentSize();
|
| - hr = bscb->OnDataAvailable(
|
| - BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION |
|
| - BSCF_DATAFULLYAVAILABLE, data->GetCachedContentSize(), &format_etc,
|
| - &medium);
|
| -
|
| - // OnDataAvailable might report a failure such as INET_E_TERMINATED_BIND
|
| - // when mshtml decides not to handle the request.
|
| - // We ignore the return value from OnStopBinding and return whatever
|
| - // OnDataAvailable gave us.
|
| - if (FAILED(hr)) {
|
| - binding->OverrideBindResults(hr);
|
| - } else if (cache_out) {
|
| - *cache_out = cache.Detach();
|
| - }
|
| -
|
| - bscb->OnStopBinding(hr, NULL);
|
| - }
|
| -
|
| return hr;
|
| -}
|
| -
|
| +}
|
|
|