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"
9 #include "base/json/json_writer.h"
10 #include "base/metrics/histogram.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/values.h"
13 #include "chrome/common/localized_error.h"
14 #include "chrome/common/net/net_error_info.h"
15 #include "chrome/common/render_messages.h"
16 #include "content/public/common/content_client.h"
17 #include "content/public/common/url_constants.h"
18 #include "content/public/renderer/content_renderer_client.h"
19 #include "content/public/renderer/render_thread.h"
20 #include "content/public/renderer/render_view.h"
21 #include "content/public/renderer/resource_fetcher.h"
22 #include "grit/renderer_resources.h"
23 #include "ipc/ipc_message.h"
24 #include "ipc/ipc_message_macros.h"
25 #include "third_party/WebKit/public/platform/WebURL.h"
26 #include "third_party/WebKit/public/platform/WebURLError.h"
27 #include "third_party/WebKit/public/platform/WebURLRequest.h"
28 #include "third_party/WebKit/public/platform/WebURLResponse.h"
29 #include "third_party/WebKit/public/web/WebDataSource.h"
30 #include "third_party/WebKit/public/web/WebFrame.h"
31 #include "third_party/WebKit/public/web/WebView.h"
32 #include "ui/base/resource/resource_bundle.h"
33 #include "ui/base/webui/jstemplate_builder.h"
36 using base::JSONWriter;
37 using chrome_common_net::DnsProbeStatus;
38 using chrome_common_net::DnsProbeStatusToString;
39 using content::RenderThread;
40 using content::RenderView;
41 using content::RenderViewObserver;
42 using content::kUnreachableWebDataURL;
46 // Number of seconds to wait for the alternate error page server. If it takes
47 // too long, just use the local error page.
48 static const int kAlterErrorPageFetchTimeoutSec = 3000;
50 NetErrorHelperCore::PageType GetLoadingPageType(const blink::WebFrame* frame) {
51 GURL url = frame->provisionalDataSource()->request().url();
52 if (!url.is_valid() || url.spec() != kUnreachableWebDataURL)
53 return NetErrorHelperCore::NON_ERROR_PAGE;
54 return NetErrorHelperCore::ERROR_PAGE;
57 NetErrorHelperCore::FrameType GetFrameType(const blink::WebFrame* frame) {
59 return NetErrorHelperCore::MAIN_FRAME;
60 return NetErrorHelperCore::SUB_FRAME;
65 NetErrorHelper::NetErrorHelper(RenderView* render_view)
66 : RenderViewObserver(render_view),
67 content::RenderViewObserverTracker<NetErrorHelper>(render_view),
71 NetErrorHelper::~NetErrorHelper() {
74 void NetErrorHelper::DidStartProvisionalLoad(blink::WebFrame* frame) {
75 core_.OnStartLoad(GetFrameType(frame), GetLoadingPageType(frame));
78 void NetErrorHelper::DidCommitProvisionalLoad(blink::WebFrame* frame,
79 bool is_new_navigation) {
80 core_.OnCommitLoad(GetFrameType(frame));
83 void NetErrorHelper::DidFinishLoad(blink::WebFrame* frame) {
84 core_.OnFinishLoad(GetFrameType(frame));
87 void NetErrorHelper::OnStop() {
91 bool NetErrorHelper::OnMessageReceived(const IPC::Message& message) {
94 IPC_BEGIN_MESSAGE_MAP(NetErrorHelper, message)
95 IPC_MESSAGE_HANDLER(ChromeViewMsg_NetErrorInfo, OnNetErrorInfo)
96 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetAltErrorPageURL, OnSetAltErrorPageURL);
97 IPC_MESSAGE_UNHANDLED(handled = false)
103 void NetErrorHelper::GetErrorHTML(
104 blink::WebFrame* frame,
105 const blink::WebURLError& error,
107 std::string* error_html) {
108 core_.GetErrorHTML(GetFrameType(frame), error, is_failed_post, error_html);
111 void NetErrorHelper::GenerateLocalizedErrorPage(const blink::WebURLError& error,
113 std::string* error_html) const {
116 int resource_id = IDR_NET_ERROR_HTML;
117 const base::StringPiece template_html(
118 ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id));
119 if (template_html.empty()) {
120 NOTREACHED() << "unable to load template.";
122 base::DictionaryValue error_strings;
123 LocalizedError::GetStrings(error.reason, error.domain.utf8(),
124 error.unreachableURL, is_failed_post,
125 RenderThread::Get()->GetLocale(),
126 render_view()->GetAcceptLanguages(),
128 // "t" is the id of the template's root node.
129 *error_html = webui::GetTemplatesHtml(template_html, &error_strings, "t");
133 void NetErrorHelper::LoadErrorPageInMainFrame(const std::string& html,
134 const GURL& failed_url) {
135 blink::WebView* web_view = render_view()->GetWebView();
138 blink::WebFrame* frame = web_view->mainFrame();
139 frame->loadHTMLString(html, GURL(kUnreachableWebDataURL), failed_url, true);
142 void NetErrorHelper::UpdateErrorPage(const blink::WebURLError& error,
143 bool is_failed_post) {
144 base::DictionaryValue error_strings;
145 LocalizedError::GetStrings(error.reason,
147 error.unreachableURL,
149 RenderThread::Get()->GetLocale(),
150 render_view()->GetAcceptLanguages(),
154 JSONWriter::Write(&error_strings, &json);
156 std::string js = "if (window.updateForDnsProbe) "
157 "updateForDnsProbe(" + json + ");";
159 if (!base::UTF8ToUTF16(js.c_str(), js.length(), &js16)) {
164 base::string16 frame_xpath;
165 render_view()->EvaluateScript(frame_xpath, js16, 0, false);
168 void NetErrorHelper::FetchErrorPage(const GURL& url) {
169 DCHECK(!alt_error_page_fetcher_.get());
171 blink::WebView* web_view = render_view()->GetWebView();
174 blink::WebFrame* frame = web_view->mainFrame();
176 alt_error_page_fetcher_.reset(
177 content::ResourceFetcher::Create(
178 url, frame, blink::WebURLRequest::TargetIsMainFrame,
179 base::Bind(&NetErrorHelper::OnAlternateErrorPageRetrieved,
180 base::Unretained(this))));
182 alt_error_page_fetcher_->SetTimeout(
183 base::TimeDelta::FromSeconds(kAlterErrorPageFetchTimeoutSec));
186 void NetErrorHelper::CancelFetchErrorPage() {
187 alt_error_page_fetcher_.reset();
190 void NetErrorHelper::OnNetErrorInfo(int status_num) {
191 DCHECK(status_num >= 0 && status_num < chrome_common_net::DNS_PROBE_MAX);
193 DVLOG(1) << "Received status " << DnsProbeStatusToString(status_num);
195 core_.OnNetErrorInfo(static_cast<DnsProbeStatus>(status_num));
198 void NetErrorHelper::OnSetAltErrorPageURL(const GURL& alt_error_page_url) {
199 core_.set_alt_error_page_url(alt_error_page_url);
202 void NetErrorHelper::OnAlternateErrorPageRetrieved(
203 const blink::WebURLResponse& response,
204 const std::string& data) {
205 // The fetcher may only be deleted after |data| is passed to |core_|. Move
206 // it to a temporary to prevent any potential re-entrancy issues.
207 scoped_ptr<content::ResourceFetcher> fetcher(
208 alt_error_page_fetcher_.release());
209 if (!response.isNull() && response.httpStatusCode() == 200) {
210 core_.OnAlternateErrorPageFetched(data);
212 core_.OnAlternateErrorPageFetched("");