diff options
Diffstat (limited to 'chromium/chrome/browser/net/net_error_tab_helper.cc')
-rw-r--r-- | chromium/chrome/browser/net/net_error_tab_helper.cc | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/chromium/chrome/browser/net/net_error_tab_helper.cc b/chromium/chrome/browser/net/net_error_tab_helper.cc new file mode 100644 index 00000000000..2f45389e0e7 --- /dev/null +++ b/chromium/chrome/browser/net/net_error_tab_helper.cc @@ -0,0 +1,309 @@ +// 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/browser/net/net_error_tab_helper.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "chrome/browser/net/dns_probe_service.h" +#include "chrome/browser/net/dns_probe_service_factory.h" +#include "chrome/browser/net/net_error_diagnostics_dialog.h" +#include "chrome/browser/platform_util.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/render_messages.h" +#include "components/error_page/common/net_error_info.h" +#include "components/pref_registry/pref_registry_syncable.h" +#include "components/prefs/pref_service.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/navigation_entry.h" +#include "content/public/browser/navigation_handle.h" +#include "content/public/browser/render_frame_host.h" +#include "ipc/ipc_message_macros.h" +#include "mojo/public/cpp/bindings/associated_remote.h" +#include "net/base/net_errors.h" +#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" +#include "url/gurl.h" + +#if BUILDFLAG(ENABLE_OFFLINE_PAGES) +#include "chrome/browser/offline_pages/offline_page_utils.h" +#include "components/offline_pages/core/client_namespace_constants.h" +#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES) + +using content::BrowserContext; +using content::BrowserThread; +using content::WebContents; +using content::WebContentsObserver; +using error_page::DnsProbeStatus; +using error_page::DnsProbeStatusToString; +using ui::PageTransition; + +namespace chrome_browser_net { + +namespace { + +static NetErrorTabHelper::TestingState testing_state_ = + NetErrorTabHelper::TESTING_DEFAULT; + +} // namespace + +NetErrorTabHelper::~NetErrorTabHelper() { +} + +// static +void NetErrorTabHelper::set_state_for_testing(TestingState state) { + testing_state_ = state; +} + +void NetErrorTabHelper::RenderFrameCreated( + content::RenderFrameHost* render_frame_host) { + // Ignore subframe creation - only main frame error pages can link to the + // platform's network diagnostics dialog. + if (render_frame_host->GetParent()) + return; + + mojo::AssociatedRemote<chrome::mojom::NetworkDiagnosticsClient> client; + render_frame_host->GetRemoteAssociatedInterfaces()->GetInterface(&client); + client->SetCanShowNetworkDiagnosticsDialog( + CanShowNetworkDiagnosticsDialog(web_contents())); +} + +void NetErrorTabHelper::DidStartNavigation( + content::NavigationHandle* navigation_handle) { + if (!navigation_handle->IsInMainFrame()) + return; + + if (navigation_handle->IsErrorPage() && + PageTransitionCoreTypeIs(navigation_handle->GetPageTransition(), + ui::PAGE_TRANSITION_RELOAD)) { + error_page::RecordEvent( + error_page::NETWORK_ERROR_PAGE_BROWSER_INITIATED_RELOAD); + } +} + +void NetErrorTabHelper::DidFinishNavigation( + content::NavigationHandle* navigation_handle) { + if (!navigation_handle->IsInMainFrame()) + return; + + if (net::IsDnsError(navigation_handle->GetNetErrorCode())) { + dns_error_active_ = true; + OnMainFrameDnsError(); + } + + // Resend status every time an error page commits; this is somewhat spammy, + // but ensures that the status will make it to the real error page, even if + // the link doctor loads a blank intermediate page or the tab switches + // renderer processes. + if (navigation_handle->IsErrorPage() && dns_error_active_) { + dns_error_page_committed_ = true; + DVLOG(1) << "Committed error page; resending status."; + SendInfo(); + } else if (navigation_handle->HasCommitted() && + !navigation_handle->IsErrorPage()) { + dns_error_active_ = false; + dns_error_page_committed_ = false; +#if BUILDFLAG(ENABLE_OFFLINE_PAGES) + is_showing_download_button_in_error_page_ = false; +#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES) + } +} + +bool NetErrorTabHelper::OnMessageReceived( + const IPC::Message& message, + content::RenderFrameHost* render_frame_host) { + if (render_frame_host != web_contents()->GetMainFrame()) + return false; +#if BUILDFLAG(ENABLE_OFFLINE_PAGES) + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(NetErrorTabHelper, message) + IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DownloadPageLater, + OnDownloadPageLater) + IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SetIsShowingDownloadButtonInErrorPage, + OnSetIsShowingDownloadButtonInErrorPage) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + + return handled; +#else + return false; +#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES) +} + +NetErrorTabHelper::NetErrorTabHelper(WebContents* contents) + : WebContentsObserver(contents), + network_diagnostics_bindings_(contents, this), + network_easter_egg_bindings_(contents, this), + is_error_page_(false), + dns_error_active_(false), + dns_error_page_committed_(false), +#if BUILDFLAG(ENABLE_OFFLINE_PAGES) + is_showing_download_button_in_error_page_(false), +#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES) + dns_probe_status_(error_page::DNS_PROBE_POSSIBLE) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + // If this helper is under test, it won't have a WebContents. + if (contents) + InitializePref(contents); +} + +void NetErrorTabHelper::OnMainFrameDnsError() { + if (ProbesAllowed()) { + // Don't start more than one probe at a time. + if (dns_probe_status_ != error_page::DNS_PROBE_STARTED) { + StartDnsProbe(); + dns_probe_status_ = error_page::DNS_PROBE_STARTED; + } + } else { + dns_probe_status_ = error_page::DNS_PROBE_NOT_RUN; + } +} + +void NetErrorTabHelper::StartDnsProbe() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK(dns_error_active_); + DCHECK_NE(error_page::DNS_PROBE_STARTED, dns_probe_status_); + + DVLOG(1) << "Starting DNS probe."; + + DnsProbeService* probe_service = DnsProbeServiceFactory::GetForContext( + web_contents()->GetBrowserContext()); + probe_service->ProbeDns(base::BindOnce(&NetErrorTabHelper::OnDnsProbeFinished, + weak_factory_.GetWeakPtr())); +} + +void NetErrorTabHelper::OnDnsProbeFinished(DnsProbeStatus result) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_EQ(error_page::DNS_PROBE_STARTED, dns_probe_status_); + DCHECK(error_page::DnsProbeStatusIsFinished(result)); + + DVLOG(1) << "Finished DNS probe with result " + << DnsProbeStatusToString(result) << "."; + + dns_probe_status_ = result; + + if (dns_error_page_committed_) + SendInfo(); +} + +#if BUILDFLAG(ENABLE_OFFLINE_PAGES) +void NetErrorTabHelper::OnDownloadPageLater() { + // Makes sure that this is coming from an error page. + content::NavigationEntry* entry = + web_contents()->GetController().GetLastCommittedEntry(); + if (!entry || entry->GetPageType() != content::PAGE_TYPE_ERROR) + return; + + // Only download the page for HTTP/HTTPS URLs. + GURL url(entry->GetVirtualURL()); + if (!url.SchemeIsHTTPOrHTTPS()) + return; + + DownloadPageLaterHelper(url); +} + +void NetErrorTabHelper::OnSetIsShowingDownloadButtonInErrorPage( + bool is_showing_download_button) { + is_showing_download_button_in_error_page_ = is_showing_download_button; +} +#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES) + +// static +void NetErrorTabHelper::RegisterProfilePrefs( + user_prefs::PrefRegistrySyncable* prefs) { + // prefs::kAlternateErrorPagesEnabled is registered by + // NavigationCorrectionTabObserver. + + prefs->RegisterIntegerPref(prefs::kNetworkEasterEggHighScore, 0, + user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); +} + +void NetErrorTabHelper::InitializePref(WebContents* contents) { + DCHECK(contents); + + BrowserContext* browser_context = contents->GetBrowserContext(); + Profile* profile = Profile::FromBrowserContext(browser_context); + resolve_errors_with_web_service_.Init( + prefs::kAlternateErrorPagesEnabled, + profile->GetPrefs()); + easter_egg_high_score_.Init(prefs::kNetworkEasterEggHighScore, + profile->GetPrefs()); +} + +bool NetErrorTabHelper::ProbesAllowed() const { + if (testing_state_ != TESTING_DEFAULT) + return testing_state_ == TESTING_FORCE_ENABLED; + + // TODO(juliatuttle): Disable on mobile? + return *resolve_errors_with_web_service_; +} + +void NetErrorTabHelper::SendInfo() { + DCHECK_NE(error_page::DNS_PROBE_POSSIBLE, dns_probe_status_); + DCHECK(dns_error_page_committed_); + + DVLOG(1) << "Sending status " << DnsProbeStatusToString(dns_probe_status_); + content::RenderFrameHost* rfh = web_contents()->GetMainFrame(); + + mojo::AssociatedRemote<chrome::mojom::NetworkDiagnosticsClient> client; + rfh->GetRemoteAssociatedInterfaces()->GetInterface(&client); + client->DNSProbeStatus(dns_probe_status_); + + if (!dns_probe_status_snoop_callback_.is_null()) + dns_probe_status_snoop_callback_.Run(dns_probe_status_); +} + +void NetErrorTabHelper::RunNetworkDiagnostics(const GURL& url) { + // Only run diagnostics on HTTP or HTTPS URLs. Shouldn't receive URLs with + // any other schemes, but the renderer is not trusted. + if (!url.is_valid() || !url.SchemeIsHTTPOrHTTPS()) + return; + + // Sanitize URL prior to running diagnostics on it. + RunNetworkDiagnosticsHelper(url.GetOrigin().spec()); +} + +void NetErrorTabHelper::RunNetworkDiagnosticsHelper( + const std::string& sanitized_url) { + // The button shouldn't even be shown in this case, but still best to be safe, + // since the renderer isn't trusted. + if (!CanShowNetworkDiagnosticsDialog(web_contents())) + return; + + if (network_diagnostics_bindings_.GetCurrentTargetFrame() + != web_contents()->GetMainFrame()) { + return; + } + + ShowNetworkDiagnosticsDialog(web_contents(), sanitized_url); +} + +#if BUILDFLAG(ENABLE_OFFLINE_PAGES) +void NetErrorTabHelper::DownloadPageLaterHelper(const GURL& page_url) { + offline_pages::OfflinePageUtils::ScheduleDownload( + web_contents(), offline_pages::kAsyncNamespace, page_url, + offline_pages::OfflinePageUtils::DownloadUIActionFlags::PROMPT_DUPLICATE); +} +#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES) + +void NetErrorTabHelper::GetHighScore(GetHighScoreCallback callback) { + std::move(callback).Run( + static_cast<uint32_t>(easter_egg_high_score_.GetValue())); +} + +void NetErrorTabHelper::UpdateHighScore(uint32_t high_score) { + if (high_score <= static_cast<uint32_t>(easter_egg_high_score_.GetValue())) + return; + easter_egg_high_score_.SetValue(static_cast<int>(high_score)); +} + +void NetErrorTabHelper::ResetHighScore() { + easter_egg_high_score_.SetValue(0); +} + +WEB_CONTENTS_USER_DATA_KEY_IMPL(NetErrorTabHelper) + +} // namespace chrome_browser_net |