| Index: chrome_frame/protocol_sink_wrap.cc
|
| ===================================================================
|
| --- chrome_frame/protocol_sink_wrap.cc (revision 0)
|
| +++ chrome_frame/protocol_sink_wrap.cc (revision 0)
|
| @@ -0,0 +1,615 @@
|
| +// Copyright (c) 2009 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include <htiframe.h>
|
| +
|
| +#include "chrome_frame/protocol_sink_wrap.h"
|
| +
|
| +#include "base/scoped_bstr_win.h"
|
| +#include "base/logging.h"
|
| +#include "base/registry.h"
|
| +#include "base/scoped_bstr_win.h"
|
| +#include "base/singleton.h"
|
| +#include "base/string_util.h"
|
| +
|
| +#include "chrome_frame/utils.h"
|
| +#include "chrome_frame/vtable_patch_manager.h"
|
| +
|
| +// BINDSTATUS_SERVER_MIMETYPEAVAILABLE == 54. Introduced in IE 8, so
|
| +// not in everyone's headers yet. See:
|
| +// http://msdn.microsoft.com/en-us/library/ms775133(VS.85,loband).aspx
|
| +#ifndef BINDSTATUS_SERVER_MIMETYPEAVAILABLE
|
| +#define BINDSTATUS_SERVER_MIMETYPEAVAILABLE 54
|
| +#endif
|
| +
|
| +static const wchar_t* kChromeMimeType = L"application/chromepage";
|
| +static const char kTextHtmlMimeType[] = "text/html";
|
| +
|
| +static const int kInternetProtocolStartIndex = 3;
|
| +static const int kInternetProtocolReadIndex = 9;
|
| +static const int kInternetProtocolStartExIndex = 13;
|
| +
|
| +BEGIN_VTABLE_PATCHES(IInternetProtocol)
|
| + 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)
|
| +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) {
|
| + memset(buffer_, 0, arraysize(buffer_));
|
| +}
|
| +
|
| +ProtocolSinkWrap::~ProtocolSinkWrap() {
|
| + 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();
|
| +}
|
| +
|
| +bool ProtocolSinkWrap::PatchProtocolHandler(const wchar_t* dll,
|
| + const CLSID& handler_clsid) {
|
| + HMODULE module = ::GetModuleHandle(dll);
|
| + if (!module) {
|
| + NOTREACHED() << "urlmon is not yet loaded. Error: " << GetLastError();
|
| + return false;
|
| + }
|
| +
|
| + 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 false;
|
| + }
|
| +
|
| + ScopedComPtr<IClassFactory> protocol_class_factory;
|
| + HRESULT hr = fn(handler_clsid, IID_IClassFactory,
|
| + reinterpret_cast<LPVOID*>(protocol_class_factory.Receive()));
|
| + if (FAILED(hr)) {
|
| + NOTREACHED() << "DllGetclassObject failed. Error: " << hr;
|
| + return false;
|
| + }
|
| +
|
| + 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;
|
| + return false;
|
| + }
|
| +
|
| + ScopedComPtr<IInternetProtocolEx> ipex;
|
| + ipex.QueryFrom(handler_instance);
|
| + if (ipex) {
|
| + vtable_patch::PatchInterfaceMethods(ipex, IInternetProtocolEx_PatchInfo);
|
| + } else {
|
| + vtable_patch::PatchInterfaceMethods(handler_instance,
|
| + IInternetProtocol_PatchInfo);
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +// 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;
|
| +
|
| + ScopedComPtr<IInternetProtocolSink> sink_to_use(MaybeWrapSink(protocol,
|
| + prot_sink, url));
|
| + return orig_start(protocol, url, sink_to_use, bind_info, flags, reserved);
|
| +}
|
| +
|
| +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;
|
| +
|
| + ScopedComPtr<IInternetProtocolSink> sink_to_use(MaybeWrapSink(protocol,
|
| + prot_sink, url));
|
| + return orig_start_ex(protocol, uri, sink_to_use, bind_info, flags, reserved);
|
| +}
|
| +
|
| +HRESULT ProtocolSinkWrap::OnRead(InternetProtocol_Read_Fn orig_read,
|
| + IInternetProtocol* protocol, void* buffer, ULONG size, ULONG* size_read) {
|
| + DCHECK(orig_read);
|
| +
|
| + 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);
|
| + }
|
| +
|
| + return hr;
|
| +}
|
| +
|
| +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;
|
| +}
|
| +
|
| +HRESULT WINAPI ProtocolSinkWrap::CheckOutgoingInterface(void* obj,
|
| + REFIID iid, LPVOID* ret, DWORD cookie) {
|
| + ProtocolSinkWrap* instance = reinterpret_cast<ProtocolSinkWrap*>(obj);
|
| + HRESULT hr = E_NOINTERFACE;
|
| + if (instance && instance->delegate_)
|
| + hr = instance->delegate_->QueryInterface(iid, ret);
|
| +
|
| +#ifndef NDEBUG
|
| + if (SUCCEEDED(hr)) {
|
| + wchar_t iid_string[64] = {0};
|
| + StringFromGUID2(iid, iid_string, arraysize(iid_string));
|
| + DLOG(INFO) << "Giving out wrapped interface: " << iid_string;
|
| + }
|
| +#endif
|
| +
|
| + return hr;
|
| +}
|
| +
|
| +HRESULT WINAPI ProtocolSinkWrap::IfDelegateSupports(void* obj,
|
| + REFIID iid, LPVOID* ret, DWORD cookie) {
|
| + HRESULT hr = E_NOINTERFACE;
|
| + ProtocolSinkWrap* instance = reinterpret_cast<ProtocolSinkWrap*>(obj);
|
| + if (instance && instance->delegate_) {
|
| + ScopedComPtr<IUnknown> original;
|
| + hr = instance->delegate_->QueryInterface(iid,
|
| + reinterpret_cast<void**>(original.Receive()));
|
| + if (original) {
|
| + IUnknown* supported_interface = reinterpret_cast<IUnknown*>(
|
| + reinterpret_cast<DWORD_PTR>(obj) + cookie);
|
| + supported_interface->AddRef();
|
| + *ret = supported_interface;
|
| + hr = S_OK;
|
| + }
|
| + }
|
| +
|
| + return hr;
|
| +}
|
| +
|
| +// IInternetProtocolSink methods
|
| +STDMETHODIMP ProtocolSinkWrap::Switch(PROTOCOLDATA* protocol_data) {
|
| + HRESULT hr = E_FAIL;
|
| + if (delegate_)
|
| + hr = delegate_->Switch(protocol_data);
|
| + return hr;
|
| +}
|
| +
|
| +STDMETHODIMP ProtocolSinkWrap::ReportProgress(ULONG status_code,
|
| + LPCWSTR status_text) {
|
| + DLOG(INFO) << "ProtocolSinkWrap::ReportProgress: Code:" << status_code <<
|
| + " Text: " << (status_text ? status_text : L"");
|
| + 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;
|
| + }
|
| + }
|
| + }
|
| +
|
| + HRESULT hr = E_FAIL;
|
| + if (delegate_)
|
| + hr = delegate_->ReportProgress(status_code, status_text);
|
| + return hr;
|
| +}
|
| +
|
| +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()) {
|
| + 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;
|
| +
|
| + // 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_VERIFIEDMIMETYPEAVAILABLE, kChromeMimeType);
|
| +
|
| + delegate_->ReportData(
|
| + BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE, 0, 0);
|
| + }
|
| + break;
|
| + }
|
| + }
|
| + }
|
| +
|
| + // we call original only if the renderer type is other
|
| + if (renderer_type() == OTHER) {
|
| + hr = delegate_->ReportData(flags, progress, max_progress);
|
| +
|
| + if (is_saved_result_) {
|
| + is_saved_result_ = false;
|
| + delegate_->ReportResult(result_code_, result_error_,
|
| + result_text_.c_str());
|
| + }
|
| + }
|
| +
|
| + report_data_recursiveness_--;
|
| + return hr;
|
| +}
|
| +
|
| +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;
|
| + return S_OK;
|
| + }
|
| +
|
| + HRESULT hr = E_FAIL;
|
| + if (delegate_)
|
| + hr = delegate_->ReportResult(result, error, result_text);
|
| +
|
| + return hr;
|
| +}
|
| +
|
| +// 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;
|
| +}
|
| +
|
| +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;
|
| +}
|
| +
|
| +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;
|
| +}
|
| +
|
| +// 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;
|
| +}
|
| +
|
| +// 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;
|
| +}
|
| +
|
| +// 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;
|
| +}
|
| +
|
| +STDMETHODIMP ProtocolSinkWrap::Continue(PROTOCOLDATA* protocol_data) {
|
| + ScopedComPtr<IInternetProtocolRoot> protocol;
|
| + HRESULT hr = protocol.QueryFrom(delegate_);
|
| + if (protocol)
|
| + hr = protocol->Continue(protocol_data);
|
| + return hr;
|
| +}
|
| +
|
| +STDMETHODIMP ProtocolSinkWrap::Abort(HRESULT reason, DWORD options) {
|
| + ScopedComPtr<IInternetProtocolRoot> protocol;
|
| + HRESULT hr = protocol.QueryFrom(delegate_);
|
| + if (protocol)
|
| + hr = protocol->Abort(reason, options);
|
| + return hr;
|
| +}
|
| +
|
| +STDMETHODIMP ProtocolSinkWrap::Terminate(DWORD options) {
|
| + ScopedComPtr<IInternetProtocolRoot> protocol;
|
| + HRESULT hr = protocol.QueryFrom(delegate_);
|
| + if (protocol)
|
| + hr = protocol->Terminate(options);
|
| + return hr;
|
| +}
|
| +
|
| +STDMETHODIMP ProtocolSinkWrap::Suspend() {
|
| + ScopedComPtr<IInternetProtocolRoot> protocol;
|
| + HRESULT hr = protocol.QueryFrom(delegate_);
|
| + if (protocol)
|
| + hr = protocol->Suspend();
|
| + return hr;
|
| +}
|
| +
|
| +STDMETHODIMP ProtocolSinkWrap::Resume() {
|
| + ScopedComPtr<IInternetProtocolRoot> protocol;
|
| + HRESULT hr = protocol.QueryFrom(delegate_);
|
| + if (protocol)
|
| + hr = protocol->Resume();
|
| + return hr;
|
| +}
|
| +
|
| +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;
|
| +}
|
| +
|
| +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;
|
| +}
|
| +
|
| +STDMETHODIMP ProtocolSinkWrap::LockRequest(DWORD options) {
|
| + ScopedComPtr<IInternetProtocol> protocol;
|
| + HRESULT hr = protocol.QueryFrom(delegate_);
|
| + if (protocol)
|
| + hr = protocol->LockRequest(options);
|
| + return hr;
|
| +}
|
| +
|
| +STDMETHODIMP ProtocolSinkWrap::UnlockRequest() {
|
| + ScopedComPtr<IInternetProtocol> protocol;
|
| + HRESULT hr = protocol.QueryFrom(delegate_);
|
| + if (protocol)
|
| + hr = protocol->UnlockRequest();
|
| + return hr;
|
| +}
|
| +
|
| +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;
|
| +}
|
| +
|
| +// 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;
|
| +}
|
| +
|
| +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;
|
| +}
|
| +
|
| +// 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;
|
| +}
|
| +
|
| +
|
| +// 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);
|
| + 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;
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +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;
|
| + }
|
| + }
|
| +
|
| + 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;
|
| +}
|
| +
|
| +HRESULT ProtocolSinkWrap::WebBrowserFromProtocolSink(
|
| + IInternetProtocolSink* sink, IWebBrowser2** web_browser) {
|
| + // TODO(tommi): GUID_NULL doesn't work when loading 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, sink, http_negotiate.Receive());
|
| + if (http_negotiate)
|
| + hr = DoQueryService(IID_ITargetFrame2, http_negotiate, web_browser);
|
| +
|
| + return hr;
|
| +}
|
| +
|
| +ScopedComPtr<IInternetProtocolSink> ProtocolSinkWrap::MaybeWrapSink(
|
| + IInternetProtocol* protocol, IInternetProtocolSink* prot_sink,
|
| + const wchar_t* url) {
|
| + ScopedComPtr<IInternetProtocolSink> sink_to_use;
|
| + sink_to_use.QueryFrom(prot_sink);
|
| + ScopedComPtr<IWebBrowser2> web_browser;
|
| + WebBrowserFromProtocolSink(prot_sink, web_browser.Receive());
|
| + if (web_browser) {
|
| + CComObject<ProtocolSinkWrap>* wrap = NULL;
|
| + CComObject<ProtocolSinkWrap>::CreateInstance(&wrap);
|
| + DCHECK(wrap);
|
| + if (wrap->Initialize(protocol, prot_sink, url)) {
|
| + sink_to_use = wrap;
|
| + }
|
| + }
|
| +
|
| + return sink_to_use;
|
| +}
|
|
|