Add a FrameHostMsg_BeginNavigation IPC
[chromium-blink-merge.git] / chrome / renderer / net / net_error_helper.cc
blob315c7872cf614e407c6f17459807e72473677925
1 // Copyright (c) 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.
5 #include "chrome/renderer/net/net_error_helper.h"
7 #include <string>
9 #include "base/command_line.h"
10 #include "base/i18n/rtl.h"
11 #include "base/json/json_writer.h"
12 #include "base/metrics/histogram.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/values.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "chrome/common/localized_error.h"
17 #include "chrome/common/net/net_error_info.h"
18 #include "chrome/common/render_messages.h"
19 #include "chrome/renderer/net/net_error_page_controller.h"
20 #include "content/public/common/content_client.h"
21 #include "content/public/common/url_constants.h"
22 #include "content/public/renderer/content_renderer_client.h"
23 #include "content/public/renderer/document_state.h"
24 #include "content/public/renderer/render_frame.h"
25 #include "content/public/renderer/render_thread.h"
26 #include "content/public/renderer/render_view.h"
27 #include "content/public/renderer/resource_fetcher.h"
28 #include "grit/renderer_resources.h"
29 #include "ipc/ipc_message.h"
30 #include "ipc/ipc_message_macros.h"
31 #include "third_party/WebKit/public/platform/WebURL.h"
32 #include "third_party/WebKit/public/platform/WebURLError.h"
33 #include "third_party/WebKit/public/platform/WebURLRequest.h"
34 #include "third_party/WebKit/public/platform/WebURLResponse.h"
35 #include "third_party/WebKit/public/web/WebDataSource.h"
36 #include "third_party/WebKit/public/web/WebDocument.h"
37 #include "third_party/WebKit/public/web/WebFrame.h"
38 #include "third_party/WebKit/public/web/WebView.h"
39 #include "ui/base/resource/resource_bundle.h"
40 #include "ui/base/webui/jstemplate_builder.h"
41 #include "url/gurl.h"
43 using base::JSONWriter;
44 using chrome_common_net::DnsProbeStatus;
45 using chrome_common_net::DnsProbeStatusToString;
46 using content::DocumentState;
47 using content::RenderFrame;
48 using content::RenderFrameObserver;
49 using content::RenderThread;
50 using content::kUnreachableWebDataURL;
52 namespace {
54 // Number of seconds to wait for the navigation correction service to return
55 // suggestions. If it takes too long, just use the local error page.
56 static const int kNavigationCorrectionFetchTimeoutSec = 3;
58 NetErrorHelperCore::PageType GetLoadingPageType(const blink::WebFrame* frame) {
59 GURL url = frame->provisionalDataSource()->request().url();
60 if (!url.is_valid() || url.spec() != kUnreachableWebDataURL)
61 return NetErrorHelperCore::NON_ERROR_PAGE;
62 return NetErrorHelperCore::ERROR_PAGE;
65 NetErrorHelperCore::FrameType GetFrameType(const blink::WebFrame* frame) {
66 if (!frame->parent())
67 return NetErrorHelperCore::MAIN_FRAME;
68 return NetErrorHelperCore::SUB_FRAME;
71 } // namespace
73 NetErrorHelper::NetErrorHelper(RenderFrame* render_frame)
74 : RenderFrameObserver(render_frame),
75 content::RenderFrameObserverTracker<NetErrorHelper>(render_frame) {
76 RenderThread::Get()->AddObserver(this);
77 CommandLine* command_line = CommandLine::ForCurrentProcess();
78 bool auto_reload_enabled =
79 command_line->HasSwitch(switches::kEnableOfflineAutoReload);
80 bool auto_reload_visible_only =
81 command_line->HasSwitch(switches::kEnableOfflineAutoReloadVisibleOnly);
82 core_.reset(new NetErrorHelperCore(this,
83 auto_reload_enabled,
84 auto_reload_visible_only,
85 !render_frame->IsHidden()));
88 NetErrorHelper::~NetErrorHelper() {
89 RenderThread::Get()->RemoveObserver(this);
92 void NetErrorHelper::ReloadButtonPressed() {
93 core_->ExecuteButtonPress(NetErrorHelperCore::RELOAD_BUTTON);
96 void NetErrorHelper::LoadStaleButtonPressed() {
97 core_->ExecuteButtonPress(NetErrorHelperCore::LOAD_STALE_BUTTON);
100 void NetErrorHelper::MoreButtonPressed() {
101 core_->ExecuteButtonPress(NetErrorHelperCore::MORE_BUTTON);
104 void NetErrorHelper::DidStartProvisionalLoad() {
105 blink::WebFrame* frame = render_frame()->GetWebFrame();
106 core_->OnStartLoad(GetFrameType(frame), GetLoadingPageType(frame));
109 void NetErrorHelper::DidCommitProvisionalLoad(bool is_new_navigation) {
110 blink::WebFrame* frame = render_frame()->GetWebFrame();
111 core_->OnCommitLoad(GetFrameType(frame), frame->document().url());
114 void NetErrorHelper::DidFinishLoad() {
115 blink::WebFrame* frame = render_frame()->GetWebFrame();
116 core_->OnFinishLoad(GetFrameType(frame));
119 void NetErrorHelper::OnStop() {
120 core_->OnStop();
123 void NetErrorHelper::WasShown() {
124 core_->OnWasShown();
127 void NetErrorHelper::WasHidden() {
128 core_->OnWasHidden();
131 bool NetErrorHelper::OnMessageReceived(const IPC::Message& message) {
132 bool handled = true;
134 IPC_BEGIN_MESSAGE_MAP(NetErrorHelper, message)
135 IPC_MESSAGE_HANDLER(ChromeViewMsg_NetErrorInfo, OnNetErrorInfo)
136 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetNavigationCorrectionInfo,
137 OnSetNavigationCorrectionInfo);
138 IPC_MESSAGE_UNHANDLED(handled = false)
139 IPC_END_MESSAGE_MAP()
141 return handled;
144 void NetErrorHelper::NetworkStateChanged(bool enabled) {
145 core_->NetworkStateChanged(enabled);
148 void NetErrorHelper::GetErrorHTML(
149 blink::WebFrame* frame,
150 const blink::WebURLError& error,
151 bool is_failed_post,
152 std::string* error_html) {
153 core_->GetErrorHTML(GetFrameType(frame), error, is_failed_post, error_html);
156 bool NetErrorHelper::ShouldSuppressErrorPage(blink::WebFrame* frame,
157 const GURL& url) {
158 return core_->ShouldSuppressErrorPage(GetFrameType(frame), url);
161 void NetErrorHelper::TrackClick(int tracking_id) {
162 core_->TrackClick(tracking_id);
165 void NetErrorHelper::GenerateLocalizedErrorPage(
166 const blink::WebURLError& error,
167 bool is_failed_post,
168 scoped_ptr<LocalizedError::ErrorPageParams> params,
169 bool* reload_button_shown,
170 bool* load_stale_button_shown,
171 std::string* error_html) const {
172 error_html->clear();
174 int resource_id = IDR_NET_ERROR_HTML;
175 const base::StringPiece template_html(
176 ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id));
177 if (template_html.empty()) {
178 NOTREACHED() << "unable to load template.";
179 } else {
180 CommandLine* command_line = CommandLine::ForCurrentProcess();
181 bool load_stale_cache_enabled =
182 command_line->HasSwitch(switches::kEnableOfflineLoadStaleCache);
184 base::DictionaryValue error_strings;
185 LocalizedError::GetStrings(error.reason, error.domain.utf8(),
186 error.unreachableURL, is_failed_post,
187 (load_stale_cache_enabled &&
188 error.staleCopyInCache && !is_failed_post),
189 RenderThread::Get()->GetLocale(),
190 render_frame()->GetRenderView()->
191 GetAcceptLanguages(),
192 params.Pass(), &error_strings);
193 *reload_button_shown = error_strings.Get("reloadButton", NULL);
194 *load_stale_button_shown = error_strings.Get("staleLoadButton", NULL);
196 // "t" is the id of the template's root node.
197 *error_html = webui::GetTemplatesHtml(template_html, &error_strings, "t");
201 void NetErrorHelper::LoadErrorPageInMainFrame(const std::string& html,
202 const GURL& failed_url) {
203 blink::WebView* web_view = render_frame()->GetRenderView()->GetWebView();
204 if (!web_view)
205 return;
206 blink::WebFrame* frame = web_view->mainFrame();
207 frame->loadHTMLString(html, GURL(kUnreachableWebDataURL), failed_url, true);
210 void NetErrorHelper::EnablePageHelperFunctions() {
211 NetErrorPageController::Install(render_frame());
214 void NetErrorHelper::UpdateErrorPage(const blink::WebURLError& error,
215 bool is_failed_post) {
216 CommandLine* command_line = CommandLine::ForCurrentProcess();
217 bool load_stale_cache_enabled =
218 command_line->HasSwitch(switches::kEnableOfflineLoadStaleCache);
220 base::DictionaryValue error_strings;
221 LocalizedError::GetStrings(error.reason,
222 error.domain.utf8(),
223 error.unreachableURL,
224 is_failed_post,
225 (load_stale_cache_enabled &&
226 error.staleCopyInCache && !is_failed_post),
227 RenderThread::Get()->GetLocale(),
228 render_frame()->GetRenderView()->
229 GetAcceptLanguages(),
230 scoped_ptr<LocalizedError::ErrorPageParams>(),
231 &error_strings);
233 std::string json;
234 JSONWriter::Write(&error_strings, &json);
236 std::string js = "if (window.updateForDnsProbe) "
237 "updateForDnsProbe(" + json + ");";
238 base::string16 js16;
239 if (!base::UTF8ToUTF16(js.c_str(), js.length(), &js16)) {
240 NOTREACHED();
241 return;
244 render_frame()->ExecuteJavaScript(js16);
247 void NetErrorHelper::FetchNavigationCorrections(
248 const GURL& navigation_correction_url,
249 const std::string& navigation_correction_request_body) {
250 DCHECK(!correction_fetcher_.get());
252 blink::WebView* web_view = render_frame()->GetRenderView()->GetWebView();
253 if (!web_view)
254 return;
255 blink::WebFrame* frame = web_view->mainFrame();
257 correction_fetcher_.reset(
258 content::ResourceFetcher::Create(navigation_correction_url));
259 correction_fetcher_->SetMethod("POST");
260 correction_fetcher_->SetBody(navigation_correction_request_body);
261 correction_fetcher_->SetHeader("Content-Type", "application/json");
262 correction_fetcher_->Start(
263 frame, blink::WebURLRequest::TargetIsMainFrame,
264 base::Bind(&NetErrorHelper::OnNavigationCorrectionsFetched,
265 base::Unretained(this)));
267 correction_fetcher_->SetTimeout(
268 base::TimeDelta::FromSeconds(kNavigationCorrectionFetchTimeoutSec));
271 void NetErrorHelper::CancelFetchNavigationCorrections() {
272 correction_fetcher_.reset();
275 void NetErrorHelper::SendTrackingRequest(
276 const GURL& tracking_url,
277 const std::string& tracking_request_body) {
278 blink::WebView* web_view = render_frame()->GetRenderView()->GetWebView();
279 if (!web_view)
280 return;
281 blink::WebFrame* frame = web_view->mainFrame();
283 // If there's already a pending tracking request, this will cancel it.
284 tracking_fetcher_.reset(content::ResourceFetcher::Create(tracking_url));
285 tracking_fetcher_->SetMethod("POST");
286 tracking_fetcher_->SetBody(tracking_request_body);
287 tracking_fetcher_->SetHeader("Content-Type", "application/json");
288 tracking_fetcher_->Start(
289 frame, blink::WebURLRequest::TargetIsMainFrame,
290 base::Bind(&NetErrorHelper::OnTrackingRequestComplete,
291 base::Unretained(this)));
294 void NetErrorHelper::ReloadPage() {
295 render_frame()->GetWebFrame()->reload(false);
298 void NetErrorHelper::LoadPageFromCache(const GURL& page_url) {
299 blink::WebFrame* web_frame = render_frame()->GetWebFrame();
300 DCHECK(!EqualsASCII(web_frame->dataSource()->request().httpMethod(), "POST"));
302 blink::WebURLRequest request(page_url);
303 request.setCachePolicy(blink::WebURLRequest::ReturnCacheDataDontLoad);
305 web_frame->loadRequest(request);
308 void NetErrorHelper::OnNetErrorInfo(int status_num) {
309 DCHECK(status_num >= 0 && status_num < chrome_common_net::DNS_PROBE_MAX);
311 DVLOG(1) << "Received status " << DnsProbeStatusToString(status_num);
313 core_->OnNetErrorInfo(static_cast<DnsProbeStatus>(status_num));
316 void NetErrorHelper::OnSetNavigationCorrectionInfo(
317 const GURL& navigation_correction_url,
318 const std::string& language,
319 const std::string& country_code,
320 const std::string& api_key,
321 const GURL& search_url) {
322 core_->OnSetNavigationCorrectionInfo(navigation_correction_url, language,
323 country_code, api_key, search_url);
326 void NetErrorHelper::OnNavigationCorrectionsFetched(
327 const blink::WebURLResponse& response,
328 const std::string& data) {
329 // The fetcher may only be deleted after |data| is passed to |core_|. Move
330 // it to a temporary to prevent any potential re-entrancy issues.
331 scoped_ptr<content::ResourceFetcher> fetcher(
332 correction_fetcher_.release());
333 bool success = (!response.isNull() && response.httpStatusCode() == 200);
334 core_->OnNavigationCorrectionsFetched(
335 success ? data : "",
336 render_frame()->GetRenderView()->GetAcceptLanguages(),
337 base::i18n::IsRTL());
340 void NetErrorHelper::OnTrackingRequestComplete(
341 const blink::WebURLResponse& response,
342 const std::string& data) {
343 tracking_fetcher_.reset();