#include <string>
+#include "base/command_line.h"
+#include "base/i18n/rtl.h"
#include "base/json/json_writer.h"
#include "base/metrics/histogram.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/localized_error.h"
#include "chrome/common/net/net_error_info.h"
#include "chrome/common/render_messages.h"
+#include "chrome/grit/renderer_resources.h"
+#include "chrome/renderer/net/net_error_page_controller.h"
#include "content/public/common/content_client.h"
#include "content/public/common/url_constants.h"
#include "content/public/renderer/content_renderer_client.h"
+#include "content/public/renderer/document_state.h"
+#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/render_view.h"
#include "content/public/renderer/resource_fetcher.h"
-#include "grit/renderer_resources.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_macros.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
#include "third_party/WebKit/public/web/WebDataSource.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebView.h"
#include "ui/base/resource/resource_bundle.h"
using base::JSONWriter;
using chrome_common_net::DnsProbeStatus;
using chrome_common_net::DnsProbeStatusToString;
+using content::DocumentState;
+using content::RenderFrame;
+using content::RenderFrameObserver;
using content::RenderThread;
-using content::RenderView;
-using content::RenderViewObserver;
using content::kUnreachableWebDataURL;
namespace {
-// Number of seconds to wait for the alternate error page server. If it takes
-// too long, just use the local error page.
-static const int kAlterErrorPageFetchTimeoutSec = 3000;
+// Number of seconds to wait for the navigation correction service to return
+// suggestions. If it takes too long, just use the local error page.
+static const int kNavigationCorrectionFetchTimeoutSec = 3;
NetErrorHelperCore::PageType GetLoadingPageType(const blink::WebFrame* frame) {
GURL url = frame->provisionalDataSource()->request().url();
} // namespace
-NetErrorHelper::NetErrorHelper(RenderView* render_view)
- : RenderViewObserver(render_view),
- content::RenderViewObserverTracker<NetErrorHelper>(render_view),
- core_(this) {
+NetErrorHelper::NetErrorHelper(RenderFrame* render_frame)
+ : RenderFrameObserver(render_frame),
+ content::RenderFrameObserverTracker<NetErrorHelper>(render_frame) {
+ RenderThread::Get()->AddObserver(this);
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ bool auto_reload_enabled =
+ command_line->HasSwitch(switches::kEnableOfflineAutoReload);
+ bool auto_reload_visible_only =
+ command_line->HasSwitch(switches::kEnableOfflineAutoReloadVisibleOnly);
+ core_.reset(new NetErrorHelperCore(this,
+ auto_reload_enabled,
+ auto_reload_visible_only,
+ !render_frame->IsHidden()));
}
NetErrorHelper::~NetErrorHelper() {
+ RenderThread::Get()->RemoveObserver(this);
}
-void NetErrorHelper::DidStartProvisionalLoad(blink::WebFrame* frame) {
- core_.OnStartLoad(GetFrameType(frame), GetLoadingPageType(frame));
+void NetErrorHelper::ReloadButtonPressed() {
+ core_->ExecuteButtonPress(NetErrorHelperCore::RELOAD_BUTTON);
}
-void NetErrorHelper::DidCommitProvisionalLoad(blink::WebFrame* frame,
- bool is_new_navigation) {
- core_.OnCommitLoad(GetFrameType(frame));
+void NetErrorHelper::LoadStaleButtonPressed() {
+ core_->ExecuteButtonPress(NetErrorHelperCore::LOAD_STALE_BUTTON);
}
-void NetErrorHelper::DidFinishLoad(blink::WebFrame* frame) {
- core_.OnFinishLoad(GetFrameType(frame));
+void NetErrorHelper::MoreButtonPressed() {
+ core_->ExecuteButtonPress(NetErrorHelperCore::MORE_BUTTON);
+}
+
+void NetErrorHelper::DidStartProvisionalLoad() {
+ blink::WebFrame* frame = render_frame()->GetWebFrame();
+ core_->OnStartLoad(GetFrameType(frame), GetLoadingPageType(frame));
+}
+
+void NetErrorHelper::DidCommitProvisionalLoad(bool is_new_navigation) {
+ blink::WebFrame* frame = render_frame()->GetWebFrame();
+ core_->OnCommitLoad(GetFrameType(frame), frame->document().url());
+}
+
+void NetErrorHelper::DidFinishLoad() {
+ blink::WebFrame* frame = render_frame()->GetWebFrame();
+ core_->OnFinishLoad(GetFrameType(frame));
}
void NetErrorHelper::OnStop() {
- core_.OnStop();
+ core_->OnStop();
+}
+
+void NetErrorHelper::WasShown() {
+ core_->OnWasShown();
+}
+
+void NetErrorHelper::WasHidden() {
+ core_->OnWasHidden();
}
bool NetErrorHelper::OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(NetErrorHelper, message)
IPC_MESSAGE_HANDLER(ChromeViewMsg_NetErrorInfo, OnNetErrorInfo)
- IPC_MESSAGE_HANDLER(ChromeViewMsg_SetAltErrorPageURL, OnSetAltErrorPageURL);
+ IPC_MESSAGE_HANDLER(ChromeViewMsg_SetNavigationCorrectionInfo,
+ OnSetNavigationCorrectionInfo);
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
+void NetErrorHelper::NetworkStateChanged(bool enabled) {
+ core_->NetworkStateChanged(enabled);
+}
+
void NetErrorHelper::GetErrorHTML(
blink::WebFrame* frame,
const blink::WebURLError& error,
bool is_failed_post,
std::string* error_html) {
- core_.GetErrorHTML(GetFrameType(frame), error, is_failed_post, error_html);
+ core_->GetErrorHTML(GetFrameType(frame), error, is_failed_post, error_html);
+}
+
+bool NetErrorHelper::ShouldSuppressErrorPage(blink::WebFrame* frame,
+ const GURL& url) {
+ return core_->ShouldSuppressErrorPage(GetFrameType(frame), url);
+}
+
+void NetErrorHelper::TrackClick(int tracking_id) {
+ core_->TrackClick(tracking_id);
}
-void NetErrorHelper::GenerateLocalizedErrorPage(const blink::WebURLError& error,
- bool is_failed_post,
- std::string* error_html) const {
+void NetErrorHelper::GenerateLocalizedErrorPage(
+ const blink::WebURLError& error,
+ bool is_failed_post,
+ scoped_ptr<LocalizedError::ErrorPageParams> params,
+ bool* reload_button_shown,
+ bool* load_stale_button_shown,
+ std::string* error_html) const {
error_html->clear();
int resource_id = IDR_NET_ERROR_HTML;
if (template_html.empty()) {
NOTREACHED() << "unable to load template.";
} else {
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ bool load_stale_cache_enabled =
+ command_line->HasSwitch(switches::kEnableOfflineLoadStaleCache);
+
base::DictionaryValue error_strings;
LocalizedError::GetStrings(error.reason, error.domain.utf8(),
error.unreachableURL, is_failed_post,
+ (load_stale_cache_enabled &&
+ error.staleCopyInCache && !is_failed_post),
RenderThread::Get()->GetLocale(),
- render_view()->GetAcceptLanguages(),
- &error_strings);
+ render_frame()->GetRenderView()->
+ GetAcceptLanguages(),
+ params.Pass(), &error_strings);
+ *reload_button_shown = error_strings.Get("reloadButton", NULL);
+ *load_stale_button_shown = error_strings.Get("staleLoadButton", NULL);
+
// "t" is the id of the template's root node.
*error_html = webui::GetTemplatesHtml(template_html, &error_strings, "t");
}
void NetErrorHelper::LoadErrorPageInMainFrame(const std::string& html,
const GURL& failed_url) {
- blink::WebView* web_view = render_view()->GetWebView();
+ blink::WebView* web_view = render_frame()->GetRenderView()->GetWebView();
if (!web_view)
return;
blink::WebFrame* frame = web_view->mainFrame();
frame->loadHTMLString(html, GURL(kUnreachableWebDataURL), failed_url, true);
}
+void NetErrorHelper::EnablePageHelperFunctions() {
+ NetErrorPageController::Install(render_frame());
+}
+
void NetErrorHelper::UpdateErrorPage(const blink::WebURLError& error,
bool is_failed_post) {
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ bool load_stale_cache_enabled =
+ command_line->HasSwitch(switches::kEnableOfflineLoadStaleCache);
+
base::DictionaryValue error_strings;
LocalizedError::GetStrings(error.reason,
error.domain.utf8(),
error.unreachableURL,
is_failed_post,
+ (load_stale_cache_enabled &&
+ error.staleCopyInCache && !is_failed_post),
RenderThread::Get()->GetLocale(),
- render_view()->GetAcceptLanguages(),
+ render_frame()->GetRenderView()->
+ GetAcceptLanguages(),
+ scoped_ptr<LocalizedError::ErrorPageParams>(),
&error_strings);
std::string json;
return;
}
- base::string16 frame_xpath;
- render_view()->EvaluateScript(frame_xpath, js16, 0, false);
+ render_frame()->ExecuteJavaScript(js16);
+}
+
+void NetErrorHelper::FetchNavigationCorrections(
+ const GURL& navigation_correction_url,
+ const std::string& navigation_correction_request_body) {
+ DCHECK(!correction_fetcher_.get());
+
+ blink::WebView* web_view = render_frame()->GetRenderView()->GetWebView();
+ if (!web_view)
+ return;
+ blink::WebFrame* frame = web_view->mainFrame();
+
+ correction_fetcher_.reset(
+ content::ResourceFetcher::Create(navigation_correction_url));
+ correction_fetcher_->SetMethod("POST");
+ correction_fetcher_->SetBody(navigation_correction_request_body);
+ correction_fetcher_->SetHeader("Content-Type", "application/json");
+
+ correction_fetcher_->Start(
+ frame,
+ blink::WebURLRequest::RequestContextInternal,
+ blink::WebURLRequest::FrameTypeTopLevel,
+ base::Bind(&NetErrorHelper::OnNavigationCorrectionsFetched,
+ base::Unretained(this)));
+
+ correction_fetcher_->SetTimeout(
+ base::TimeDelta::FromSeconds(kNavigationCorrectionFetchTimeoutSec));
}
-void NetErrorHelper::FetchErrorPage(const GURL& url) {
- DCHECK(!alt_error_page_fetcher_.get());
+void NetErrorHelper::CancelFetchNavigationCorrections() {
+ correction_fetcher_.reset();
+}
- blink::WebView* web_view = render_view()->GetWebView();
+void NetErrorHelper::SendTrackingRequest(
+ const GURL& tracking_url,
+ const std::string& tracking_request_body) {
+ blink::WebView* web_view = render_frame()->GetRenderView()->GetWebView();
if (!web_view)
return;
blink::WebFrame* frame = web_view->mainFrame();
- alt_error_page_fetcher_.reset(
- content::ResourceFetcher::Create(
- url, frame, blink::WebURLRequest::TargetIsMainFrame,
- base::Bind(&NetErrorHelper::OnAlternateErrorPageRetrieved,
- base::Unretained(this))));
+ // If there's already a pending tracking request, this will cancel it.
+ tracking_fetcher_.reset(content::ResourceFetcher::Create(tracking_url));
+ tracking_fetcher_->SetMethod("POST");
+ tracking_fetcher_->SetBody(tracking_request_body);
+ tracking_fetcher_->SetHeader("Content-Type", "application/json");
+
+ tracking_fetcher_->Start(
+ frame,
+ blink::WebURLRequest::RequestContextInternal,
+ blink::WebURLRequest::FrameTypeTopLevel,
+ base::Bind(&NetErrorHelper::OnTrackingRequestComplete,
+ base::Unretained(this)));
+}
- alt_error_page_fetcher_->SetTimeout(
- base::TimeDelta::FromSeconds(kAlterErrorPageFetchTimeoutSec));
+void NetErrorHelper::ReloadPage() {
+ render_frame()->GetWebFrame()->reload(false);
}
-void NetErrorHelper::CancelFetchErrorPage() {
- alt_error_page_fetcher_.reset();
+void NetErrorHelper::LoadPageFromCache(const GURL& page_url) {
+ blink::WebFrame* web_frame = render_frame()->GetWebFrame();
+ DCHECK(!EqualsASCII(web_frame->dataSource()->request().httpMethod(), "POST"));
+
+ blink::WebURLRequest request(page_url);
+ request.setCachePolicy(blink::WebURLRequest::ReturnCacheDataDontLoad);
+
+ web_frame->loadRequest(request);
}
void NetErrorHelper::OnNetErrorInfo(int status_num) {
DVLOG(1) << "Received status " << DnsProbeStatusToString(status_num);
- core_.OnNetErrorInfo(static_cast<DnsProbeStatus>(status_num));
+ core_->OnNetErrorInfo(static_cast<DnsProbeStatus>(status_num));
}
-void NetErrorHelper::OnSetAltErrorPageURL(const GURL& alt_error_page_url) {
- core_.set_alt_error_page_url(alt_error_page_url);
+void NetErrorHelper::OnSetNavigationCorrectionInfo(
+ const GURL& navigation_correction_url,
+ const std::string& language,
+ const std::string& country_code,
+ const std::string& api_key,
+ const GURL& search_url) {
+ core_->OnSetNavigationCorrectionInfo(navigation_correction_url, language,
+ country_code, api_key, search_url);
}
-void NetErrorHelper::OnAlternateErrorPageRetrieved(
+void NetErrorHelper::OnNavigationCorrectionsFetched(
const blink::WebURLResponse& response,
const std::string& data) {
// The fetcher may only be deleted after |data| is passed to |core_|. Move
// it to a temporary to prevent any potential re-entrancy issues.
scoped_ptr<content::ResourceFetcher> fetcher(
- alt_error_page_fetcher_.release());
- if (!response.isNull() && response.httpStatusCode() == 200) {
- core_.OnAlternateErrorPageFetched(data);
- } else {
- core_.OnAlternateErrorPageFetched("");
- }
+ correction_fetcher_.release());
+ bool success = (!response.isNull() && response.httpStatusCode() == 200);
+ core_->OnNavigationCorrectionsFetched(
+ success ? data : "",
+ render_frame()->GetRenderView()->GetAcceptLanguages(),
+ base::i18n::IsRTL());
+}
+
+void NetErrorHelper::OnTrackingRequestComplete(
+ const blink::WebURLResponse& response,
+ const std::string& data) {
+ tracking_fetcher_.reset();
}