diff options
Diffstat (limited to 'chrome_frame')
-rw-r--r-- | chrome_frame/bho.cc | 9 | ||||
-rw-r--r-- | chrome_frame/bind_context_info.h | 11 | ||||
-rw-r--r-- | chrome_frame/protocol_sink_wrap.cc | 1005 | ||||
-rw-r--r-- | chrome_frame/protocol_sink_wrap.h | 238 | ||||
-rw-r--r-- | chrome_frame/test/test_mock_with_web_server.cc | 12 | ||||
-rw-r--r-- | chrome_frame/test/test_with_web_server.cc | 12 | ||||
-rw-r--r-- | chrome_frame/utils.cc | 112 | ||||
-rw-r--r-- | chrome_frame/utils.h | 7 |
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_ |