Index: chrome_frame/bho.cc |
diff --git a/chrome_frame/bho.cc b/chrome_frame/bho.cc |
deleted file mode 100644 |
index cf207b381d3d73370f36a1af5c6e9eddf95e5ed3..0000000000000000000000000000000000000000 |
--- a/chrome_frame/bho.cc |
+++ /dev/null |
@@ -1,365 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "chrome_frame/bho.h" |
- |
-#include <shlguid.h> |
- |
-#include "base/files/file_path.h" |
-#include "base/logging.h" |
-#include "base/path_service.h" |
-#include "base/strings/string_util.h" |
-#include "base/strings/stringprintf.h" |
-#include "base/time/time.h" |
-#include "base/win/scoped_bstr.h" |
-#include "chrome_frame/buggy_bho_handling.h" |
-#include "chrome_frame/crash_reporting/crash_metrics.h" |
-#include "chrome_frame/extra_system_apis.h" |
-#include "chrome_frame/html_utils.h" |
-#include "chrome_frame/http_negotiate.h" |
-#include "chrome_frame/metrics_service.h" |
-#include "chrome_frame/protocol_sink_wrap.h" |
-#include "chrome_frame/turndown_prompt/turndown_prompt.h" |
-#include "chrome_frame/urlmon_moniker.h" |
-#include "chrome_frame/utils.h" |
-#include "chrome_frame/vtable_patch_manager.h" |
- |
-static const int kIBrowserServiceOnHttpEquivIndex = 30; |
-static const DWORD kMaxHttpConnections = 6; |
- |
-PatchHelper g_patch_helper; |
- |
-BEGIN_VTABLE_PATCHES(IBrowserService) |
- VTABLE_PATCH_ENTRY(kIBrowserServiceOnHttpEquivIndex, Bho::OnHttpEquiv) |
-END_VTABLE_PATCHES() |
- |
-_ATL_FUNC_INFO Bho::kBeforeNavigate2Info = { |
- CC_STDCALL, VT_EMPTY, 7, { |
- VT_DISPATCH, |
- VT_VARIANT | VT_BYREF, |
- VT_VARIANT | VT_BYREF, |
- VT_VARIANT | VT_BYREF, |
- VT_VARIANT | VT_BYREF, |
- VT_VARIANT | VT_BYREF, |
- VT_BOOL | VT_BYREF |
- } |
-}; |
- |
-_ATL_FUNC_INFO Bho::kNavigateComplete2Info = { |
- CC_STDCALL, VT_EMPTY, 2, { |
- VT_DISPATCH, |
- VT_VARIANT | VT_BYREF |
- } |
-}; |
- |
-_ATL_FUNC_INFO Bho::kDocumentCompleteInfo = { |
- CC_STDCALL, VT_EMPTY, 2, { |
- VT_DISPATCH, |
- VT_VARIANT | VT_BYREF |
- } |
-}; |
- |
-Bho::Bho() { |
-} |
- |
-HRESULT Bho::FinalConstruct() { |
- return S_OK; |
-} |
- |
-void Bho::FinalRelease() { |
-} |
- |
-STDMETHODIMP Bho::SetSite(IUnknown* site) { |
- HRESULT hr = S_OK; |
- if (site) { |
- base::TimeTicks start = base::TimeTicks::Now(); |
- base::win::ScopedComPtr<IWebBrowser2> web_browser2; |
- web_browser2.QueryFrom(site); |
- if (web_browser2) { |
- hr = DispEventAdvise(web_browser2, &DIID_DWebBrowserEvents2); |
- DCHECK(SUCCEEDED(hr)) << "DispEventAdvise failed. Error: " << hr; |
- |
- turndown_prompt::Configure(web_browser2); |
- } |
- |
- if (g_patch_helper.state() == PatchHelper::PATCH_IBROWSER) { |
- base::win::ScopedComPtr<IBrowserService> browser_service; |
- hr = DoQueryService(SID_SShellBrowser, site, browser_service.Receive()); |
- DCHECK(browser_service) << "DoQueryService - SID_SShellBrowser failed." |
- << " Site: " << site << " Error: " << hr; |
- if (browser_service) { |
- g_patch_helper.PatchBrowserService(browser_service); |
- DCHECK(SUCCEEDED(hr)) << "vtable_patch::PatchInterfaceMethods failed." |
- << " Site: " << site << " Error: " << hr; |
- } |
- } |
- // Save away our BHO instance in TLS which enables it to be referenced by |
- // our active document/activex instances to query referrer and other |
- // information for a URL. |
- AddRef(); |
- RegisterThreadInstance(); |
- MetricsService::Start(); |
- |
- if (!IncreaseWinInetConnections(kMaxHttpConnections)) { |
- DLOG(WARNING) << "Failed to bump up HTTP connections. Error:" |
- << ::GetLastError(); |
- } |
- |
- base::TimeDelta delta = base::TimeTicks::Now() - start; |
- UMA_HISTOGRAM_TIMES("ChromeFrame.BhoLoadSetSite", delta); |
- } else { |
- UnregisterThreadInstance(); |
- buggy_bho::BuggyBhoTls::DestroyInstance(); |
- base::win::ScopedComPtr<IWebBrowser2> web_browser2; |
- web_browser2.QueryFrom(m_spUnkSite); |
- DispEventUnadvise(web_browser2, &DIID_DWebBrowserEvents2); |
- Release(); |
- } |
- |
- return IObjectWithSiteImpl<Bho>::SetSite(site); |
-} |
- |
-STDMETHODIMP Bho::BeforeNavigate2(IDispatch* dispatch, VARIANT* url, |
- VARIANT* flags, VARIANT* target_frame_name, VARIANT* post_data, |
- VARIANT* headers, VARIANT_BOOL* cancel) { |
- if (!url || url->vt != VT_BSTR || url->bstrVal == NULL) { |
- DLOG(WARNING) << "Invalid URL passed in"; |
- return S_OK; |
- } |
- |
- base::win::ScopedComPtr<IWebBrowser2> web_browser2; |
- if (dispatch) |
- web_browser2.QueryFrom(dispatch); |
- |
- if (!web_browser2) { |
- NOTREACHED() << "Can't find WebBrowser2 with given dispatch"; |
- return S_OK; |
- } |
- |
- DVLOG(1) << "BeforeNavigate2: " << url->bstrVal; |
- |
- base::win::ScopedComPtr<IBrowserService> browser_service; |
- DoQueryService(SID_SShellBrowser, web_browser2, browser_service.Receive()); |
- if (!browser_service || !CheckForCFNavigation(browser_service, false)) { |
- // TODO(tommi): Remove? Isn't this done below by calling set_referrer("")? |
- referrer_.clear(); |
- } |
- |
- VARIANT_BOOL is_top_level = VARIANT_FALSE; |
- web_browser2->get_TopLevelContainer(&is_top_level); |
- if (is_top_level) { |
- set_url(url->bstrVal); |
- set_referrer(""); |
- set_post_data(post_data); |
- set_headers(headers); |
- } |
- return S_OK; |
-} |
- |
-STDMETHODIMP_(void) Bho::NavigateComplete2(IDispatch* dispatch, VARIANT* url) { |
- DVLOG(1) << __FUNCTION__; |
-} |
- |
-STDMETHODIMP_(void) Bho::DocumentComplete(IDispatch* dispatch, VARIANT* url) { |
- DVLOG(1) << __FUNCTION__; |
- |
- base::win::ScopedComPtr<IWebBrowser2> web_browser2; |
- if (dispatch) |
- web_browser2.QueryFrom(dispatch); |
- |
- if (web_browser2) { |
- VARIANT_BOOL is_top_level = VARIANT_FALSE; |
- web_browser2->get_TopLevelContainer(&is_top_level); |
- if (is_top_level) { |
- CrashMetricsReporter::GetInstance()->IncrementMetric( |
- CrashMetricsReporter::NAVIGATION_COUNT); |
- } |
- } |
-} |
- |
-namespace { |
- |
-// See comments in Bho::OnHttpEquiv for details. |
-void ClearDocumentContents(IUnknown* browser) { |
- base::win::ScopedComPtr<IWebBrowser2> web_browser2; |
- if (SUCCEEDED(DoQueryService(SID_SWebBrowserApp, browser, |
- web_browser2.Receive()))) { |
- base::win::ScopedComPtr<IDispatch> doc_disp; |
- web_browser2->get_Document(doc_disp.Receive()); |
- base::win::ScopedComPtr<IHTMLDocument2> doc; |
- if (doc_disp && SUCCEEDED(doc.QueryFrom(doc_disp))) { |
- SAFEARRAY* sa = ::SafeArrayCreateVector(VT_UI1, 0, 0); |
- doc->write(sa); |
- ::SafeArrayDestroy(sa); |
- } |
- } |
-} |
- |
-// Returns true if the currently loaded document in the browser has |
-// any embedded items such as a frame or an iframe. |
-bool DocumentHasEmbeddedItems(IUnknown* browser) { |
- bool has_embedded_items = false; |
- |
- base::win::ScopedComPtr<IWebBrowser2> web_browser2; |
- base::win::ScopedComPtr<IDispatch> document; |
- if (SUCCEEDED(DoQueryService(SID_SWebBrowserApp, browser, |
- web_browser2.Receive())) && |
- SUCCEEDED(web_browser2->get_Document(document.Receive()))) { |
- base::win::ScopedComPtr<IOleContainer> container; |
- if (SUCCEEDED(container.QueryFrom(document))) { |
- base::win::ScopedComPtr<IEnumUnknown> enumerator; |
- container->EnumObjects(OLECONTF_EMBEDDINGS, enumerator.Receive()); |
- if (enumerator) { |
- base::win::ScopedComPtr<IUnknown> unk; |
- DWORD fetched = 0; |
- while (!has_embedded_items && |
- SUCCEEDED(enumerator->Next(1, unk.Receive(), &fetched)) |
- && fetched) { |
- // If a top level document has embedded iframes then the theory is |
- // that first the top level document finishes loading and then the |
- // iframes load. We should only treat an embedded element as an |
- // iframe if it supports the IWebBrowser interface. |
- base::win::ScopedComPtr<IWebBrowser2> embedded_web_browser2; |
- if (SUCCEEDED(embedded_web_browser2.QueryFrom(unk))) { |
- // If we initiate a top level navigation then at times MSHTML |
- // creates a temporary IWebBrowser2 interface which basically shows |
- // up as a temporary iframe in the parent document. It is not clear |
- // as to how we can detect this. I tried the usual stuff like |
- // getting to the parent IHTMLWindow2 interface. They all end up |
- // pointing to dummy tear off interfaces owned by MSHTML. |
- // As a temporary workaround, we found that the location url in |
- // this case is about:blank. We now check for the same and don't |
- // treat it as an iframe. This should be fine in most cases as we |
- // hit this code only when the actual page has a meta tag. However |
- // this would break for cases like the initial src url for an |
- // iframe pointing to about:blank and the page then writing to it |
- // via document.write. |
- // TODO(ananta) |
- // Revisit this and come up with a better approach. |
- base::win::ScopedBstr location_url; |
- embedded_web_browser2->get_LocationURL(location_url.Receive()); |
- |
- std::wstring location_url_string; |
- location_url_string.assign(location_url, location_url.Length()); |
- |
- if (!LowerCaseEqualsASCII(location_url_string, "about:blank")) { |
- has_embedded_items = true; |
- } |
- } |
- |
- fetched = 0; |
- unk.Release(); |
- } |
- } |
- } |
- } |
- |
- return has_embedded_items; |
-} |
- |
-} // end namespace |
- |
-HRESULT Bho::OnHttpEquiv(IBrowserService_OnHttpEquiv_Fn original_httpequiv, |
- IBrowserService* browser, IShellView* shell_view, BOOL done, |
- VARIANT* in_arg, VARIANT* out_arg) { |
- DVLOG(1) << __FUNCTION__ << " done:" << done; |
- |
- // OnHttpEquiv with 'done' set to TRUE is called for all pages. |
- // 0 or more calls with done set to FALSE are made. |
- // When done is FALSE, the current moniker may not represent the page |
- // being navigated to so we always have to wait for done to be TRUE |
- // before re-initiating the navigation. |
- |
- if (!done && in_arg && VT_BSTR == V_VT(in_arg)) { |
- if (StrStrI(V_BSTR(in_arg), kChromeContentPrefix)) { |
- // OnHttpEquiv is invoked for meta tags within sub frames as well. |
- // We want to switch renderers only for the top level frame. |
- // The theory here is that if there are any existing embedded items |
- // (frames or iframes) in the current document, then the http-equiv |
- // notification is coming from those and not the top level document. |
- // The embedded items should only be created once the top level |
- // doc has been created. |
- if (!DocumentHasEmbeddedItems(browser)) { |
- NavigationManager* mgr = NavigationManager::GetThreadInstance(); |
- DCHECK(mgr); |
- DVLOG(1) << "Found tag in page. Marking browser." |
- << base::StringPrintf(" tid=0x%08X", ::GetCurrentThreadId()); |
- if (mgr) { |
- // TODO(tommi): See if we can't figure out a cleaner way to avoid |
- // this. For some documents we can hit a problem here. When we |
- // attempt to navigate the document again in CF, mshtml can "complete" |
- // the current navigation (if all data is available) and fire off |
- // script events such as onload and even render the page. |
- // This will happen inside NavigateBrowserToMoniker below. |
- // To work around this, we clear the contents of the document before |
- // opening it up in CF. |
- ClearDocumentContents(browser); |
- mgr->NavigateToCurrentUrlInCF(browser); |
- } |
- } |
- } |
- } |
- |
- return original_httpequiv(browser, shell_view, done, in_arg, out_arg); |
-} |
- |
-// static |
-void Bho::ProcessOptInUrls(IWebBrowser2* browser, BSTR url) { |
- if (!browser || !url) { |
- NOTREACHED(); |
- return; |
- } |
- |
-#ifndef NDEBUG |
- // This check must already have been made. |
- VARIANT_BOOL is_top_level = VARIANT_FALSE; |
- browser->get_TopLevelContainer(&is_top_level); |
- DCHECK(is_top_level); |
-#endif |
- |
- std::wstring current_url(url, SysStringLen(url)); |
- if (IsValidUrlScheme(GURL(current_url), false)) { |
- bool cf_protocol = StartsWith(current_url, kChromeProtocolPrefix, false); |
- if (!cf_protocol && IsChrome(RendererTypeForUrl(current_url))) { |
- DVLOG(1) << "Opt-in URL. Switching to cf."; |
- base::win::ScopedComPtr<IBrowserService> browser_service; |
- DoQueryService(SID_SShellBrowser, browser, browser_service.Receive()); |
- DCHECK(browser_service) << "DoQueryService - SID_SShellBrowser failed."; |
- MarkBrowserOnThreadForCFNavigation(browser_service); |
- } |
- } |
-} |
- |
-bool PatchHelper::InitializeAndPatchProtocolsIfNeeded() { |
- bool ret = false; |
- |
- _pAtlModule->m_csStaticDataInitAndTypeInfo.Lock(); |
- |
- if (state_ == UNKNOWN) { |
- g_trans_hooks.InstallHooks(); |
- HttpNegotiatePatch::Initialize(); |
- state_ = PATCH_PROTOCOL; |
- ret = true; |
- } |
- |
- _pAtlModule->m_csStaticDataInitAndTypeInfo.Unlock(); |
- |
- return ret; |
-} |
- |
-void PatchHelper::PatchBrowserService(IBrowserService* browser_service) { |
- DCHECK(state_ == PATCH_IBROWSER); |
- if (!IS_PATCHED(IBrowserService)) { |
- vtable_patch::PatchInterfaceMethods(browser_service, |
- IBrowserService_PatchInfo); |
- } |
-} |
- |
-void PatchHelper::UnpatchIfNeeded() { |
- if (state_ == PATCH_PROTOCOL) { |
- g_trans_hooks.RevertHooks(); |
- HttpNegotiatePatch::Uninitialize(); |
- } |
- state_ = UNKNOWN; |
-} |