1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_RENDERER_NET_NET_ERROR_HELPER_CORE_H_
6#define CHROME_RENDERER_NET_NET_ERROR_HELPER_CORE_H_
7
8#include <string>
9
10#include "base/callback.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/memory/weak_ptr.h"
13#include "base/timer/timer.h"
14#include "chrome/common/localized_error.h"
15#include "chrome/common/net/net_error_info.h"
16#include "url/gurl.h"
17
18namespace base {
19class ListValue;
20}
21
22namespace blink {
23struct WebURLError;
24}
25
26// Class that contains the logic for how the NetErrorHelper.  This allows for
27// testing the logic without a RenderView or WebFrame, which are difficult to
28// mock, and for testing races which are impossible to reliably reproduce
29// with real RenderViews or WebFrames.
30class NetErrorHelperCore {
31 public:
32  enum FrameType {
33    MAIN_FRAME,
34    SUB_FRAME,
35  };
36
37  enum PageType {
38    NON_ERROR_PAGE,
39    ERROR_PAGE,
40  };
41
42  enum Button {
43    NO_BUTTON,
44    RELOAD_BUTTON,
45    LOAD_STALE_BUTTON,
46    MORE_BUTTON,
47  };
48
49  // The Delegate handles all interaction with the RenderView, WebFrame, and
50  // the network, as well as the generation of error pages.
51  class Delegate {
52   public:
53    // Generates an error page's HTML for the given error.
54    virtual void GenerateLocalizedErrorPage(
55        const blink::WebURLError& error,
56        bool is_failed_post,
57        scoped_ptr<LocalizedError::ErrorPageParams> params,
58        bool* reload_button_shown,
59        bool* load_stale_button_shown,
60        std::string* html) const = 0;
61
62    // Loads the given HTML in the main frame for use as an error page.
63    virtual void LoadErrorPageInMainFrame(const std::string& html,
64                                          const GURL& failed_url) = 0;
65
66    // Create extra Javascript bindings in the error page.
67    virtual void EnablePageHelperFunctions() = 0;
68
69    // Updates the currently displayed error page with a new error code.  The
70    // currently displayed error page must have finished loading, and must have
71    // been generated by a call to GenerateLocalizedErrorPage.
72    virtual void UpdateErrorPage(const blink::WebURLError& error,
73                                 bool is_failed_post) = 0;
74
75    // Fetches an error page and calls into OnErrorPageFetched when done.  Any
76    // previous fetch must either be canceled or finished before calling.  Can't
77    // be called synchronously after a previous fetch completes.
78    virtual void FetchNavigationCorrections(
79        const GURL& navigation_correction_url,
80        const std::string& navigation_correction_request_body) = 0;
81
82    // Cancels fetching navigation corrections.  Does nothing if no fetch is
83    // ongoing.
84    virtual void CancelFetchNavigationCorrections() = 0;
85
86    // Sends an HTTP request used to track which link on the page was clicked to
87    // the navigation correction service.
88    virtual void SendTrackingRequest(
89        const GURL& tracking_url,
90        const std::string& tracking_request_body) = 0;
91
92    // Starts a reload of the page in the observed frame.
93    virtual void ReloadPage() = 0;
94
95    // Load the original page from cache.
96    virtual void LoadPageFromCache(const GURL& page_url) = 0;
97
98   protected:
99    virtual ~Delegate() {}
100  };
101
102  struct NavigationCorrectionParams {
103    NavigationCorrectionParams();
104    ~NavigationCorrectionParams();
105
106    // URL used both for getting the suggestions and tracking clicks.
107    GURL url;
108
109    std::string language;
110    std::string country_code;
111    std::string api_key;
112    GURL search_url;
113  };
114
115  NetErrorHelperCore(Delegate* delegate,
116                     bool auto_reload_enabled,
117                     bool auto_reload_visible_only,
118                     bool is_visible);
119  ~NetErrorHelperCore();
120
121  // Examines |frame| and |error| to see if this is an error worthy of a DNS
122  // probe.  If it is, initializes |error_strings| based on |error|,
123  // |is_failed_post|, and |locale| with suitable strings and returns true.
124  // If not, returns false, in which case the caller should look up error
125  // strings directly using LocalizedError::GetNavigationErrorStrings.
126  //
127  // Updates the NetErrorHelper with the assumption the page will be loaded
128  // immediately.
129  void GetErrorHTML(FrameType frame_type,
130                    const blink::WebURLError& error,
131                    bool is_failed_post,
132                    std::string* error_html);
133
134  // These methods handle tracking the actual state of the page.
135  void OnStartLoad(FrameType frame_type, PageType page_type);
136  void OnCommitLoad(FrameType frame_type, const GURL& url);
137  void OnFinishLoad(FrameType frame_type);
138  void OnStop();
139  void OnWasShown();
140  void OnWasHidden();
141
142  void CancelPendingFetches();
143
144  // Called when an error page have has been retrieved over the network.  |html|
145  // must be an empty string on error.
146  void OnNavigationCorrectionsFetched(const std::string& corrections,
147                                      const std::string& accept_languages,
148                                      bool is_rtl);
149
150  // Notifies |this| that network error information from the browser process
151  // has been received.
152  void OnNetErrorInfo(chrome_common_net::DnsProbeStatus status);
153
154  void OnSetNavigationCorrectionInfo(const GURL& navigation_correction_url,
155                                     const std::string& language,
156                                     const std::string& country_code,
157                                     const std::string& api_key,
158                                     const GURL& search_url);
159  // Notifies |this| that the network's online status changed.
160  // Handler for NetworkStateChanged notification from the browser process. If
161  // the network state changes to online, this method is responsible for
162  // starting the auto-reload process.
163  //
164  // Warning: if there are many tabs sitting at an error page, this handler will
165  // be run at the same time for each of their top-level renderframes, which can
166  // cause many requests to be started at the same time. There's no current
167  // protection against this kind of "reload storm".
168  //
169  // TODO(rdsmith): prevent the reload storm.
170  void NetworkStateChanged(bool online);
171
172  int auto_reload_count() const { return auto_reload_count_; }
173
174  bool ShouldSuppressErrorPage(FrameType frame_type, const GURL& url);
175
176  void set_timer_for_testing(scoped_ptr<base::Timer> timer) {
177    auto_reload_timer_.reset(timer.release());
178  }
179
180  // Execute the effect of pressing the specified button.
181  // Note that the visual effects of the 'MORE' button are taken
182  // care of in JavaScript.
183  void ExecuteButtonPress(Button button);
184
185  // Reports to the correction service that the link with the given tracking
186  // ID was clicked.  Only pages generated with information from the service
187  // have links with tracking IDs.  Duplicate requests from the same page with
188  // the same tracking ID are ignored.
189  void TrackClick(int tracking_id);
190
191 private:
192  struct ErrorPageInfo;
193
194  // Gets HTML for a main frame error page.  Depending on
195  // |pending_error_page_info|, may use the navigation correction service, or
196  // show a DNS probe error page.  May modify |pending_error_page_info|.
197  void GetErrorHtmlForMainFrame(ErrorPageInfo* pending_error_page_info,
198                                std::string* error_html);
199
200  // Updates the currently displayed error page with a new error based on the
201  // most recently received DNS probe result.  The page must have finished
202  // loading before this is called.
203  void UpdateErrorPage();
204
205  blink::WebURLError GetUpdatedError(const blink::WebURLError& error) const;
206
207  void Reload();
208  bool MaybeStartAutoReloadTimer();
209  void StartAutoReloadTimer();
210  void AutoReloadTimerFired();
211  void PauseAutoReloadTimer();
212
213  static bool IsReloadableError(const ErrorPageInfo& info);
214
215  Delegate* delegate_;
216
217  // The last DnsProbeStatus received from the browser.
218  chrome_common_net::DnsProbeStatus last_probe_status_;
219
220  // Information for the provisional / "pre-provisional" error page.  NULL when
221  // there's no page pending, or the pending page is not an error page.
222  scoped_ptr<ErrorPageInfo> pending_error_page_info_;
223
224  // Information for the committed error page.  NULL when the committed page is
225  // not an error page.
226  scoped_ptr<ErrorPageInfo> committed_error_page_info_;
227
228  NavigationCorrectionParams navigation_correction_params_;
229
230  // True if auto-reload is enabled at all.
231  const bool auto_reload_enabled_;
232
233  // True if auto-reload should only run when the observed frame is visible.
234  const bool auto_reload_visible_only_;
235
236  // Timer used to wait for auto-reload attempts.
237  scoped_ptr<base::Timer> auto_reload_timer_;
238
239  // True if the auto-reload timer would be running but is waiting for an
240  // offline->online network transition.
241  bool auto_reload_paused_;
242
243  // True if there is an uncommitted-but-started load, error page or not. This
244  // is used to inhibit starting auto-reload when an error page finishes, in
245  // case this happens:
246  //   Error page starts
247  //   Error page commits
248  //   Non-error page starts
249  //   Error page finishes
250  bool uncommitted_load_started_;
251
252  // Is the browser online?
253  bool online_;
254
255  // Is the RenderFrame this object is observing visible?
256  bool visible_;
257
258  int auto_reload_count_;
259
260  // This value is set only when a navigation has been initiated from
261  // the error page.  It is used to detect when such navigations result
262  // in errors.
263  Button navigation_from_button_;
264};
265
266#endif  // CHROME_RENDERER_NET_NET_ERROR_HELPER_CORE_H_
267