Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / renderer / net / net_error_helper.cc
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.
4
5 #include "chrome/renderer/net/net_error_helper.h"
6
7 #include <string>
8
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/grit/renderer_resources.h"
20 #include "chrome/renderer/net/net_error_page_controller.h"
21 #include "content/public/common/content_client.h"
22 #include "content/public/common/url_constants.h"
23 #include "content/public/renderer/content_renderer_client.h"
24 #include "content/public/renderer/document_state.h"
25 #include "content/public/renderer/render_frame.h"
26 #include "content/public/renderer/render_thread.h"
27 #include "content/public/renderer/render_view.h"
28 #include "content/public/renderer/resource_fetcher.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/WebLocalFrame.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"
42
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;
51
52 namespace {
53
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;
57
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;
63 }
64
65 NetErrorHelperCore::FrameType GetFrameType(const blink::WebFrame* frame) {
66   if (!frame->parent())
67     return NetErrorHelperCore::MAIN_FRAME;
68   return NetErrorHelperCore::SUB_FRAME;
69 }
70
71 }  // namespace
72
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()));
86 }
87
88 NetErrorHelper::~NetErrorHelper() {
89   RenderThread::Get()->RemoveObserver(this);
90 }
91
92 void NetErrorHelper::ReloadButtonPressed() {
93   core_->ExecuteButtonPress(NetErrorHelperCore::RELOAD_BUTTON);
94 }
95
96 void NetErrorHelper::LoadStaleButtonPressed() {
97   core_->ExecuteButtonPress(NetErrorHelperCore::LOAD_STALE_BUTTON);
98 }
99
100 void NetErrorHelper::MoreButtonPressed() {
101   core_->ExecuteButtonPress(NetErrorHelperCore::MORE_BUTTON);
102 }
103
104 void NetErrorHelper::DidStartProvisionalLoad() {
105   blink::WebFrame* frame = render_frame()->GetWebFrame();
106   core_->OnStartLoad(GetFrameType(frame), GetLoadingPageType(frame));
107 }
108
109 void NetErrorHelper::DidCommitProvisionalLoad(bool is_new_navigation) {
110   blink::WebFrame* frame = render_frame()->GetWebFrame();
111   core_->OnCommitLoad(GetFrameType(frame), frame->document().url());
112 }
113
114 void NetErrorHelper::DidFinishLoad() {
115   blink::WebFrame* frame = render_frame()->GetWebFrame();
116   core_->OnFinishLoad(GetFrameType(frame));
117 }
118
119 void NetErrorHelper::OnStop() {
120   core_->OnStop();
121 }
122
123 void NetErrorHelper::WasShown() {
124   core_->OnWasShown();
125 }
126
127 void NetErrorHelper::WasHidden() {
128   core_->OnWasHidden();
129 }
130
131 bool NetErrorHelper::OnMessageReceived(const IPC::Message& message) {
132   bool handled = true;
133
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()
140
141   return handled;
142 }
143
144 void NetErrorHelper::NetworkStateChanged(bool enabled) {
145   core_->NetworkStateChanged(enabled);
146 }
147
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);
154 }
155
156 bool NetErrorHelper::ShouldSuppressErrorPage(blink::WebFrame* frame,
157                                              const GURL& url) {
158   return core_->ShouldSuppressErrorPage(GetFrameType(frame), url);
159 }
160
161 void NetErrorHelper::TrackClick(int tracking_id) {
162   core_->TrackClick(tracking_id);
163 }
164
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();
173
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);
183
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);
195
196     // "t" is the id of the template's root node.
197     *error_html = webui::GetTemplatesHtml(template_html, &error_strings, "t");
198   }
199 }
200
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);
208 }
209
210 void NetErrorHelper::EnablePageHelperFunctions() {
211   NetErrorPageController::Install(render_frame());
212 }
213
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);
219
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);
232
233   std::string json;
234   JSONWriter::Write(&error_strings, &json);
235
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;
242   }
243
244   render_frame()->ExecuteJavaScript(js16);
245 }
246
247 void NetErrorHelper::FetchNavigationCorrections(
248     const GURL& navigation_correction_url,
249     const std::string& navigation_correction_request_body) {
250   DCHECK(!correction_fetcher_.get());
251
252   blink::WebView* web_view = render_frame()->GetRenderView()->GetWebView();
253   if (!web_view)
254     return;
255   blink::WebFrame* frame = web_view->mainFrame();
256
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
263   correction_fetcher_->Start(
264       frame,
265       blink::WebURLRequest::RequestContextInternal,
266       blink::WebURLRequest::FrameTypeTopLevel,
267       content::ResourceFetcher::PLATFORM_LOADER,
268       base::Bind(&NetErrorHelper::OnNavigationCorrectionsFetched,
269                  base::Unretained(this)));
270
271   correction_fetcher_->SetTimeout(
272       base::TimeDelta::FromSeconds(kNavigationCorrectionFetchTimeoutSec));
273 }
274
275 void NetErrorHelper::CancelFetchNavigationCorrections() {
276   correction_fetcher_.reset();
277 }
278
279 void NetErrorHelper::SendTrackingRequest(
280     const GURL& tracking_url,
281     const std::string& tracking_request_body) {
282   blink::WebView* web_view = render_frame()->GetRenderView()->GetWebView();
283   if (!web_view)
284     return;
285   blink::WebFrame* frame = web_view->mainFrame();
286
287   // If there's already a pending tracking request, this will cancel it.
288   tracking_fetcher_.reset(content::ResourceFetcher::Create(tracking_url));
289   tracking_fetcher_->SetMethod("POST");
290   tracking_fetcher_->SetBody(tracking_request_body);
291   tracking_fetcher_->SetHeader("Content-Type", "application/json");
292
293   tracking_fetcher_->Start(
294       frame,
295       blink::WebURLRequest::RequestContextInternal,
296       blink::WebURLRequest::FrameTypeTopLevel,
297       content::ResourceFetcher::PLATFORM_LOADER,
298       base::Bind(&NetErrorHelper::OnTrackingRequestComplete,
299                  base::Unretained(this)));
300 }
301
302 void NetErrorHelper::ReloadPage() {
303   render_frame()->GetWebFrame()->reload(false);
304 }
305
306 void NetErrorHelper::LoadPageFromCache(const GURL& page_url) {
307   blink::WebFrame* web_frame = render_frame()->GetWebFrame();
308   DCHECK(!EqualsASCII(web_frame->dataSource()->request().httpMethod(), "POST"));
309
310   blink::WebURLRequest request(page_url);
311   request.setCachePolicy(blink::WebURLRequest::ReturnCacheDataDontLoad);
312
313   web_frame->loadRequest(request);
314 }
315
316 void NetErrorHelper::OnNetErrorInfo(int status_num) {
317   DCHECK(status_num >= 0 && status_num < chrome_common_net::DNS_PROBE_MAX);
318
319   DVLOG(1) << "Received status " << DnsProbeStatusToString(status_num);
320
321   core_->OnNetErrorInfo(static_cast<DnsProbeStatus>(status_num));
322 }
323
324 void NetErrorHelper::OnSetNavigationCorrectionInfo(
325     const GURL& navigation_correction_url,
326     const std::string& language,
327     const std::string& country_code,
328     const std::string& api_key,
329     const GURL& search_url) {
330   core_->OnSetNavigationCorrectionInfo(navigation_correction_url, language,
331                                       country_code, api_key, search_url);
332 }
333
334 void NetErrorHelper::OnNavigationCorrectionsFetched(
335     const blink::WebURLResponse& response,
336     const std::string& data) {
337   // The fetcher may only be deleted after |data| is passed to |core_|.  Move
338   // it to a temporary to prevent any potential re-entrancy issues.
339   scoped_ptr<content::ResourceFetcher> fetcher(
340       correction_fetcher_.release());
341   bool success = (!response.isNull() && response.httpStatusCode() == 200);
342   core_->OnNavigationCorrectionsFetched(
343       success ? data : "",
344       render_frame()->GetRenderView()->GetAcceptLanguages(),
345       base::i18n::IsRTL());
346 }
347
348 void NetErrorHelper::OnTrackingRequestComplete(
349     const blink::WebURLResponse& response,
350     const std::string& data) {
351   tracking_fetcher_.reset();
352 }