summaryrefslogtreecommitdiffstats
path: root/chrome_frame
diff options
context:
space:
mode:
authorstoyan@chromium.org <stoyan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-09 16:54:12 +0000
committerstoyan@chromium.org <stoyan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-09 16:54:12 +0000
commitce2b9f923c23700d24658b5118ab9c1d2f330d8b (patch)
treebdd559fc120cc9b5e5111a5c53efc4e3e0184466 /chrome_frame
parent78c7e2c68da0079869252bb464f4633373e5d067 (diff)
downloadchromium_src-ce2b9f923c23700d24658b5118ab9c1d2f330d8b.zip
chromium_src-ce2b9f923c23700d24658b5118ab9c1d2f330d8b.tar.gz
chromium_src-ce2b9f923c23700d24658b5118ab9c1d2f330d8b.tar.bz2
A new way of hooking internet protocols.
TEST=chrome frame tests Review URL: http://codereview.chromium.org/2620001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@49265 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame')
-rw-r--r--chrome_frame/bho.cc9
-rw-r--r--chrome_frame/bind_context_info.h11
-rw-r--r--chrome_frame/protocol_sink_wrap.cc1005
-rw-r--r--chrome_frame/protocol_sink_wrap.h238
-rw-r--r--chrome_frame/test/test_mock_with_web_server.cc12
-rw-r--r--chrome_frame/test/test_with_web_server.cc12
-rw-r--r--chrome_frame/utils.cc112
-rw-r--r--chrome_frame/utils.h7
8 files changed, 698 insertions, 708 deletions
diff --git a/chrome_frame/bho.cc b/chrome_frame/bho.cc
index 48838a9..6cdb0a6 100644
--- a/chrome_frame/bho.cc
+++ b/chrome_frame/bho.cc
@@ -123,8 +123,7 @@ STDMETHODIMP Bho::BeforeNavigate2(IDispatch* dispatch, VARIANT* url,
if (is_top_level) {
set_url(url->bstrVal);
set_referrer("");
- // The moniker patch checks opt-in URLs in SniffData::DetermineRendererType.
- if (!MonikerPatchEnabled()) {
+ if (IsIBrowserServicePatchEnabled()) {
ProcessOptInUrls(web_browser2, url->bstrVal);
}
}
@@ -320,10 +319,10 @@ bool PatchHelper::InitializeAndPatchProtocolsIfNeeded() {
ProtocolPatchMethod patch_method = GetPatchMethod();
if (patch_method == PATCH_METHOD_INET_PROTOCOL) {
- ProtocolSinkWrap::PatchProtocolHandlers();
+ g_trans_hooks.InstallHooks();
state_ = PATCH_PROTOCOL;
} else if (patch_method == PATCH_METHOD_IBROWSER) {
- state_ = PATCH_IBROWSER;
+ state_ = PATCH_IBROWSER;
} else {
DCHECK(patch_method == PATCH_METHOD_MONIKER);
state_ = PATCH_MONIKER;
@@ -348,7 +347,7 @@ void PatchHelper::PatchBrowserService(IBrowserService* browser_service) {
void PatchHelper::UnpatchIfNeeded() {
if (state_ == PATCH_PROTOCOL) {
- ProtocolSinkWrap::UnpatchProtocolHandlers();
+ g_trans_hooks.RevertHooks();
} else if (state_ == PATCH_IBROWSER) {
vtable_patch::UnpatchInterfaceMethods(IBrowserService_PatchInfo);
MonikerPatch::Uninitialize();
diff --git a/chrome_frame/bind_context_info.h b/chrome_frame/bind_context_info.h
index 07ec284..1778604 100644
--- a/chrome_frame/bind_context_info.h
+++ b/chrome_frame/bind_context_info.h
@@ -10,6 +10,7 @@
#include "base/scoped_bstr_win.h"
#include "base/scoped_comptr_win.h"
+#include "chrome_frame/protocol_sink_wrap.h"
class __declspec(uuid("71CC3EC7-7E8A-457f-93BC-1090CF31CC18"))
IBindContextInfoInternal : public IUnknown {
@@ -80,6 +81,14 @@ class __declspec(uuid("00000000-0000-0000-0000-000000000000")) BindContextInfo
return url_;
}
+ void set_prot_data(ProtData* data) {
+ prot_data_ = data;
+ }
+
+ scoped_refptr<ProtData> get_prot_data() {
+ return prot_data_;
+ }
+
protected:
STDMETHOD(GetCppObject)(void** me) {
DCHECK(me);
@@ -97,9 +106,9 @@ class __declspec(uuid("00000000-0000-0000-0000-000000000000")) BindContextInfo
bool is_switching_;
std::wstring url_;
ScopedComPtr<IUnknown> ftm_;
+ scoped_refptr<ProtData> prot_data_;
DISALLOW_COPY_AND_ASSIGN(BindContextInfo);
};
#endif // CHROME_FRAME_BIND_CONTEXT_INFO_
-
diff --git a/chrome_frame/protocol_sink_wrap.cc b/chrome_frame/protocol_sink_wrap.cc
index 683ec0f..b429e14 100644
--- a/chrome_frame/protocol_sink_wrap.cc
+++ b/chrome_frame/protocol_sink_wrap.cc
@@ -13,6 +13,8 @@
#include "base/singleton.h"
#include "base/string_util.h"
+#include "chrome_frame/bind_context_info.h"
+#include "chrome_frame/function_stub.h"
#include "chrome_frame/utils.h"
// BINDSTATUS_SERVER_MIMETYPEAVAILABLE == 54. Introduced in IE 8, so
@@ -29,640 +31,595 @@ static const int kInternetProtocolStartIndex = 3;
static const int kInternetProtocolReadIndex = 9;
static const int kInternetProtocolStartExIndex = 13;
-// TODO(ananta)
-// We should avoid duplicate VTable declarations.
-BEGIN_VTABLE_PATCHES(IInternetProtocol)
- VTABLE_PATCH_ENTRY(kInternetProtocolStartIndex, ProtocolSinkWrap::OnStart)
- VTABLE_PATCH_ENTRY(kInternetProtocolReadIndex, ProtocolSinkWrap::OnRead)
-END_VTABLE_PATCHES()
-
-BEGIN_VTABLE_PATCHES(IInternetProtocolSecure)
- VTABLE_PATCH_ENTRY(kInternetProtocolStartIndex, ProtocolSinkWrap::OnStart)
- VTABLE_PATCH_ENTRY(kInternetProtocolReadIndex, ProtocolSinkWrap::OnRead)
-END_VTABLE_PATCHES()
-BEGIN_VTABLE_PATCHES(IInternetProtocolEx)
- VTABLE_PATCH_ENTRY(kInternetProtocolStartIndex, ProtocolSinkWrap::OnStart)
- VTABLE_PATCH_ENTRY(kInternetProtocolReadIndex, ProtocolSinkWrap::OnRead)
- VTABLE_PATCH_ENTRY(kInternetProtocolStartExIndex, ProtocolSinkWrap::OnStartEx)
+// IInternetProtocol/Ex patches.
+STDMETHODIMP Hook_Start(InternetProtocol_Start_Fn orig_start,
+ IInternetProtocol* protocol,
+ LPCWSTR url,
+ IInternetProtocolSink* prot_sink,
+ IInternetBindInfo* bind_info,
+ DWORD flags,
+ HANDLE_PTR reserved);
+
+STDMETHODIMP Hook_StartEx(InternetProtocol_StartEx_Fn orig_start_ex,
+ IInternetProtocolEx* protocol,
+ IUri* uri,
+ IInternetProtocolSink* prot_sink,
+ IInternetBindInfo* bind_info,
+ DWORD flags,
+ HANDLE_PTR reserved);
+
+STDMETHODIMP Hook_Read(InternetProtocol_Read_Fn orig_read,
+ IInternetProtocol* protocol,
+ void* buffer,
+ ULONG size,
+ ULONG* size_read);
+
+/////////////////////////////////////////////////////////////////////////////
+BEGIN_VTABLE_PATCHES(CTransaction)
+ VTABLE_PATCH_ENTRY(kInternetProtocolStartIndex, Hook_Start)
+ VTABLE_PATCH_ENTRY(kInternetProtocolReadIndex, Hook_Read)
END_VTABLE_PATCHES()
-BEGIN_VTABLE_PATCHES(IInternetProtocolExSecure)
- VTABLE_PATCH_ENTRY(kInternetProtocolStartIndex, ProtocolSinkWrap::OnStart)
- VTABLE_PATCH_ENTRY(kInternetProtocolReadIndex, ProtocolSinkWrap::OnRead)
- VTABLE_PATCH_ENTRY(kInternetProtocolStartExIndex, ProtocolSinkWrap::OnStartEx)
+BEGIN_VTABLE_PATCHES(CTransaction2)
+ VTABLE_PATCH_ENTRY(kInternetProtocolStartExIndex, Hook_StartEx)
END_VTABLE_PATCHES()
//
// ProtocolSinkWrap implementation
-//
// Static map initialization
-ProtocolSinkWrap::ProtocolSinkMap ProtocolSinkWrap::sink_map_;
-CComAutoCriticalSection ProtocolSinkWrap::sink_map_lock_;
-
-ProtocolSinkWrap::ProtocolSinkWrap()
- : protocol_(NULL), renderer_type_(UNDETERMINED),
- buffer_size_(0), buffer_pos_(0), is_saved_result_(false),
- result_code_(0), result_error_(0), report_data_recursiveness_(0),
- determining_renderer_type_(false) {
- memset(buffer_, 0, arraysize(buffer_));
+ProtData::ProtocolDataMap ProtData::datamap_;
+Lock ProtData::datamap_lock_;
+
+ProtocolSinkWrap::ProtocolSinkWrap() {
+ DLOG(INFO) << __FUNCTION__ << StringPrintf(" 0x%08X", this);
}
ProtocolSinkWrap::~ProtocolSinkWrap() {
- // This object may be destroyed before Initialize is called.
- if (protocol_ != NULL) {
- CComCritSecLock<CComAutoCriticalSection> lock(sink_map_lock_);
- DCHECK(sink_map_.end() != sink_map_.find(protocol_));
- sink_map_.erase(protocol_);
- protocol_ = NULL;
- }
- DLOG(INFO) << "ProtocolSinkWrap: active sinks: " << sink_map_.size();
+ DLOG(INFO) << __FUNCTION__ << StringPrintf(" 0x%08X", this);
}
-bool ProtocolSinkWrap::PatchProtocolHandlers() {
- HRESULT hr = PatchProtocolMethods(CLSID_HttpProtocol,
- IInternetProtocol_PatchInfo,
- IInternetProtocolEx_PatchInfo);
- if (FAILED(hr)) {
- NOTREACHED() << "Failed to patch IInternetProtocol interface."
- << " Error: " << hr;
- return false;
- }
-
- hr = PatchProtocolMethods(CLSID_HttpSProtocol,
- IInternetProtocolSecure_PatchInfo,
- IInternetProtocolExSecure_PatchInfo);
- if (FAILED(hr)) {
- NOTREACHED() << "Failed to patch IInternetProtocol secure interface."
- << " Error: " << hr;
- return false;
- }
-
- return true;
+ScopedComPtr<IInternetProtocolSink> ProtocolSinkWrap::CreateNewSink(
+ IInternetProtocolSink* sink, ProtData* data) {
+ DCHECK(sink != NULL);
+ DCHECK(data != NULL);
+ CComObject<ProtocolSinkWrap>* new_sink = NULL;
+ CComObject<ProtocolSinkWrap>::CreateInstance(&new_sink);
+ new_sink->delegate_ = sink;
+ new_sink->prot_data_ = data;
+ return ScopedComPtr<IInternetProtocolSink>(new_sink);
}
-void ProtocolSinkWrap::UnpatchProtocolHandlers() {
- vtable_patch::UnpatchInterfaceMethods(IInternetProtocol_PatchInfo);
- vtable_patch::UnpatchInterfaceMethods(IInternetProtocolEx_PatchInfo);
- vtable_patch::UnpatchInterfaceMethods(IInternetProtocolSecure_PatchInfo);
- vtable_patch::UnpatchInterfaceMethods(IInternetProtocolExSecure_PatchInfo);
+// IInternetProtocolSink methods
+STDMETHODIMP ProtocolSinkWrap::Switch(PROTOCOLDATA* protocol_data) {
+ HRESULT hr = E_FAIL;
+ if (delegate_)
+ hr = delegate_->Switch(protocol_data);
+ return hr;
}
-HRESULT ProtocolSinkWrap::CreateProtocolHandlerInstance(
- const CLSID& clsid, IInternetProtocol** protocol) {
- if (!protocol) {
- return E_INVALIDARG;
- }
+STDMETHODIMP ProtocolSinkWrap::ReportProgress(ULONG status_code,
+ LPCWSTR status_text) {
+ DLOG(INFO) << "ProtocolSinkWrap::ReportProgress: "
+ << BindStatus2Str(status_code)
+ << " Status: " << (status_text ? status_text : L"");
- HMODULE module = ::GetModuleHandle(kUrlMonDllName);
- if (!module) {
- NOTREACHED() << "urlmon is not yet loaded. Error: " << GetLastError();
- return E_FAIL;
- }
+ HRESULT hr = prot_data_->ReportProgress(delegate_, status_code, status_text);
+ return hr;
+}
- typedef HRESULT (WINAPI* DllGetClassObject_Fn)(REFCLSID, REFIID, LPVOID*);
- DllGetClassObject_Fn fn = reinterpret_cast<DllGetClassObject_Fn>(
- ::GetProcAddress(module, "DllGetClassObject"));
- if (!fn) {
- NOTREACHED() << "DllGetClassObject not found in urlmon.dll";
- return E_FAIL;
- }
+STDMETHODIMP ProtocolSinkWrap::ReportData(DWORD flags, ULONG progress,
+ ULONG max_progress) {
+ DCHECK(delegate_);
+ DLOG(INFO) << "ProtocolSinkWrap::ReportData: " << Bscf2Str(flags) <<
+ " progress: " << progress << " progress_max: " << max_progress;
- ScopedComPtr<IClassFactory> protocol_class_factory;
- HRESULT hr = fn(clsid, IID_IClassFactory,
- reinterpret_cast<LPVOID*>(protocol_class_factory.Receive()));
- if (FAILED(hr)) {
- NOTREACHED() << "DllGetclassObject failed. Error: " << hr;
- return hr;
- }
+ HRESULT hr = prot_data_->ReportData(delegate_, flags, progress, max_progress);
+ return hr;
+}
- ScopedComPtr<IInternetProtocol> handler_instance;
- hr = protocol_class_factory->CreateInstance(NULL, IID_IInternetProtocol,
- reinterpret_cast<void**>(handler_instance.Receive()));
- if (FAILED(hr)) {
- NOTREACHED() << "ClassFactory::CreateInstance failed for InternetProtocol."
- << " Error: " << hr;
- } else {
- *protocol = handler_instance.Detach();
- }
+STDMETHODIMP ProtocolSinkWrap::ReportResult(HRESULT result, DWORD error,
+ LPCWSTR result_text) {
+ DLOG(INFO) << "ProtocolSinkWrap::ReportResult: result: " << result <<
+ " error: " << error << " Text: " << (result_text ? result_text : L"");
+ DCHECK_NE(UNDETERMINED, prot_data_->renderer_type());
+
+ HRESULT hr = E_FAIL;
+ if (delegate_)
+ hr = delegate_->ReportResult(result, error, result_text);
return hr;
}
-HRESULT ProtocolSinkWrap::PatchProtocolMethods(
- const CLSID& clsid_protocol,
- vtable_patch::MethodPatchInfo* protocol_patch_info,
- vtable_patch::MethodPatchInfo* protocol_ex_patch_info) {
- if (!protocol_patch_info || !protocol_ex_patch_info) {
- return E_INVALIDARG;
- }
- ScopedComPtr<IInternetProtocol> http_protocol;
- HRESULT hr = CreateProtocolHandlerInstance(clsid_protocol,
- http_protocol.Receive());
- if (FAILED(hr)) {
- NOTREACHED() << "ClassFactory::CreateInstance failed for InternetProtocol."
- << " Error: " << hr;
- return false;
+// Helpers
+ScopedComPtr<IBindCtx> BindCtxFromIBindInfo(IInternetBindInfo* bind_info) {
+ LPOLESTR bind_ctx_string = NULL;
+ ULONG count;
+ ScopedComPtr<IBindCtx> bind_ctx;
+ bind_info->GetBindString(BINDSTRING_PTR_BIND_CONTEXT, &bind_ctx_string, 1,
+ &count);
+ if (bind_ctx_string) {
+ IBindCtx* pbc = reinterpret_cast<IBindCtx*>(StringToInt(bind_ctx_string));
+ bind_ctx.Attach(pbc);
+ CoTaskMemFree(bind_ctx_string);
}
- ScopedComPtr<IInternetProtocolEx> ipex;
- ipex.QueryFrom(http_protocol);
- if (ipex) {
- hr = vtable_patch::PatchInterfaceMethods(ipex, protocol_ex_patch_info);
- } else {
- hr = vtable_patch::PatchInterfaceMethods(http_protocol,
- protocol_patch_info);
- }
- return hr;
+ return bind_ctx;
}
-// IInternetProtocol/Ex method implementation.
-HRESULT ProtocolSinkWrap::OnStart(InternetProtocol_Start_Fn orig_start,
- IInternetProtocol* protocol, LPCWSTR url, IInternetProtocolSink* prot_sink,
- IInternetBindInfo* bind_info, DWORD flags, HANDLE_PTR reserved) {
- DCHECK(orig_start);
- DLOG_IF(INFO, url != NULL) << "OnStart: " << url;
+bool ShouldWrapSink(IInternetProtocolSink* sink, const wchar_t* url) {
+ // TODO(stoyan): check the url scheme for http/https.
+ ScopedComPtr<IHttpNegotiate> http_negotiate;
+ HRESULT hr = DoQueryService(GUID_NULL, sink, http_negotiate.Receive());
+ if (http_negotiate && !IsSubFrameRequest(http_negotiate))
+ return true;
- ScopedComPtr<IInternetProtocolSink> sink_to_use(MaybeWrapSink(protocol,
- prot_sink, url));
- return orig_start(protocol, url, sink_to_use, bind_info, flags, reserved);
+ return false;
}
-HRESULT ProtocolSinkWrap::OnStartEx(InternetProtocol_StartEx_Fn orig_start_ex,
- IInternetProtocolEx* protocol, IUri* uri, IInternetProtocolSink* prot_sink,
- IInternetBindInfo* bind_info, DWORD flags, HANDLE_PTR reserved) {
- DCHECK(orig_start_ex);
-
- ScopedBstr url;
- uri->GetPropertyBSTR(Uri_PROPERTY_ABSOLUTE_URI, url.Receive(), 0);
- DLOG_IF(INFO, url != NULL) << "OnStartEx: " << url;
+// High level helpers
+bool IsCFRequest(IBindCtx* pbc) {
+ ScopedComPtr<BindContextInfo> info;
+ BindContextInfo::FromBindContext(pbc, info.Receive());
+ DCHECK(info);
+ if (info && info->chrome_request())
+ return true;
- ScopedComPtr<IInternetProtocolSink> sink_to_use(MaybeWrapSink(protocol,
- prot_sink, url));
- return orig_start_ex(protocol, uri, sink_to_use, bind_info, flags, reserved);
+ return false;
}
-HRESULT ProtocolSinkWrap::OnRead(InternetProtocol_Read_Fn orig_read,
- IInternetProtocol* protocol, void* buffer, ULONG size, ULONG* size_read) {
- DCHECK(orig_read);
+void PutProtData(IBindCtx* pbc, ProtData* data) {
+ ScopedComPtr<BindContextInfo> info;
+ BindContextInfo::FromBindContext(pbc, info.Receive());
+ if (info)
+ info->set_prot_data(data);
+}
- scoped_refptr<ProtocolSinkWrap> instance =
- ProtocolSinkWrap::InstanceFromProtocol(protocol);
- HRESULT hr;
- if (instance) {
- DCHECK(instance->protocol_ == protocol);
- hr = instance->OnReadImpl(buffer, size, size_read, orig_read);
- } else {
- hr = orig_read(protocol, buffer, size, size_read);
+bool IsTextHtml(const wchar_t* status_text) {
+ if (!status_text)
+ return false;
+ size_t status_text_length = lstrlenW(status_text);
+ const wchar_t* status_text_end = status_text +
+ std::min(status_text_length, arraysize(kTextHtmlMimeType) - 1);
+ bool is_text_html = LowerCaseEqualsASCII(status_text, status_text_end,
+ kTextHtmlMimeType);
+ return is_text_html;
+}
+
+RendererType DetermineRendererType(void* buffer, DWORD size, bool last_chance) {
+ RendererType type = UNDETERMINED;
+ if (last_chance)
+ type = OTHER;
+
+ std::wstring html_contents;
+ // TODO(joshia): detect and handle different content encodings
+ UTF8ToWide(reinterpret_cast<char*>(buffer), size, &html_contents);
+
+ // 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)) {
+ type = CHROME;
}
- return hr;
+ return type;
}
-bool ProtocolSinkWrap::Initialize(IInternetProtocol* protocol,
- IInternetProtocolSink* original_sink, const wchar_t* url) {
- DCHECK(original_sink);
- delegate_ = original_sink;
- protocol_ = protocol;
- if (url)
- url_ = url;
-
- CComCritSecLock<CComAutoCriticalSection> lock(sink_map_lock_);
- DCHECK(sink_map_.end() == sink_map_.find(protocol));
- sink_map_[protocol] = this;
- DLOG(INFO) << "ProtocolSinkWrap: active sinks: " << sink_map_.size();
- return true;
+// ProtData
+ProtData::ProtData(IInternetProtocol* protocol,
+ InternetProtocol_Read_Fn read_fun, const wchar_t* url)
+ : has_suggested_mime_type_(false), has_server_mime_type_(false),
+ report_data_received_(false), buffer_size_(0), buffer_pos_(0),
+ renderer_type_(UNDETERMINED), protocol_(protocol), read_fun_(read_fun),
+ url_(url) {
+ memset(buffer_, 0, arraysize(buffer_));
+ DLOG(INFO) << __FUNCTION__ << " " << this;
+
+ // Add to map.
+ AutoLock lock(datamap_lock_);
+ DCHECK(datamap_.end() == datamap_.find(protocol_));
+ datamap_[protocol] = this;
}
-// IInternetProtocolSink methods
-STDMETHODIMP ProtocolSinkWrap::Switch(PROTOCOLDATA* protocol_data) {
- HRESULT hr = E_FAIL;
- if (delegate_)
- hr = delegate_->Switch(protocol_data);
- return hr;
+ProtData::~ProtData() {
+ DLOG(INFO) << __FUNCTION__ << " " << this;
+
+ // Remove from map.
+ AutoLock lock(datamap_lock_);
+ DCHECK(datamap_.end() != datamap_.find(protocol_));
+ datamap_.erase(protocol_);
}
-STDMETHODIMP ProtocolSinkWrap::ReportProgress(ULONG status_code,
- LPCWSTR status_text) {
- DLOG(INFO) << "ProtocolSinkWrap::ReportProgress: Code:" << status_code <<
- " Text: " << (status_text ? status_text : L"");
- if (!delegate_) {
- return E_FAIL;
+HRESULT ProtData::Read(void* buffer, ULONG size, ULONG* size_read) {
+ if (renderer_type_ == UNDETERMINED) {
+ return E_PENDING;
}
- if ((BINDSTATUS_MIMETYPEAVAILABLE == status_code) ||
- (BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE == status_code)) {
- // If we have a MIMETYPE and that MIMETYPE is not "text/html". we don't
- // want to do anything with this.
- if (status_text) {
- size_t status_text_length = lstrlenW(status_text);
- const wchar_t* status_text_end = status_text + std::min(
- status_text_length, arraysize(kTextHtmlMimeType) - 1);
- if (!LowerCaseEqualsASCII(status_text, status_text_end,
- kTextHtmlMimeType)) {
- renderer_type_ = OTHER;
- }
+
+ const ULONG bytes_available = buffer_size_ - buffer_pos_;
+ const ULONG bytes_to_copy = std::min(bytes_available, size);
+ if (bytes_to_copy) {
+ // Copy from the local buffer.
+ memcpy(buffer, buffer_ + buffer_pos_, bytes_to_copy);
+ *size_read = bytes_to_copy;
+ buffer_pos_ += bytes_to_copy;
+
+ HRESULT hr = S_OK;
+ ULONG new_data = 0;
+ if (size > bytes_available) {
+ // User buffer is greater than what we have.
+ buffer = reinterpret_cast<uint8*>(buffer) + bytes_to_copy;
+ size -= bytes_to_copy;
+ hr = read_fun_(protocol_, buffer, size, &new_data);
}
+
+ if (size_read)
+ *size_read = bytes_to_copy + new_data;
+ return hr;
}
- HRESULT hr = S_OK;
- if (delegate_ && renderer_type_ != CHROME) {
- hr = delegate_->ReportProgress(status_code, status_text);
+ return read_fun_(protocol_, buffer, size, size_read);
+}
+
+
+HRESULT ProtData::ReportProgress(IInternetProtocolSink* delegate,
+ ULONG status_code, LPCWSTR status_text) {
+ switch (status_code) {
+ case BINDSTATUS_DIRECTBIND:
+ renderer_type_ = OTHER;
+ break;
+
+ case BINDSTATUS_REDIRECTING:
+ url_.empty();
+ if (status_text)
+ url_ = status_text;
+ break;
+
+ case BINDSTATUS_SERVER_MIMETYPEAVAILABLE:
+ has_server_mime_type_ = true;
+ SaveSuggestedMimeType(status_text);
+ return S_OK;
+
+ // TODO(stoyan): BINDSTATUS_RAWMIMETYPE
+ case BINDSTATUS_MIMETYPEAVAILABLE:
+ case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
+ SaveSuggestedMimeType(status_text);
+ return S_OK;
}
- return hr;
+
+ return delegate->ReportProgress(status_code, status_text);
}
-STDMETHODIMP ProtocolSinkWrap::ReportData(DWORD flags, ULONG progress,
- ULONG max_progress) {
- DCHECK(protocol_);
- DCHECK(delegate_);
- DLOG(INFO) << "ProtocolSinkWrap::ReportData: flags: " << flags <<
- " progress: " << progress << " progress_max: " << max_progress;
-
- scoped_refptr<ProtocolSinkWrap> self_ref(this);
-
- // Maintain a stack depth to make a determination. ReportData is called
- // recursively in IE8. If the request can be served in a single Read, the
- // situation ends up like this:
- // orig_prot
- // |--> ProtocolSinkWrap::ReportData (BSCF_FIRSTDATANOTIFICATION)
- // |--> orig_prot->Read(...) - 1st read - S_OK and data
- // |--> ProtocolSinkWrap::ReportData (BSCF_LASTDATANOTIFICATION)
- // |--> orig_prot->Read(...) - 2nd read S_FALSE, 0 bytes
- //
- // Inner call returns S_FALSE and no data. We try to make a determination
- // of render type then and incorrectly set it to 'OTHER' as we don't have
- // any data yet. However, we can make a determination in the context of
- // outer ReportData since the first read will return S_OK with data. Then
- // the next Read in the loop will return S_FALSE and we will enter the
- // determination logic.
-
- // NOTE: We use the report_data_recursiveness_ variable to detect situations
- // in which calls to ReportData are re-entrant (such as when the entire
- // contents of a page fit inside a single packet). In these cases, we
- // don't care about re-entrant calls beyond the second, and so we compare
- // report_data_recursiveness_ inside the while loop, making sure we skip
- // what would otherwise be spurious calls to ReportProgress().
- report_data_recursiveness_++;
-
- HRESULT hr = S_OK;
- if (is_undetermined()) {
- CheckAndReportChromeMimeTypeForRequest();
+HRESULT ProtData::ReportData(IInternetProtocolSink* delegate,
+ DWORD flags, ULONG progress, ULONG max_progress) {
+ if (renderer_type_ != UNDETERMINED) {
+ return delegate->ReportData(flags, progress, max_progress);
}
- // we call original only if the renderer type is other
- if (renderer_type() == OTHER) {
- hr = delegate_->ReportData(flags, progress, max_progress);
+ // Do these checks only once.
+ if (!report_data_received_) {
+ report_data_received_ = true;
+
+ DLOG_IF(INFO, (flags & BSCF_FIRSTDATANOTIFICATION) == 0) <<
+ "BUGBUG: BSCF_FIRSTDATANOTIFICATION is not set properly!";
- if (is_saved_result_) {
- is_saved_result_ = false;
- delegate_->ReportResult(result_code_, result_error_,
- result_text_.c_str());
+
+ // We check here, instead in ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE)
+ // to be safe when following multiple redirects.?
+ if (!IsTextHtml(suggested_mime_type_)) {
+ renderer_type_ = OTHER;
+ FireSugestedMimeType(delegate);
+ return delegate->ReportData(flags, progress, max_progress);
+ }
+
+ if (!url_.empty() && IsOptInUrl(url_.c_str())) {
+ // TODO(stoyan): We may attempt to remove ourselves from the bind context.
+ renderer_type_ = CHROME;
+ delegate->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, kChromeMimeType);
+ return delegate->ReportData(flags, progress, max_progress);
}
}
- report_data_recursiveness_--;
- return hr;
-}
+ HRESULT hr = FillBuffer();
-STDMETHODIMP ProtocolSinkWrap::ReportResult(HRESULT result, DWORD error,
- LPCWSTR result_text) {
- DLOG(INFO) << "ProtocolSinkWrap::ReportResult: result: " << result <<
- " error: " << error << " Text: " << (result_text ? result_text : L"");
-
- // If this request failed, we don't want to have anything to do with this.
- if (FAILED(result))
- renderer_type_ = OTHER;
-
- // if we are still not sure about the renderer type, cache the result,
- // othewise urlmon will get confused about getting reported about a
- // success result for which it never received any data.
- if (is_undetermined()) {
- is_saved_result_ = true;
- result_code_ = result;
- result_error_ = error;
- if (result_text)
- result_text_ = result_text;
+ bool last_chance = false;
+ if (hr == S_OK || hr == S_FALSE) {
+ last_chance = true;
+ }
+
+ renderer_type_ = DetermineRendererType(buffer_, buffer_size_, last_chance);
+
+ if (renderer_type_ == UNDETERMINED) {
+ // do not report anything, we need more data.
return S_OK;
}
- HRESULT hr = E_FAIL;
- if (delegate_)
- hr = delegate_->ReportResult(result, error, result_text);
+ if (renderer_type_ == CHROME) {
+ DLOG(INFO) << "Forwarding BINDSTATUS_MIMETYPEAVAILABLE "
+ << kChromeMimeType;
+ delegate->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, kChromeMimeType);
+ }
- return hr;
-}
+ if (renderer_type_ == OTHER) {
+ FireSugestedMimeType(delegate);
+ }
-// IInternetBindInfoEx
-STDMETHODIMP ProtocolSinkWrap::GetBindInfo(DWORD* flags,
- BINDINFO* bind_info_ret) {
- ScopedComPtr<IInternetBindInfo> bind_info;
- HRESULT hr = bind_info.QueryFrom(delegate_);
- if (bind_info)
- hr = bind_info->GetBindInfo(flags, bind_info_ret);
- return hr;
-}
+ // This is the first data notification we forward.
+ flags |= BSCF_FIRSTDATANOTIFICATION;
-STDMETHODIMP ProtocolSinkWrap::GetBindString(ULONG string_type,
- LPOLESTR* string_array, ULONG array_size, ULONG* size_returned) {
- ScopedComPtr<IInternetBindInfo> bind_info;
- HRESULT hr = bind_info.QueryFrom(delegate_);
- if (bind_info)
- hr = bind_info->GetBindString(string_type, string_array,
- array_size, size_returned);
- return hr;
-}
+ if (hr == S_FALSE) {
+ flags |= (BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE);
+ }
-STDMETHODIMP ProtocolSinkWrap::GetBindInfoEx(DWORD* flags, BINDINFO* bind_info,
- DWORD* bindf2, DWORD* reserved) {
- ScopedComPtr<IInternetBindInfoEx> bind_info_ex;
- HRESULT hr = bind_info_ex.QueryFrom(delegate_);
- if (bind_info_ex)
- hr = bind_info_ex->GetBindInfoEx(flags, bind_info, bindf2, reserved);
- return hr;
+ return delegate->ReportData(flags, progress, max_progress);
}
-// IServiceProvider
-STDMETHODIMP ProtocolSinkWrap::QueryService(REFGUID service_guid,
- REFIID riid, void** service) {
- ScopedComPtr<IServiceProvider> service_provider;
- HRESULT hr = service_provider.QueryFrom(delegate_);
- if (service_provider)
- hr = service_provider->QueryService(service_guid, riid, service);
- return hr;
+void ProtData::UpdateUrl(const wchar_t* url) {
+ url_ = url;
}
-// IAuthenticate
-STDMETHODIMP ProtocolSinkWrap::Authenticate(HWND* window,
- LPWSTR* user_name, LPWSTR* password) {
- ScopedComPtr<IAuthenticate> authenticate;
- HRESULT hr = authenticate.QueryFrom(delegate_);
- if (authenticate)
- hr = authenticate->Authenticate(window, user_name, password);
- return hr;
-}
+// S_FALSE - EOF
+// S_OK - buffer fully filled
+// E_PENDING - some data added to buffer, but buffer is not yet full
+// E_XXXX - some other error.
+HRESULT ProtData::FillBuffer() {
+ HRESULT hr_read = S_OK;
-// IInternetProtocolEx
-STDMETHODIMP ProtocolSinkWrap::Start(LPCWSTR url,
- IInternetProtocolSink *protocol_sink, IInternetBindInfo* bind_info,
- DWORD flags, HANDLE_PTR reserved) {
- ScopedComPtr<IInternetProtocolRoot> protocol;
- HRESULT hr = protocol.QueryFrom(delegate_);
- if (protocol)
- hr = protocol->Start(url, protocol_sink, bind_info, flags, reserved);
- return hr;
-}
+ while ((hr_read == S_OK) && (buffer_size_ < kMaxContentSniffLength)) {
+ ULONG size_read = 0;
+ hr_read = read_fun_(protocol_, buffer_ + buffer_size_,
+ kMaxContentSniffLength - buffer_size_, &size_read);
+ buffer_size_ += size_read;
+ }
-STDMETHODIMP ProtocolSinkWrap::Continue(PROTOCOLDATA* protocol_data) {
- ScopedComPtr<IInternetProtocolRoot> protocol;
- HRESULT hr = protocol.QueryFrom(delegate_);
- if (protocol)
- hr = protocol->Continue(protocol_data);
- return hr;
+ return hr_read;
}
-STDMETHODIMP ProtocolSinkWrap::Abort(HRESULT reason, DWORD options) {
- ScopedComPtr<IInternetProtocolRoot> protocol;
- HRESULT hr = protocol.QueryFrom(delegate_);
- if (protocol)
- hr = protocol->Abort(reason, options);
- return hr;
+void ProtData::SaveSuggestedMimeType(LPCWSTR status_text) {
+ has_suggested_mime_type_ = true;
+ suggested_mime_type_.Allocate(status_text);
}
-STDMETHODIMP ProtocolSinkWrap::Terminate(DWORD options) {
- ScopedComPtr<IInternetProtocolRoot> protocol;
- HRESULT hr = protocol.QueryFrom(delegate_);
- if (protocol)
- hr = protocol->Terminate(options);
- return hr;
-}
+void ProtData::FireSugestedMimeType(IInternetProtocolSink* delegate) {
+ if (has_server_mime_type_) {
+ DLOG(INFO) << "Forwarding BINDSTATUS_SERVER_MIMETYPEAVAILABLE "
+ << suggested_mime_type_;
+ delegate->ReportProgress(BINDSTATUS_SERVER_MIMETYPEAVAILABLE,
+ suggested_mime_type_);
+ return;
+ }
-STDMETHODIMP ProtocolSinkWrap::Suspend() {
- ScopedComPtr<IInternetProtocolRoot> protocol;
- HRESULT hr = protocol.QueryFrom(delegate_);
- if (protocol)
- hr = protocol->Suspend();
- return hr;
+ if (has_suggested_mime_type_) {
+ DLOG(INFO) << "Forwarding BINDSTATUS_MIMETYPEAVAILABLE "
+ << suggested_mime_type_;
+ delegate->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE,
+ suggested_mime_type_);
+ }
}
-STDMETHODIMP ProtocolSinkWrap::Resume() {
- ScopedComPtr<IInternetProtocolRoot> protocol;
- HRESULT hr = protocol.QueryFrom(delegate_);
- if (protocol)
- hr = protocol->Resume();
- return hr;
+scoped_refptr<ProtData> ProtData::DataFromProtocol(
+ IInternetProtocol* protocol) {
+ scoped_refptr<ProtData> instance;
+ AutoLock lock(datamap_lock_);
+ ProtocolDataMap::iterator it = datamap_.find(protocol);
+ if (datamap_.end() != it)
+ instance = it->second;
+ return instance;
}
-STDMETHODIMP ProtocolSinkWrap::Read(void *buffer, ULONG size,
- ULONG* size_read) {
- ScopedComPtr<IInternetProtocol> protocol;
- HRESULT hr = protocol.QueryFrom(delegate_);
- if (protocol)
- hr = protocol->Read(buffer, size, size_read);
- return hr;
-}
+// IInternetProtocol/Ex hooks.
+STDMETHODIMP Hook_Start(InternetProtocol_Start_Fn orig_start,
+ IInternetProtocol* protocol, LPCWSTR url, IInternetProtocolSink* prot_sink,
+ IInternetBindInfo* bind_info, DWORD flags, HANDLE_PTR reserved) {
+ DCHECK(orig_start);
+ if (!url || !prot_sink || !bind_info)
+ return E_INVALIDARG;
+ DLOG_IF(INFO, url != NULL) << "OnStart: " << url << PiFlags2Str(flags);
+
+ ScopedComPtr<IBindCtx> bind_ctx = BindCtxFromIBindInfo(bind_info);
+ if (!bind_ctx) {
+ // MSHTML sometimes takes a short path, skips the creation of
+ // moniker and binding, by directly grabbing protocol from InternetSession
+ DLOG(INFO) << "DirectBind for " << url;
+ return orig_start(protocol, url, prot_sink, bind_info, flags, reserved);
+ }
-STDMETHODIMP ProtocolSinkWrap::Seek(LARGE_INTEGER move, DWORD origin,
- ULARGE_INTEGER* new_pos) {
- ScopedComPtr<IInternetProtocol> protocol;
- HRESULT hr = protocol.QueryFrom(delegate_);
- if (protocol)
- hr = protocol->Seek(move, origin, new_pos);
- return hr;
-}
+ if (IsCFRequest(bind_ctx)) {
+ return orig_start(protocol, url, prot_sink, bind_info, flags, reserved);
+ }
-STDMETHODIMP ProtocolSinkWrap::LockRequest(DWORD options) {
- ScopedComPtr<IInternetProtocol> protocol;
- HRESULT hr = protocol.QueryFrom(delegate_);
- if (protocol)
- hr = protocol->LockRequest(options);
- return hr;
-}
+ scoped_refptr<ProtData> prot_data = ProtData::DataFromProtocol(protocol);
+ if (prot_data) {
+ DLOG(INFO) << "Found existing ProtData!";
+ prot_data->UpdateUrl(url);
+ ScopedComPtr<IInternetProtocolSink> new_sink =
+ ProtocolSinkWrap::CreateNewSink(prot_sink, prot_data);
+ return orig_start(protocol, url, new_sink, bind_info, flags, reserved);
+ }
-STDMETHODIMP ProtocolSinkWrap::UnlockRequest() {
- ScopedComPtr<IInternetProtocol> protocol;
- HRESULT hr = protocol.QueryFrom(delegate_);
- if (protocol)
- hr = protocol->UnlockRequest();
- return hr;
-}
+ if (!ShouldWrapSink(prot_sink, url)) {
+ return orig_start(protocol, url, prot_sink, bind_info, flags, reserved);
+ }
-STDMETHODIMP ProtocolSinkWrap::StartEx(IUri* uri,
- IInternetProtocolSink* protocol_sink, IInternetBindInfo* bind_info,
- DWORD flags, HANDLE_PTR reserved) {
- ScopedComPtr<IInternetProtocolEx> protocol;
- HRESULT hr = protocol.QueryFrom(delegate_);
- if (protocol)
- hr = protocol->StartEx(uri, protocol_sink, bind_info, flags, reserved);
- return hr;
-}
+ // Fresh request.
+ InternetProtocol_Read_Fn read_fun = reinterpret_cast<InternetProtocol_Read_Fn>
+ (CTransaction_PatchInfo[1].stub_->argument());
+ prot_data = new ProtData(protocol, read_fun, url);
+ PutProtData(bind_ctx, prot_data);
-// IInternetPriority
-STDMETHODIMP ProtocolSinkWrap::SetPriority(LONG priority) {
- ScopedComPtr<IInternetPriority> internet_priority;
- HRESULT hr = internet_priority.QueryFrom(delegate_);
- if (internet_priority)
- hr = internet_priority->SetPriority(priority);
- return hr;
+ ScopedComPtr<IInternetProtocolSink> new_sink =
+ ProtocolSinkWrap::CreateNewSink(prot_sink, prot_data);
+ return orig_start(protocol, url, new_sink, bind_info, flags, reserved);
}
-STDMETHODIMP ProtocolSinkWrap::GetPriority(LONG* priority) {
- ScopedComPtr<IInternetPriority> internet_priority;
- HRESULT hr = internet_priority.QueryFrom(delegate_);
- if (internet_priority)
- hr = internet_priority->GetPriority(priority);
- return hr;
-}
+STDMETHODIMP Hook_StartEx(InternetProtocol_StartEx_Fn orig_start_ex,
+ IInternetProtocolEx* protocol, IUri* uri, IInternetProtocolSink* prot_sink,
+ IInternetBindInfo* bind_info, DWORD flags, HANDLE_PTR reserved) {
+ DCHECK(orig_start_ex);
+ if (!uri || !prot_sink || !bind_info)
+ return E_INVALIDARG;
-// IWrappedProtocol
-STDMETHODIMP ProtocolSinkWrap::GetWrapperCode(LONG *code, DWORD_PTR reserved) {
- ScopedComPtr<IWrappedProtocol> wrapped_protocol;
- HRESULT hr = wrapped_protocol.QueryFrom(delegate_);
- if (wrapped_protocol)
- hr = wrapped_protocol->GetWrapperCode(code, reserved);
- return hr;
+ ScopedBstr url;
+ uri->GetPropertyBSTR(Uri_PROPERTY_ABSOLUTE_URI, url.Receive(), 0);
+ DLOG_IF(INFO, url != NULL) << "OnStartEx: " << url << PiFlags2Str(flags);
+
+ ScopedComPtr<IBindCtx> bind_ctx = BindCtxFromIBindInfo(bind_info);
+ if (!bind_ctx) {
+ // MSHTML sometimes takes a short path, skips the creation of
+ // moniker and binding, by directly grabbing protocol from InternetSession.
+ DLOG(INFO) << "DirectBind for " << url;
+ return orig_start_ex(protocol, uri, prot_sink, bind_info, flags, reserved);
+ }
+
+ if (IsCFRequest(bind_ctx)) {
+ return orig_start_ex(protocol, uri, prot_sink, bind_info, flags, reserved);
+ }
+
+ scoped_refptr<ProtData> prot_data = ProtData::DataFromProtocol(protocol);
+ if (prot_data) {
+ DLOG(INFO) << "Found existing ProtData!";
+ prot_data->UpdateUrl(url);
+ ScopedComPtr<IInternetProtocolSink> new_sink =
+ ProtocolSinkWrap::CreateNewSink(prot_sink, prot_data);
+ return orig_start_ex(protocol, uri, new_sink, bind_info, flags, reserved);
+ }
+
+ if (!ShouldWrapSink(prot_sink, url)) {
+ return orig_start_ex(protocol, uri, prot_sink, bind_info, flags, reserved);
+ }
+
+ // Fresh request.
+ InternetProtocol_Read_Fn read_fun = reinterpret_cast<InternetProtocol_Read_Fn>
+ (CTransaction_PatchInfo[1].stub_->argument());
+ prot_data = new ProtData(protocol, read_fun, url);
+ PutProtData(bind_ctx, prot_data);
+
+ ScopedComPtr<IInternetProtocolSink> new_sink =
+ ProtocolSinkWrap::CreateNewSink(prot_sink, prot_data);
+ return orig_start_ex(protocol, uri, new_sink, bind_info, flags, reserved);
}
+STDMETHODIMP Hook_Read(InternetProtocol_Read_Fn orig_read,
+ IInternetProtocol* protocol, void* buffer, ULONG size, ULONG* size_read) {
+ DCHECK(orig_read);
+ scoped_refptr<ProtData> prot_data = ProtData::DataFromProtocol(protocol);
+ if (!prot_data) {
+ return orig_read(protocol, buffer, size, size_read);
+ }
-// public IUriContainer
-STDMETHODIMP ProtocolSinkWrap::GetIUri(IUri** uri) {
- ScopedComPtr<IUriContainer> uri_container;
- HRESULT hr = uri_container.QueryFrom(delegate_);
- if (uri_container)
- hr = uri_container->GetIUri(uri);
+ HRESULT hr = prot_data->Read(buffer, size, size_read);
return hr;
}
-// Protected helpers
-
-void ProtocolSinkWrap::DetermineRendererType() {
- if (is_undetermined()) {
- if (IsOptInUrl(url_.c_str())) {
- renderer_type_ = CHROME;
- } else {
- std::wstring xua_compat_content;
- // 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.
- DCHECK(buffer_size_ < arraysize(buffer_));
- buffer_[buffer_size_] = 0;
- std::wstring html_contents;
- // TODO(joshia): detect and handle different content encodings
- UTF8ToWide(buffer_, buffer_size_, &html_contents);
- UtilGetXUACompatContentValue(html_contents, &xua_compat_content);
- if (StrStrI(xua_compat_content.c_str(), kChromeContentPrefix)) {
- renderer_type_ = CHROME;
- } else {
- renderer_type_ = OTHER;
- }
- }
+// Patching / Hooking code.
+class FakeProtocol : public CComObjectRootEx<CComSingleThreadModel>,
+ public IInternetProtocol {
+ public:
+ BEGIN_COM_MAP(FakeProtocol)
+ COM_INTERFACE_ENTRY(IInternetProtocol)
+ COM_INTERFACE_ENTRY(IInternetProtocolRoot)
+ END_COM_MAP()
+
+ STDMETHOD(Start)(LPCWSTR url, IInternetProtocolSink *protocol_sink,
+ IInternetBindInfo* bind_info, DWORD flags, HANDLE_PTR reserved) {
+ transaction_.QueryFrom(protocol_sink);
+ // Return some unusual error code.
+ return INET_E_INVALID_CERTIFICATE;
}
-}
-HRESULT ProtocolSinkWrap::CheckAndReportChromeMimeTypeForRequest() {
- if (!is_undetermined())
- return S_OK;
+ STDMETHOD(Continue)(PROTOCOLDATA* protocol_data) { return S_OK; }
+ STDMETHOD(Abort)(HRESULT reason, DWORD options) { return S_OK; }
+ STDMETHOD(Terminate)(DWORD options) { return S_OK; }
+ STDMETHOD(Suspend)() { return S_OK; }
+ STDMETHOD(Resume)() { return S_OK; }
+ STDMETHOD(Read)(void *buffer, ULONG size, ULONG* size_read) { return S_OK; }
+ STDMETHOD(Seek)(LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER* new_pos)
+ { return S_OK; }
+ STDMETHOD(LockRequest)(DWORD options) { return S_OK; }
+ STDMETHOD(UnlockRequest)() { return S_OK; }
+
+ ScopedComPtr<IInternetProtocol> transaction_;
+};
+
+struct FakeFactory : public IClassFactory,
+ public CComObjectRootEx<CComSingleThreadModel> {
+ BEGIN_COM_MAP(FakeFactory)
+ COM_INTERFACE_ENTRY(IClassFactory)
+ END_COM_MAP()
+
+ STDMETHOD(CreateInstance)(IUnknown *pUnkOuter, REFIID riid, void **ppvObj) {
+ if (pUnkOuter)
+ return CLASS_E_NOAGGREGATION;
+ HRESULT hr = obj_->QueryInterface(riid, ppvObj);
+ return hr;
+ }
- // This function could get invoked recursively in the context of
- // IInternetProtocol::Read. Check for the same and bail.
- if (determining_renderer_type_)
+ STDMETHOD(LockServer)(BOOL fLock) {
return S_OK;
+ }
- determining_renderer_type_ = true;
+ IUnknown* obj_;
+};
- HRESULT hr_read = S_OK;
- while (hr_read == S_OK) {
- ULONG size_read = 0;
- hr_read = protocol_->Read(buffer_ + buffer_size_,
- kMaxContentSniffLength - buffer_size_, &size_read);
- buffer_size_ += size_read;
+static void HookTransactionVtable(IInternetProtocol* p) {
+ ScopedComPtr<IInternetProtocolEx> ex;
+ ex.QueryFrom(p);
- // Attempt to determine the renderer type if we have received
- // sufficient data. Do not attempt this when we are called recursively.
- if (report_data_recursiveness_ < 2 && (S_FALSE == hr_read) ||
- (buffer_size_ >= kMaxContentSniffLength)) {
- DetermineRendererType();
- if (renderer_type() == CHROME) {
- // Workaround for IE 8 and "nosniff". See:
- // http://blogs.msdn.com/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx
- delegate_->ReportProgress(
- BINDSTATUS_SERVER_MIMETYPEAVAILABLE, kChromeMimeType);
- // For IE < 8.
- delegate_->ReportProgress(
- BINDSTATUS_MIMETYPEAVAILABLE, kChromeMimeType);
-
- delegate_->ReportProgress(
- BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE, kChromeMimeType);
-
- delegate_->ReportData(
- BSCF_FIRSTDATANOTIFICATION, 0, 0);
-
- delegate_->ReportData(
- BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE, 0, 0);
- }
- break;
- }
+ HRESULT hr = vtable_patch::PatchInterfaceMethods(p, CTransaction_PatchInfo);
+ if (hr == S_OK && ex) {
+ vtable_patch::PatchInterfaceMethods(ex.get(), CTransaction2_PatchInfo);
}
-
- determining_renderer_type_ = false;
- return hr_read;
}
-HRESULT ProtocolSinkWrap::OnReadImpl(void* buffer, ULONG size, ULONG* size_read,
- InternetProtocol_Read_Fn orig_read) {
- // We want to switch the renderer to chrome, we cannot return any
- // data now.
- if (CHROME == renderer_type())
- return S_FALSE;
-
- // Serve data from our buffer first.
- if (OTHER == renderer_type()) {
- const ULONG bytes_to_copy = std::min(buffer_size_ - buffer_pos_, size);
- if (bytes_to_copy) {
- memcpy(buffer, buffer_ + buffer_pos_, bytes_to_copy);
- *size_read = bytes_to_copy;
- buffer_pos_ += bytes_to_copy;
- return S_OK;
- }
+void TransactionHooks::InstallHooks() {
+ if (IS_PATCHED(CTransaction)) {
+ DLOG(WARNING) << __FUNCTION__ << " called more than once.";
+ return;
}
- return orig_read(protocol_, buffer, size, size_read);
-}
-
-scoped_refptr<ProtocolSinkWrap> ProtocolSinkWrap::InstanceFromProtocol(
- IInternetProtocol* protocol) {
- CComCritSecLock<CComAutoCriticalSection> lock(sink_map_lock_);
- scoped_refptr<ProtocolSinkWrap> instance;
- ProtocolSinkMap::iterator it = sink_map_.find(protocol);
- if (sink_map_.end() != it)
- instance = it->second;
- return instance;
-}
+ CComObjectStackEx<FakeProtocol> prot;
+ CComObjectStackEx<FakeFactory> factory;
+ factory.obj_ = &prot;
+ ScopedComPtr<IInternetSession> session;
+ HRESULT hr = ::CoInternetGetSession(0, session.Receive(), 0);
+ hr = session->RegisterNameSpace(&factory, CLSID_NULL, L"611", 0, 0, 0);
+ DLOG_IF(FATAL, FAILED(hr)) << "Failed to register namespace";
+ if (hr != S_OK)
+ return;
+
+ do {
+ ScopedComPtr<IMoniker> mk;
+ ScopedComPtr<IBindCtx> bc;
+ ScopedComPtr<IStream> stream;
+ hr = ::CreateAsyncBindCtxEx(0, 0, 0, 0, bc.Receive(), 0);
+ DLOG_IF(FATAL, FAILED(hr)) << "CreateAsyncBindCtxEx failed " << hr;
+ if (hr != S_OK)
+ break;
-ScopedComPtr<IInternetProtocolSink> ProtocolSinkWrap::MaybeWrapSink(
- IInternetProtocol* protocol, IInternetProtocolSink* prot_sink,
- const wchar_t* url) {
- ScopedComPtr<IInternetProtocolSink> sink_to_use(prot_sink);
+ hr = ::CreateURLMoniker(NULL, L"611://512", mk.Receive());
+ DLOG_IF(FATAL, FAILED(hr)) << "CreateURLMoniker failed " << hr;
+ if (hr != S_OK)
+ break;
- // FYI: GUID_NULL doesn't work when the URL is being loaded from history.
- // asking for IID_IHttpNegotiate as the service id works, but
- // getting the IWebBrowser2 interface still doesn't work.
- ScopedComPtr<IHttpNegotiate> http_negotiate;
- HRESULT hr = DoQueryService(GUID_NULL, prot_sink, http_negotiate.Receive());
-
- if (http_negotiate && !IsSubFrameRequest(http_negotiate)) {
- CComObject<ProtocolSinkWrap>* wrap = NULL;
- CComObject<ProtocolSinkWrap>::CreateInstance(&wrap);
- DCHECK(wrap);
- if (wrap) {
- wrap->AddRef();
- if (wrap->Initialize(protocol, prot_sink, url)) {
- sink_to_use = wrap;
- }
- wrap->Release();
- }
+ hr = mk->BindToStorage(bc, NULL, IID_IStream,
+ reinterpret_cast<void**>(stream.Receive()));
+ DLOG_IF(FATAL, hr != INET_E_INVALID_CERTIFICATE) <<
+ "BindToStorage failed " << hr;
+ } while (0);
+
+ hr = session->UnregisterNameSpace(&factory, L"611");
+ if (prot.transaction_) {
+ HookTransactionVtable(prot.transaction_);
+ // Explicit release, otherwise ~CComObjectStackEx will complain about
+ // outstanding reference to us, because it runs before ~FakeProtocol
+ prot.transaction_.Release();
}
+}
- return sink_to_use;
+void TransactionHooks::RevertHooks() {
+ vtable_patch::UnpatchInterfaceMethods(CTransaction_PatchInfo);
+ vtable_patch::UnpatchInterfaceMethods(CTransaction2_PatchInfo);
}
diff --git a/chrome_frame/protocol_sink_wrap.h b/chrome_frame/protocol_sink_wrap.h
index 53812ba..2b8a08d0 100644
--- a/chrome_frame/protocol_sink_wrap.h
+++ b/chrome_frame/protocol_sink_wrap.h
@@ -16,6 +16,7 @@
#include "base/basictypes.h"
#include "base/ref_counted.h"
#include "base/scoped_comptr_win.h"
+#include "base/scoped_bstr_win.h"
#include "googleurl/src/gurl.h"
#include "chrome_frame/chrome_frame_delegate.h"
#include "chrome_frame/ie8_types.h"
@@ -37,6 +38,15 @@ typedef HRESULT (STDMETHODCALLTYPE* InternetProtocol_StartEx_Fn)(
typedef HRESULT (STDMETHODCALLTYPE* InternetProtocolRoot_Continue_Fn)(
IInternetProtocolRoot* me, PROTOCOLDATA* data);
+
+enum RendererType {
+ UNDETERMINED,
+ CHROME,
+ OTHER
+};
+
+class ProtData;
+
// A class to wrap protocol sink in IInternetProtocol::Start[Ex] for
// HTTP and HTTPS protocols.
//
@@ -50,199 +60,101 @@ typedef HRESULT (STDMETHODCALLTYPE* InternetProtocolRoot_Continue_Fn)(
// but delegate simply the QI.
class ProtocolSinkWrap
: public CComObjectRootEx<CComMultiThreadModel>,
- public IInternetProtocolSink,
- public IInternetBindInfoEx,
- public IServiceProvider,
- public IAuthenticate,
- public IInternetProtocolEx,
- public IInternetPriority,
- public IWrappedProtocol,
- // public IPreBindingSupport, // undocumented
- // public ITransProtocolSink, // Undocumented
- // public ITransactionInternal, // undocumented
- public IUriContainer {
+ public IInternetProtocolSink {
public:
BEGIN_COM_MAP(ProtocolSinkWrap)
COM_INTERFACE_ENTRY(IInternetProtocolSink)
- COM_INTERFACE_ENTRY(IInternetBindInfo)
- COM_INTERFACE_ENTRY(IInternetBindInfoEx)
- COM_INTERFACE_ENTRY(IServiceProvider)
- COM_INTERFACE_ENTRY(IAuthenticate)
- COM_INTERFACE_ENTRY(IInternetProtocolRoot)
- COM_INTERFACE_ENTRY(IInternetProtocol)
- COM_INTERFACE_ENTRY(IInternetProtocolEx)
- COM_INTERFACE_ENTRY(IInternetPriority)
- COM_INTERFACE_ENTRY(IWrappedProtocol)
- COM_INTERFACE_ENTRY_IF_DELEGATE_SUPPORTS(IUriContainer)
COM_INTERFACE_BLIND_DELEGATE()
END_COM_MAP()
- ProtocolSinkWrap();
- virtual ~ProtocolSinkWrap();
-
- bool Initialize(IInternetProtocol* protocol,
- IInternetProtocolSink* original_sink, const wchar_t* url);
-
- // VTable patches the IInternetProtocol and IIntenetProtocolEx interface.
- // Returns true on success.
- static bool PatchProtocolHandlers();
-
- // Unpatches the IInternetProtocol and IInternetProtocolEx interfaces.
- static void UnpatchProtocolHandlers();
+ static ScopedComPtr<IInternetProtocolSink> CreateNewSink(
+ IInternetProtocolSink* sink, ProtData* prot_data);
- // IInternetProtocol/Ex patches.
- static STDMETHODIMP OnStart(InternetProtocol_Start_Fn orig_start,
- IInternetProtocol* protocol, LPCWSTR url,
- IInternetProtocolSink* prot_sink, IInternetBindInfo* bind_info,
- DWORD flags, HANDLE_PTR reserved);
-
- static STDMETHODIMP OnStartEx(
- InternetProtocol_StartEx_Fn orig_start_ex, IInternetProtocolEx* protocol,
- IUri* uri, IInternetProtocolSink* prot_sink,
- IInternetBindInfo* bind_info, DWORD flags, HANDLE_PTR reserved);
+ // Apparently this has to be public, to satisfy COM_INTERFACE_BLIND_DELEGATE
+ IInternetProtocolSink* delegate() {
+ return delegate_;
+ }
- static STDMETHODIMP OnRead(InternetProtocol_Read_Fn orig_read,
- IInternetProtocol* protocol, void* buffer, ULONG size, ULONG* size_read);
+ protected:
+ ProtocolSinkWrap();
+ ~ProtocolSinkWrap();
+ private:
// IInternetProtocolSink methods
STDMETHOD(Switch)(PROTOCOLDATA* protocol_data);
STDMETHOD(ReportProgress)(ULONG status_code, LPCWSTR status_text);
STDMETHOD(ReportData)(DWORD flags, ULONG progress, ULONG max_progress);
STDMETHOD(ReportResult)(HRESULT result, DWORD error, LPCWSTR result_text);
- // IInternetBindInfoEx
- STDMETHOD(GetBindInfo)(DWORD* flags, BINDINFO* bind_info);
- STDMETHOD(GetBindString)(ULONG string_type, LPOLESTR* string_array,
- ULONG array_size, ULONG* size_returned);
- STDMETHOD(GetBindInfoEx)(DWORD *flags, BINDINFO* bind_info,
- DWORD* bindf2, DWORD *reserved);
-
- // IServiceProvider
- STDMETHOD(QueryService)(REFGUID service_guid, REFIID riid, void** service);
-
- // IAuthenticate
- STDMETHOD(Authenticate)(HWND* window, LPWSTR* user_name, LPWSTR* password);
-
- // IInternetProtocolEx
- STDMETHOD(Start)(LPCWSTR url, IInternetProtocolSink *protocol_sink,
- IInternetBindInfo* bind_info, DWORD flags, HANDLE_PTR reserved);
- STDMETHOD(Continue)(PROTOCOLDATA* protocol_data);
- STDMETHOD(Abort)(HRESULT reason, DWORD options);
- STDMETHOD(Terminate)(DWORD options);
- STDMETHOD(Suspend)();
- STDMETHOD(Resume)();
- STDMETHOD(Read)(void *buffer, ULONG size, ULONG* size_read);
- STDMETHOD(Seek)(LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER* new_pos);
- STDMETHOD(LockRequest)(DWORD options);
- STDMETHOD(UnlockRequest)();
- STDMETHOD(StartEx)(IUri* uri, IInternetProtocolSink* protocol_sink,
- IInternetBindInfo* bind_info, DWORD flags, HANDLE_PTR reserved);
-
- // IInternetPriority
- STDMETHOD(SetPriority)(LONG priority);
- STDMETHOD(GetPriority)(LONG* priority);
-
- // IWrappedProtocol
- STDMETHOD(GetWrapperCode)(LONG *code, DWORD_PTR reserved);
-
- // public IUriContainer
- STDMETHOD(GetIUri)(IUri** uri);
-
- // IPreBindingSupport, // undocumented
- // ITransProtocolSink, // Undocumented
- // ITransactionInternal, // undocumented
-
- IInternetProtocolSink* delegate() const {
- return delegate_;
- }
+ // Remember original sink
+ ScopedComPtr<IInternetProtocolSink> delegate_;
+ scoped_refptr<ProtData> prot_data_;
+ DISALLOW_COPY_AND_ASSIGN(ProtocolSinkWrap);
+};
- protected:
- enum RendererType {
- UNDETERMINED,
- CHROME,
- OTHER
- };
-
- typedef std::map<IInternetProtocol*, ProtocolSinkWrap*> ProtocolSinkMap;
- static const int kMaxContentSniffLength = 1024;
-
- static scoped_refptr<ProtocolSinkWrap> InstanceFromProtocol(
- IInternetProtocol* protocol);
- static ScopedComPtr<IInternetProtocolSink> MaybeWrapSink(
- IInternetProtocol* protocol, IInternetProtocolSink* prot_sink,
- const wchar_t* url);
-
- void DetermineRendererType();
-
- HRESULT OnReadImpl(void* buffer, ULONG size, ULONG* size_read,
- InternetProtocol_Read_Fn orig_read);
-
- // This function determines whether the current request should be handled
- // by Chrome. If yes it reports the mime type as application/chromepage,
- // which ensures that the ChromeFrame is instantiated for handling this
- // request.
- // Returns S_OK on success.
- HRESULT CheckAndReportChromeMimeTypeForRequest();
-
- bool is_undetermined() const {
- return (UNDETERMINED == renderer_type_);
- }
- RendererType renderer_type() const {
+class ProtData : public base::RefCounted<ProtData> {
+ public:
+ ProtData(IInternetProtocol* protocol, InternetProtocol_Read_Fn read_fun,
+ const wchar_t* url);
+ ~ProtData();
+ HRESULT Read(void* buffer, ULONG size, ULONG* size_read);
+ HRESULT ReportProgress(IInternetProtocolSink* delegate,
+ ULONG status_code,
+ LPCWSTR status_text);
+ HRESULT ReportData(IInternetProtocolSink* delegate,
+ DWORD flags, ULONG progress, ULONG max_progress);
+ HRESULT ReportResult(IInternetProtocolSink* delegate, HRESULT result,
+ DWORD error, LPCWSTR result_text);
+ void UpdateUrl(const wchar_t* url);
+ static scoped_refptr<ProtData> DataFromProtocol(IInternetProtocol* protocol);
+
+ RendererType renderer_type() {
return renderer_type_;
}
- // Creates an instance of the specified protocol handler and returns the
- // IInternetProtocol interface pointer.
- // Returns S_OK on success.
- static HRESULT CreateProtocolHandlerInstance(const CLSID& clsid,
- IInternetProtocol** protocol);
-
- // Helper function for patching the VTable of the IInternetProtocol
- // interface. It instantiates the object identified by the protocol_clsid
- // parameter and patches its VTable.
- // Returns S_OK on success.
- static HRESULT PatchProtocolMethods(
- const CLSID& protocol_clsid,
- vtable_patch::MethodPatchInfo* protocol_patch_info,
- vtable_patch::MethodPatchInfo* protocol_ex_patch_info);
-
- // WARNING: Don't use GURL variables here. Please see
- // http://b/issue?id=2102171 for details.
-
- // Remember original sink
- ScopedComPtr<IInternetProtocolSink> delegate_;
+ private:
+ typedef std::map<IInternetProtocol*, ProtData*> ProtocolDataMap;
+ static ProtocolDataMap datamap_;
+ static Lock datamap_lock_;
- // Cannot take a reference on the protocol.
+ // Url we are retrieving. Used for IsOptInUrl() only.
+ std::wstring url_;
+ // Our gate to IInternetProtocol::Read()
IInternetProtocol* protocol_;
+ InternetProtocol_Read_Fn read_fun_;
+
+ // What BINDSTATUS_MIMETYPEAVAILABLE and Co. tells us.
+ ScopedBstr suggested_mime_type_;
+ // At least one of the following has been received:
+ // BINDSTATUS_MIMETYPEAVAILABLE,
+ // MIMESTATUS_VERIFIEDMIMETYPEAVAILABLE
+ // BINDSTATUS_SERVER_MIMETYPEAVAILABLE
+ bool has_suggested_mime_type_;
+ // BINDSTATUS_SERVER_MIMETYPEAVAILABLE received, so we shall fire one.
+ bool has_server_mime_type_;
+
+ // Did we received ReportData()
+ bool report_data_received_;
RendererType renderer_type_;
// Buffer for accumulated data including 1 extra for NULL-terminator
+ static const size_t kMaxContentSniffLength = 2 * 1024;
char buffer_[kMaxContentSniffLength + 1];
unsigned long buffer_size_; // NOLINT
unsigned long buffer_pos_; // NOLINT
- // Accumulated result
- bool is_saved_result_;
- HRESULT result_code_;
- DWORD result_error_;
- std::wstring result_text_;
- // For tracking re-entrency and preventing duplicate Read()s from
- // distorting the outcome of ReportData.
- int report_data_recursiveness_;
-
- static ProtocolSinkMap sink_map_;
- // TODO(joshia): Replace with Lock
- static CComAutoCriticalSection sink_map_lock_;
-
- std::wstring url_;
-
- // Set to true if we are in the context of determining the desired renderer
- // type.
- bool determining_renderer_type_;
+ HRESULT FillBuffer();
+ void SaveSuggestedMimeType(LPCWSTR status_text);
+ void FireSugestedMimeType(IInternetProtocolSink* delegate);
+};
- private:
- DISALLOW_COPY_AND_ASSIGN(ProtocolSinkWrap);
+struct TransactionHooks {
+ void InstallHooks();
+ void RevertHooks();
};
+DECLSPEC_SELECTANY struct TransactionHooks g_trans_hooks;
+
#endif // CHROME_FRAME_PROTOCOL_SINK_WRAP_H_
+
diff --git a/chrome_frame/test/test_mock_with_web_server.cc b/chrome_frame/test/test_mock_with_web_server.cc
index ffc2f9e..f0c59b5 100644
--- a/chrome_frame/test/test_mock_with_web_server.cc
+++ b/chrome_frame/test/test_mock_with_web_server.cc
@@ -1285,8 +1285,8 @@ TEST_F(ChromeFrameTestWithWebServer,
}
TEST(IEPrivacy, NavigationToRestrictedSite) {
- if (!MonikerPatchEnabled()) {
- LOG(ERROR) << "Not running test. Moniker patch not enabled.";
+ if (IsIBrowserServicePatchEnabled()) {
+ LOG(ERROR) << "Not running test. IBrowserServicePatch is in place.";
return;
}
CloseIeAtEndOfScope last_resort_close_ie;
@@ -1340,8 +1340,8 @@ TEST(IEPrivacy, NavigationToRestrictedSite) {
// See bug 36694 for details. http://crbug.com/36694
TEST_F(ChromeFrameTestWithWebServer,
DISABLED_FullTabModeIE_TestDownloadFromForm) {
- if (!MonikerPatchEnabled()) {
- LOG(ERROR) << "Not running test. Moniker patch not enabled.";
+ if (IsIBrowserServicePatchEnabled()) {
+ LOG(ERROR) << "Not running test. IBrowserServicePatch is in place.";
return;
}
@@ -1488,8 +1488,8 @@ TEST_F(ChromeFrameTestWithWebServer,
// to ChromeFrame correctly.
TEST_F(ChromeFrameTestWithWebServer,
FLAKY_FullTabModeIE_AltD_AnchorUrlNavigate) {
- if (!MonikerPatchEnabled()) {
- LOG(ERROR) << "Not running test. Moniker patch not enabled.";
+ if (IsIBrowserServicePatchEnabled()) {
+ LOG(ERROR) << "Not running test. IBrowserServicePatch is in place.";
return;
}
diff --git a/chrome_frame/test/test_with_web_server.cc b/chrome_frame/test/test_with_web_server.cc
index 9486135..003c179 100644
--- a/chrome_frame/test/test_with_web_server.cc
+++ b/chrome_frame/test/test_with_web_server.cc
@@ -800,8 +800,8 @@ const wchar_t kAnchorUrlNavigate[] =
// http://code.google.com/p/chromium/issues/detail?id=35341
TEST_F(ChromeFrameTestWithWebServer,
FLAKY_FullTabModeIE_AnchorUrlNavigateTest) {
- if (!MonikerPatchEnabled()) {
- LOG(ERROR) << "Not running test. Moniker patch not enabled.";
+ if (IsIBrowserServicePatchEnabled()) {
+ LOG(ERROR) << "Not running test. IBrowserServicePatch is in place.";
return;
}
@@ -817,8 +817,8 @@ TEST_F(ChromeFrameTestWithWebServer,
// Test whether POST-ing a form from an mshtml page to a CF page will cause
// the request to get reissued. It should not.
TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_TestPostReissue) {
- if (!MonikerPatchEnabled()) {
- LOG(ERROR) << "Not running test. Moniker patch not enabled.";
+ if (IsIBrowserServicePatchEnabled()) {
+ LOG(ERROR) << "Not running test. IBrowserServicePatch is in place.";
return;
}
@@ -854,8 +854,8 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_TestPostReissue) {
// Test whether following a link from an mshtml page to a CF page will cause
// multiple network requests. It should not.
TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_TestMultipleGet) {
- if (!MonikerPatchEnabled()) {
- LOG(ERROR) << "Not running test. Moniker patch not enabled.";
+ if (IsIBrowserServicePatchEnabled()) {
+ LOG(ERROR) << "Not running test. IBrowserServicePatch is in place.";
return;
}
diff --git a/chrome_frame/utils.cc b/chrome_frame/utils.cc
index 8647d86..b375dcc 100644
--- a/chrome_frame/utils.cc
+++ b/chrome_frame/utils.cc
@@ -1078,8 +1078,116 @@ ProtocolPatchMethod GetPatchMethod() {
return patch_method;
}
-bool MonikerPatchEnabled() {
+bool IsIBrowserServicePatchEnabled() {
ProtocolPatchMethod patch_method = GetPatchMethod();
- return patch_method == PATCH_METHOD_MONIKER;
+ return patch_method == PATCH_METHOD_IBROWSER;
}
+std::string BindStatus2Str(ULONG bind_status) {
+ std::string s;
+ static const char* const bindstatus_txt[] = {
+ "BINDSTATUS_FINDINGRESOURCE",
+ "BINDSTATUS_CONNECTING",
+ "BINDSTATUS_REDIRECTING",
+ "BINDSTATUS_BEGINDOWNLOADDATA",
+ "BINDSTATUS_DOWNLOADINGDATA",
+ "BINDSTATUS_ENDDOWNLOADDATA",
+ "BINDSTATUS_BEGINDOWNLOADCOMPONENTS",
+ "BINDSTATUS_INSTALLINGCOMPONENTS",
+ "BINDSTATUS_ENDDOWNLOADCOMPONENTS",
+ "BINDSTATUS_USINGCACHEDCOPY",
+ "BINDSTATUS_SENDINGREQUEST",
+ "BINDSTATUS_CLASSIDAVAILABLE",
+ "BINDSTATUS_MIMETYPEAVAILABLE",
+ "BINDSTATUS_CACHEFILENAMEAVAILABLE",
+ "BINDSTATUS_BEGINSYNCOPERATION",
+ "BINDSTATUS_ENDSYNCOPERATION",
+ "BINDSTATUS_BEGINUPLOADDATA",
+ "BINDSTATUS_UPLOADINGDATA",
+ "BINDSTATUS_ENDUPLOADINGDATA",
+ "BINDSTATUS_PROTOCOLCLASSID",
+ "BINDSTATUS_ENCODING",
+ "BINDSTATUS_VERFIEDMIMETYPEAVAILABLE",
+ "BINDSTATUS_CLASSINSTALLLOCATION",
+ "BINDSTATUS_DECODING",
+ "BINDSTATUS_LOADINGMIMEHANDLER",
+ "BINDSTATUS_CONTENTDISPOSITIONATTACH",
+ "BINDSTATUS_FILTERREPORTMIMETYPE",
+ "BINDSTATUS_CLSIDCANINSTANTIATE",
+ "BINDSTATUS_IUNKNOWNAVAILABLE",
+ "BINDSTATUS_DIRECTBIND",
+ "BINDSTATUS_RAWMIMETYPE",
+ "BINDSTATUS_PROXYDETECTING",
+ "BINDSTATUS_ACCEPTRANGES",
+ "BINDSTATUS_COOKIE_SENT",
+ "BINDSTATUS_COMPACT_POLICY_RECEIVED",
+ "BINDSTATUS_COOKIE_SUPPRESSED",
+ "BINDSTATUS_COOKIE_STATE_UNKNOWN",
+ "BINDSTATUS_COOKIE_STATE_ACCEPT",
+ "BINDSTATUS_COOKIE_STATE_REJECT",
+ "BINDSTATUS_COOKIE_STATE_PROMPT",
+ "BINDSTATUS_COOKIE_STATE_LEASH",
+ "BINDSTATUS_COOKIE_STATE_DOWNGRADE",
+ "BINDSTATUS_POLICY_HREF",
+ "BINDSTATUS_P3P_HEADER",
+ "BINDSTATUS_SESSION_COOKIE_RECEIVED",
+ "BINDSTATUS_PERSISTENT_COOKIE_RECEIVED",
+ "BINDSTATUS_SESSION_COOKIES_ALLOWED",
+ "BINDSTATUS_CACHECONTROL",
+ "BINDSTATUS_CONTENTDISPOSITIONFILENAME",
+ "BINDSTATUS_MIMETEXTPLAINMISMATCH",
+ "BINDSTATUS_PUBLISHERAVAILABLE",
+ "BINDSTATUS_DISPLAYNAMEAVAILABLE",
+ "BINDSTATUS_SSLUX_NAVBLOCKED",
+ "BINDSTATUS_SERVER_MIMETYPEAVAILABLE",
+ "BINDSTATUS_SNIFFED_CLASSIDAVAILABLE",
+ "BINDSTATUS_64BIT_PROGRESS"
+ };
+ if (bind_status >= 1 && bind_status <= BINDSTATUS_64BIT_PROGRESS)
+ s = bindstatus_txt[bind_status - 1];
+ else
+ s = StringPrintf("UnDoc[%#x]", bind_status);
+ return s;
+}
+
+std::string PiFlags2Str(DWORD flags) {
+#define ADD_PI_FLAG(x) if (flags & x) { s.append(#x ## " "); flags &= ~x; }
+ std::string s = " flags ";
+ ADD_PI_FLAG(PI_PARSE_URL);
+ ADD_PI_FLAG(PI_FILTER_MODE);
+ ADD_PI_FLAG(PI_FORCE_ASYNC);
+ ADD_PI_FLAG(PI_USE_WORKERTHREAD);
+ ADD_PI_FLAG(PI_MIMEVERIFICATION);
+ ADD_PI_FLAG(PI_CLSIDLOOKUP);
+ ADD_PI_FLAG(PI_DATAPROGRESS);
+ ADD_PI_FLAG(PI_SYNCHRONOUS);
+ ADD_PI_FLAG(PI_APARTMENTTHREADED);
+ ADD_PI_FLAG(PI_CLASSINSTALL);
+ ADD_PI_FLAG(PI_PASSONBINDCTX);
+ ADD_PI_FLAG(PI_NOMIMEHANDLER);
+ ADD_PI_FLAG(PI_LOADAPPDIRECT);
+ ADD_PI_FLAG(PD_FORCE_SWITCH);
+ ADD_PI_FLAG(PI_PREFERDEFAULTHANDLER);
+
+ if (flags)
+ s += StringPrintf("+UnDoc[%#x]", flags);
+ return s;
+#undef ADD_PI_FLAG
+}
+
+std::string Bscf2Str(DWORD flags) {
+#define ADD_BSCF_FLAG(x) if (flags & x) { s.append(#x ## " "); flags &= ~x; }
+ std::string s = " flags ";
+ ADD_BSCF_FLAG(BSCF_FIRSTDATANOTIFICATION)
+ ADD_BSCF_FLAG(BSCF_INTERMEDIATEDATANOTIFICATION)
+ ADD_BSCF_FLAG(BSCF_LASTDATANOTIFICATION)
+ ADD_BSCF_FLAG(BSCF_DATAFULLYAVAILABLE)
+ ADD_BSCF_FLAG(BSCF_AVAILABLEDATASIZEUNKNOWN)
+ ADD_BSCF_FLAG(BSCF_SKIPDRAINDATAFORFILEURLS)
+ ADD_BSCF_FLAG(BSCF_64BITLENGTHDOWNLOAD)
+
+ if (flags)
+ s += StringPrintf("+UnDoc[%#x]", flags);
+ return s;
+#undef ADD_BSCF_FLAG
+}
diff --git a/chrome_frame/utils.h b/chrome_frame/utils.h
index d0f64d5..c60dfab 100644
--- a/chrome_frame/utils.h
+++ b/chrome_frame/utils.h
@@ -437,7 +437,7 @@ bool IsTextHtmlClipFormat(CLIPFORMAT cf);
ProtocolPatchMethod GetPatchMethod();
// Returns true if the IMoniker patch is enabled.
-bool MonikerPatchEnabled();
+bool IsIBrowserServicePatchEnabled();
// STL helper class that implements a functor to delete objects.
// E.g: std::for_each(v.begin(), v.end(), utils::DeleteObject());
@@ -451,4 +451,9 @@ class DeleteObject {
};
}
+// Convert various protocol flags to text representation. Used for logging.
+std::string BindStatus2Str(ULONG bind_status);
+std::string PiFlags2Str(DWORD flags);
+std::string Bscf2Str(DWORD flags);
+
#endif // CHROME_FRAME_UTILS_H_