blob: 67c79a2e4da7b4013a894bade153a48996a8c721 [file] [log] [blame]
// Copyright 2013 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 <memory>
#include <string>
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
#include "components/error_page/common/error.h"
#include "components/error_page/common/localized_error.h"
#include "components/error_page/common/net_error_info.h"
#include "net/base/net_errors.h"
#include "url/gurl.h"
#if defined(OS_ANDROID)
#include "chrome/renderer/net/available_offline_content_helper.h"
#include "chrome/renderer/net/page_auto_fetcher_helper_android.h"
namespace content {
class RenderFrame;
namespace error_page {
struct ErrorPageParams;
// Class that contains the logic for how the NetErrorHelper. This allows for
// testing the logic without a RenderView or WebFrame, which are difficult to
// mock, and for testing races which are impossible to reliably reproduce
// with real RenderViews or WebFrames.
class NetErrorHelperCore {
enum FrameType {
enum PageType {
enum Button {
SHOW_CACHED_COPY_BUTTON, // "Google cached copy" button label experiment.
DOWNLOAD_BUTTON, // "Download page later" experiment.
// The Delegate handles all interaction with the RenderView, WebFrame, and
// the network, as well as the generation of error pages.
class Delegate {
// Generates an error page's HTML for the given error.
virtual void GenerateLocalizedErrorPage(
const error_page::Error& error,
bool is_failed_post,
bool can_show_network_diagnostics_dialog,
std::unique_ptr<error_page::ErrorPageParams> params,
bool* reload_button_shown,
bool* show_saved_copy_button_shown,
bool* show_cached_copy_button_shown,
bool* download_button_shown,
bool* auto_fetch_allowed,
std::string* html) const = 0;
// Loads the given HTML in the frame for use as an error page.
virtual void LoadErrorPage(const std::string& html,
const GURL& failed_url) = 0;
// Create extra Javascript bindings in the error page. Will only be invoked
// after an error page has finished loading.
virtual void EnablePageHelperFunctions(net::Error net_error) = 0;
// Updates the currently displayed error page with a new error code. The
// currently displayed error page must have finished loading, and must have
// been generated by a call to GenerateLocalizedErrorPage.
virtual void UpdateErrorPage(const error_page::Error& error,
bool is_failed_post,
bool can_show_network_diagnostics_dialog) = 0;
// Tell the currently displayed error page about the user's current easter
// egg game high score (from the user's synced preferences). The currently
// displayed error page must have finished loading, and must have been
// generated by a call to GenerateLocalizedErrorPage.
virtual void InitializeErrorPageEasterEggHighScore(int high_score) = 0;
// Request the current easter egg high score stored in the user's synced
// preferences from the browser. The delegate should call
// OnEasterEggHighScoreReceived() with the response.
virtual void RequestEasterEggHighScore() = 0;
// Fetches an error page and calls into OnErrorPageFetched when done. Any
// previous fetch must either be canceled or finished before calling. Can't
// be called synchronously after a previous fetch completes.
virtual void FetchNavigationCorrections(
const GURL& navigation_correction_url,
const std::string& navigation_correction_request_body) = 0;
// Cancels fetching navigation corrections. Does nothing if no fetch is
// ongoing.
virtual void CancelFetchNavigationCorrections() = 0;
// Sends an HTTP request used to track which link on the page was clicked to
// the navigation correction service.
virtual void SendTrackingRequest(
const GURL& tracking_url,
const std::string& tracking_request_body) = 0;
// Starts a reload of the page in the observed frame.
virtual void ReloadPage(bool bypass_cache) = 0;
// Load the original page from cache.
virtual void LoadPageFromCache(const GURL& page_url) = 0;
// Run the platform diagnostics too for the specified URL.
virtual void DiagnoseError(const GURL& page_url) = 0;
// Schedule to download the page at a later time.
virtual void DownloadPageLater() = 0;
// Inform that download button is being shown in the error page.
virtual void SetIsShowingDownloadButton(bool show) = 0;
// Signals that offline content is available.
virtual void OfflineContentAvailable(
bool list_visible_by_prefs,
const std::string& offline_content_json) = 0;
// Signals that offline content summary is available.
virtual void OfflineContentSummaryAvailable(
const std::string& offline_content_summary_json) = 0;
// Returns the render frame associated with NetErrorHelper.
virtual content::RenderFrame* GetRenderFrame() = 0;
#if defined(OS_ANDROID)
// Called after an attempt to automatically schedule a background fetch for
// a page with a network error.
virtual void SetAutoFetchState(
chrome::mojom::OfflinePageAutoFetcherScheduleResult result) = 0;
virtual ~Delegate() {}
struct NavigationCorrectionParams {
NavigationCorrectionParams(const NavigationCorrectionParams& other);
// URL used both for getting the suggestions and tracking clicks.
GURL url;
std::string language;
std::string country_code;
std::string api_key;
GURL search_url;
NetErrorHelperCore(Delegate* delegate,
bool auto_reload_enabled,
bool auto_reload_visible_only,
bool is_visible);
// Sets values in |pending_error_page_info_|. If |error_html| is not null, it
// initializes |error_html| with the HTML of an error page in response to
// |error|. Updates internals state with the assumption the page will be
// loaded immediately.
void PrepareErrorPage(FrameType frame_type,
const error_page::Error& error,
bool is_failed_post,
bool is_ignoring_cache,
std::string* error_html);
// These methods handle tracking the actual state of the page.
void OnStartLoad(FrameType frame_type, PageType page_type);
void OnCommitLoad(FrameType frame_type, const GURL& url);
void OnFinishLoad(FrameType frame_type);
void OnStop();
void OnWasShown();
void OnWasHidden();
void CancelPendingFetches();
// Called when an error page have has been retrieved over the network. |html|
// must be an empty string on error.
void OnNavigationCorrectionsFetched(const std::string& corrections,
bool is_rtl);
// Notifies |this| that network error information from the browser process
// has been received.
void OnNetErrorInfo(error_page::DnsProbeStatus status);
// Notifies |this| if it can use a local error diagnostics service through its
// delegate.
void OnSetCanShowNetworkDiagnosticsDialog(
bool can_show_network_diagnostics_dialog);
void OnSetNavigationCorrectionInfo(const GURL& navigation_correction_url,
const std::string& language,
const std::string& country_code,
const std::string& api_key,
const GURL& search_url);
// Notifies |this| about the current high score that's saved in the user's
// synced preferences.
void OnEasterEggHighScoreReceived(int high_score);
// Notifies |this| that the network's online status changed.
// Handler for NetworkStateChanged notification from the browser process. If
// the network state changes to online, this method is responsible for
// starting the auto-reload process.
// Warning: if there are many tabs sitting at an error page, this handler will
// be run at the same time for each of their top-level renderframes, which can
// cause many requests to be started at the same time. There's no current
// protection against this kind of "reload storm".
// TODO(rdsmith): prevent the reload storm.
void NetworkStateChanged(bool online);
int auto_reload_count() const { return auto_reload_count_; }
bool ShouldSuppressErrorPage(FrameType frame_type, const GURL& url);
void set_timer_for_testing(std::unique_ptr<base::OneShotTimer> timer) {
auto_reload_timer_ = std::move(timer);
#if defined(OS_ANDROID)
void SetPageAutoFetcherHelperForTesting(
std::unique_ptr<PageAutoFetcherHelper> page_auto_fetcher_helper);
// Execute the effect of pressing the specified button.
// Note that the visual effects of the 'MORE' button are taken
// care of in JavaScript.
void ExecuteButtonPress(Button button);
// Reports to the correction service that the link with the given tracking
// ID was clicked. Only pages generated with information from the service
// have links with tracking IDs. Duplicate requests from the same page with
// the same tracking ID are ignored.
void TrackClick(int tracking_id);
// Opens a suggested offline item.
void LaunchOfflineItem(const std::string& id, const std::string& name_space);
// Shows all available offline content.
void LaunchDownloadsPage();
void CancelSavePage();
void SavePageForLater();
// Signals the user changed the visibility of the offline content list in the
// dino page.
void ListVisibilityChanged(bool is_visible);
struct ErrorPageInfo;
// Sets values in |pending_error_page_info| for a main frame error page. If
// |error_html| is not null, it also fetches the string containing the error
// page HTML, and sets error_html to it. Depending on
// |pending_error_page_info|, may use the navigation correction service, or
// show a DNS probe error page. May modify |pending_error_page_info|.
void PrepareErrorPageForMainFrame(ErrorPageInfo* pending_error_page_info,
std::string* error_html);
// Updates the currently displayed error page with a new error based on the
// most recently received DNS probe result. The page must have finished
// loading before this is called.
void UpdateErrorPage();
error_page::Error GetUpdatedError(const error_page::Error& error) const;
void Reload(bool bypass_cache);
bool MaybeStartAutoReloadTimer();
void StartAutoReloadTimer();
void AutoReloadTimerFired();
void PauseAutoReloadTimer();
static bool IsReloadableError(const ErrorPageInfo& info);
Delegate* delegate_;
// The last DnsProbeStatus received from the browser.
error_page::DnsProbeStatus last_probe_status_;
// Information for the provisional / "pre-provisional" error page. NULL when
// there's no page pending, or the pending page is not an error page.
std::unique_ptr<ErrorPageInfo> pending_error_page_info_;
// Information for the committed error page. NULL when the committed page is
// not an error page.
std::unique_ptr<ErrorPageInfo> committed_error_page_info_;
bool can_show_network_diagnostics_dialog_;
NavigationCorrectionParams navigation_correction_params_;
// True if auto-reload is enabled at all.
const bool auto_reload_enabled_;
// True if auto-reload should only run when the observed frame is visible.
const bool auto_reload_visible_only_;
// Timer used to wait for auto-reload attempts.
std::unique_ptr<base::OneShotTimer> auto_reload_timer_;
// True if the auto-reload timer would be running but is waiting for an
// offline->online network transition.
bool auto_reload_paused_;
// Whether an auto-reload-initiated Reload() attempt is in flight.
bool auto_reload_in_flight_;
// True if there is an uncommitted-but-started load, error page or not. This
// is used to inhibit starting auto-reload when an error page finishes, in
// case this happens:
// Error page starts
// Error page commits
// Non-error page starts
// Error page finishes
bool uncommitted_load_started_;
// Is the browser online?
bool online_;
// Is the RenderFrame this object is observing visible?
bool visible_;
int auto_reload_count_;
// This value is set only when a navigation has been initiated from
// the error page. It is used to detect when such navigations result
// in errors.
Button navigation_from_button_;
#if defined(OS_ANDROID)
AvailableOfflineContentHelper available_content_helper_;
std::unique_ptr<PageAutoFetcherHelper> page_auto_fetcher_helper_;