summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoramit@chromium.org <amit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-09 00:51:10 +0000
committeramit@chromium.org <amit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-09 00:51:10 +0000
commit97965e190cb9f5009f6c97195bef9225c6034931 (patch)
tree96f2320c853a50d06664a1b2134a0dcb97c42bac
parent4a626f876a6dcd77e4d2cfc5d2496acdd44d7fe1 (diff)
downloadchromium_src-97965e190cb9f5009f6c97195bef9225c6034931.zip
chromium_src-97965e190cb9f5009f6c97195bef9225c6034931.tar.gz
chromium_src-97965e190cb9f5009f6c97195bef9225c6034931.tar.bz2
Switch renderer in Moniker patch
Step one of the changes. Inspect data and cause a switch in the moniker patch. Review URL: http://codereview.chromium.org/1589013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@44038 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome_frame/bho.cc23
-rw-r--r--chrome_frame/bho.h2
-rw-r--r--chrome_frame/bind_status_callback_impl.cc228
-rw-r--r--chrome_frame/bind_status_callback_impl.h98
-rw-r--r--chrome_frame/chrome_active_document.cc27
-rw-r--r--chrome_frame/chrome_active_document.h6
-rw-r--r--chrome_frame/chrome_frame.gyp11
-rw-r--r--chrome_frame/chrome_frame_activex_base.h4
-rw-r--r--chrome_frame/stream_impl.cc95
-rw-r--r--chrome_frame/stream_impl.h44
-rw-r--r--chrome_frame/test/test_with_web_server.cc4
-rw-r--r--chrome_frame/test/urlmon_moniker_integration_test.cc50
-rw-r--r--chrome_frame/test/urlmon_moniker_tests.h194
-rw-r--r--chrome_frame/test/urlmon_moniker_unittest.cc411
-rw-r--r--chrome_frame/urlmon_bind_status_callback.cc469
-rw-r--r--chrome_frame/urlmon_bind_status_callback.h161
-rw-r--r--chrome_frame/urlmon_moniker.cc525
-rw-r--r--chrome_frame/urlmon_moniker.h261
-rw-r--r--chrome_frame/urlmon_moniker_base.h156
-rw-r--r--chrome_frame/urlmon_upload_data_stream.h51
-rw-r--r--chrome_frame/urlmon_url_request.cc16
-rw-r--r--chrome_frame/urlmon_url_request_private.h1
-rw-r--r--chrome_frame/utils.h6
23 files changed, 1307 insertions, 1536 deletions
diff --git a/chrome_frame/bho.cc b/chrome_frame/bho.cc
index 4432c9f..3a731bc 100644
--- a/chrome_frame/bho.cc
+++ b/chrome_frame/bho.cc
@@ -251,16 +251,6 @@ HRESULT Bho::OnHttpEquiv(IBrowserService_OnHttpEquiv_Fn original_httpequiv,
}
}
}
- } else if (done) {
- if (!CheckForCFNavigation(browser, false)) {
- DLOG(INFO) << "Releasing cached data.";
- NavigationManager* mgr = NavigationManager::GetThreadInstance();
- if (mgr)
- mgr->ReleaseRequestData();
- } else {
- DLOG(INFO) << __FUNCTION__
- << " not freeing request data - browser tagged";
- }
}
return original_httpequiv(browser, shell_view, done, in_arg, out_arg);
@@ -326,18 +316,17 @@ bool PatchHelper::InitializeAndPatchProtocolsIfNeeded() {
ProtocolPatchMethod patch_method =
static_cast<ProtocolPatchMethod>(
GetConfigInt(PATCH_METHOD_IBROWSER, kPatchProtocols));
-
if (patch_method == PATCH_METHOD_INET_PROTOCOL) {
ProtocolSinkWrap::PatchProtocolHandlers();
state_ = PATCH_PROTOCOL;
+ } else if (patch_method == PATCH_METHOD_IBROWSER) {
+ state_ = PATCH_IBROWSER;
} else {
- DCHECK(patch_method == PATCH_METHOD_IBROWSER ||
- patch_method == PATCH_METHOD_IBROWSER_AND_MONIKER);
- state_ = PATCH_IBROWSER;
- if (patch_method == PATCH_METHOD_IBROWSER_AND_MONIKER) {
- MonikerPatch::Initialize();
- }
+ DCHECK(patch_method == PATCH_METHOD_MONIKER);
+ state_ = PATCH_MONIKER;
+ MonikerPatch::Initialize();
}
+
ret = true;
}
diff --git a/chrome_frame/bho.h b/chrome_frame/bho.h
index 430436b..466dcdb 100644
--- a/chrome_frame/bho.h
+++ b/chrome_frame/bho.h
@@ -27,7 +27,7 @@ class DeleteChromeHistory;
class PatchHelper {
public:
- enum State { UNKNOWN, PATCH_IBROWSER, PATCH_PROTOCOL };
+ enum State { UNKNOWN, PATCH_IBROWSER, PATCH_PROTOCOL, PATCH_MONIKER };
PatchHelper() : state_(UNKNOWN) {
}
diff --git a/chrome_frame/bind_status_callback_impl.cc b/chrome_frame/bind_status_callback_impl.cc
new file mode 100644
index 0000000..90da0916
--- /dev/null
+++ b/chrome_frame/bind_status_callback_impl.cc
@@ -0,0 +1,228 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome_frame/bind_status_callback_impl.h"
+
+#include "base/logging.h"
+#include "base/string_util.h"
+
+BSCBImpl::BSCBImpl() {
+ DLOG(INFO) << __FUNCTION__ << me();
+}
+
+BSCBImpl::~BSCBImpl() {
+ DLOG(INFO) << __FUNCTION__ << me();
+}
+
+std::string BSCBImpl::me() {
+ return StringPrintf(" obj=0x%08X",
+ static_cast<BSCBImpl*>(this));
+}
+
+HRESULT BSCBImpl::DelegateQI(void* obj, REFIID iid, void** ret, DWORD cookie) {
+ BSCBImpl* me = reinterpret_cast<BSCBImpl*>(obj);
+ HRESULT hr = E_NOINTERFACE;
+ if (me->delegate_)
+ hr = me->delegate_.QueryInterface(iid, ret);
+ return hr;
+}
+
+void BSCBImpl::Initialize(IBindStatusCallback* original) {
+ DCHECK(!delegate_);
+ delegate_ = original;
+}
+
+HRESULT BSCBImpl::AttachToBind(IBindCtx* bind_ctx) {
+ HRESULT hr = S_OK;
+ hr = ::RegisterBindStatusCallback(bind_ctx, this, delegate_.Receive(), 0);
+ if (SUCCEEDED(hr)) {
+ bind_ctx_ = bind_ctx;
+ }
+
+ return hr;
+}
+
+HRESULT BSCBImpl::ReleaseBind() {
+ HRESULT hr = S_OK;
+ if (delegate_ && bind_ctx_) {
+ ScopedComPtr<IBindStatusCallback> this_callback;
+ hr = ::RegisterBindStatusCallback(bind_ctx_, delegate_,
+ this_callback.Receive(), 0);
+ DCHECK(this_callback &&
+ (this_callback == static_cast<IBindStatusCallback*>(this)));
+ }
+
+ delegate_.Release();
+ bind_ctx_.Release();
+ return hr;
+}
+
+// IServiceProvider
+HRESULT BSCBImpl::QueryService(REFGUID service, REFIID iid, void** object) {
+ HRESULT hr = E_NOINTERFACE;
+ if (delegate_) {
+ ScopedComPtr<IServiceProvider> svc;
+ svc.QueryFrom(delegate_);
+ if (svc) {
+ hr = svc->QueryService(service, iid, object);
+ }
+ }
+ return hr;
+}
+
+// IBindStatusCallback
+HRESULT BSCBImpl::OnStartBinding(DWORD reserved, IBinding* binding) {
+ DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i",
+ PlatformThread::CurrentId());
+ HRESULT hr = S_OK;
+ if (delegate_)
+ hr = delegate_->OnStartBinding(reserved, binding);
+ return hr;
+}
+
+HRESULT BSCBImpl::GetPriority(LONG* priority) {
+ DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i",
+ PlatformThread::CurrentId());
+ HRESULT hr = S_OK;
+ if (delegate_)
+ hr = delegate_->GetPriority(priority);
+ return hr;
+}
+
+HRESULT BSCBImpl::OnLowResource(DWORD reserved) {
+ DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i",
+ PlatformThread::CurrentId());
+ HRESULT hr = S_OK;
+ if (delegate_)
+ hr = delegate_->OnLowResource(reserved);
+ return hr;
+}
+
+HRESULT BSCBImpl::OnProgress(ULONG progress, ULONG progress_max,
+ ULONG status_code, LPCWSTR status_text) {
+ DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" status=%i tid=%i %ls",
+ status_code, PlatformThread::CurrentId(), status_text);
+ HRESULT hr = S_OK;
+ if (delegate_)
+ delegate_->OnProgress(progress, progress_max, status_code, status_text);
+ return hr;
+}
+
+HRESULT BSCBImpl::OnStopBinding(HRESULT hresult, LPCWSTR error) {
+ DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" hr=0x%08X '%ls' tid=%i",
+ hresult, error, PlatformThread::CurrentId());
+ HRESULT hr = S_OK;
+ if (delegate_)
+ delegate_->OnStopBinding(hresult, error);
+ return hr;
+}
+
+HRESULT BSCBImpl::GetBindInfo(DWORD* bindf, BINDINFO* bind_info) {
+ DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i",
+ PlatformThread::CurrentId());
+ HRESULT hr = S_OK;
+ if (delegate_)
+ delegate_->GetBindInfo(bindf, bind_info);
+ return hr;
+}
+
+HRESULT BSCBImpl::OnDataAvailable(DWORD bscf, DWORD size,
+ FORMATETC* format_etc, STGMEDIUM* stgmed) {
+ DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i",
+ PlatformThread::CurrentId());
+ HRESULT hr = S_OK;
+ if (delegate_)
+ hr = delegate_->OnDataAvailable(bscf, size, format_etc, stgmed);
+ return hr;
+}
+
+HRESULT BSCBImpl::OnObjectAvailable(REFIID iid, IUnknown* unk) {
+ DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i",
+ PlatformThread::CurrentId());
+ HRESULT hr = S_OK;
+ if (delegate_)
+ delegate_->OnObjectAvailable(iid, unk);
+ return hr;
+}
+
+// IBindStatusCallbackEx
+HRESULT BSCBImpl::GetBindInfoEx(DWORD* bindf, BINDINFO* bind_info,
+ DWORD* bindf2, DWORD* reserved) {
+ DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i",
+ PlatformThread::CurrentId());
+ HRESULT hr = S_OK;
+ if (delegate_) {
+ ScopedComPtr<IBindStatusCallbackEx> bscbex;
+ bscbex.QueryFrom(delegate_);
+ if (bscbex)
+ hr = bscbex->GetBindInfoEx(bindf, bind_info, bindf2, reserved);
+ }
+ return hr;
+}
+
+HRESULT BSCBImpl::BeginningTransaction(LPCWSTR url, LPCWSTR headers,
+ DWORD reserved,
+ LPWSTR* additional_headers) {
+ DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i",
+ PlatformThread::CurrentId());
+
+ HRESULT hr = S_OK;
+ if (delegate_) {
+ ScopedComPtr<IHttpNegotiate> http_negotiate;
+ http_negotiate.QueryFrom(delegate_);
+ if (http_negotiate) {
+ hr = http_negotiate->BeginningTransaction(url, headers, reserved,
+ additional_headers);
+ }
+ }
+
+ DLOG_IF(ERROR, FAILED(hr)) << __FUNCTION__;
+ return hr;
+}
+
+HRESULT BSCBImpl::OnResponse(DWORD response_code, LPCWSTR response_headers,
+ LPCWSTR request_headers,
+ LPWSTR* additional_headers) {
+ DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i",
+ PlatformThread::CurrentId());
+
+ HRESULT hr = S_OK;
+ if (delegate_) {
+ ScopedComPtr<IHttpNegotiate> http_negotiate;
+ http_negotiate.QueryFrom(delegate_);
+ if (http_negotiate) {
+ hr = http_negotiate->OnResponse(response_code, response_headers,
+ request_headers, additional_headers);
+ }
+ }
+ return hr;
+}
+
+HRESULT BSCBImpl::GetRootSecurityId(BYTE* security_id, DWORD* security_id_size,
+ DWORD_PTR reserved) {
+ HRESULT hr = S_OK;
+ if (delegate_) {
+ ScopedComPtr<IHttpNegotiate2> http_negotiate;
+ http_negotiate.QueryFrom(delegate_);
+ if (http_negotiate) {
+ hr = http_negotiate->GetRootSecurityId(security_id, security_id_size,
+ reserved);
+ }
+ }
+ return hr;
+}
+
+HRESULT BSCBImpl::GetSerializedClientCertContext(BYTE** cert,
+ DWORD* cert_size) {
+ HRESULT hr = S_OK;
+ if (delegate_) {
+ ScopedComPtr<IHttpNegotiate3> http_negotiate;
+ http_negotiate.QueryFrom(delegate_);
+ if (http_negotiate) {
+ return http_negotiate->GetSerializedClientCertContext(cert, cert_size);
+ }
+ }
+ return hr;
+}
+
diff --git a/chrome_frame/bind_status_callback_impl.h b/chrome_frame/bind_status_callback_impl.h
new file mode 100644
index 0000000..7066050
--- /dev/null
+++ b/chrome_frame/bind_status_callback_impl.h
@@ -0,0 +1,98 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_FRAME_BIND_STATUS_CALLBACK_IMPL_H_
+#define CHROME_FRAME_BIND_STATUS_CALLBACK_IMPL_H_
+
+#include <atlbase.h>
+#include <atlcom.h>
+#include <string>
+#include <urlmon.h>
+
+#include "base/scoped_comptr_win.h"
+#include "chrome_frame/utils.h"
+
+// A generic base class for IBindStatus callback implementation.
+// If initialized with delegate, it will hand over all the calls
+// to the delegate. This can also be used as a base class to
+// provide the base implementation by not providing any delegate.
+class BSCBImpl
+ : public CComObjectRootEx<CComMultiThreadModel>,
+ public IBindStatusCallbackEx,
+ public IHttpNegotiate3,
+ public IServiceProvider {
+ public:
+ BSCBImpl();
+ ~BSCBImpl();
+
+BEGIN_COM_MAP(BSCBImpl)
+ COM_INTERFACE_ENTRY(IBindStatusCallback)
+ COM_INTERFACE_ENTRY(IHttpNegotiate)
+ COM_INTERFACE_ENTRY_IF_DELEGATE_SUPPORTS(IBindStatusCallbackEx)
+ COM_INTERFACE_ENTRY_IF_DELEGATE_SUPPORTS(IHttpNegotiate2)
+ COM_INTERFACE_ENTRY_IF_DELEGATE_SUPPORTS(IHttpNegotiate3)
+ COM_INTERFACE_ENTRY_IF_DELEGATE_SUPPORTS(IServiceProvider)
+ COM_INTERFACE_ENTRY_FUNC_BLIND(0, DelegateQI)
+END_COM_MAP()
+
+ static STDMETHODIMP DelegateQI(void* obj, REFIID iid, void** ret,
+ DWORD cookie);
+
+ void Initialize(IBindStatusCallback* original);
+ HRESULT AttachToBind(IBindCtx* original);
+ HRESULT ReleaseBind();
+
+ // For the COM_INTERFACE_ENTRY_IF_DELEGATE_SUPPORTS macro.
+ IBindStatusCallback* delegate() const {
+ return delegate_;
+ }
+
+ IBindCtx* bind_ctx() const {
+ return bind_ctx_;
+ }
+
+ // IServiceProvider
+ STDMETHOD(QueryService)(REFGUID service, REFIID iid, void** object);
+
+ // IBindStatusCallback
+ STDMETHOD(OnStartBinding)(DWORD reserved, IBinding* binding);
+ STDMETHOD(GetPriority)(LONG* priority);
+ STDMETHOD(OnLowResource)(DWORD reserved);
+ STDMETHOD(OnProgress)(ULONG progress, ULONG progress_max, ULONG status_code,
+ LPCWSTR status_text);
+ STDMETHOD(OnStopBinding)(HRESULT hresult, LPCWSTR error);
+ STDMETHOD(GetBindInfo)(DWORD* bindf, BINDINFO* bind_info);
+ STDMETHOD(OnDataAvailable)(DWORD bscf, DWORD size, FORMATETC* format_etc,
+ STGMEDIUM* stgmed);
+ STDMETHOD(OnObjectAvailable)(REFIID iid, IUnknown* unk);
+
+ // IBindStatusCallbackEx
+ STDMETHOD(GetBindInfoEx)(DWORD* bindf, BINDINFO* bind_info, DWORD* bindf2,
+ DWORD* reserved);
+
+ // IHttpNegotiate
+ STDMETHOD(BeginningTransaction)(LPCWSTR url, LPCWSTR headers, DWORD reserved,
+ LPWSTR* additional_headers);
+ STDMETHOD(OnResponse)(DWORD response_code, LPCWSTR response_headers,
+ LPCWSTR request_headers, LPWSTR* additional_headers);
+
+ // IHttpNegotiate2
+ STDMETHOD(GetRootSecurityId)(BYTE* security_id, DWORD* security_id_size,
+ DWORD_PTR reserved);
+
+ // IHttpNegotiate3
+ STDMETHOD(GetSerializedClientCertContext)(BYTE** cert, DWORD* cert_size);
+
+ protected:
+ // used for logging.
+ std::string me();
+
+ ScopedComPtr<IBindStatusCallback> delegate_;
+ ScopedComPtr<IBindCtx> bind_ctx_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BSCBImpl);
+};
+
+#endif // CHROME_FRAME_BIND_STATUS_CALLBACK_IMPL_H_
diff --git a/chrome_frame/chrome_active_document.cc b/chrome_frame/chrome_active_document.cc
index cec1b46..04d914e 100644
--- a/chrome_frame/chrome_active_document.cc
+++ b/chrome_frame/chrome_active_document.cc
@@ -85,7 +85,7 @@ HRESULT ChromeActiveDocument::FinalConstruct() {
// and initializes it, which would spawn a new Chrome process, etc.
// We don't want to be doing this if we have a cached document, whose
// automation client instance can be reused.
- HRESULT hr = Base::FinalConstruct();
+ HRESULT hr = BaseActiveX::FinalConstruct();
if (FAILED(hr))
return hr;
}
@@ -119,7 +119,7 @@ ChromeActiveDocument::~ChromeActiveDocument() {
find_dialog_.DestroyWindow();
}
// ChromeFramePlugin
- Base::Uninitialize();
+ BaseActiveX::Uninitialize();
}
// Override DoVerb
@@ -193,8 +193,8 @@ STDMETHODIMP ChromeActiveDocument::IsDirty() {
}
void ChromeActiveDocument::OnAutomationServerReady() {
- Base::OnAutomationServerReady();
- Base::GiveFocusToChrome();
+ BaseActiveX::OnAutomationServerReady();
+ BaseActiveX::GiveFocusToChrome();
}
STDMETHODIMP ChromeActiveDocument::Load(BOOL fully_avalable,
@@ -240,15 +240,11 @@ STDMETHODIMP ChromeActiveDocument::Load(BOOL fully_avalable,
moniker_name, bind_context,
mgr ? mgr->original_url_with_fragment() : std::wstring()));
- scoped_refptr<RequestData> data;
if (mgr) {
+ mgr->set_url(L"");
mgr->set_original_url_with_fragment(L"");
- data = mgr->GetActiveRequestData(url.c_str());
}
- DLOG_IF(INFO, data) << "Got active request data";
- DLOG_IF(WARNING, data.get() == NULL) << "NO active request data";
-
// The is_new_navigation variable indicates if this a navigation initiated
// by typing in a URL for e.g. in the IE address bar, or from Chrome by
// a window.open call from javascript, in which case the current IE tab
@@ -467,7 +463,7 @@ HRESULT ChromeActiveDocument::IOleObject_SetClientSite(
}
if (client_site != m_spClientSite) {
- return Base::IOleObject_SetClientSite(client_site);
+ return BaseActiveX::IOleObject_SetClientSite(client_site);
}
return S_OK;
@@ -578,7 +574,7 @@ void ChromeActiveDocument::OnAcceleratorPressed(int tab_handle,
// Handle the showing of the find dialog explicitly.
OnFindInPage();
} else {
- Base::OnAcceleratorPressed(tab_handle, accel_message);
+ BaseActiveX::OnAcceleratorPressed(tab_handle, accel_message);
}
} else {
DLOG(INFO) << "IE handled accel key " << accel_message.wParam;
@@ -665,7 +661,6 @@ void ChromeActiveDocument::UpdateNavigationState(
DCHECK(mgr);
if (mgr) {
mgr->set_url(url_);
- mgr->ReleaseRequestData();
}
}
@@ -789,7 +784,7 @@ void ChromeActiveDocument::OnOpenURL(int tab_handle,
g_active_doc_cache.Set(this);
}
- Base::OnOpenURL(tab_handle, url_to_open, referrer, open_disposition);
+ BaseActiveX::OnOpenURL(tab_handle, url_to_open, referrer, open_disposition);
}
void ChromeActiveDocument::OnAttachExternalTab(int tab_handle,
@@ -808,7 +803,7 @@ void ChromeActiveDocument::OnAttachExternalTab(int tab_handle,
}
// Allow popup
if (hr == S_OK) {
- Base::OnAttachExternalTab(tab_handle, params);
+ BaseActiveX::OnAttachExternalTab(tab_handle, params);
return;
}
@@ -838,7 +833,7 @@ bool ChromeActiveDocument::PreProcessContextMenu(HMENU menu) {
}
// Call base class (adds 'About' item)
- return Base::PreProcessContextMenu(menu);
+ return BaseActiveX::PreProcessContextMenu(menu);
}
bool ChromeActiveDocument::HandleContextMenuCommand(UINT cmd,
@@ -860,7 +855,7 @@ bool ChromeActiveDocument::HandleContextMenuCommand(UINT cmd,
break;
default:
- return Base::HandleContextMenuCommand(cmd, params);
+ return BaseActiveX::HandleContextMenuCommand(cmd, params);
}
return true;
diff --git a/chrome_frame/chrome_active_document.h b/chrome_frame/chrome_active_document.h
index 7a7d560..575c06a 100644
--- a/chrome_frame/chrome_active_document.h
+++ b/chrome_frame/chrome_active_document.h
@@ -208,7 +208,7 @@ class ATL_NO_VTABLE ChromeActiveDocument
public HTMLPrivateWindowImpl<IHTMLPrivateWindow> {
public:
typedef ChromeFrameActivexBase<ChromeActiveDocument,
- CLSID_ChromeActiveDocument> Base;
+ CLSID_ChromeActiveDocument> BaseActiveX;
ChromeActiveDocument();
~ChromeActiveDocument();
@@ -227,14 +227,14 @@ BEGIN_COM_MAP(ChromeActiveDocument)
COM_INTERFACE_ENTRY(IHTMLWindow2)
COM_INTERFACE_ENTRY(IHTMLPrivateWindow)
COM_INTERFACE_ENTRY(IEnumPrivacyRecords)
- COM_INTERFACE_ENTRY_CHAIN(Base)
+ COM_INTERFACE_ENTRY_CHAIN(BaseActiveX)
END_COM_MAP()
BEGIN_MSG_MAP(ChromeActiveDocument)
MESSAGE_HANDLER(WM_FIRE_PRIVACY_CHANGE_NOTIFICATION, OnFirePrivacyChange)
COMMAND_ID_HANDLER(IDC_FORWARD, OnForward)
COMMAND_ID_HANDLER(IDC_BACK, OnBack)
- CHAIN_MSG_MAP(Base)
+ CHAIN_MSG_MAP(BaseActiveX)
END_MSG_MAP()
HRESULT FinalConstruct();
diff --git a/chrome_frame/chrome_frame.gyp b/chrome_frame/chrome_frame.gyp
index 0aacce7..7689d2c 100644
--- a/chrome_frame/chrome_frame.gyp
+++ b/chrome_frame/chrome_frame.gyp
@@ -154,9 +154,14 @@
],
'conditions': [
['OS=="win"', {
+ 'link_settings': {
+ 'libraries': [
+ '-lshdocvw.lib',
+ ],
+ },
'msvs_settings': {
'VCLinkerTool': {
- 'DelayLoadDLLs': ['xpcom.dll', 'nspr4.dll'],
+ 'DelayLoadDLLs': ['xpcom.dll', 'nspr4.dll', 'shdocvw.dll'],
},
},
'dependencies': [
@@ -600,6 +605,8 @@
'bho.cc',
'bho.h',
'bho.rgs',
+ 'bind_status_callback_impl.cc',
+ 'bind_status_callback_impl.h',
'chrome_active_document.cc',
'chrome_active_document.h',
'chrome_active_document.rgs',
@@ -633,6 +640,8 @@
'ole_document_impl.h',
'protocol_sink_wrap.cc',
'protocol_sink_wrap.h',
+ 'stream_impl.cc',
+ 'stream_impl.h',
'sync_msg_reply_dispatcher.cc',
'sync_msg_reply_dispatcher.h',
'extra_system_apis.h',
diff --git a/chrome_frame/chrome_frame_activex_base.h b/chrome_frame/chrome_frame_activex_base.h
index d43c4ea..c382f95 100644
--- a/chrome_frame/chrome_frame_activex_base.h
+++ b/chrome_frame/chrome_frame_activex_base.h
@@ -170,7 +170,7 @@ class ATL_NO_VTABLE ChromeFrameActivexBase : // NOLINT
public ChromeFramePlugin<T> {
protected:
typedef std::set<ScopedComPtr<IDispatch> > EventHandlers;
- typedef ChromeFrameActivexBase<T, class_id> Base;
+ typedef ChromeFrameActivexBase<T, class_id> BasePlugin;
public:
ChromeFrameActivexBase()
@@ -450,7 +450,7 @@ END_MSG_MAP()
virtual void OnHandleContextMenu(int tab_handle, HANDLE menu_handle,
int align_flags,
const IPC::ContextMenuParams& params) {
- scoped_refptr<Base> ref(this);
+ scoped_refptr<BasePlugin> ref(this);
ChromeFramePlugin<T>::OnHandleContextMenu(tab_handle, menu_handle,
align_flags, params);
}
diff --git a/chrome_frame/stream_impl.cc b/chrome_frame/stream_impl.cc
new file mode 100644
index 0000000..246e7ea
--- /dev/null
+++ b/chrome_frame/stream_impl.cc
@@ -0,0 +1,95 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome_frame/stream_impl.h"
+
+#include "base/logging.h"
+
+void StreamImpl::Initialize(IStream* delegate) {
+ delegate_ = delegate;
+}
+
+STDMETHODIMP StreamImpl::Write(const void * buffer, ULONG size,
+ ULONG* size_written) {
+ HRESULT hr = E_NOTIMPL;
+ if (delegate_)
+ hr = delegate_->Write(buffer, size, size_written);
+ return hr;
+}
+
+STDMETHODIMP StreamImpl::Read(void* pv, ULONG cb, ULONG* read) {
+ HRESULT hr = E_NOTIMPL;
+ if (delegate_)
+ hr = delegate_->Read(pv, cb, read);
+ return hr;
+}
+
+STDMETHODIMP StreamImpl::Seek(LARGE_INTEGER move, DWORD origin,
+ ULARGE_INTEGER* new_pos) {
+ HRESULT hr = E_NOTIMPL;
+ if (delegate_)
+ hr = delegate_->Seek(move, origin, new_pos);
+ return hr;
+}
+
+STDMETHODIMP StreamImpl::SetSize(ULARGE_INTEGER new_size) {
+ HRESULT hr = E_NOTIMPL;
+ if (delegate_)
+ hr = delegate_->SetSize(new_size);
+ return hr;
+}
+
+STDMETHODIMP StreamImpl::CopyTo(IStream* stream, ULARGE_INTEGER cb,
+ ULARGE_INTEGER* read,
+ ULARGE_INTEGER* written) {
+ HRESULT hr = E_NOTIMPL;
+ if (delegate_)
+ hr = delegate_->CopyTo(stream, cb, read, written);
+ return hr;
+}
+
+STDMETHODIMP StreamImpl::Commit(DWORD flags) {
+ HRESULT hr = E_NOTIMPL;
+ if (delegate_)
+ hr = delegate_->Commit(flags);
+ return hr;
+}
+
+STDMETHODIMP StreamImpl::Revert() {
+ HRESULT hr = E_NOTIMPL;
+ if (delegate_)
+ hr = delegate_->Revert();
+ return hr;
+}
+
+STDMETHODIMP StreamImpl::LockRegion(ULARGE_INTEGER offset, ULARGE_INTEGER cb,
+ DWORD type) {
+ HRESULT hr = E_NOTIMPL;
+ if (delegate_)
+ hr = delegate_->LockRegion(offset, cb, type);
+ return hr;
+}
+
+STDMETHODIMP StreamImpl::UnlockRegion(ULARGE_INTEGER offset, ULARGE_INTEGER cb,
+ DWORD type) {
+ HRESULT hr = E_NOTIMPL;
+ if (delegate_)
+ hr = delegate_->UnlockRegion(offset, cb, type);
+ return hr;
+}
+
+STDMETHODIMP StreamImpl::Stat(STATSTG* statstg, DWORD flag) {
+ HRESULT hr = E_NOTIMPL;
+ if (delegate_)
+ hr = delegate_->Stat(statstg, flag);
+ return hr;
+}
+
+STDMETHODIMP StreamImpl::Clone(IStream** stream) {
+ HRESULT hr = E_NOTIMPL;
+ if (delegate_)
+ hr = delegate_->Clone(stream);
+ return hr;
+}
+
diff --git a/chrome_frame/stream_impl.h b/chrome_frame/stream_impl.h
new file mode 100644
index 0000000..9cced3e
--- /dev/null
+++ b/chrome_frame/stream_impl.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_FRAME_STREAM_IMPL_H_
+#define CHROME_FRAME_STREAM_IMPL_H_
+
+#include <atlbase.h>
+#include <atlcom.h>
+
+#include "base/scoped_comptr_win.h"
+
+// A generic base class for IStream implementation. If provided
+// with a delegate, it delegated calls to it otherwise can be
+// used a as a base class for an IStream implementation.
+class StreamImpl : public IStream {
+ public:
+ StreamImpl() {}
+
+ void Initialize(IStream* delegate);
+
+ STDMETHOD(Write)(const void * buffer, ULONG size, ULONG* size_written);
+ STDMETHOD(Read)(void* pv, ULONG cb, ULONG* read);
+ STDMETHOD(Seek)(LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER* new_pos);
+ STDMETHOD(SetSize)(ULARGE_INTEGER new_size);
+ STDMETHOD(CopyTo)(IStream* stream, ULARGE_INTEGER cb, ULARGE_INTEGER* read,
+ ULARGE_INTEGER* written);
+ STDMETHOD(Commit)(DWORD flags);
+ STDMETHOD(Revert)();
+ STDMETHOD(LockRegion)(ULARGE_INTEGER offset, ULARGE_INTEGER cb,
+ DWORD type);
+ STDMETHOD(UnlockRegion)(ULARGE_INTEGER offset, ULARGE_INTEGER cb,
+ DWORD type);
+ STDMETHOD(Stat)(STATSTG* statstg, DWORD flag);
+ STDMETHOD(Clone)(IStream** stream);
+
+ protected:
+ ScopedComPtr<IStream> delegate_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StreamImpl);
+};
+
+#endif // CHROME_FRAME_STREAM_IMPL_H_
diff --git a/chrome_frame/test/test_with_web_server.cc b/chrome_frame/test/test_with_web_server.cc
index 6f4350d..637f37d 100644
--- a/chrome_frame/test/test_with_web_server.cc
+++ b/chrome_frame/test/test_with_web_server.cc
@@ -20,9 +20,9 @@ bool MonikerPatchEnabled() {
ProtocolPatchMethod patch_method =
static_cast<ProtocolPatchMethod>(
GetConfigInt(PATCH_METHOD_IBROWSER, kPatchProtocols));
- LOG_IF(ERROR, patch_method != PATCH_METHOD_IBROWSER_AND_MONIKER)
+ LOG_IF(ERROR, patch_method != PATCH_METHOD_MONIKER)
<< "Not running test. Moniker patch not enabled.";
- return patch_method == PATCH_METHOD_IBROWSER_AND_MONIKER;
+ return patch_method == PATCH_METHOD_MONIKER;
}
class ChromeFrameTestEnvironment: public testing::Environment {
diff --git a/chrome_frame/test/urlmon_moniker_integration_test.cc b/chrome_frame/test/urlmon_moniker_integration_test.cc
index 3103504..57cc03d 100644
--- a/chrome_frame/test/urlmon_moniker_integration_test.cc
+++ b/chrome_frame/test/urlmon_moniker_integration_test.cc
@@ -8,7 +8,7 @@
#include "base/scoped_comptr_win.h"
#include "base/thread.h"
#include "chrome_frame/bho.h"
-#include "chrome_frame/urlmon_moniker.h"
+//#include "chrome_frame/urlmon_moniker.h"
#include "chrome_frame/test/test_server.h"
#include "chrome_frame/test/chrome_frame_test_utils.h"
#include "chrome_frame/test/urlmon_moniker_tests.h"
@@ -25,9 +25,10 @@ using testing::Invoke;
using testing::SetArgumentPointee;
using testing::StrEq;
using testing::Return;
-using testing::WithArg;
+using testing::DoAll;
using testing::WithArgs;
+
static int kUrlmonMonikerTimeoutSec = 5;
namespace {
@@ -88,35 +89,45 @@ class RunTestServer : public base::Thread {
class UrlmonMonikerTestManager {
public:
explicit UrlmonMonikerTestManager(const wchar_t* test_url) {
- mock_mgr_.RegisterThreadInstance();
- mock_mgr_.set_url(test_url);
EXPECT_EQ(true, MonikerPatch::Initialize());
}
~UrlmonMonikerTestManager() {
MonikerPatch::Uninitialize();
- mock_mgr_.UnregisterThreadInstance();
}
chrome_frame_test::TimedMsgLoop& loop() {
return loop_;
}
- TestNavigationManager& nav_manager() {
- return mock_mgr_;
- }
-
protected:
- TestNavigationManager mock_mgr_;
chrome_frame_test::TimedMsgLoop loop_;
};
+ACTION_P(SetBindInfo, is_async) {
+ DWORD* flags = arg0;
+ BINDINFO* bind_info = arg1;
+
+ DCHECK(flags);
+ DCHECK(bind_info);
+ DCHECK(bind_info->cbSize >= sizeof(BINDINFO));
+
+ *flags = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;
+ if (is_async)
+ *flags |= BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE;
+
+ bind_info->dwBindVerb = BINDVERB_GET;
+ memset(&bind_info->stgmedData, 0, sizeof(STGMEDIUM));
+ bind_info->grfBindInfoF = 0;
+ bind_info->szCustomVerb = NULL;
+}
+
// Wraps the MockBindStatusCallbackImpl mock object and allows the user
// to specify expectations on the callback object.
class UrlmonMonikerTestCallback {
public:
explicit UrlmonMonikerTestCallback(UrlmonMonikerTestManager* mgr)
- : mgr_(mgr) {
+ : mgr_(mgr), clip_format_(0) {
}
~UrlmonMonikerTestCallback() {
@@ -137,16 +148,10 @@ class UrlmonMonikerTestCallback {
if (bind_info_handling == REQUEST_ASYNCHRONOUS) {
EXPECT_CALL(callback_, GetBindInfo(_, _))
- .WillOnce(DoAll(
- WithArgs<0, 1>(
- Invoke(&MockBindStatusCallbackImpl::SetAsyncBindInfo)),
- Return(S_OK)));
+ .WillOnce(DoAll(SetBindInfo(true), Return(S_OK)));
} else if (bind_info_handling == REQUEST_SYNCHRONOUS) {
EXPECT_CALL(callback_, GetBindInfo(_, _))
- .WillOnce(DoAll(
- WithArgs<0, 1>(
- Invoke(&MockBindStatusCallbackImpl::SetSyncBindInfo)),
- Return(S_OK)));
+ .WillOnce(DoAll(SetBindInfo(false), Return(S_OK)));
} else {
DCHECK(bind_info_handling == EXPECT_NO_CALL);
}
@@ -192,6 +197,7 @@ class UrlmonMonikerTestCallback {
protected:
CComObjectStackEx<MockBindStatusCallbackImpl> callback_;
UrlmonMonikerTestManager* mgr_;
+ CLIPFORMAT clip_format_;
};
// Tests synchronously binding to a moniker and downloading the target.
@@ -217,8 +223,6 @@ TEST_F(UrlmonMonikerTest, BindToStorageSynchronous) {
EXPECT_EQ(0, release->Release());
server_thread.Stop();
-
- EXPECT_FALSE(test.nav_manager().HasRequestData());
}
// Tests asynchronously binding to a moniker and downloading the target.
@@ -242,8 +246,6 @@ TEST_F(UrlmonMonikerTest, BindToStorageAsynchronous) {
IBindCtx* release = bind_ctx.Detach();
EXPECT_EQ(0, release->Release());
-
- EXPECT_FALSE(test.nav_manager().HasRequestData());
}
// Responds with the Chrome mime type.
@@ -259,6 +261,7 @@ class ResponseWithContentType : public test_server::SimpleResponse {
}
};
+/*
// Downloads a document asynchronously and then verifies that the downloaded
// contents were cached and the cache contents are correct.
// TODO(tommi): Fix and re-enable.
@@ -340,3 +343,4 @@ TEST_F(UrlmonMonikerTest, BindToStorageCachedContent) {
}
}
+*/
diff --git a/chrome_frame/test/urlmon_moniker_tests.h b/chrome_frame/test/urlmon_moniker_tests.h
index 4c5b832..ce58b03 100644
--- a/chrome_frame/test/urlmon_moniker_tests.h
+++ b/chrome_frame/test/urlmon_moniker_tests.h
@@ -8,51 +8,9 @@
#include <atlbase.h>
#include <atlcom.h>
-#include "chrome_frame/bho.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
-class MockBindingImpl
- : public SimpleBindingImpl,
- public IServiceProvider {
- public:
-BEGIN_COM_MAP(MockBindingImpl)
- COM_INTERFACE_ENTRY(IBinding)
- COM_INTERFACE_ENTRY(IServiceProvider)
-END_COM_MAP()
-
- MOCK_METHOD0_WITH_CALLTYPE(__stdcall, Abort,
- HRESULT ()); // NOLINT
- MOCK_METHOD3_WITH_CALLTYPE(__stdcall, QueryService,
- HRESULT (REFGUID svc, // NOLINT
- REFIID riid,
- void** obj));
- MOCK_METHOD4_WITH_CALLTYPE(__stdcall, GetBindResult,
- HRESULT (CLSID* protocol, // NOLINT
- DWORD* result_code,
- LPOLESTR* result,
- DWORD* reserved));
-};
-
-class MockHttpNegotiateImpl
- : public CComObjectRootEx<CComSingleThreadModel>,
- public IHttpNegotiate {
- public:
-BEGIN_COM_MAP(MockHttpNegotiateImpl)
- COM_INTERFACE_ENTRY(IHttpNegotiate)
-END_COM_MAP()
- MOCK_METHOD4_WITH_CALLTYPE(__stdcall, BeginningTransaction,
- HRESULT (LPCWSTR url, // NOLINT
- LPCWSTR headers,
- DWORD reserved,
- LPWSTR* additional));
- MOCK_METHOD4_WITH_CALLTYPE(__stdcall, OnResponse,
- HRESULT (DWORD code, // NOLINT
- LPCWSTR response_headers,
- LPCWSTR request_headers,
- LPWSTR* additional));
-};
-
class MockBindStatusCallbackImpl
: public CComObjectRootEx<CComSingleThreadModel>,
public IBindStatusCallback {
@@ -60,6 +18,7 @@ class MockBindStatusCallbackImpl
BEGIN_COM_MAP(MockBindStatusCallbackImpl)
COM_INTERFACE_ENTRY(IBindStatusCallback)
END_COM_MAP()
+
MOCK_METHOD2_WITH_CALLTYPE(__stdcall, OnStartBinding,
HRESULT (DWORD reserved, IBinding* binding)); // NOLINT
@@ -92,51 +51,122 @@ END_COM_MAP()
MOCK_METHOD2_WITH_CALLTYPE(__stdcall, OnObjectAvailable,
HRESULT (REFIID riid, // NOLINT
IUnknown* unk));
+};
+
+class MockBindCtxImpl
+ : public CComObjectRootEx<CComSingleThreadModel>,
+ public IBindCtx {
+ public:
+BEGIN_COM_MAP(MockBindCtxImpl)
+ COM_INTERFACE_ENTRY(IBindCtx)
+END_COM_MAP()
+
+ MOCK_METHOD1_WITH_CALLTYPE(__stdcall, RegisterObjectBound,
+ HRESULT (IUnknown* object)); // NOLINT
+
+ MOCK_METHOD1_WITH_CALLTYPE(__stdcall, RevokeObjectBound,
+ HRESULT (IUnknown* object)); // NOLINT
+
+ MOCK_METHOD0_WITH_CALLTYPE(__stdcall, ReleaseBoundObjects,
+ HRESULT ()); // NOLINT
+
+ MOCK_METHOD1_WITH_CALLTYPE(__stdcall, SetBindOptions,
+ HRESULT (BIND_OPTS* options)); // NOLINT
+
+ MOCK_METHOD1_WITH_CALLTYPE(__stdcall, GetBindOptions,
+ HRESULT (BIND_OPTS* options)); // NOLINT
- static void ReadAllData(STGMEDIUM* storage) {
- DCHECK(storage);
- DCHECK(storage->tymed == TYMED_ISTREAM);
- char buffer[0xff];
- HRESULT hr;
- DWORD read = 0;
- do {
- hr = storage->pstm->Read(buffer, sizeof(buffer), &read);
- } while (hr == S_OK && read);
- }
-
- static void SetSyncBindInfo(DWORD* flags, BINDINFO* bind_info) {
- DCHECK(flags);
- DCHECK(bind_info);
- *flags = BINDF_PULLDATA | BINDF_NOWRITECACHE;
- DCHECK(bind_info->cbSize >= sizeof(BINDINFO));
- bind_info->dwBindVerb = BINDVERB_GET;
- memset(&bind_info->stgmedData, 0, sizeof(STGMEDIUM));
- bind_info->grfBindInfoF = 0;
- bind_info->szCustomVerb = NULL;
- }
-
- static void SetAsyncBindInfo(DWORD* flags, BINDINFO* bind_info) {
- DCHECK(flags);
- DCHECK(bind_info);
- *flags = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA |
- BINDF_NOWRITECACHE;
- DCHECK(bind_info->cbSize >= sizeof(BINDINFO));
- bind_info->dwBindVerb = BINDVERB_GET;
- memset(&bind_info->stgmedData, 0, sizeof(STGMEDIUM));
- bind_info->grfBindInfoF = 0;
- bind_info->szCustomVerb = NULL;
- }
+ MOCK_METHOD1_WITH_CALLTYPE(__stdcall, GetRunningObjectTable,
+ HRESULT (IRunningObjectTable** rot)); // NOLINT
+
+ MOCK_METHOD2_WITH_CALLTYPE(__stdcall, RegisterObjectParam,
+ HRESULT (LPOLESTR key, // NOLINT
+ IUnknown* param));
+
+ MOCK_METHOD2_WITH_CALLTYPE(__stdcall, GetObjectParam,
+ HRESULT (LPOLESTR key, // NOLINT
+ IUnknown** param));
+
+ MOCK_METHOD1_WITH_CALLTYPE(__stdcall, EnumObjectParam,
+ HRESULT (IEnumString** enum_params)); // NOLINT
+
+ MOCK_METHOD1_WITH_CALLTYPE(__stdcall, RevokeObjectParam,
+ HRESULT (LPOLESTR key)); // NOLINT
};
-class TestNavigationManager : public NavigationManager {
+class MockMonikerImpl
+ : public CComObjectRootEx<CComSingleThreadModel>,
+ public IMoniker {
public:
- TestNavigationManager() {
- }
+BEGIN_COM_MAP(MockMonikerImpl)
+ COM_INTERFACE_ENTRY(IMoniker)
+END_COM_MAP()
- bool HasRequestData() const {
- return request_data_.get() != NULL;
- }
+ MOCK_METHOD4_WITH_CALLTYPE(__stdcall, BindToObject,
+ HRESULT (IBindCtx* bind_context, // NOLINT
+ IMoniker* left,
+ REFIID result_iid,
+ void** object));
+
+ MOCK_METHOD4_WITH_CALLTYPE(__stdcall, BindToStorage,
+ HRESULT (IBindCtx* bind_context, // NOLINT
+ IMoniker* left,
+ REFIID result_iid,
+ void** storage));
+
+ MOCK_METHOD4_WITH_CALLTYPE(__stdcall, Reduce,
+ HRESULT (IBindCtx* bind_context, // NOLINT
+ DWORD reduce_depth,
+ IMoniker* left,
+ IMoniker** reduced));
+
+ MOCK_METHOD3_WITH_CALLTYPE(__stdcall, ComposeWith,
+ HRESULT (IBindCtx* right, // NOLINT
+ BOOL is_not_generic,
+ IMoniker** composite));
+
+ MOCK_METHOD2_WITH_CALLTYPE(__stdcall, Enum,
+ HRESULT (BOOL is_forward, // NOLINT
+ IEnumMoniker** moniker_enum));
+
+ MOCK_METHOD1_WITH_CALLTYPE(__stdcall, IsEqual,
+ HRESULT (IMoniker* other)); // NOLINT
+
+ MOCK_METHOD3_WITH_CALLTYPE(__stdcall, IsRunning,
+ HRESULT (IBindCtx* bind_context, // NOLINT
+ IMoniker* left,
+ IMoniker** newly_running));
+
+ MOCK_METHOD3_WITH_CALLTYPE(__stdcall, GetTimeOfLastChange,
+ HRESULT (IBindCtx* bind_context, // NOLINT
+ IMoniker* left,
+ FILETIME *pFileTime));
+
+ MOCK_METHOD1_WITH_CALLTYPE(__stdcall, Inverse,
+ HRESULT (IMoniker** inversed)); // NOLINT
+
+ MOCK_METHOD2_WITH_CALLTYPE(__stdcall, CommonPrefixWith,
+ HRESULT (IMoniker* other, // NOLINT
+ IMoniker** prefix));
+
+ MOCK_METHOD2_WITH_CALLTYPE(__stdcall, RelativePathTo,
+ HRESULT (IMoniker* other, // NOLINT
+ IMoniker** relative));
+
+ MOCK_METHOD3_WITH_CALLTYPE(__stdcall, GetDisplayName,
+ HRESULT (IBindCtx* bind_context, // NOLINT
+ IMoniker* left,
+ LPOLESTR* display_name));
+
+ MOCK_METHOD5_WITH_CALLTYPE(__stdcall, ParseDisplayName,
+ HRESULT (IBindCtx* bind_context, // NOLINT
+ IMoniker* left,
+ LPOLESTR display_name,
+ ULONG *pchEaten,
+ IMoniker** ret));
+
+ MOCK_METHOD1_WITH_CALLTYPE(__stdcall, IsSystemMoniker,
+ HRESULT (DWORD* is_system)); // NOLINT
};
#endif // CHROME_FRAME_TEST_URLMON_MONIKER_TESTS_H_
-
diff --git a/chrome_frame/test/urlmon_moniker_unittest.cc b/chrome_frame/test/urlmon_moniker_unittest.cc
index 08795fc..f50bd86 100644
--- a/chrome_frame/test/urlmon_moniker_unittest.cc
+++ b/chrome_frame/test/urlmon_moniker_unittest.cc
@@ -5,222 +5,245 @@
#include <atlbase.h>
#include <atlcom.h>
+#include "base/file_util.h"
+#include "base/path_service.h"
#include "base/scoped_comptr_win.h"
-#include "chrome_frame/bho.h"
-#include "chrome_frame/urlmon_moniker.h"
+#include "chrome_frame/urlmon_bind_status_callback.h"
#include "chrome_frame/test/urlmon_moniker_tests.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-using testing::_;
using testing::Return;
-using testing::WithArg;
-using testing::WithArgs;
-using testing::SetArgumentPointee;
-using testing::StrEq;
using testing::Eq;
-class UrlmonMonikerTest : public testing::Test {
+class MonikerPatchTest : public testing::Test {
protected:
- UrlmonMonikerTest() {
+ MonikerPatchTest() {
}
+
+ virtual void SetUp() {
+ PathService::Get(base::DIR_SOURCE_ROOT, &test_file_path_);
+ test_file_path_ = test_file_path_.Append(FILE_PATH_LITERAL("chrome_frame"))
+ .Append(FILE_PATH_LITERAL("test"))
+ .Append(FILE_PATH_LITERAL("data"));
+ }
+
+ bool ReadFileAsString(const wchar_t* file_name, std::string* file_contents) {
+ EXPECT_TRUE(file_name);
+ FilePath file_path = test_file_path_.Append(file_name);
+ return file_util::ReadFileToString(file_path, file_contents);
+ }
+
+ static bool StringToStream(const std::string& data, IStream** ret) {
+ EXPECT_TRUE(!data.empty());
+
+ ScopedComPtr<IStream> stream;
+ HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, stream.Receive());
+ EXPECT_HRESULT_SUCCEEDED(hr);
+ if (FAILED(hr)) {
+ return false;
+ }
+
+ DWORD written = 0;
+ hr = stream->Write(data.c_str(), data.size(), &written);
+ EXPECT_HRESULT_SUCCEEDED(hr);
+ EXPECT_EQ(data.size(), written);
+
+ bool result = false;
+ if (SUCCEEDED(hr)) {
+ RewindStream(stream);
+ *ret = stream.Detach();
+ result = true;
+ }
+
+ return result;
+ }
+
+ FilePath test_file_path_;
};
-// Tests the ReadStreamCache class by writing content into a stream object
-// and verify that reading that stream through the ReadStreamCache class
-// reads the correct content and also verifies that ReadStreamCache caches
-// all the reads.
-TEST_F(UrlmonMonikerTest, ReadStreamCache) {
- CComObjectStackEx<ReadStreamCache> read_stream;
- EXPECT_EQ(NULL, read_stream.cache());
-
- ScopedComPtr<IStream> test_stream;
- ::CreateStreamOnHGlobal(NULL, TRUE, test_stream.Receive());
- EXPECT_TRUE(NULL != test_stream);
- const char test_string[] = "ReadStreamCacheTest";
- DWORD written;
- EXPECT_HRESULT_SUCCEEDED(test_stream->Write(test_string, sizeof(test_string),
- &written));
- EXPECT_HRESULT_SUCCEEDED(RewindStream(test_stream));
-
- read_stream.SetDelegate(test_stream);
-
- char buffer[0xff];
+// Tests the CacheStream class by writing content into a stream object
+// and verify that reading that stream back
+TEST_F(MonikerPatchTest, CacheStream) {
+ const char data[] = "ReadStreamCacheTest";
+ char ret[2 * sizeof(data)] = {0};
DWORD read = 0;
- EXPECT_HRESULT_SUCCEEDED(read_stream.Read(buffer, sizeof(buffer), &read));
- EXPECT_EQ(read, sizeof(test_string));
- EXPECT_EQ(read_stream.GetCacheSize(), sizeof(test_string));
- read_stream.RewindCache();
- IStream* cache = read_stream.cache();
- EXPECT_TRUE(NULL != cache);
- if (cache) {
- read = 0;
- EXPECT_HRESULT_SUCCEEDED(cache->Read(buffer, sizeof(buffer), &read));
- EXPECT_EQ(read, sizeof(test_string));
- EXPECT_EQ(0, memcmp(test_string, buffer, sizeof(test_string)));
- }
+
+ // Test 1: empty stream reads nothing
+ CComObjectStackEx<CacheStream> cache_stream1;
+ EXPECT_EQ(E_PENDING, cache_stream1.Read(ret, sizeof(ret), &read));
+ EXPECT_EQ(0, read);
+
+ // Test 2: Read from initialized cache
+ CComObjectStackEx<CacheStream> cache_stream2;
+ cache_stream2.Initialize(data, sizeof(data));
+ EXPECT_HRESULT_SUCCEEDED(cache_stream2.Read(ret, sizeof(ret), &read));
+ EXPECT_EQ(sizeof(data), read);
+ EXPECT_EQ(std::string(data), std::string(ret));
+
+ read = 0;
+ EXPECT_EQ(E_PENDING, cache_stream2.Read(ret, sizeof(ret), &read));
+ EXPECT_EQ(0, read);
}
-// Verifies that we can override bind results by using the SimpleBindingImpl
-// class.
-TEST_F(UrlmonMonikerTest, SimpleBindingImpl1) {
- CComObjectStackEx<SimpleBindingImpl> test;
- ScopedComPtr<IBinding> binding;
- binding.QueryFrom(&test);
- EXPECT_TRUE(binding != NULL);
- test.OverrideBindResults(E_INVALIDARG);
- DWORD hr = E_UNEXPECTED;
- EXPECT_HRESULT_SUCCEEDED(binding->GetBindResult(NULL, &hr, NULL, NULL));
- EXPECT_EQ(E_INVALIDARG, hr);
- test.OverrideBindResults(E_ACCESSDENIED);
- // {1AF15145-104B-4bd8-AA4F-97CEFD40D370} - just something non-null.
- GUID guid = { 0x1af15145, 0x104b, 0x4bd8,
- { 0xaa, 0x4f, 0x97, 0xce, 0xfd, 0x40, 0xd3, 0x70 } };
- EXPECT_HRESULT_SUCCEEDED(binding->GetBindResult(&guid, &hr, NULL, NULL));
- EXPECT_EQ(E_ACCESSDENIED, hr);
- EXPECT_TRUE(guid == GUID_NULL);
+ACTION_P3(ReadStream, buffer, size, ret) {
+ EXPECT_EQ(TYMED_ISTREAM, arg3->tymed);
+ *ret = arg3->pstm->Read(buffer, *size, size);
}
-// Tests the SimpleBindingImpl class with a delegate. Verifies that the
-// delegate gets called and also that we can override the bind results.
-TEST_F(UrlmonMonikerTest, SimpleBindingImpl2) {
- CComObjectStackEx<MockBindingImpl> mock;
- CComObjectStackEx<SimpleBindingImpl> test;
-
- EXPECT_CALL(mock, QueryService(_, _, _))
- .WillOnce(Return(E_ACCESSDENIED));
- EXPECT_CALL(mock, GetBindResult(_, _, _, _))
- .WillRepeatedly(DoAll(SetArgumentPointee<1>(E_ACCESSDENIED),
- Return(S_OK)));
- EXPECT_CALL(mock, Abort())
- .WillOnce(Return(E_ACCESSDENIED));
-
- ScopedComPtr<IServiceProvider> svc;
- svc.QueryFrom(test.GetUnknown());
- EXPECT_TRUE(svc == NULL);
-
- test.SetDelegate(&mock);
-
- // Now we should have access to IServiceProvider
- svc.QueryFrom(test.GetUnknown());
- EXPECT_TRUE(svc != NULL);
-
- ScopedComPtr<IUnknown> unk;
- EXPECT_EQ(E_ACCESSDENIED, svc->QueryService(GUID_NULL, IID_NULL,
- reinterpret_cast<void**>(unk.Receive())));
-
- // Call through to the mock's GetBindResult implementation.
- DWORD result;
- test.GetBindResult(NULL, &result, NULL, NULL);
- EXPECT_TRUE(result == E_ACCESSDENIED);
- // Let the binding override the result code.
- test.OverrideBindResults(INET_E_TERMINATED_BIND);
- test.GetBindResult(NULL, &result, NULL, NULL);
- EXPECT_TRUE(result == INET_E_TERMINATED_BIND);
-
- EXPECT_EQ(E_ACCESSDENIED, test.Abort());
+// Tests the implementation of BSCBFeedData to feed data to the
+// specified IBindStatusCallback
+TEST_F(MonikerPatchTest, BSCBFeedData) {
+ CComObjectStackEx<MockBindStatusCallbackImpl> mock;
+ const char data[] = "ReadStreamCacheTest";
+ const DWORD size = sizeof(data);
+ const CLIPFORMAT cf = 0xd0d0;
+ const DWORD flags = BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION;
+ const DWORD kArbitraryreadSize = 0xdeadbabe;
+
+ char read_buffer1[size] = {0}, read_buffer2[size] = {0};
+ DWORD read_size1 = size, read_size2 = kArbitraryreadSize;
+ HRESULT ret1 = E_FAIL, ret2 = E_FAIL;
+
+ EXPECT_CALL(mock, OnDataAvailable(flags, size,
+ testing::Field(&FORMATETC::cfFormat, cf),
+ testing::Field(&STGMEDIUM::tymed, TYMED_ISTREAM)))
+ .WillOnce(testing::DoAll(
+ ReadStream(read_buffer1, &read_size1, &ret1),
+ ReadStream(read_buffer2, &read_size2, &ret2),
+ Return(S_OK)));
+
+ EXPECT_HRESULT_SUCCEEDED(CacheStream::BSCBFeedData(&mock, data, size, cf,
+ flags));
+
+ EXPECT_HRESULT_SUCCEEDED(ret1);
+ EXPECT_STREQ(data, read_buffer1);
+ EXPECT_EQ(size, read_size1);
+
+ EXPECT_EQ(E_PENDING, ret2);
+ EXPECT_STREQ("", read_buffer2);
+ EXPECT_EQ(kArbitraryreadSize, read_size2);
}
-// Tests the RequestData class. Content is fed to the object via OnX methods
-// and then we verify that the cached content is correct by calling
-// FireHttpNegotiateEvents and see if the notifications contain the correct
-// content.
-TEST_F(UrlmonMonikerTest, RequestHeaders) {
- scoped_refptr<RequestData> test(new RequestData());
- test->Initialize(NULL);
-
- const wchar_t url[] = L"http://www.chromium.org";
- const wchar_t begin_headers[] = L"Cookie: endilega\r\n";
- const wchar_t request_headers[] = L"GET / HTTP/1.0\r\nHost: cough\r\n\rn";
- const wchar_t response_headers[] = L"HTTP 200 OK\r\nHave-a: good-day\r\n\r\n";
- const wchar_t additional_headers[] = L"Referer: http://foo.com\r\n";
-
- // Null pointers should be ignored.
- RequestHeaders* headers = test->headers();
- EXPECT_TRUE(NULL != headers);
- headers->OnBeginningTransaction(NULL, NULL, NULL);
- headers->OnBeginningTransaction(url, begin_headers, additional_headers);
- headers->OnResponse(500, NULL, NULL);
- headers->OnResponse(200, response_headers, request_headers);
-
- CComObjectStackEx<MockHttpNegotiateImpl> mock;
- EXPECT_CALL(mock, BeginningTransaction(StrEq(url), StrEq(begin_headers),
- _, _))
- .WillOnce(Return(S_OK));
- EXPECT_CALL(mock, OnResponse(Eq(200), StrEq(response_headers),
- StrEq(request_headers), _))
- .WillOnce(Return(S_OK));
-
- EXPECT_EQ(0, headers->request_url().compare(url));
-
- headers->FireHttpNegotiateEvents(&mock);
+const wchar_t kSmallHtmlMetaTag[] = L"sub_frame1.html";
+const wchar_t kSmallHtmlNoMetaTag[] = L"host_browser.html";
+
+// Test various aspects of the SniffData class
+TEST_F(MonikerPatchTest, SniffDataMetaTag) {
+ std::string small_html_meta_tag, small_html_no_meta_tag;
+ ASSERT_TRUE(ReadFileAsString(kSmallHtmlMetaTag, &small_html_meta_tag));
+ ASSERT_TRUE(ReadFileAsString(kSmallHtmlNoMetaTag, &small_html_no_meta_tag));
+
+ ScopedComPtr<IStream> stream_with_meta, stream_no_meta;
+ ASSERT_TRUE(StringToStream(small_html_meta_tag, stream_with_meta.Receive()));
+ ASSERT_TRUE(StringToStream(small_html_no_meta_tag,
+ stream_no_meta.Receive()));
+
+ // Initialize 2 sniffers 1 with meta tag and 1 without.
+ SniffData sniffer1, sniffer2;
+ EXPECT_TRUE(sniffer1.InitializeCache(std::wstring()));
+ EXPECT_TRUE(sniffer2.InitializeCache(std::wstring()));
+ EXPECT_HRESULT_SUCCEEDED(sniffer1.ReadIntoCache(stream_with_meta, true));
+ EXPECT_HRESULT_SUCCEEDED(sniffer2.ReadIntoCache(stream_no_meta, true));
+
+ // Verify renderer type and size read.
+ EXPECT_TRUE(sniffer1.is_chrome());
+ EXPECT_EQ(SniffData::OTHER, sniffer2.renderer_type());
+ EXPECT_EQ(small_html_meta_tag.size(), sniffer1.size());
+ EXPECT_EQ(small_html_no_meta_tag.size(), sniffer2.size());
}
-// Tests the HTML content portion of the RequestData class.
-// Here we provide content in the form of a stream object and call
-// OnDataAvailable to make the object cache the contents.
-// Then we fetch the cached content stream by calling
-// GetResetCachedContentStream and verify that it's contents are correct.
-// In order to also test when data is cached outside of OnDataAvailable
-// calls, we also call DelegateDataRead. In this test we simply use the
-// original content again which will make the end results that the cached
-// content should be double the test content.
-TEST_F(UrlmonMonikerTest, RequestDataContent) {
- scoped_refptr<RequestData> test(new RequestData());
- test->Initialize(NULL);
+// Now test how the data is fed back the the bind status callback.
+// case 1: callback reads data in 1 read
+TEST_F(MonikerPatchTest, SniffDataPlayback1) {
+ std::string small_html_meta_tag;
+ ScopedComPtr<IStream> stream_with_meta;
+ SniffData sniffer;
- CComObjectStackEx<MockBindStatusCallbackImpl> mock;
+ EXPECT_TRUE(sniffer.InitializeCache(std::wstring()));
+ ASSERT_TRUE(ReadFileAsString(kSmallHtmlMetaTag, &small_html_meta_tag));
+ ASSERT_TRUE(StringToStream(small_html_meta_tag, stream_with_meta.Receive()));
+ EXPECT_HRESULT_SUCCEEDED(sniffer.ReadIntoCache(stream_with_meta, true));
- ScopedComPtr<IStream> data;
- ::CreateStreamOnHGlobal(NULL, TRUE, data.Receive());
- const char content[] = "<html><head>"
- "<meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\" />"
- "</head><body>Test HTML content</body></html>";
- data->Write(content, sizeof(content) - 1, NULL);
- STATSTG stat = {0};
- data->Stat(&stat, STATFLAG_NONAME);
- DCHECK(stat.cbSize.LowPart == (sizeof(content) - 1));
- RewindStream(data);
-
- FORMATETC format = {0};
- format.cfFormat = ::RegisterClipboardFormat(L"application/chromepage");
- format.tymed = TYMED_ISTREAM;
- STGMEDIUM storage = {0};
- storage.tymed = TYMED_ISTREAM;
- storage.pstm = data;
-
- DWORD flags = BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION |
- BSCF_DATAFULLYAVAILABLE;
-
- EXPECT_CALL(mock, OnDataAvailable(Eq(flags), Eq(stat.cbSize.LowPart), _, _))
- .WillOnce(DoAll(
- WithArgs<3>(testing::Invoke(
- &MockBindStatusCallbackImpl::ReadAllData)),
+ CComObjectStackEx<MockBindStatusCallbackImpl> mock;
+ const CLIPFORMAT cf = 0xd0d0;
+ const DWORD flags = BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION;
+ const DWORD data_size = small_html_meta_tag.size();
+
+ DWORD read_size1 = data_size * 2;
+ scoped_ptr<char> read_buffer1(new char[read_size1]);
+ ZeroMemory(read_buffer1.get(), read_size1);
+
+ char read_buffer2[10] = {0};
+ DWORD read_size2 = sizeof(read_buffer2);
+ HRESULT ret1 = E_FAIL, ret2 = E_FAIL;
+
+ EXPECT_CALL(mock, OnDataAvailable(flags, data_size,
+ testing::Field(&FORMATETC::cfFormat, cf),
+ testing::Field(&STGMEDIUM::tymed, TYMED_ISTREAM)))
+ .WillOnce(testing::DoAll(
+ ReadStream(read_buffer1.get(), &read_size1, &ret1),
+ ReadStream(read_buffer2, &read_size2, &ret2),
Return(S_OK)));
- size_t bytes_read = 0;
- test->DelegateDataRead(&mock, flags, stat.cbSize.LowPart, &format, &storage,
- &bytes_read);
-
- DCHECK(bytes_read == stat.cbSize.LowPart);
- DCHECK(test->GetCachedContentSize() == bytes_read);
-
- // Also test that the CacheAll method appends the stream.
- RewindStream(data);
- test->CacheAll(data);
- DCHECK(test->GetCachedContentSize() == (bytes_read * 2));
-
- ScopedComPtr<IStream> cache;
- EXPECT_HRESULT_SUCCEEDED(test->GetResetCachedContentStream(cache.Receive()));
- if (cache) {
- char buffer[0xffff];
- DCHECK((bytes_read * 2) <= sizeof(buffer));
- DWORD read = 0;
- cache->Read(buffer, sizeof(buffer), &read);
- EXPECT_EQ(read, bytes_read * 2);
- EXPECT_EQ(0, memcmp(content, buffer, sizeof(content) - 1));
- EXPECT_EQ(0, memcmp(content, buffer + sizeof(content) - 1,
- sizeof(content) - 1));
- }
+ EXPECT_HRESULT_SUCCEEDED(sniffer.DrainCache(&mock, flags, cf));
+
+ EXPECT_HRESULT_SUCCEEDED(ret1);
+ EXPECT_EQ(small_html_meta_tag, read_buffer1.get());
+ EXPECT_EQ(data_size, read_size1);
+
+ EXPECT_EQ(E_PENDING, ret2);
+ EXPECT_STREQ("", read_buffer2);
+ EXPECT_EQ(sizeof(read_buffer2), read_size2);
}
+// case 2: callback reads data in 2 reads.
+TEST_F(MonikerPatchTest, SniffDataPlayback2) {
+ std::string small_html_meta_tag;
+ ScopedComPtr<IStream> stream_with_meta;
+ SniffData sniffer;
+
+ EXPECT_TRUE(sniffer.InitializeCache(std::wstring()));
+ ASSERT_TRUE(ReadFileAsString(kSmallHtmlMetaTag, &small_html_meta_tag));
+ ASSERT_TRUE(StringToStream(small_html_meta_tag, stream_with_meta.Receive()));
+ EXPECT_HRESULT_SUCCEEDED(sniffer.ReadIntoCache(stream_with_meta, true));
+
+ CComObjectStackEx<MockBindStatusCallbackImpl> mock;
+ const CLIPFORMAT cf = 0xd0d0;
+ const DWORD flags = BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION;
+ const DWORD data_size = small_html_meta_tag.size();
+
+ DWORD read_size1 = data_size / 2; // First read is half the data.
+ DWORD read_size2 = data_size; // Second read, try to read past data.
+ scoped_ptr<char> read_buffer1(new char[read_size1]);
+ scoped_ptr<char> read_buffer2(new char[read_size2]);
+ ZeroMemory(read_buffer1.get(), read_size1);
+ ZeroMemory(read_buffer2.get(), read_size2);
+
+ char read_buffer3[10] = {0};
+ DWORD read_size3 = sizeof(read_buffer3);
+ HRESULT ret1 = E_FAIL, ret2 = E_FAIL, ret3 = E_FAIL;
+
+ EXPECT_CALL(mock, OnDataAvailable(flags, data_size,
+ testing::Field(&FORMATETC::cfFormat, cf),
+ testing::Field(&STGMEDIUM::tymed, TYMED_ISTREAM)))
+ .WillOnce(testing::DoAll(
+ ReadStream(read_buffer1.get(), &read_size1, &ret1),
+ ReadStream(read_buffer2.get(), &read_size2, &ret2),
+ ReadStream(read_buffer3, &read_size3, &ret3),
+ Return(S_OK)));
+
+ EXPECT_HRESULT_SUCCEEDED(sniffer.DrainCache(&mock, flags, cf));
+
+ EXPECT_HRESULT_SUCCEEDED(ret1);
+ EXPECT_HRESULT_SUCCEEDED(ret2);
+ EXPECT_EQ(data_size/2, read_size1);
+ EXPECT_EQ(data_size - read_size1, read_size2);
+
+ std::string data_read;
+ data_read.append(read_buffer1.get(), read_size1);
+ data_read.append(read_buffer2.get(), read_size2);
+ EXPECT_EQ(small_html_meta_tag, data_read);
+
+ EXPECT_EQ(E_PENDING, ret3);
+ EXPECT_STREQ("", read_buffer3);
+ EXPECT_EQ(sizeof(read_buffer3), read_size3);
+}
diff --git a/chrome_frame/urlmon_bind_status_callback.cc b/chrome_frame/urlmon_bind_status_callback.cc
index ec51c57..cb90bf2 100644
--- a/chrome_frame/urlmon_bind_status_callback.cc
+++ b/chrome_frame/urlmon_bind_status_callback.cc
@@ -4,307 +4,312 @@
#include "chrome_frame/urlmon_bind_status_callback.h"
+#include <mshtml.h>
#include <shlguid.h>
#include "base/logging.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
-CFUrlmonBindStatusCallback::CFUrlmonBindStatusCallback()
- : only_buffer_(false), data_(new RequestData()) {
- DLOG(INFO) << __FUNCTION__ << me();
-}
-
-CFUrlmonBindStatusCallback::~CFUrlmonBindStatusCallback() {
- DLOG(INFO) << __FUNCTION__ << me();
-}
+#include "chrome_frame/urlmon_moniker.h"
+#include "chrome_tab.h" // NOLINT
-std::string CFUrlmonBindStatusCallback::me() {
- return StringPrintf(" obj=0x%08X",
- static_cast<CFUrlmonBindStatusCallback*>(this));
-}
-HRESULT CFUrlmonBindStatusCallback::DelegateQI(void* obj, REFIID iid,
- void** ret, DWORD cookie) {
- CFUrlmonBindStatusCallback* me =
- reinterpret_cast<CFUrlmonBindStatusCallback*>(obj);
- HRESULT hr = me->delegate_.QueryInterface(iid, ret);
- return hr;
-}
+// A helper to given feed data to the specified |bscb| using
+// CacheStream instance.
+HRESULT CacheStream::BSCBFeedData(IBindStatusCallback* bscb, const char* data,
+ size_t size, CLIPFORMAT clip_format,
+ size_t flags) {
+ if (!bscb) {
+ NOTREACHED() << "invalid IBindStatusCallback";
+ return E_INVALIDARG;
+ }
-HRESULT CFUrlmonBindStatusCallback::Initialize(IBindCtx* bind_ctx,
- RequestHeaders* headers) {
- DLOG(INFO) << __FUNCTION__ << me();
- DCHECK(bind_ctx);
- DCHECK(!binding_delegate_.get());
- // headers may be NULL.
-
- data_->Initialize(headers);
-
- bind_ctx_ = bind_ctx;
-
- // Replace the bind context callback with ours.
- HRESULT hr = ::RegisterBindStatusCallback(bind_ctx, this,
- delegate_.Receive(), 0);
- if (!delegate_) {
- NOTREACHED() << "Failed to find registered bind status callback";
- ::RevokeBindStatusCallback(bind_ctx_, this);
- bind_ctx_.Release();
- hr = E_UNEXPECTED;
+ // We can't use a CComObjectStackEx here since mshtml will hold
+ // onto the stream pointer.
+ CComObject<CacheStream>* cache_stream = NULL;
+ HRESULT hr = CComObject<CacheStream>::CreateInstance(&cache_stream);
+ if (FAILED(hr)) {
+ NOTREACHED();
+ return hr;
}
+ cache_stream->AddRef();
+ cache_stream->Initialize(data, size);
+
+ FORMATETC format_etc = { clip_format, NULL, DVASPECT_CONTENT, -1,
+ TYMED_ISTREAM };
+ STGMEDIUM medium = {0};
+ medium.tymed = TYMED_ISTREAM;
+ medium.pstm = cache_stream;
+
+ hr = bscb->OnDataAvailable(flags, size, &format_etc, &medium);
+
+ cache_stream->Release();
return hr;
}
-HRESULT CFUrlmonBindStatusCallback::QueryService(REFGUID service, REFIID iid,
- void** object) {
- HRESULT hr = E_NOINTERFACE;
- if (delegate_) {
- ScopedComPtr<IServiceProvider> svc;
- svc.QueryFrom(delegate_);
- if (svc) {
- hr = svc->QueryService(service, iid, object);
- }
+void CacheStream::Initialize(const char* cache, size_t size) {
+ cache_ = cache;
+ size_ = size;
+ position_ = 0;
+}
+
+// Read is the only call that we expect. Return E_PENDING if there
+// is no more data to serve. Otherwise this will result in a
+// read with 0 bytes indicating that no more data is available.
+STDMETHODIMP CacheStream::Read(void* pv, ULONG cb, ULONG* read) {
+ if (!pv || !read)
+ return E_INVALIDARG;
+
+ // Default to E_PENDING to signal that this is a partial data.
+ HRESULT hr = E_PENDING;
+ if (position_ < size_) {
+ *read = std::min(size_ - position_, size_t(cb));
+ memcpy(pv, cache_ + position_, *read);
+ position_ += *read;
+ hr = S_OK;
}
+
return hr;
}
-// IBindStatusCallback
-HRESULT CFUrlmonBindStatusCallback::OnStartBinding(DWORD reserved,
- IBinding* binding) {
- DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i",
- PlatformThread::CurrentId());
- DCHECK(!binding_delegate_.get());
- CComObject<SimpleBindingImpl>* binding_delegate;
- HRESULT hr = CComObject<SimpleBindingImpl>::CreateInstance(&binding_delegate);
+/////////////////////////////////////////////////////////////////////
+
+bool SniffData::InitializeCache(const std::wstring& url) {
+ url_ = url;
+ renderer_type_ = UNDETERMINED;
+
+ const int kAllocationSize = 32 * 1024;
+ HGLOBAL memory = GlobalAlloc(0, kAllocationSize);
+ HRESULT hr = CreateStreamOnHGlobal(memory, TRUE, cache_.Receive());
if (FAILED(hr)) {
+ GlobalFree(memory);
NOTREACHED();
- return hr;
+ return false;
}
- binding_delegate_ = binding_delegate;
- DCHECK_EQ(binding_delegate->m_dwRef, 1);
- binding_delegate_->SetDelegate(binding);
-
- return delegate_->OnStartBinding(reserved, binding_delegate_);
+ return true;
}
-HRESULT CFUrlmonBindStatusCallback::GetPriority(LONG* priority) {
- DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i",
- PlatformThread::CurrentId());
- return delegate_->GetPriority(priority);
-}
-
-HRESULT CFUrlmonBindStatusCallback::OnLowResource(DWORD reserved) {
- DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i",
- PlatformThread::CurrentId());
- return delegate_->OnLowResource(reserved);
-}
-
-HRESULT CFUrlmonBindStatusCallback::OnProgress(ULONG progress,
- ULONG progress_max,
- ULONG status_code,
- LPCWSTR status_text) {
- DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" status=%i tid=%i %ls",
- status_code, PlatformThread::CurrentId(), status_text);
- if (status_code == BINDSTATUS_REDIRECTING && status_text) {
- redirected_url_ = status_text;
+HRESULT SniffData::ReadIntoCache(IStream* stream, bool force_determination) {
+ if (!stream) {
+ NOTREACHED();
+ return E_INVALIDARG;
}
- return delegate_->OnProgress(progress, progress_max, status_code,
- status_text);
-}
-HRESULT CFUrlmonBindStatusCallback::OnStopBinding(HRESULT hresult,
- LPCWSTR error) {
- DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" hr=0x%08X '%ls' tid=%i",
- hresult, error, PlatformThread::CurrentId());
- if (SUCCEEDED(hresult)) {
- // Notify the BHO that this is the one and only RequestData object.
- NavigationManager* mgr = NavigationManager::GetThreadInstance();
- DCHECK(mgr);
- if (mgr && data_->GetCachedContentSize()) {
- mgr->SetActiveRequestData(data_);
- if (!redirected_url_.empty()) {
- mgr->set_url(redirected_url_.c_str());
- }
+ HRESULT hr = S_OK;
+ while (SUCCEEDED(hr)) {
+ const size_t kChunkSize = 4 * 1024;
+ char buffer[kChunkSize];
+ DWORD read = 0;
+ hr = stream->Read(buffer, sizeof(buffer), &read);
+ if (read) {
+ DWORD written = 0;
+ cache_->Write(buffer, read, &written);
+ size_ += written;
}
- if (only_buffer_) {
- hresult = INET_E_TERMINATED_BIND;
- DLOG(INFO) << " - changed to INET_E_TERMINATED_BIND";
- }
+ if ((S_FALSE == hr) || !read)
+ break;
}
- // Hold a reference to ourselves while we release the bind context
- // and disconnect the callback.
- AddRef();
+ if (force_determination || (size() >= kMaxSniffSize)) {
+ DetermineRendererType();
+ }
- HRESULT hr = delegate_->OnStopBinding(hresult, error);
+ return hr;
+}
- if (bind_ctx_) {
- ::RevokeBindStatusCallback(bind_ctx_, this);
- bind_ctx_.Release();
+HRESULT SniffData::DrainCache(IBindStatusCallback* bscb, DWORD bscf,
+ CLIPFORMAT clip_format) {
+ if (!is_cache_valid()) {
+ return S_OK;
}
- binding_delegate_.Release();
-
- // After this call, this object might be gone.
- Release();
+ // Ideally we could just use the cache_ IStream implementation but
+ // can't use it here since we have to return E_PENDING for the
+ // last call
+ HGLOBAL memory = NULL;
+ HRESULT hr = GetHGlobalFromStream(cache_, &memory);
+ if (SUCCEEDED(hr) && memory) {
+ char* buffer = reinterpret_cast<char*>(GlobalLock(memory));
+ hr = CacheStream::BSCBFeedData(bscb, buffer, size_, clip_format, bscf);
+ GlobalUnlock(memory);
+ }
+ size_ = 0;
+ cache_.Release();
return hr;
}
-HRESULT CFUrlmonBindStatusCallback::GetBindInfo(DWORD* bindf,
- BINDINFO* bind_info) {
- DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i",
- PlatformThread::CurrentId());
- return delegate_->GetBindInfo(bindf, bind_info);
-}
-
-HRESULT CFUrlmonBindStatusCallback::OnDataAvailable(DWORD bscf, DWORD size,
- FORMATETC* format_etc,
- STGMEDIUM* stgmed) {
- DCHECK(format_etc);
-#ifndef NDEBUG
- wchar_t clip_fmt_name[MAX_PATH] = {0};
- if (format_etc) {
- ::GetClipboardFormatNameW(format_etc->cfFormat, clip_fmt_name,
- arraysize(clip_fmt_name));
+// Scan the buffer or OptIn URL list and decide if the renderer is
+// to be switched
+void SniffData::DetermineRendererType() {
+ if (is_undetermined()) {
+ if (IsOptInUrl(url_.c_str())) {
+ renderer_type_ = CHROME;
+ } else {
+ renderer_type_ = OTHER;
+ if (is_cache_valid() && cache_) {
+ HGLOBAL memory = NULL;
+ GetHGlobalFromStream(cache_, &memory);
+ char* buffer = reinterpret_cast<char*>(GlobalLock(memory));
+
+ std::wstring html_contents;
+ // TODO(joshia): detect and handle different content encodings
+ if (buffer && size_) {
+ UTF8ToWide(buffer, size_, &html_contents);
+ GlobalUnlock(memory);
+ }
+
+ // Note that document_contents_ may have NULL characters in it. While
+ // browsers may handle this properly, we don't and will stop scanning
+ // for the XUACompat content value if we encounter one.
+ std::wstring xua_compat_content;
+ UtilGetXUACompatContentValue(html_contents, &xua_compat_content);
+ if (StrStrI(xua_compat_content.c_str(), kChromeContentPrefix)) {
+ renderer_type_ = CHROME;
+ }
+ }
+ }
}
- DLOG(INFO) << __FUNCTION__ << me()
- << StringPrintf(" tid=%i original fmt=%ls",
- PlatformThread::CurrentId(), clip_fmt_name);
+}
- if (!stgmed) {
- NOTREACHED() << "Invalid STGMEDIUM received";
- return delegate_->OnDataAvailable(bscf, size, format_etc, stgmed);
- }
+/////////////////////////////////////////////////////////////////////
- if (stgmed->tymed != TYMED_ISTREAM) {
- DLOG(INFO) << "Not handling medium:" << stgmed->tymed;
- return delegate_->OnDataAvailable(bscf, size, format_etc, stgmed);
- }
+HRESULT BSCBStorageBind::Initialize(IMoniker* moniker, IBindCtx* bind_ctx) {
+ DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i",
+ PlatformThread::CurrentId());
- if (bscf & BSCF_FIRSTDATANOTIFICATION) {
- DLOG(INFO) << "first data notification";
+ HRESULT hr = AttachToBind(bind_ctx);
+ if (FAILED(hr)) {
+ NOTREACHED() << __FUNCTION__ << me() << "AttachToBind error: " << hr;
+ return hr;
}
-#endif
- HRESULT hr = S_OK;
- size_t bytes_read = 0;
- if (!only_buffer_) {
- hr = data_->DelegateDataRead(delegate_, bscf, size, format_etc, stgmed,
- &bytes_read);
+ if (!delegate()) {
+ NOTREACHED() << __FUNCTION__ << me() << "No existing callback: " << hr;
+ return E_FAIL;
}
- DLOG(INFO) << __FUNCTION__ << StringPrintf(" - 0x%08x", hr);
- if (hr == INET_E_TERMINATED_BIND) {
- // Check if the content type is CF's mime type.
- UINT cf_format = ::RegisterClipboardFormatW(kChromeMimeType);
- bool override_bind_results = (format_etc->cfFormat == cf_format);
- if (!override_bind_results) {
- ScopedComPtr<IBrowserService> browser_service;
- DoQueryService(SID_SShellBrowser, delegate_, browser_service.Receive());
- override_bind_results = (browser_service != NULL) &&
- CheckForCFNavigation(browser_service, false);
- }
+ std::wstring url = GetActualUrlFromMoniker(moniker, bind_ctx,
+ std::wstring());
+ data_sniffer_.InitializeCache(url);
+ return hr;
+}
- if (override_bind_results) {
- // We want to complete fetching the entire document even though the
- // delegate isn't interested in continuing.
- // This happens when we switch from mshtml to CF.
- // We take over and buffer the document and once we're done, we report
- // INET_E_TERMINATED to mshtml so that it will continue as usual.
- hr = S_OK;
- only_buffer_ = true;
- binding_delegate_->OverrideBindResults(INET_E_TERMINATED_BIND);
- }
- }
+STDMETHODIMP BSCBStorageBind::OnProgress(ULONG progress, ULONG progress_max,
+ ULONG status_code, LPCWSTR status_text) {
+ DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" status=%i tid=%i %ls",
+ status_code, PlatformThread::CurrentId(), status_text);
- if (only_buffer_) {
- data_->CacheAll(stgmed->pstm);
- DCHECK(hr == S_OK);
+ HRESULT hr = S_OK;
+ if (data_sniffer_.is_undetermined()) {
+ Progress new_progress = { progress, progress_max, status_code,
+ status_text ? status_text : std::wstring() };
+ saved_progress_.push_back(new_progress);
+ } else {
+ hr = CallbackImpl::OnProgress(progress, progress_max, status_code,
+ status_text);
}
return hr;
}
-HRESULT CFUrlmonBindStatusCallback::OnObjectAvailable(REFIID iid,
- IUnknown* unk) {
+// Refer to urlmon_moniker.h for explanation of how things work.
+STDMETHODIMP BSCBStorageBind::OnDataAvailable(DWORD flags, DWORD size,
+ FORMATETC* format_etc,
+ STGMEDIUM* stgmed) {
DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i",
PlatformThread::CurrentId());
- return delegate_->OnObjectAvailable(iid, unk);
-}
+ if (!stgmed || !format_etc) {
+ DLOG(INFO) << __FUNCTION__ << me() << "Invalid stgmed or format_etc";
+ return CallbackImpl::OnDataAvailable(flags, size, format_etc, stgmed);
+ }
-// IBindStatusCallbackEx
-HRESULT CFUrlmonBindStatusCallback::GetBindInfoEx(DWORD* bindf,
- BINDINFO* bind_info,
- DWORD* bindf2,
- DWORD* reserved) {
- DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i",
- PlatformThread::CurrentId());
- ScopedComPtr<IBindStatusCallbackEx> bscbex;
- bscbex.QueryFrom(delegate_);
- return bscbex->GetBindInfoEx(bindf, bind_info, bindf2, reserved);
-}
+ if ((stgmed->tymed != TYMED_ISTREAM) || !stgmed->pstm) {
+ DLOG(INFO) << __FUNCTION__ << me() << "stgmedium is not a valid stream";
+ return CallbackImpl::OnDataAvailable(flags, size, format_etc, stgmed);
+ }
-HRESULT CFUrlmonBindStatusCallback::BeginningTransaction(LPCWSTR url,
- LPCWSTR headers,
- DWORD reserved,
- LPWSTR* additional_headers) {
- DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i",
- PlatformThread::CurrentId());
+ HRESULT hr = S_OK;
+ if (!clip_format_)
+ clip_format_ = format_etc->cfFormat;
+
+ if (data_sniffer_.is_undetermined()) {
+ bool force_determination = !!(flags &
+ (BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE));
+ hr = data_sniffer_.ReadIntoCache(stgmed->pstm, force_determination);
+ // If we don't have sufficient data to determine renderer type
+ // wait for the next data notification.
+ if (data_sniffer_.is_undetermined())
+ return S_OK;
+ }
+
+ DCHECK(!data_sniffer_.is_undetermined());
- ScopedComPtr<IHttpNegotiate> http_negotiate;
- HRESULT hr = http_negotiate.QueryFrom(delegate_);
- if (SUCCEEDED(hr)) {
- hr = http_negotiate->BeginningTransaction(url, headers, reserved,
- additional_headers);
+ if (data_sniffer_.is_cache_valid()) {
+ hr = MayPlayBack(flags);
+ DCHECK(!data_sniffer_.is_cache_valid());
} else {
- hr = S_OK;
+ hr = CallbackImpl::OnDataAvailable(flags, size, format_etc, stgmed);
}
- data_->headers()->OnBeginningTransaction(url, headers,
- additional_headers && *additional_headers ? *additional_headers : NULL);
-
- DLOG_IF(ERROR, FAILED(hr)) << __FUNCTION__;
return hr;
}
-HRESULT CFUrlmonBindStatusCallback::OnResponse(DWORD response_code,
- LPCWSTR response_headers,
- LPCWSTR request_headers,
- LPWSTR* additional_headers) {
- DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i",
+STDMETHODIMP BSCBStorageBind::OnStopBinding(HRESULT hresult, LPCWSTR error) {
+ DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i",
PlatformThread::CurrentId());
+ HRESULT hr = MayPlayBack(BSCF_LASTDATANOTIFICATION);
+ return CallbackImpl::OnStopBinding(hresult, error);
+}
- data_->headers()->OnResponse(response_code, response_headers,
- request_headers);
+// Play back the cached data to the delegate. Normally this would happen
+// when we have read enough data to determine the renderer. In this case
+// we first play back the data from the cache and then go into a 'pass
+// through' mode. In some cases we may end up getting OnStopBinding
+// before we get a chance to determine. Also it's possible that the
+// BindToStorage call will return before OnStopBinding is sent. Hence
+// This is called from 3 places and it's important to maintain the
+// exact sequence of calls.
+// Once the data is played back, calling this again is a no op.
+HRESULT BSCBStorageBind::MayPlayBack(DWORD flags) {
+ // Force renderer type determination if not already done since
+ // we want to play back data now.
+ data_sniffer_.DetermineRendererType();
+ DCHECK(!data_sniffer_.is_undetermined());
- ScopedComPtr<IHttpNegotiate> http_negotiate;
- HRESULT hr = http_negotiate.QueryFrom(delegate_);
- if (SUCCEEDED(hr)) {
- hr = http_negotiate->OnResponse(response_code, response_headers,
- request_headers, additional_headers);
+ HRESULT hr = S_OK;
+ if (data_sniffer_.is_chrome()) {
+ // Remember clip format. If we are switching to chrome, then in order
+ // to make mshtml return INET_E_TERMINATED_BIND and reissue navigation
+ // with the same bind context, we have to return a mime type that is
+ // special cased by mshtml.
+ static const CLIPFORMAT kMagicClipFormat =
+ RegisterClipboardFormat(CFSTR_MIME_MPEG);
+ clip_format_ = kMagicClipFormat;
} else {
- hr = S_OK;
+ if (!saved_progress_.empty()) {
+ for (std::vector<Progress>::iterator i = saved_progress_.begin();
+ i != saved_progress_.end(); i++) {
+ const wchar_t* status_text = i->status_text_.empty() ?
+ NULL : i->status_text_.c_str();
+ CallbackImpl::OnProgress(i->progress_, i->progress_max_,
+ i->status_code_, status_text);
+ }
+ saved_progress_.clear();
+ }
}
- return hr;
-}
-HRESULT CFUrlmonBindStatusCallback::GetRootSecurityId(BYTE* security_id,
- DWORD* security_id_size,
- DWORD_PTR reserved) {
- ScopedComPtr<IHttpNegotiate2> http_negotiate;
- http_negotiate.QueryFrom(delegate_);
- return http_negotiate->GetRootSecurityId(security_id, security_id_size,
- reserved);
-}
+ if (data_sniffer_.is_cache_valid()) {
+ hr = data_sniffer_.DrainCache(delegate(),
+ flags | BSCF_FIRSTDATANOTIFICATION, clip_format_);
+ if (data_sniffer_.is_chrome())
+ NavigationManager::AttachCFObject(bind_ctx_);
+ }
-HRESULT CFUrlmonBindStatusCallback::GetSerializedClientCertContext(
- BYTE** cert,
- DWORD* cert_size) {
- ScopedComPtr<IHttpNegotiate3> http_negotiate;
- http_negotiate.QueryFrom(delegate_);
- return http_negotiate->GetSerializedClientCertContext(cert, cert_size);
+ return hr;
}
diff --git a/chrome_frame/urlmon_bind_status_callback.h b/chrome_frame/urlmon_bind_status_callback.h
index d8ede6d..f1b1473 100644
--- a/chrome_frame/urlmon_bind_status_callback.h
+++ b/chrome_frame/urlmon_bind_status_callback.h
@@ -8,91 +8,122 @@
#include <atlbase.h>
#include <atlcom.h>
-#include "chrome_frame/urlmon_moniker.h"
-
-// Our implementation of IBindStatusCallback that allows us to sit on the
-// sidelines and cache all the data that passes by (using the RequestData
-// class). That cache can then be used by other monikers for the same URL
-// that immediately follow.
-class CFUrlmonBindStatusCallback
- : public CComObjectRootEx<CComMultiThreadModel>,
- public IBindStatusCallbackEx,
- public IHttpNegotiate3,
- public IServiceProvider {
+#include "chrome_frame/bind_status_callback_impl.h"
+#include "chrome_frame/stream_impl.h"
+
+
+// A fake stream class to serve cached data to arbitrary
+// IBindStatusCallback
+class CacheStream : public CComObjectRoot, public StreamImpl {
public:
- CFUrlmonBindStatusCallback();
- ~CFUrlmonBindStatusCallback();
+ BEGIN_COM_MAP(CacheStream)
+ COM_INTERFACE_ENTRY(IStream)
+ COM_INTERFACE_ENTRY(ISequentialStream)
+ END_COM_MAP()
- // used for logging.
- std::string me();
+ CacheStream() : cache_(NULL), size_(0), position_(0) {
+ }
+ void Initialize(const char* cache, size_t size);
+ static HRESULT BSCBFeedData(IBindStatusCallback* bscb, const char* data,
+ size_t size, CLIPFORMAT clip_format,
+ size_t flags);
-BEGIN_COM_MAP(CFUrlmonBindStatusCallback)
- COM_INTERFACE_ENTRY(IBindStatusCallback)
- COM_INTERFACE_ENTRY(IHttpNegotiate)
- COM_INTERFACE_ENTRY_IF_DELEGATE_SUPPORTS(IBindStatusCallbackEx)
- COM_INTERFACE_ENTRY_IF_DELEGATE_SUPPORTS(IHttpNegotiate2)
- COM_INTERFACE_ENTRY_IF_DELEGATE_SUPPORTS(IHttpNegotiate3)
- COM_INTERFACE_ENTRY_IF_DELEGATE_SUPPORTS(IServiceProvider)
- COM_INTERFACE_ENTRY_FUNC_BLIND(0, DelegateQI)
-END_COM_MAP()
+ // IStream overrides
+ STDMETHOD(Read)(void* pv, ULONG cb, ULONG* read);
+
+ protected:
+ const char* cache_;
+ size_t size_;
+ size_t position_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CacheStream);
+};
- static STDMETHODIMP DelegateQI(void* obj, REFIID iid, void** ret,
- DWORD cookie);
+// Utility class for data sniffing
+class SniffData {
+ public:
+ SniffData() : renderer_type_(OTHER), size_(0) {}
+
+ enum RendererType {
+ UNDETERMINED,
+ CHROME,
+ OTHER
+ };
+
+ bool InitializeCache(const std::wstring& url);
+ HRESULT ReadIntoCache(IStream* stream, bool force_determination);
+ HRESULT DrainCache(IBindStatusCallback* bscb, DWORD bscf,
+ CLIPFORMAT clip_format);
+ void DetermineRendererType();
+
+ bool is_undetermined() const {
+ return (UNDETERMINED == renderer_type_);
+ }
+ bool is_chrome() const {
+ return (CHROME == renderer_type_);
+ }
- HRESULT Initialize(IBindCtx* bind_ctx, RequestHeaders* headers);
+ RendererType renderer_type() const {
+ return renderer_type_;
+ }
- // For the COM_INTERFACE_ENTRY_IF_DELEGATE_SUPPORTS macro.
- IBindStatusCallback* delegate() const {
- return delegate_;
+ size_t size() const {
+ return size_;
}
- RequestData* request_data() {
- return data_;
+ bool is_cache_valid() {
+ return (size_ != 0);
}
- // IServiceProvider
- STDMETHOD(QueryService)(REFGUID service, REFIID iid, void** object);
+ ScopedComPtr<IStream> cache_;
+ std::wstring url_;
+ RendererType renderer_type_;
+ size_t size_;
+
+ static const size_t kMaxSniffSize = 2 * 1024;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SniffData);
+};
+
+// A wrapper for bind status callback in IMoniker::BindToStorage
+class BSCBStorageBind : public BSCBImpl {
+ public:
+ typedef BSCBImpl CallbackImpl;
+ BSCBStorageBind() : clip_format_(CF_NULL) {}
+
+BEGIN_COM_MAP(BSCBStorageBind)
+ COM_INTERFACE_ENTRY(IBindStatusCallback)
+ COM_INTERFACE_ENTRY_CHAIN(CallbackImpl)
+END_COM_MAP()
+
+ HRESULT Initialize(IMoniker* moniker, IBindCtx* bind_ctx);
+ HRESULT MayPlayBack(DWORD flags);
// IBindStatusCallback
- STDMETHOD(OnStartBinding)(DWORD reserved, IBinding* binding);
- STDMETHOD(GetPriority)(LONG* priority);
- STDMETHOD(OnLowResource)(DWORD reserved);
STDMETHOD(OnProgress)(ULONG progress, ULONG progress_max, ULONG status_code,
LPCWSTR status_text);
- STDMETHOD(OnStopBinding)(HRESULT hresult, LPCWSTR error);
- STDMETHOD(GetBindInfo)(DWORD* bindf, BINDINFO* bind_info);
- STDMETHOD(OnDataAvailable)(DWORD bscf, DWORD size, FORMATETC* format_etc,
+ STDMETHOD(OnDataAvailable)(DWORD flags, DWORD size, FORMATETC* format_etc,
STGMEDIUM* stgmed);
- STDMETHOD(OnObjectAvailable)(REFIID iid, IUnknown* unk);
-
- // IBindStatusCallbackEx
- STDMETHOD(GetBindInfoEx)(DWORD* bindf, BINDINFO* bind_info, DWORD* bindf2,
- DWORD* reserved);
-
- // IHttpNegotiate
- STDMETHOD(BeginningTransaction)(LPCWSTR url, LPCWSTR headers, DWORD reserved,
- LPWSTR* additional_headers);
- STDMETHOD(OnResponse)(DWORD response_code, LPCWSTR response_headers,
- LPCWSTR request_headers, LPWSTR* additional_headers);
+ STDMETHOD(OnStopBinding)(HRESULT hresult, LPCWSTR error);
- // IHttpNegotiate2
- STDMETHOD(GetRootSecurityId)(BYTE* security_id, DWORD* security_id_size,
- DWORD_PTR reserved);
+ protected:
+ SniffData data_sniffer_;
- // IHttpNegotiate3
- STDMETHOD(GetSerializedClientCertContext)(BYTE** cert, DWORD* cert_size);
+ // A structure to cache the progress notifications
+ struct Progress {
+ ULONG progress_;
+ ULONG progress_max_;
+ ULONG status_code_;
+ std::wstring status_text_;
+ };
- protected:
- ScopedComPtr<IBindStatusCallback> delegate_;
- ScopedComPtr<IBindCtx> bind_ctx_;
- ScopedComPtr<SimpleBindingImpl, &GUID_NULL> binding_delegate_;
- bool only_buffer_;
- scoped_refptr<RequestData> data_;
- std::wstring redirected_url_;
+ std::vector<Progress> saved_progress_;
+ CLIPFORMAT clip_format_;
private:
- DISALLOW_COPY_AND_ASSIGN(CFUrlmonBindStatusCallback);
+ DISALLOW_COPY_AND_ASSIGN(BSCBStorageBind);
};
#endif // CHROME_FRAME_URLMON_BIND_STATUS_CALLBACK_H_
-
diff --git a/chrome_frame/urlmon_moniker.cc b/chrome_frame/urlmon_moniker.cc
index 77c1fc6..fc66e9f 100644
--- a/chrome_frame/urlmon_moniker.cc
+++ b/chrome_frame/urlmon_moniker.cc
@@ -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,258 +50,6 @@ std::string FindReferrerFromHeaders(const wchar_t* headers,
} // 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;
-}
////////////////////////////
@@ -309,9 +59,12 @@ HRESULT NavigationManager::NavigateToCurrentUrlInCF(IBrowserService* browser) {
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 @@ HRESULT NavigationManager::NavigateToCurrentUrlInCF(IBrowserService* browser) {
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 @@ void NavigationManager::UnregisterThreadInstance() {
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 @@ void MonikerPatch::Uninitialize() {
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 @@ HRESULT MonikerPatch::BindToStorage(IMoniker_BindToStorage_Fn original,
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;
-}
-
-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
-
- 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);
- }
+ hr = original(me, bind_ctx, to_left, iid, obj);
- 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);
- }
+ // 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);
return hr;
-}
-
+} \ No newline at end of file
diff --git a/chrome_frame/urlmon_moniker.h b/chrome_frame/urlmon_moniker.h
index d4b6bbb..885b7fe 100644
--- a/chrome_frame/urlmon_moniker.h
+++ b/chrome_frame/urlmon_moniker.h
@@ -14,8 +14,6 @@
#include "base/logging.h"
#include "base/scoped_comptr_win.h"
#include "base/thread_local.h"
-
-#include "chrome_frame/urlmon_moniker_base.h"
#include "chrome_frame/utils.h"
// This file contains classes that are used to cache the contents of a top-level
@@ -29,14 +27,12 @@
// - Bho::BeforeNavigate - top level url = www.msn.com
// - MSHTML -> MonikerPatch::BindToStorage.
// (IEFrame starts this by calling mshtml!*SuperNavigate*)
-// - request_data is NULL
// - check if the url is a top level url
// - iff the url is a top level url, we switch in our own callback object
-// and hook it up to the bind context (CFUrlmonBindStatusCallback)
-// The callback object caches the document in memory.
+// and hook it up to the bind context (BSCBStorageBind)
// - otherwise just call the original
-// - Bho::OnHttpEquiv is called with done == TRUE. At this point we determine
-// that the page did not have the CF meta tag in it and we delete the cache.
+// - BSCBStorageBind::OnDataAvailable - sniffs data and determines that the
+// renderer is not chrome. Goes into pass through mode.
// - The page loads in mshtml.
//
@@ -47,41 +43,18 @@
// (IEFrame starts this by calling mshtml!*SuperNavigate*)
// - request_data is NULL
// - check if the url is a top level url
-// - iff the url is a top level url (in this case, yes), we switch in our own
-// callback object and hook it up to the bind context
-// (CFUrlmonBindStatusCallback)
-// - As the document is fetched, the callback object caches the
-// document in memory.
-// - Bho::OnHttpEquiv (done == FALSE)
-// - mgr->NavigateToCurrentUrlInCF
-// - Set TLS (MarkBrowserOnThreadForCFNavigation)
-// - Create new bind context, moniker for the URL
-// - NavigateBrowserToMoniker with new moniker, bind context
-// - Our callback _may_ get an error from mshtml indicating that mshtml
-// isn't interested in the data anymore (since we started a new
-// navigation). If that happens, our callback class
-// (CFUrlmonBindStatusCallback) will continue to cache the document
-// until all of it has been retrieved successfully. When the data
-// is all read, we report INET_E_TERMINATE_BIND (see SimpleBindingImpl)
-// as the end result.
-// - In the case where all of the data has been downloaded before
-// - OnHttpEquiv is called, we will already have the cache but the
-// end bind status in the callback will be S_OK.
-// - Bho::BeforeNavigate2 - top level url = http://wave.google.com/
+// - iff the url is a top level url, we switch in our own callback object
+// and hook it up to the bind context (BSCBStorageBind)
+// - BSCBStorageBind::OnDataAvailable - sniffs data and determines that the
+// renderer is chrome. It then registers a special bind context param and
+// sets a magic clip format in the format_etc. Then goes into pass through
+// mode.
+// - mshtml looks at the clip format and re-issues the navigation with the
+// same bind context. Also returns INET_E_TERMINATED_BIND so that same
+// underlying transaction objects are used.
// - IEFrame -> MonikerPatch::BindToStorage
-// - request_data is not NULL since we now have a cached copy of the content.
-// - We call BindToStorageFromCache.
-// - HttpNegotiatePatch::ReportProgress
-// - Check TLS (CheckForCFNavigation) and report chrome mime type
-// - IEFrame does the following:
-// - Creates a new moniker
-// - Calls MonikerPatch::BindToObject
-// - We create an instance of ChromeActiveDocument and initialize it
-// with the cached document.
-// - ChromeActiveDocument gives the UrlmonUrlRequestManager the cached
-// contents (RequestData) which the manager will use as the content
-// when serving up content for the CF document.
-//
+// - We check for the special bind context param and instantiate and
+// return our ActiveDoc
//
// Scenario 3: CF navigation through mshtml link
@@ -102,169 +75,6 @@
// - [Scenario 2]
//
-// An implementation of IStream that delegates to another source
-// but caches all data that is read from the source.
-class ReadStreamCache
- : public CComObjectRootEx<CComSingleThreadModel>,
- public DelegatingReadStream {
- public:
- ReadStreamCache() {
- DLOG(INFO) << __FUNCTION__;
- }
-
- ~ReadStreamCache() {
- DLOG(INFO) << __FUNCTION__ << " cache: " << GetCacheSize();
- }
-
-BEGIN_COM_MAP(ReadStreamCache)
- COM_INTERFACE_ENTRY(IStream)
- COM_INTERFACE_ENTRY(ISequentialStream)
-END_COM_MAP()
-
- IStream* cache() const {
- return cache_;
- }
-
- void RewindCache() const;
-
- HRESULT WriteToCache(const void* data, ULONG size, ULONG* written);
-
- // Returns how many bytes we've cached. Used for logging.
- size_t GetCacheSize() const;
-
- // ISequentialStream.
- STDMETHOD(Read)(void* pv, ULONG cb, ULONG* read);
-
- protected:
- ScopedComPtr<IStream> cache_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ReadStreamCache);
-};
-
-// Basic implementation of IBinding with the option of offering a way
-// to override the bind result error value.
-class SimpleBindingImpl
- : public CComObjectRootEx<CComSingleThreadModel>,
- public DelegatingBinding {
- public:
- SimpleBindingImpl() : bind_results_(S_OK) {
- }
-
- ~SimpleBindingImpl() {
- }
-
-BEGIN_COM_MAP(SimpleBindingImpl)
- COM_INTERFACE_ENTRY(IBinding)
- COM_INTERFACE_ENTRY_FUNC_BLIND(0, DelegateQI)
-END_COM_MAP()
-
- static STDMETHODIMP DelegateQI(void* obj, REFIID iid, void** ret,
- DWORD cookie);
-
- STDMETHOD(GetBindResult)(CLSID* protocol, DWORD* result_code,
- LPOLESTR* result, DWORD* reserved);
-
- void OverrideBindResults(HRESULT results) {
- bind_results_ = results;
- }
-
- protected:
- HRESULT bind_results_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SimpleBindingImpl);
-};
-
-class RequestHeaders
- : public base::RefCountedThreadSafe<RequestHeaders> {
- public:
- RequestHeaders() : response_code_(-1) {
- }
-
- ~RequestHeaders() {
- }
-
- void OnBeginningTransaction(const wchar_t* url, const wchar_t* headers,
- const wchar_t* additional_headers);
-
- void OnResponse(DWORD response_code, const wchar_t* response_headers,
- const wchar_t* request_headers);
-
- const std::wstring& request_url() const {
- return request_url_;
- }
-
- // Invokes BeginningTransaction and OnResponse on the |http| object
- // providing already cached headers and status values.
- // Any additional headers returned from either of the two methods are ignored.
- HRESULT FireHttpNegotiateEvents(IHttpNegotiate* http) const;
-
- std::string GetReferrer();
-
- protected:
- std::wstring request_url_;
- std::wstring begin_request_headers_;
- std::wstring additional_request_headers_;
- std::wstring request_headers_;
- std::wstring response_headers_;
- DWORD response_code_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(RequestHeaders);
-};
-
-// Holds cached data for a urlmon request.
-class RequestData
- : public base::RefCountedThreadSafe<RequestData> {
- public:
- RequestData();
- ~RequestData();
-
- void Initialize(RequestHeaders* headers);
-
- // Calls IBindStatusCallback::OnDataAvailable and caches any data that is
- // read during that operation.
- // We also cache the format of the data stream if available during the first
- // call to this method.
- HRESULT DelegateDataRead(IBindStatusCallback* callback, DWORD flags,
- DWORD size, FORMATETC* format, STGMEDIUM* storage,
- size_t* bytes_read);
-
- // Reads everything that's available from |data| into a cached stream.
- void CacheAll(IStream* data);
-
- // Returns a new stream object to read the cache.
- // The returned stream object's seek pointer is at pos 0.
- HRESULT GetResetCachedContentStream(IStream** clone);
-
- size_t GetCachedContentSize() const {
- return stream_delegate_->GetCacheSize();
- }
-
- const FORMATETC& format() const {
- return format_;
- }
-
- RequestHeaders* headers() const {
- return headers_;
- }
-
- void set_headers(RequestHeaders* headers) {
- DCHECK(headers);
- DCHECK(headers_ == NULL);
- headers_ = headers;
- }
-
- protected:
- ScopedComPtr<ReadStreamCache, &GUID_NULL> stream_delegate_;
- FORMATETC format_;
- scoped_refptr<RequestHeaders> headers_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(RequestData);
-};
-
// This class is the link between a few static, moniker related functions to
// the bho. The specific services needed by those functions are abstracted into
// this interface for easier testability.
@@ -277,6 +87,11 @@ class NavigationManager {
// TLS. Returns NULL if no instance exists on the current thread.
static NavigationManager* GetThreadInstance();
+ // Mark a bind context for navigation by storing a bind context param.
+ static HRESULT AttachCFObject(IBindCtx* bind_context);
+ static HRESULT DetachCFObject(IMoniker* moniker, IBindCtx* bind_context,
+ IUnknown** object);
+
void RegisterThreadInstance();
void UnregisterThreadInstance();
@@ -313,14 +128,6 @@ class NavigationManager {
referrer_ = referrer;
}
- // Called when a top level navigation has finished and we don't need to
- // keep the cached content around anymore.
- virtual void ReleaseRequestData() {
- DLOG(INFO) << __FUNCTION__;
- url_.clear();
- SetActiveRequestData(NULL);
- }
-
// Return true if this is a URL that represents a top-level
// document that might have to be rendered in CF.
virtual bool IsTopLevelUrl(const wchar_t* url) {
@@ -338,30 +145,10 @@ class NavigationManager {
// and need to switch over from mshtml to CF.
virtual HRESULT NavigateToCurrentUrlInCF(IBrowserService* browser);
- virtual void SetActiveRequestData(RequestData* request_data);
-
- // When BindToObject is called on a URL before BindToStorage is called,
- // the request and response headers are reported on that moniker.
- // Later BindToStorage is called to fetch the content. We use the
- // RequestHeaders class to carry over the headers to the RequestData object
- // that will be created to hold the content.
- virtual void SetActiveRequestHeaders(RequestHeaders* request_headers) {
- request_headers_ = request_headers;
- }
-
- virtual RequestHeaders* GetActiveRequestHeaders() {
- return request_headers_;
- }
-
- virtual RequestData* GetActiveRequestData(const wchar_t* url) {
- return IsTopLevelUrl(url) ? request_data_.get() : NULL;
- }
-
protected:
std::string referrer_;
std::wstring url_;
- scoped_refptr<RequestData> request_data_;
- scoped_refptr<RequestHeaders> request_headers_;
+
static base::LazyInstance<base::ThreadLocalPointer<NavigationManager> >
thread_singleton_;
@@ -404,14 +191,6 @@ class MonikerPatch {
IMoniker* me, IBindCtx* bind_ctx,
IMoniker* to_left, REFIID iid, void** obj);
- // Reads content from cache (owned by RequestData) and simulates a regular
- // binding by calling the expected methods on the callback object bound to
- // the bind context.
- static HRESULT BindToStorageFromCache(IBindCtx* bind_ctx,
- const wchar_t* mime_type,
- RequestData* data,
- SimpleBindingImpl* binding,
- IStream** cache_out);
};
#endif // CHROME_FRAME_URLMON_MONIKER_H_
diff --git a/chrome_frame/urlmon_moniker_base.h b/chrome_frame/urlmon_moniker_base.h
deleted file mode 100644
index 6dd022c..0000000
--- a/chrome_frame/urlmon_moniker_base.h
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_FRAME_URLMON_MONIKER_BASE_H_
-#define CHROME_FRAME_URLMON_MONIKER_BASE_H_
-
-#include <atlbase.h>
-#include <atlcom.h>
-
-// An implementation of IStream (minus IUnknown) that delegates to
-// another source. Most of the methods contain a NOTREACHED() as the
-// class is used by the ReadStreamCache class where we don't expect those
-// calls under normal circumstances.
-class DelegatingReadStream : public IStream {
- public:
- DelegatingReadStream() {
- }
-
- ~DelegatingReadStream() {
- }
-
- void SetDelegate(IStream* delegate) {
- delegate_ = delegate;
- }
-
- // ISequentialStream.
- STDMETHOD(Read)(void* pv, ULONG cb, ULONG* read) {
- return delegate_->Read(pv, cb, read);
- }
-
- STDMETHOD(Write)(const void* pv, ULONG cb, ULONG* written) {
- NOTREACHED();
- return delegate_->Write(pv, cb, written);
- }
-
- // IStream.
- STDMETHOD(Seek)(LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER* new_pos) {
- NOTREACHED();
- return delegate_->Seek(move, origin, new_pos);
- }
-
- STDMETHOD(SetSize)(ULARGE_INTEGER new_size) {
- NOTREACHED();
- return delegate_->SetSize(new_size);
- }
-
- STDMETHOD(CopyTo)(IStream* stream, ULARGE_INTEGER cb, ULARGE_INTEGER* read,
- ULARGE_INTEGER* written) {
- NOTREACHED();
- return delegate_->CopyTo(stream, cb, read, written);
- }
-
- STDMETHOD(Commit)(DWORD commit_flags) {
- NOTREACHED();
- return delegate_->Commit(commit_flags);
- }
-
- STDMETHOD(Revert)() {
- NOTREACHED();
- return delegate_->Revert();
- }
-
- STDMETHOD(LockRegion)(ULARGE_INTEGER offset, ULARGE_INTEGER cb,
- DWORD lock_type) {
- NOTREACHED();
- return delegate_->LockRegion(offset, cb, lock_type);
- }
-
- STDMETHOD(UnlockRegion)(ULARGE_INTEGER offset, ULARGE_INTEGER cb,
- DWORD lock_type) {
- NOTREACHED();
- return delegate_->UnlockRegion(offset, cb, lock_type);
- }
-
- STDMETHOD(Stat)(STATSTG* stat_stg, DWORD stat_flag) {
- DCHECK(delegate_);
- return delegate_->Stat(stat_stg, stat_flag);
- }
-
- STDMETHOD(Clone)(IStream** stream) {
- NOTREACHED();
- return delegate_->Clone(stream);
- }
-
- protected:
- ScopedComPtr<IStream> delegate_;
-};
-
-// A very basic implementation of IBinding that forwards all calls
-// to a delegate.
-class DelegatingBinding : public IBinding {
- public:
- DelegatingBinding() {
- }
-
- ~DelegatingBinding() {
- }
-
- IBinding* delegate() const {
- return delegate_;
- }
-
- void SetDelegate(IBinding* delegate) {
- delegate_ = delegate;
- }
-
- STDMETHOD(Abort)() {
- DCHECK(delegate_);
- if (!delegate_)
- return S_OK;
- return delegate_->Abort();
- }
-
- STDMETHOD(Suspend)() {
- DCHECK(delegate_);
- if (!delegate_)
- return E_FAIL;
- return delegate_->Suspend();
- }
-
- STDMETHOD(Resume)() {
- DCHECK(delegate_);
- if (!delegate_)
- return E_FAIL;
- return delegate_->Resume();
- }
-
- STDMETHOD(SetPriority)(LONG priority) {
- DCHECK(delegate_);
- if (!delegate_)
- return E_FAIL;
- return delegate_->SetPriority(priority);
- }
-
- STDMETHOD(GetPriority)(LONG* priority) {
- DCHECK(delegate_);
- if (!delegate_)
- return E_FAIL;
- return delegate_->GetPriority(priority);
- }
-
- STDMETHOD(GetBindResult)(CLSID* protocol, DWORD* result_code,
- LPOLESTR* result, DWORD* reserved) {
- DCHECK(delegate_);
- if (!delegate_)
- return E_FAIL;
- return delegate_->GetBindResult(protocol, result_code, result, reserved);
- }
-
- protected:
- ScopedComPtr<IBinding> delegate_;
-};
-
-#endif // CHROME_FRAME_URLMON_MONIKER_BASE_H_
-
diff --git a/chrome_frame/urlmon_upload_data_stream.h b/chrome_frame/urlmon_upload_data_stream.h
index 30b7271..03316b7 100644
--- a/chrome_frame/urlmon_upload_data_stream.h
+++ b/chrome_frame/urlmon_upload_data_stream.h
@@ -11,14 +11,14 @@
#include "base/logging.h"
#include "base/ref_counted.h"
-
+#include "chrome_frame/stream_impl.h"
#include "net/base/upload_data.h"
#include "net/base/upload_data_stream.h"
// Provides an IStream interface to the very different UploadDataStream
// implementation.
class UrlmonUploadDataStream : public CComObjectRootEx<CComMultiThreadModel>,
- public IStream {
+ public StreamImpl {
public:
UrlmonUploadDataStream() {}
@@ -31,56 +31,9 @@ class UrlmonUploadDataStream : public CComObjectRootEx<CComMultiThreadModel>,
// Partial implementation of IStream.
STDMETHOD(Read)(void* pv, ULONG cb, ULONG* read);
-
- // E_NOTIMPL the rest and DCHECK if they get called (could also use
- // IStreamImpl but we'd lose the DCHECKS().
- STDMETHOD(Write)(const void * buffer, ULONG size, ULONG* size_written) {
- DCHECK(false) << __FUNCTION__;
- return E_NOTIMPL;
- }
-
- STDMETHOD(CopyTo)(IStream* stream, ULARGE_INTEGER cb, ULARGE_INTEGER* read,
- ULARGE_INTEGER* written) {
- DCHECK(false) << __FUNCTION__;
- return E_NOTIMPL;
- }
-
STDMETHOD(Seek)(LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER* new_pos);
-
- STDMETHOD(SetSize)(ULARGE_INTEGER new_size) {
- DCHECK(false) << __FUNCTION__;
- return E_NOTIMPL;
- }
-
- STDMETHOD(Commit)(DWORD flags) {
- DCHECK(false) << __FUNCTION__;
- return E_NOTIMPL;
- }
-
- STDMETHOD(Revert)() {
- DCHECK(false) << __FUNCTION__;
- return E_NOTIMPL;
- }
-
- STDMETHOD(LockRegion)(ULARGE_INTEGER offset, ULARGE_INTEGER cb,
- DWORD type) {
- DCHECK(false) << __FUNCTION__;
- return E_NOTIMPL;
- }
-
- STDMETHOD(UnlockRegion)(ULARGE_INTEGER offset, ULARGE_INTEGER cb,
- DWORD type) {
- DCHECK(false) << __FUNCTION__;
- return E_NOTIMPL;
- }
-
STDMETHOD(Stat)(STATSTG *pstatstg, DWORD grfStatFlag);
- STDMETHOD(Clone)(IStream** stream) {
- DCHECK(false) << __FUNCTION__;
- return E_NOTIMPL;
- }
-
private:
scoped_refptr<net::UploadData> upload_data_;
scoped_ptr<net::UploadDataStream> request_body_stream_;
diff --git a/chrome_frame/urlmon_url_request.cc b/chrome_frame/urlmon_url_request.cc
index c2ac15d..364f01d 100644
--- a/chrome_frame/urlmon_url_request.cc
+++ b/chrome_frame/urlmon_url_request.cc
@@ -41,21 +41,7 @@ bool UrlmonUrlRequest::Start() {
// StartAsyncDownload if BindToStorage finishes synchronously with an error.
// Grab a reference to protect against this.
scoped_refptr<UrlmonUrlRequest> ref(this);
- HRESULT hr = E_UNEXPECTED;
- if (request_data_) {
- DCHECK(bind_context_ == NULL);
- hr = CreateAsyncBindCtxEx(NULL, 0, this, NULL, bind_context_.Receive(), 0);
- DCHECK(SUCCEEDED(hr));
- CComObject<SimpleBindingImpl>* binding = NULL;
- CComObject<SimpleBindingImpl>::CreateInstance(&binding);
- binding->AddRef();
- hr = MonikerPatch::BindToStorageFromCache(bind_context_, NULL,
- request_data_, binding, NULL);
- binding->Release();
- } else {
- hr = StartAsyncDownload();
- }
-
+ HRESULT hr = StartAsyncDownload();
if (FAILED(hr) && status_.get_state() != UrlmonUrlRequest::Status::DONE) {
status_.Done();
status_.set_result(URLRequestStatus::FAILED, HresultToNetError(hr));
diff --git a/chrome_frame/urlmon_url_request_private.h b/chrome_frame/urlmon_url_request_private.h
index 239deb5..4dc973f 100644
--- a/chrome_frame/urlmon_url_request_private.h
+++ b/chrome_frame/urlmon_url_request_private.h
@@ -245,7 +245,6 @@ class UrlmonUrlRequest
ScopedComPtr<IBinding> binding_;
ScopedComPtr<IMoniker> moniker_;
ScopedComPtr<IBindCtx> bind_context_;
- scoped_refptr<RequestData> request_data_;
Cache cached_data_;
size_t pending_read_size_;
PlatformThreadId thread_;
diff --git a/chrome_frame/utils.h b/chrome_frame/utils.h
index bf8a33ec..ad5a335 100644
--- a/chrome_frame/utils.h
+++ b/chrome_frame/utils.h
@@ -31,7 +31,7 @@ extern const wchar_t kChromeMimeType[];
typedef enum ProtocolPatchMethod {
PATCH_METHOD_IBROWSER = 0,
PATCH_METHOD_INET_PROTOCOL, // 1
- PATCH_METHOD_IBROWSER_AND_MONIKER, // 2
+ PATCH_METHOD_MONIKER, // 2
};
// A REG_DWORD config value that maps to the ProtocolPatchMethod enum.
@@ -248,10 +248,6 @@ HRESULT DoQueryService(const IID& service_id, IUnknown* unk, T** service) {
return hr;
}
-// Get url (display name) from a moniker, |bind_context| is optional
-HRESULT GetUrlFromMoniker(IMoniker* moniker, IBindCtx* bind_context,
- std::wstring* url);
-
// Navigates an IWebBrowser2 object to a moniker.
// |headers| can be NULL.
HRESULT NavigateBrowserToMoniker(IUnknown* browser, IMoniker* moniker,