diff options
author | mmenke@chromium.org <mmenke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-13 23:48:29 +0000 |
---|---|---|
committer | mmenke@chromium.org <mmenke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-13 23:48:29 +0000 |
commit | 3d612f5775f80b7d8f91a37c44aebc9c83faf3e6 (patch) | |
tree | 54db55c4e5cc4db841e86207da662d6d6ad07d04 /chrome/renderer/net | |
parent | 8f7c18685dd79743fc8aa8098b7ddf139730d7cc (diff) | |
download | chromium_src-3d612f5775f80b7d8f91a37c44aebc9c83faf3e6.zip chromium_src-3d612f5775f80b7d8f91a37c44aebc9c83faf3e6.tar.gz chromium_src-3d612f5775f80b7d8f91a37c44aebc9c83faf3e6.tar.bz2 |
Move LinkDoctor out of content and into chrome.
This is in preparation for using the new LinkDoctor API.
BUG=308232
R=darin@chromium.org, tsepez@chromium.org, ttuttle@chromium.org
Review URL: https://codereview.chromium.org/67283002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@244611 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer/net')
-rw-r--r-- | chrome/renderer/net/net_error_helper.cc | 258 | ||||
-rw-r--r-- | chrome/renderer/net/net_error_helper.h | 94 | ||||
-rw-r--r-- | chrome/renderer/net/net_error_helper_core.cc | 318 | ||||
-rw-r--r-- | chrome/renderer/net/net_error_helper_core.h | 131 | ||||
-rw-r--r-- | chrome/renderer/net/net_error_helper_core_unittest.cc | 1304 | ||||
-rw-r--r-- | chrome/renderer/net/net_error_helper_unittest.cc | 412 |
6 files changed, 1895 insertions, 622 deletions
diff --git a/chrome/renderer/net/net_error_helper.cc b/chrome/renderer/net/net_error_helper.cc index 088b0ad..2c16add 100644 --- a/chrome/renderer/net/net_error_helper.cc +++ b/chrome/renderer/net/net_error_helper.cc @@ -18,18 +18,23 @@ #include "content/public/renderer/content_renderer_client.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 "net/base/net_errors.h" #include "third_party/WebKit/public/platform/WebURL.h" +#include "third_party/WebKit/public/platform/WebURLError.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/WebFrame.h" +#include "third_party/WebKit/public/web/WebView.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/base/webui/jstemplate_builder.h" #include "url/gurl.h" using base::JSONWriter; using chrome_common_net::DnsProbeStatus; -using chrome_common_net::DnsProbeStatusIsFinished; using chrome_common_net::DnsProbeStatusToString; using content::RenderThread; using content::RenderView; @@ -38,123 +43,49 @@ using content::kUnreachableWebDataURL; namespace { -bool IsLoadingErrorPage(blink::WebFrame* frame) { - GURL url = frame->provisionalDataSource()->request().url(); - if (!url.is_valid()) - return false; - return url.spec() == kUnreachableWebDataURL; -} +// 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; -bool IsMainFrame(const blink::WebFrame* frame) { - return !frame->parent(); +NetErrorHelperCore::PageType GetLoadingPageType(const blink::WebFrame* frame) { + GURL url = frame->provisionalDataSource()->request().url(); + if (!url.is_valid() || url.spec() != kUnreachableWebDataURL) + return NetErrorHelperCore::NON_ERROR_PAGE; + return NetErrorHelperCore::ERROR_PAGE; } -// Returns whether |net_error| is a DNS-related error (and therefore whether -// the tab helper should start a DNS probe after receiving it.) -bool IsDnsError(const blink::WebURLError& error) { - return std::string(error.domain.utf8()) == net::kErrorDomain && - (error.reason == net::ERR_NAME_NOT_RESOLVED || - error.reason == net::ERR_NAME_RESOLUTION_FAILED); +NetErrorHelperCore::FrameType GetFrameType(const blink::WebFrame* frame) { + if (!frame->parent()) + return NetErrorHelperCore::MAIN_FRAME; + return NetErrorHelperCore::SUB_FRAME; } } // namespace NetErrorHelper::NetErrorHelper(RenderView* render_view) : RenderViewObserver(render_view), - last_probe_status_(chrome_common_net::DNS_PROBE_POSSIBLE), - last_start_was_error_page_(false), - last_fail_was_dns_error_(false), - forwarding_probe_results_(false), - is_failed_post_(false) { + content::RenderViewObserverTracker<NetErrorHelper>(render_view), + core_(this) { } NetErrorHelper::~NetErrorHelper() { } void NetErrorHelper::DidStartProvisionalLoad(blink::WebFrame* frame) { - OnStartLoad(IsMainFrame(frame), IsLoadingErrorPage(frame)); -} - -void NetErrorHelper::DidFailProvisionalLoad(blink::WebFrame* frame, - const blink::WebURLError& error) { - const bool main_frame = IsMainFrame(frame); - const bool dns_error = IsDnsError(error); - - OnFailLoad(main_frame, dns_error); - - if (main_frame && dns_error) { - last_error_ = error; - - blink::WebDataSource* data_source = frame->provisionalDataSource(); - const blink::WebURLRequest& failed_request = data_source->request(); - is_failed_post_ = EqualsASCII(failed_request.httpMethod(), "POST"); - } + core_.OnStartLoad(GetFrameType(frame), GetLoadingPageType(frame)); } void NetErrorHelper::DidCommitProvisionalLoad(blink::WebFrame* frame, bool is_new_navigation) { - OnCommitLoad(IsMainFrame(frame)); + core_.OnCommitLoad(GetFrameType(frame)); } void NetErrorHelper::DidFinishLoad(blink::WebFrame* frame) { - OnFinishLoad(IsMainFrame(frame)); + core_.OnFinishLoad(GetFrameType(frame)); } -void NetErrorHelper::OnStartLoad(bool is_main_frame, bool is_error_page) { - DVLOG(1) << "OnStartLoad(is_main_frame=" << is_main_frame - << ", is_error_page=" << is_error_page << ")"; - if (!is_main_frame) - return; - - last_start_was_error_page_ = is_error_page; -} - -void NetErrorHelper::OnFailLoad(bool is_main_frame, bool is_dns_error) { - DVLOG(1) << "OnFailLoad(is_main_frame=" << is_main_frame - << ", is_dns_error=" << is_dns_error << ")"; - - if (!is_main_frame) - return; - - last_fail_was_dns_error_ = is_dns_error; - - if (is_dns_error) { - last_probe_status_ = chrome_common_net::DNS_PROBE_POSSIBLE; - // If the helper was forwarding probe results and another DNS error has - // occurred, stop forwarding probe results until the corresponding (new) - // error page loads. - forwarding_probe_results_ = false; - } -} - -void NetErrorHelper::OnCommitLoad(bool is_main_frame) { - DVLOG(1) << "OnCommitLoad(is_main_frame=" << is_main_frame << ")"; - - if (!is_main_frame) - return; - - // Stop forwarding results. If the page is a DNS error page, forwarding - // will resume once the page is loaded; if not, it should stay stopped until - // the next DNS error page. - forwarding_probe_results_ = false; -} - -void NetErrorHelper::OnFinishLoad(bool is_main_frame) { - DVLOG(1) << "OnFinishLoad(is_main_frame=" << is_main_frame << ")"; - - if (!is_main_frame) - return; - - // If a DNS error page just finished loading, start forwarding probe results - // to it. - forwarding_probe_results_ = - last_fail_was_dns_error_ && last_start_was_error_page_; - - if (forwarding_probe_results_ && - last_probe_status_ != chrome_common_net::DNS_PROBE_POSSIBLE) { - DVLOG(1) << "Error page finished loading; sending saved status."; - UpdateErrorPage(); - } +void NetErrorHelper::OnStop() { + core_.OnStop(); } bool NetErrorHelper::OnMessageReceived(const IPC::Message& message) { @@ -162,63 +93,59 @@ 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_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } -// static -bool NetErrorHelper::GetErrorStringsForDnsProbe( +void NetErrorHelper::GetErrorHTML( blink::WebFrame* frame, const blink::WebURLError& error, bool is_failed_post, - const std::string& locale, - const std::string& accept_languages, - base::DictionaryValue* error_strings) { - if (!IsMainFrame(frame)) - return false; - - if (!IsDnsError(error)) - return false; - - // Get the strings for a fake "DNS probe possible" error. - LocalizedError::GetStrings( - chrome_common_net::DNS_PROBE_POSSIBLE, - chrome_common_net::kDnsProbeErrorDomain, - error.unreachableURL, - is_failed_post, locale, accept_languages, error_strings); - return true; + std::string* error_html) { + core_.GetErrorHTML(GetFrameType(frame), error, is_failed_post, error_html); +} + +void NetErrorHelper::GenerateLocalizedErrorPage(const blink::WebURLError& error, + bool is_failed_post, + std::string* error_html) const { + error_html->clear(); + + int resource_id = IDR_NET_ERROR_HTML; + const base::StringPiece template_html( + ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id)); + if (template_html.empty()) { + NOTREACHED() << "unable to load template."; + } else { + base::DictionaryValue error_strings; + LocalizedError::GetStrings(error.reason, error.domain.utf8(), + error.unreachableURL, is_failed_post, + RenderThread::Get()->GetLocale(), + render_view()->GetAcceptLanguages(), + &error_strings); + // "t" is the id of the template's root node. + *error_html = webui::GetTemplatesHtml(template_html, &error_strings, "t"); + } } -void NetErrorHelper::OnNetErrorInfo(int status_num) { - DCHECK(status_num >= 0 && status_num < chrome_common_net::DNS_PROBE_MAX); - - DVLOG(1) << "Received status " << DnsProbeStatusToString(status_num); - - DnsProbeStatus status = static_cast<DnsProbeStatus>(status_num); - DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, status); - - if (!(last_fail_was_dns_error_ || forwarding_probe_results_)) { - DVLOG(1) << "Ignoring NetErrorInfo: no DNS error"; +void NetErrorHelper::LoadErrorPageInMainFrame(const std::string& html, + const GURL& failed_url) { + blink::WebView* web_view = render_view()->GetWebView(); + if (!web_view) return; - } - - last_probe_status_ = status; - - if (forwarding_probe_results_) - UpdateErrorPage(); + blink::WebFrame* frame = web_view->mainFrame(); + frame->loadHTMLString(html, GURL(kUnreachableWebDataURL), failed_url, true); } -void NetErrorHelper::UpdateErrorPage() { - DCHECK(forwarding_probe_results_); - - blink::WebURLError error = GetUpdatedError(); +void NetErrorHelper::UpdateErrorPage(const blink::WebURLError& error, + bool is_failed_post) { base::DictionaryValue error_strings; LocalizedError::GetStrings(error.reason, error.domain.utf8(), error.unreachableURL, - is_failed_post_, + is_failed_post, RenderThread::Get()->GetLocale(), render_view()->GetAcceptLanguages(), &error_strings); @@ -234,31 +161,54 @@ void NetErrorHelper::UpdateErrorPage() { return; } - DVLOG(1) << "Updating error page with status " - << chrome_common_net::DnsProbeStatusToString(last_probe_status_); - DVLOG(2) << "New strings: " << js; - base::string16 frame_xpath; render_view()->EvaluateScript(frame_xpath, js16, 0, false); +} + +void NetErrorHelper::FetchErrorPage(const GURL& url) { + DCHECK(!alt_error_page_fetcher_.get()); - UMA_HISTOGRAM_ENUMERATION("DnsProbe.ErrorPageUpdateStatus", - last_probe_status_, - chrome_common_net::DNS_PROBE_MAX); + blink::WebView* web_view = render_view()->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)))); + + alt_error_page_fetcher_->SetTimeout( + base::TimeDelta::FromSeconds(kAlterErrorPageFetchTimeoutSec)); } -blink::WebURLError NetErrorHelper::GetUpdatedError() const { - // If a probe didn't run or wasn't conclusive, restore the original error. - if (last_probe_status_ == chrome_common_net::DNS_PROBE_NOT_RUN || - last_probe_status_ == - chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE) { - return last_error_; - } +void NetErrorHelper::CancelFetchErrorPage() { + alt_error_page_fetcher_.reset(); +} + +void NetErrorHelper::OnNetErrorInfo(int status_num) { + DCHECK(status_num >= 0 && status_num < chrome_common_net::DNS_PROBE_MAX); + + DVLOG(1) << "Received status " << DnsProbeStatusToString(status_num); - blink::WebURLError error; - error.domain = blink::WebString::fromUTF8( - chrome_common_net::kDnsProbeErrorDomain); - error.reason = last_probe_status_; - error.unreachableURL = last_error_.unreachableURL; + core_.OnNetErrorInfo(static_cast<DnsProbeStatus>(status_num)); +} - return error; +void NetErrorHelper::OnSetAltErrorPageURL(const GURL& alt_error_page_url) { + core_.set_alt_error_page_url(alt_error_page_url); +} + +void NetErrorHelper::OnAlternateErrorPageRetrieved( + 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(""); + } } diff --git a/chrome/renderer/net/net_error_helper.h b/chrome/renderer/net/net_error_helper.h index 3f464b8..2af13da 100644 --- a/chrome/renderer/net/net_error_helper.h +++ b/chrome/renderer/net/net_error_helper.h @@ -8,34 +8,39 @@ #include <string> #include "chrome/common/net/net_error_info.h" +#include "chrome/renderer/net/net_error_helper_core.h" #include "content/public/renderer/render_view_observer.h" -#include "third_party/WebKit/public/platform/WebURLError.h" +#include "content/public/renderer/render_view_observer_tracker.h" -namespace base { -class DictionaryValue; +class GURL; + +namespace content { +class ResourceFetcher; } namespace blink { class WebFrame; +class WebURLResponse; +struct WebURLError; } // Listens for NetErrorInfo messages from the NetErrorTabHelper on the // browser side and updates the error page with more details (currently, just // DNS probe results) if/when available. -class NetErrorHelper : public content::RenderViewObserver { +class NetErrorHelper + : public content::RenderViewObserver, + public content::RenderViewObserverTracker<NetErrorHelper>, + public NetErrorHelperCore::Delegate { public: explicit NetErrorHelper(content::RenderView* render_view); virtual ~NetErrorHelper(); // RenderViewObserver implementation. virtual void DidStartProvisionalLoad(blink::WebFrame* frame) OVERRIDE; - virtual void DidFailProvisionalLoad( - blink::WebFrame* frame, - const blink::WebURLError& error) OVERRIDE; - virtual void DidCommitProvisionalLoad( - blink::WebFrame* frame, - bool is_new_navigation) OVERRIDE; + virtual void DidCommitProvisionalLoad(blink::WebFrame* frame, + bool is_new_navigation) OVERRIDE; virtual void DidFinishLoad(blink::WebFrame* frame) OVERRIDE; + virtual void OnStop() OVERRIDE; // IPC::Listener implementation. virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; @@ -45,58 +50,35 @@ class NetErrorHelper : public content::RenderViewObserver { // |is_failed_post|, and |locale| with suitable strings and returns true. // If not, returns false, in which case the caller should look up error // strings directly using LocalizedError::GetNavigationErrorStrings. - static bool GetErrorStringsForDnsProbe( - blink::WebFrame* frame, - const blink::WebURLError& error, - bool is_failed_post, - const std::string& locale, - const std::string& accept_languages, - base::DictionaryValue* error_strings); - - protected: - // These methods handle tracking the actual state of the page; this allows - // unit-testing of the state tracking without having to mock out WebFrames - // and such. - void OnStartLoad(bool is_main_frame, bool is_error_page); - void OnFailLoad(bool is_main_frame, bool is_dns_error); - void OnCommitLoad(bool is_main_frame); - void OnFinishLoad(bool is_main_frame); - - void OnNetErrorInfo(int status); - - // |UpdateErrorPage| is virtual so it can be mocked out in the unittest. - virtual void UpdateErrorPage(); - - // The last DnsProbeStatus received from the browser. - chrome_common_net::DnsProbeStatus last_probe_status_; + // + // Updates the NetErrorHelper with the assumption the page will be loaded + // immediately. + void GetErrorHTML(blink::WebFrame* frame, + const blink::WebURLError& error, + bool is_failed_post, + std::string* error_html); private: - blink::WebURLError GetUpdatedError() const; - - // Whether the last provisional load started was for an error page. - bool last_start_was_error_page_; + // NetErrorHelperCore::Delegate implementation: + virtual void GenerateLocalizedErrorPage(const blink::WebURLError& error, + bool is_failed_post, + std::string* html) const OVERRIDE; + virtual void LoadErrorPageInMainFrame(const std::string& html, + const GURL& failed_url) OVERRIDE; + virtual void UpdateErrorPage(const blink::WebURLError& error, + bool is_failed_post) OVERRIDE; + virtual void FetchErrorPage(const GURL& url) OVERRIDE; + virtual void CancelFetchErrorPage() OVERRIDE; - // Whether the last provisional load failure failed with a DNS error. - bool last_fail_was_dns_error_; + void OnNetErrorInfo(int status); + void OnSetAltErrorPageURL(const GURL& alternate_error_page_url); - // Ideally, this would be simply "last_commit_was_dns_error_page_". - // - // Unfortunately, that breaks if two DNS errors occur in a row; after the - // second failure, but before the second page commits, the helper can receive - // probe results. If all it knows is that the last commit was a DNS error - // page, it will cheerfully forward the results for the second probe to the - // first page. - // - // Thus, the semantics of this flag are a little weird. It is set whenever - // a DNS error page commits, and cleared whenever any other page commits, - // but it is also cleared whenever a DNS error occurs, to prevent the race - // described above. - bool forwarding_probe_results_; + void OnAlternateErrorPageRetrieved(const blink::WebURLResponse& response, + const std::string& data); - // The last main frame error seen by the helper. - blink::WebURLError last_error_; + scoped_ptr<content::ResourceFetcher> alt_error_page_fetcher_; - bool is_failed_post_; + NetErrorHelperCore core_; }; #endif // CHROME_RENDERER_NET_NET_ERROR_HELPER_H_ diff --git a/chrome/renderer/net/net_error_helper_core.cc b/chrome/renderer/net/net_error_helper_core.cc new file mode 100644 index 0000000..55cb771 --- /dev/null +++ b/chrome/renderer/net/net_error_helper_core.cc @@ -0,0 +1,318 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/renderer/net/net_error_helper_core.h" + +#include <string> + +#include "base/metrics/histogram.h" +#include "chrome/common/localized_error.h" +#include "net/base/escape.h" +#include "net/base/net_errors.h" +#include "third_party/WebKit/public/platform/WebString.h" +#include "third_party/WebKit/public/platform/WebURLError.h" +#include "url/gurl.h" + +namespace { + +// Returns whether |net_error| is a DNS-related error (and therefore whether +// the tab helper should start a DNS probe after receiving it.) +bool IsDnsError(const blink::WebURLError& error) { + return error.domain.utf8() == net::kErrorDomain && + (error.reason == net::ERR_NAME_NOT_RESOLVED || + error.reason == net::ERR_NAME_RESOLUTION_FAILED); +} + +// If an alternate error page should be retrieved remotely for a main frame load +// that failed with |error|, returns true and sets |error_page_url| to the URL +// of the remote error page. +bool GetErrorPageURL(const blink::WebURLError& error, + const GURL& alt_error_page_url, + GURL* error_page_url) { + if (!alt_error_page_url.is_valid()) + return false; + + // Parameter to send to the error page indicating the error type. + std::string error_param; + + std::string domain = error.domain.utf8(); + if (domain == "http" && error.reason == 404) { + error_param = "http404"; + } else if (IsDnsError(error)) { + error_param = "dnserror"; + } else if (domain == net::kErrorDomain && + (error.reason == net::ERR_CONNECTION_FAILED || + error.reason == net::ERR_CONNECTION_REFUSED || + error.reason == net::ERR_ADDRESS_UNREACHABLE || + error.reason == net::ERR_CONNECTION_TIMED_OUT)) { + error_param = "connectionfailure"; + } else { + return false; + } + + // Don't use the Link Doctor for HTTPS (for privacy reasons). + GURL unreachable_url(error.unreachableURL); + if (unreachable_url.SchemeIsSecure()) + return false; + + // Sanitize the unreachable URL. + GURL::Replacements remove_params; + remove_params.ClearUsername(); + remove_params.ClearPassword(); + remove_params.ClearQuery(); + remove_params.ClearRef(); + // TODO(yuusuke): change to net::FormatUrl when Link Doctor becomes + // unicode-capable. + std::string spec_to_send = + unreachable_url.ReplaceComponents(remove_params).spec(); + + // Notify Link Doctor of the url truncation by sending of "?" at the end. + if (unreachable_url.has_query()) + spec_to_send.append("?"); + + std::string params(alt_error_page_url.query()); + params.append("&url="); + params.append(net::EscapeQueryParamValue(spec_to_send, true)); + params.append("&sourceid=chrome"); + params.append("&error="); + params.append(error_param); + + // Build the final url to request. + GURL::Replacements link_doctor_params; + link_doctor_params.SetQueryStr(params); + *error_page_url = alt_error_page_url.ReplaceComponents(link_doctor_params); + return true; +} + +} // namespace + +struct NetErrorHelperCore::ErrorPageInfo { + ErrorPageInfo(blink::WebURLError error, bool was_failed_post) + : error(error), + was_failed_post(was_failed_post), + needs_dns_updates(false), + is_finished_loading(false) { + } + + // Information about the failed page load. + blink::WebURLError error; + bool was_failed_post; + + // Information about the status of the error page. + + // True if a page is a DNS error page and has not yet received a final DNS + // probe status. + bool needs_dns_updates; + + // URL of an alternate error page to repace this error page with, if it's a + // valid URL. Request will be issued when the error page finishes loading. + // This is done on load complete to ensure that there are two complete loads + // for tests to wait for. + GURL alternate_error_page_url; + + // True if a page has completed loading, at which point it can receive + // updates. + bool is_finished_loading; +}; + +NetErrorHelperCore::NetErrorHelperCore(Delegate* delegate) + : delegate_(delegate), + last_probe_status_(chrome_common_net::DNS_PROBE_POSSIBLE) { +} + +NetErrorHelperCore::~NetErrorHelperCore() { +} + +void NetErrorHelperCore::OnStop() { + // On stop, cancel loading the alternate error page, and prevent any pending + // error page load from starting a new error page load. Swapping in the error + // page when it's finished loading could abort the navigation, otherwise. + if (committed_error_page_info_) + committed_error_page_info_->alternate_error_page_url = GURL(); + if (pending_error_page_info_) + pending_error_page_info_->alternate_error_page_url = GURL(); + delegate_->CancelFetchErrorPage(); +} + +void NetErrorHelperCore::OnStartLoad(FrameType frame_type, PageType page_type) { + if (frame_type != MAIN_FRAME) + return; + + // If there's no pending error page information associated with the page load, + // or the new page is not an error page, then reset pending error page state. + if (!pending_error_page_info_ || page_type != ERROR_PAGE) { + OnStop(); + } +} + +void NetErrorHelperCore::OnCommitLoad(FrameType frame_type) { + if (frame_type != MAIN_FRAME) + return; + + committed_error_page_info_.reset(pending_error_page_info_.release()); +} + +void NetErrorHelperCore::OnFinishLoad(FrameType frame_type) { + if (frame_type != MAIN_FRAME || !committed_error_page_info_) + return; + + committed_error_page_info_->is_finished_loading = true; + + if (committed_error_page_info_->alternate_error_page_url.is_valid()) { + // If there is another pending error page load, + // |replace_with_alternate_error_page| should have been set to false. + DCHECK(!pending_error_page_info_); + DCHECK(!committed_error_page_info_->needs_dns_updates); + GURL error_page_url; + delegate_->FetchErrorPage( + committed_error_page_info_->alternate_error_page_url); + } + + if (!committed_error_page_info_->needs_dns_updates || + last_probe_status_ == chrome_common_net::DNS_PROBE_POSSIBLE) { + return; + } + DVLOG(1) << "Error page finished loading; sending saved status."; + UpdateErrorPage(); +} + +void NetErrorHelperCore::GetErrorHTML( + FrameType frame_type, + const blink::WebURLError& error, + bool is_failed_post, + std::string* error_html) { + if (frame_type == MAIN_FRAME) { + // If an alternate error page was going to be fetched, that should have been + // cancelled by loading a new page load (Which has now failed to load). + DCHECK(!committed_error_page_info_ || + !committed_error_page_info_->alternate_error_page_url.is_valid()); + + // The last probe status needs to be reset if this is a DNS error. This + // means that if a DNS error page is committed but has not yet finished + // loading, a DNS probe status scheduled to be sent to it may be thrown + // out, but since the new error page should trigger a new DNS probe, it + // will just get the results for the next page load. + if (IsDnsError(error)) + last_probe_status_ = chrome_common_net::DNS_PROBE_POSSIBLE; + + GURL error_page_url; + if (GetErrorPageURL(error, alt_error_page_url_, &error_page_url)) { + pending_error_page_info_.reset(new ErrorPageInfo(error, is_failed_post)); + pending_error_page_info_->alternate_error_page_url = error_page_url; + return; + } + } + + GenerateLocalErrorPage(frame_type, error, is_failed_post, error_html); +} + +void NetErrorHelperCore::GenerateLocalErrorPage( + FrameType frame_type, + const blink::WebURLError& error, + bool is_failed_post, + std::string* error_html) { + if (frame_type == MAIN_FRAME) { + pending_error_page_info_.reset(new ErrorPageInfo(error, is_failed_post)); + if (IsDnsError(error)) { + // This is not strictly necessary, but waiting for a new status to be + // sent as a result of the DidFinishLoading call keeps the histograms + // consistent with older versions of the code, at no real cost. + last_probe_status_ = chrome_common_net::DNS_PROBE_POSSIBLE; + + delegate_->GenerateLocalizedErrorPage( + GetUpdatedError(error), is_failed_post, error_html); + pending_error_page_info_->needs_dns_updates = true; + return; + } + } + delegate_->GenerateLocalizedErrorPage(error, is_failed_post, error_html); +} + +void NetErrorHelperCore::OnNetErrorInfo( + chrome_common_net::DnsProbeStatus status) { + DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, status); + + last_probe_status_ = status; + + if (!committed_error_page_info_ || + !committed_error_page_info_->needs_dns_updates || + !committed_error_page_info_->is_finished_loading) { + return; + } + + UpdateErrorPage(); +} + +void NetErrorHelperCore::UpdateErrorPage() { + DCHECK(committed_error_page_info_->needs_dns_updates); + DCHECK(committed_error_page_info_->is_finished_loading); + DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, last_probe_status_); + + UMA_HISTOGRAM_ENUMERATION("DnsProbe.ErrorPageUpdateStatus", + last_probe_status_, + chrome_common_net::DNS_PROBE_MAX); + // Every status other than DNS_PROBE_POSSIBLE and DNS_PROBE_STARTED is a + // final status code. Once one is reached, the page does not need further + // updates. + if (last_probe_status_ != chrome_common_net::DNS_PROBE_STARTED) + committed_error_page_info_->needs_dns_updates = false; + + delegate_->UpdateErrorPage( + GetUpdatedError(committed_error_page_info_->error), + committed_error_page_info_->was_failed_post); +} + +void NetErrorHelperCore::OnAlternateErrorPageFetched(const std::string& data) { + // Alternate error page load only starts when an error page finishes loading, + // and is cancelled with a new load + DCHECK(!pending_error_page_info_); + DCHECK(committed_error_page_info_->is_finished_loading); + + const std::string* error_html = NULL; + std::string generated_html; + if (!data.empty()) { + // If the request succeeded, use the response in place of a generated error + // page. + pending_error_page_info_.reset( + new ErrorPageInfo(committed_error_page_info_->error, + committed_error_page_info_->was_failed_post)); + error_html = &data; + } else { + // Otherwise, generate a local error page. |pending_error_page_info_| will + // be set by GenerateLocalErrorPage. + GenerateLocalErrorPage(MAIN_FRAME, + committed_error_page_info_->error, + committed_error_page_info_->was_failed_post, + &generated_html); + error_html = &generated_html; + } + + // |error_page_info| may have been destroyed by this point, since + // |pending_error_page_info_| was set to a new ErrorPageInfo. + + // TODO(mmenke): Once the new API is in place, look into replacing this + // double page load by just updating the error page, like DNS + // probes do. + delegate_->LoadErrorPageInMainFrame( + *error_html, + pending_error_page_info_->error.unreachableURL); +} + +blink::WebURLError NetErrorHelperCore::GetUpdatedError( + const blink::WebURLError& error) const { + // If a probe didn't run or wasn't conclusive, restore the original error. + if (last_probe_status_ == chrome_common_net::DNS_PROBE_NOT_RUN || + last_probe_status_ == + chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE) { + return error; + } + + blink::WebURLError updated_error; + updated_error.domain = blink::WebString::fromUTF8( + chrome_common_net::kDnsProbeErrorDomain); + updated_error.reason = last_probe_status_; + updated_error.unreachableURL = error.unreachableURL; + + return updated_error; +} diff --git a/chrome/renderer/net/net_error_helper_core.h b/chrome/renderer/net/net_error_helper_core.h new file mode 100644 index 0000000..cfbc8a1 --- /dev/null +++ b/chrome/renderer/net/net_error_helper_core.h @@ -0,0 +1,131 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_RENDERER_NET_NET_ERROR_HELPER_CORE_H_ +#define CHROME_RENDERER_NET_NET_ERROR_HELPER_CORE_H_ + +#include <string> + +#include "base/memory/weak_ptr.h" +#include "chrome/common/net/net_error_info.h" +#include "url/gurl.h" + +namespace blink { +struct WebURLError; +} + +// Class that contains the logic for how the NetErrorHelper. This allows for +// testing the logic without a RenderView or WebFrame, which are difficult to +// mock, and for testing races which are impossible to reliably reproduce +// with real RenderViews or WebFrames. +class NetErrorHelperCore { + public: + enum FrameType { + MAIN_FRAME, + SUB_FRAME, + }; + + enum PageType { + NON_ERROR_PAGE, + ERROR_PAGE, + }; + + // The Delegate handles all interaction with the RenderView, WebFrame, and + // the network, as well as the generation of error pages. + class Delegate { + public: + // Generates an error page's HTML for the given error. + virtual void GenerateLocalizedErrorPage(const blink::WebURLError& error, + bool is_failed_post, + std::string* html) const = 0; + + // Loads the given HTML in the main frame for use as an error page. + virtual void LoadErrorPageInMainFrame(const std::string& html, + const GURL& failed_url) = 0; + + // Updates the currently displayed error page with a new error code. The + // currently displayed error page must have finished loading, and must have + // been generated by a call to GenerateLocalizedErrorPage. + virtual void UpdateErrorPage(const blink::WebURLError& error, + bool is_failed_post) = 0; + + // Fetches an error page and calls into OnErrorPageFetched when done. Any + // previous fetch must either be canceled or finished before calling. Can't + // be called synchronously after a previous fetch completes. + virtual void FetchErrorPage(const GURL& url) = 0; + + // Cancels an error page fetch. Does nothing if no fetch is ongoing. + virtual void CancelFetchErrorPage() = 0; + + protected: + virtual ~Delegate() {} + }; + + explicit NetErrorHelperCore(Delegate* delegate); + ~NetErrorHelperCore(); + + // Examines |frame| and |error| to see if this is an error worthy of a DNS + // probe. If it is, initializes |error_strings| based on |error|, + // |is_failed_post|, and |locale| with suitable strings and returns true. + // If not, returns false, in which case the caller should look up error + // strings directly using LocalizedError::GetNavigationErrorStrings. + // + // Updates the NetErrorHelper with the assumption the page will be loaded + // immediately. + void GetErrorHTML(FrameType frame_type, + const blink::WebURLError& error, + bool is_failed_post, + std::string* error_html); + + // These methods handle tracking the actual state of the page. + void OnStartLoad(FrameType frame_type, PageType page_type); + void OnCommitLoad(FrameType frame_type); + void OnFinishLoad(FrameType frame_type); + void OnStop(); + + // Called when an error page have has been retrieved over the network. |html| + // must be an empty string on error. + void OnAlternateErrorPageFetched(const std::string& html); + + // Notifies |this| that network error information from the browser process + // has been received. + void OnNetErrorInfo(chrome_common_net::DnsProbeStatus status); + + void set_alt_error_page_url(const GURL& alt_error_page_url) { + alt_error_page_url_ = alt_error_page_url; + } + + private: + struct ErrorPageInfo; + + // Updates the currently displayed error page with a new error based on the + // most recently received DNS probe result. The page must have finished + // loading before this is called. + void UpdateErrorPage(); + + void GenerateLocalErrorPage( + FrameType frame_type, + const blink::WebURLError& error, + bool is_failed_post, + std::string* error_html); + + blink::WebURLError GetUpdatedError(const blink::WebURLError& error) const; + + Delegate* delegate_; + + // The last DnsProbeStatus received from the browser. + chrome_common_net::DnsProbeStatus last_probe_status_; + + // Information for the provisional / "pre-provisional" error page. NULL when + // there's no page pending, or the pending page is not an error page. + scoped_ptr<ErrorPageInfo> pending_error_page_info_; + + // Information for the committed error page. NULL when the committed page is + // not an error page. + scoped_ptr<ErrorPageInfo> committed_error_page_info_; + + GURL alt_error_page_url_; +}; + +#endif // CHROME_RENDERER_NET_NET_ERROR_HELPER_CORE_H_ diff --git a/chrome/renderer/net/net_error_helper_core_unittest.cc b/chrome/renderer/net/net_error_helper_core_unittest.cc new file mode 100644 index 0000000..bd451d6 --- /dev/null +++ b/chrome/renderer/net/net_error_helper_core_unittest.cc @@ -0,0 +1,1304 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/renderer/net/net_error_helper_core.h" + +#include "base/logging.h" +#include "base/strings/stringprintf.h" +#include "chrome/common/net/net_error_info.h" +#include "net/base/net_errors.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/public/platform/WebURLError.h" + +using blink::WebURLError; +using chrome_common_net::DnsProbeStatus; +using chrome_common_net::DnsProbeStatusToString; + +const char kFailedUrl[] = "http://failed/"; +const char kFailedHttpsUrl[] = "https://failed/"; +const char kLinkDoctorUrl[] = "http://link.doctor/"; +const char kLinkDoctorBody[] = "Link Doctor Body"; + +// Creates a string from an error that is used as a mock locally generated +// error page for that error. +std::string ErrorToString(const WebURLError& error, bool is_failed_post) { + return base::StringPrintf("(%s, %s, %i, %s)", + error.unreachableURL.string().utf8().c_str(), + error.domain.utf8().c_str(), error.reason, + is_failed_post ? "POST" : "NOT POST"); +} + +WebURLError ProbeError(DnsProbeStatus status) { + WebURLError error; + error.unreachableURL = GURL(kFailedUrl); + error.domain = blink::WebString::fromUTF8( + chrome_common_net::kDnsProbeErrorDomain); + error.reason = status; + return error; +} + +WebURLError NetError(net::Error net_error) { + WebURLError error; + error.unreachableURL = GURL(kFailedUrl); + error.domain = blink::WebString::fromUTF8(net::kErrorDomain); + error.reason = net_error; + return error; +} + +WebURLError HttpError(int status_code) { + WebURLError error; + error.unreachableURL = GURL(kFailedUrl); + error.domain = blink::WebString::fromUTF8("http"); + error.reason = status_code; + return error; +} + +// Convenience functions that create an error string for a non-POST request. + +std::string ProbeErrorString(DnsProbeStatus status) { + return ErrorToString(ProbeError(status), false); +} + +std::string NetErrorString(net::Error net_error) { + return ErrorToString(NetError(net_error), false); +} + +class NetErrorHelperCoreTest : public testing::Test, + public NetErrorHelperCore::Delegate { + public: + NetErrorHelperCoreTest() : core_(this), + update_count_(0), + error_html_update_count_(0) { + } + + virtual ~NetErrorHelperCoreTest() { + // No test finishes while an error page is being fetched. + EXPECT_FALSE(is_url_being_fetched()); + } + + NetErrorHelperCore& core() { return core_; } + + const GURL& url_being_fetched() const { return url_being_fetched_; } + bool is_url_being_fetched() const { return !url_being_fetched_.is_empty(); } + + const std::string& last_update_string() const { return last_update_string_; } + int update_count() const { return update_count_; } + + const std::string& last_error_html() const { return last_error_html_; } + int error_html_update_count() const { return error_html_update_count_; } + + void LinkDoctorLoadSuccess() { + LinkDoctorLoadFinished(kLinkDoctorBody); + } + + void LinkDoctorLoadFailure() { + LinkDoctorLoadFinished(""); + } + + private: + void LinkDoctorLoadFinished(const std::string& result) { + url_being_fetched_ = GURL(); + core().OnAlternateErrorPageFetched(result); + } + + // NetErrorHelperCore::Delegate implementation: + virtual void GenerateLocalizedErrorPage(const WebURLError& error, + bool is_failed_post, + std::string* html) const OVERRIDE { + *html = ErrorToString(error, is_failed_post); + } + + virtual void LoadErrorPageInMainFrame(const std::string& html, + const GURL& failed_url) OVERRIDE { + error_html_update_count_++; + last_error_html_ = html; + } + + virtual void UpdateErrorPage(const WebURLError& error, + bool is_failed_post) OVERRIDE { + update_count_++; + last_error_html_ = ErrorToString(error, is_failed_post); + } + + virtual void FetchErrorPage(const GURL& url) OVERRIDE { + EXPECT_TRUE(url_being_fetched_.is_empty()); + EXPECT_TRUE(url.is_valid()); + EXPECT_NE(std::string::npos, url.spec().find(kLinkDoctorUrl)); + + url_being_fetched_ = url; + } + + virtual void CancelFetchErrorPage() OVERRIDE { + url_being_fetched_ = GURL(); + } + + NetErrorHelperCore core_; + + GURL url_being_fetched_; + + // Contains the information passed to the last call to UpdateErrorPage, as a + // string. + std::string last_update_string_; + // Number of times |last_update_string_| has been changed. + int update_count_; + + // Contains the HTML set by the last call to LoadErrorPageInMainFrame. + std::string last_error_html_; + // Number of times |last_error_html_| has been changed. + int error_html_update_count_; +}; + +//------------------------------------------------------------------------------ +// Basic tests that don't update the error page for probes or load the Link +// Doctor. +//------------------------------------------------------------------------------ + +TEST_F(NetErrorHelperCoreTest, Null) { +} + +TEST_F(NetErrorHelperCoreTest, SuccessfulPageLoad) { + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_EQ(0, update_count()); + EXPECT_EQ(0, error_html_update_count()); +} + +TEST_F(NetErrorHelperCoreTest, SuccessfulPageLoadWithLinkDoctor) { + core().set_alt_error_page_url(GURL(kLinkDoctorUrl)); + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_EQ(0, update_count()); + EXPECT_EQ(0, error_html_update_count()); +} + +TEST_F(NetErrorHelperCoreTest, MainFrameNonDnsError) { + // Original page starts loading. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and an error page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_CONNECTION_RESET), false, &html); + // Should have returned a local error page. + EXPECT_FALSE(html.empty()); + EXPECT_EQ(NetErrorString(net::ERR_CONNECTION_RESET), html); + + // Error page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_EQ(0, update_count()); + EXPECT_EQ(0, error_html_update_count()); +} + +TEST_F(NetErrorHelperCoreTest, MainFrameNonDnsErrorWithLinkDoctor) { + core().set_alt_error_page_url(GURL(kLinkDoctorUrl)); + + // Original page starts loading. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and an error page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_CONNECTION_RESET), false, &html); + // Should have returned a local error page. + EXPECT_FALSE(html.empty()); + EXPECT_EQ(NetErrorString(net::ERR_CONNECTION_RESET), html); + + // Error page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_EQ(0, update_count()); + EXPECT_EQ(0, error_html_update_count()); +} + +// Much like above tests, but with a bunch of spurious DNS status messages that +// should have no effect. +TEST_F(NetErrorHelperCoreTest, MainFrameNonDnsErrorSpuriousStatus) { + // Original page starts loading. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + + // It fails, and an error page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_CONNECTION_RESET), + false, &html); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + + // Should have returned a local error page. + EXPECT_FALSE(html.empty()); + EXPECT_EQ(NetErrorString(net::ERR_CONNECTION_RESET), html); + + // Error page loads. + + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + + EXPECT_EQ(0, update_count()); + EXPECT_EQ(0, error_html_update_count()); +} + +TEST_F(NetErrorHelperCoreTest, SubFrameDnsError) { + // Original page starts loading. + core().OnStartLoad(NetErrorHelperCore::SUB_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and an error page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::SUB_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + // Should have returned a local error page. + EXPECT_EQ(NetErrorString(net::ERR_NAME_NOT_RESOLVED), html); + + // Error page loads. + core().OnStartLoad(NetErrorHelperCore::SUB_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::SUB_FRAME); + core().OnFinishLoad(NetErrorHelperCore::SUB_FRAME); + EXPECT_EQ(0, update_count()); + EXPECT_EQ(0, error_html_update_count()); +} + +TEST_F(NetErrorHelperCoreTest, SubFrameDnsErrorWithLinkDoctor) { + core().set_alt_error_page_url(GURL(kLinkDoctorUrl)); + + // Original page starts loading. + core().OnStartLoad(NetErrorHelperCore::SUB_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and an error page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::SUB_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + // Should have returned a local error page. + EXPECT_EQ(NetErrorString(net::ERR_NAME_NOT_RESOLVED), html); + + // Error page loads. + core().OnStartLoad(NetErrorHelperCore::SUB_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::SUB_FRAME); + core().OnFinishLoad(NetErrorHelperCore::SUB_FRAME); + EXPECT_EQ(0, update_count()); + EXPECT_EQ(0, error_html_update_count()); +} + +// Much like above tests, but with a bunch of spurious DNS status messages that +// should have no effect. +TEST_F(NetErrorHelperCoreTest, SubFrameDnsErrorSpuriousStatus) { + // Original page starts loading. + core().OnStartLoad(NetErrorHelperCore::SUB_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + + // It fails, and an error page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::SUB_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + + // Should have returned a local error page. + EXPECT_EQ(NetErrorString(net::ERR_NAME_NOT_RESOLVED), html); + + // Error page loads. + + core().OnStartLoad(NetErrorHelperCore::SUB_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + + core().OnCommitLoad(NetErrorHelperCore::SUB_FRAME); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + + core().OnFinishLoad(NetErrorHelperCore::SUB_FRAME); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + + EXPECT_EQ(0, update_count()); + EXPECT_EQ(0, error_html_update_count()); +} + +//------------------------------------------------------------------------------ +// Tests for updating the error page in response to DNS probe results. None +// of these have the Link Doctor enabled. +//------------------------------------------------------------------------------ + +// Test case where the error page finishes loading before receiving any DNS +// probe messages. +TEST_F(NetErrorHelperCoreTest, FinishedBeforeProbe) { + // Original page starts loading. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and an error page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + // Should have returned a local error page indicating a probe may run. + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_POSSIBLE), html); + + // Error page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_EQ(0, update_count()); + + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + EXPECT_EQ(1, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_STARTED), + last_error_html()); + + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(2, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN), + last_error_html()); + + // Any other probe updates should be ignored. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(2, update_count()); + EXPECT_EQ(0, error_html_update_count()); +} + +// Same as above, but the probe is not run. +TEST_F(NetErrorHelperCoreTest, FinishedBeforeProbeNotRun) { + // Original page starts loading. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and an error page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + // Should have returned a local error page indicating a probe may run. + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_POSSIBLE), html); + + // Error page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_EQ(0, update_count()); + + // When the not run status arrives, the page should revert to the normal dns + // error page. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_NOT_RUN); + EXPECT_EQ(1, update_count()); + EXPECT_EQ(NetErrorString(net::ERR_NAME_NOT_RESOLVED), last_error_html()); + + // Any other probe updates should be ignored. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(1, update_count()); + EXPECT_EQ(0, error_html_update_count()); +} + +// Same as above, but the probe result is inconclusive. +TEST_F(NetErrorHelperCoreTest, FinishedBeforeProbeInconclusive) { + // Original page starts loading. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and an error page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + // Should have returned a local error page indicating a probe may run. + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_POSSIBLE), html); + + // Error page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_EQ(0, update_count()); + + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + EXPECT_EQ(1, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_STARTED), + last_error_html()); + + // When the inconclusive status arrives, the page should revert to the normal + // dns error page. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE); + EXPECT_EQ(2, update_count()); + EXPECT_EQ(NetErrorString(net::ERR_NAME_NOT_RESOLVED), last_error_html()); + + // Any other probe updates should be ignored. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE); + EXPECT_EQ(2, update_count()); + EXPECT_EQ(0, error_html_update_count()); +} + +// Same as above, but the probe result is no internet. +TEST_F(NetErrorHelperCoreTest, FinishedBeforeProbeNoInternet) { + // Original page starts loading. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and an error page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + // Should have returned a local error page indicating a probe may run. + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_POSSIBLE), html); + + // Error page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_EQ(0, update_count()); + + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + EXPECT_EQ(1, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_STARTED), + last_error_html()); + + // When the inconclusive status arrives, the page should revert to the normal + // dns error page. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET); + EXPECT_EQ(2, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET), + last_error_html()); + + // Any other probe updates should be ignored. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET); + EXPECT_EQ(2, update_count()); + EXPECT_EQ(0, error_html_update_count()); +} + +// Same as above, but the probe result is bad config. +TEST_F(NetErrorHelperCoreTest, FinishedBeforeProbeBadConfig) { + // Original page starts loading. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and an error page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + // Should have returned a local error page indicating a probe may run. + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_POSSIBLE), html); + + // Error page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_EQ(0, update_count()); + + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + EXPECT_EQ(1, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_STARTED), + last_error_html()); + + // When the inconclusive status arrives, the page should revert to the normal + // dns error page. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_BAD_CONFIG); + EXPECT_EQ(2, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_FINISHED_BAD_CONFIG), + last_error_html()); + + // Any other probe updates should be ignored. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_BAD_CONFIG); + EXPECT_EQ(2, update_count()); + EXPECT_EQ(0, error_html_update_count()); +} + +// Test case where the error page finishes loading after receiving the start +// DNS probe message. +TEST_F(NetErrorHelperCoreTest, FinishedAfterStartProbe) { + // Original page starts loading. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and an error page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + // Should have returned a local error page indicating a probe may run. + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_POSSIBLE), html); + + // Error page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + + // Nothing should be done when a probe status comes in before loading + // finishes. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + EXPECT_EQ(0, update_count()); + + // When loading finishes, however, the buffered probe status should be sent + // to the page. + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_EQ(1, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_STARTED), + last_error_html()); + + // Should update the page again when the probe result comes in. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(2, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN), + last_error_html()); + + // Any other probe updates should be ignored. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_NOT_RUN); + EXPECT_EQ(2, update_count()); +} + +// Test case where the error page finishes loading before receiving any DNS +// probe messages and the request is a POST. +TEST_F(NetErrorHelperCoreTest, FinishedBeforeProbePost) { + // Original page starts loading. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and an error page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + true, &html); + // Should have returned a local error page indicating a probe may run. + EXPECT_EQ(ErrorToString( + ProbeError(chrome_common_net::DNS_PROBE_POSSIBLE), + true), + html); + + // Error page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_EQ(0, update_count()); + + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + EXPECT_EQ(1, update_count()); + EXPECT_EQ(ErrorToString( + ProbeError(chrome_common_net::DNS_PROBE_STARTED), true), + last_error_html()); + + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(2, update_count()); + EXPECT_EQ(ErrorToString( + ProbeError(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN), + true), + last_error_html()); + EXPECT_EQ(0, error_html_update_count()); +} + +// Test case where the probe finishes before the page is committed. +TEST_F(NetErrorHelperCoreTest, ProbeFinishesEarly) { + // Original page starts loading. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and an error page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + // Should have returned a local error page indicating a probe may run. + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_POSSIBLE), html); + + // Error page starts loading. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + + // Nothing should be done when the probe statuses come in before loading + // finishes. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(0, update_count()); + + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_EQ(0, update_count()); + + // When loading finishes, however, the buffered probe status should be sent + // to the page. + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_EQ(1, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN), + last_error_html()); + + // Any other probe updates should be ignored. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(1, update_count()); +} + +// Test case where one error page loads completely before a new navigation +// results in another error page. Probes are run for both pages. +TEST_F(NetErrorHelperCoreTest, TwoErrorsWithProbes) { + // Original page starts loading. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and an error page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + // Should have returned a local error page indicating a probe may run. + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_POSSIBLE), html); + + // Error page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + + // Probe results come in. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(2, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN), + last_error_html()); + + // The process starts again. + + // Normal page starts loading. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and an error page is requested. + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + // Should have returned a local error page indicating a probe may run. + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_POSSIBLE), html); + + // Error page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_EQ(2, update_count()); + + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + EXPECT_EQ(3, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_STARTED), + last_error_html()); + + // The probe returns a different result this time. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET); + EXPECT_EQ(4, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET), + last_error_html()); + EXPECT_EQ(0, error_html_update_count()); +} + +// Test case where one error page loads completely before a new navigation +// results in another error page. Probe results for the first probe are only +// received after the second load starts, but before it commits. +TEST_F(NetErrorHelperCoreTest, TwoErrorsWithProbesAfterSecondStarts) { + // Original page starts loading. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and an error page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + // Should have returned a local error page indicating a probe may run. + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_POSSIBLE), html); + + // Error page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + + // The process starts again. + + // Normal page starts loading. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and an error page is requested. + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + // Should have returned a local error page indicating a probe may run. + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_POSSIBLE), html); + + // Error page starts to load. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + + // Probe results come in, and the first page is updated. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(2, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN), + last_error_html()); + + // Second page finishes loading, and is updated using the same probe result. + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_EQ(3, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN), + last_error_html()); + + // Other probe results should be ignored. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET); + EXPECT_EQ(3, update_count()); + EXPECT_EQ(0, error_html_update_count()); +} + +// Same as above, but a new page is loaded before the error page commits. +TEST_F(NetErrorHelperCoreTest, ErrorPageLoadInterrupted) { + // Original page starts loading. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and an error page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + // Should have returned a local error page indicating a probe may run. + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_POSSIBLE), html); + + // Error page starts loading. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + // Probe statuses come in, but should be ignored. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(0, update_count()); + + // A new navigation begins while the error page is loading. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // And fails. + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + // Should have returned a local error page indicating a probe may run. + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_POSSIBLE), html); + + // Error page finishes loading. + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + + // Probe results come in. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + EXPECT_EQ(1, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_STARTED), + last_error_html()); + + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET); + EXPECT_EQ(2, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET), + last_error_html()); + EXPECT_EQ(0, error_html_update_count()); +} + +//------------------------------------------------------------------------------ +// Link Doctor tests. +//------------------------------------------------------------------------------ + +// Check that the Link Doctor is not used for HTTPS URLs. +TEST_F(NetErrorHelperCoreTest, NoLinkDoctorForHttps) { + // Original page starts loading. + core().set_alt_error_page_url(GURL(kLinkDoctorUrl)); + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // The HTTPS page fails to load. + std::string html; + blink::WebURLError error = NetError(net::ERR_NAME_NOT_RESOLVED); + error.unreachableURL = GURL(kFailedHttpsUrl); + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, error, false, &html); + + blink::WebURLError probe_error = + ProbeError(chrome_common_net::DNS_PROBE_POSSIBLE); + probe_error.unreachableURL = GURL(kFailedHttpsUrl); + EXPECT_EQ(ErrorToString(probe_error, false), html); + EXPECT_FALSE(is_url_being_fetched()); + + // The blank page loads, no error page is loaded. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_FALSE(is_url_being_fetched()); + + // Page is updated in response to DNS probes as normal. + EXPECT_EQ(0, update_count()); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(2, update_count()); + blink::WebURLError final_probe_error = + ProbeError(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + final_probe_error.unreachableURL = GURL(kFailedHttpsUrl); + EXPECT_EQ(ErrorToString(final_probe_error, false), last_error_html()); +} + +// The blank page loads, then the Link Doctor request succeeds and is loaded. +// Then the probe results come in. +TEST_F(NetErrorHelperCoreTest, LinkDoctorSucceedsBeforeProbe) { + // Original page starts loading. + core().set_alt_error_page_url(GURL(kLinkDoctorUrl)); + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + EXPECT_TRUE(html.empty()); + EXPECT_FALSE(is_url_being_fetched()); + + // The blank page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + + // Link doctor retrieval starts when the error page finishes loading. + EXPECT_FALSE(is_url_being_fetched()); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_TRUE(is_url_being_fetched()); + + // Link Doctor is retrieved. + LinkDoctorLoadSuccess(); + EXPECT_EQ(1, error_html_update_count()); + EXPECT_EQ(kLinkDoctorBody, last_error_html()); + EXPECT_FALSE(is_url_being_fetched()); + + // Link Doctor page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + + // Any probe statuses should be ignored. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + + EXPECT_EQ(0, update_count()); + EXPECT_EQ(1, error_html_update_count()); +} + +// The blank page finishes loading, then probe results come in, and then +// the Link Doctor request succeeds. +TEST_F(NetErrorHelperCoreTest, LinkDoctorSucceedsAfterProbes) { + // Original page starts loading. + core().set_alt_error_page_url(GURL(kLinkDoctorUrl)); + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and a Link Doctor page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + EXPECT_TRUE(html.empty()); + + // The blank page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_TRUE(is_url_being_fetched()); + + + // Probe statuses should be ignored. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(0, update_count()); + EXPECT_EQ(0, error_html_update_count()); + + // Link Doctor is retrieved. + EXPECT_TRUE(is_url_being_fetched()); + LinkDoctorLoadSuccess(); + EXPECT_EQ(1, error_html_update_count()); + EXPECT_EQ(kLinkDoctorBody, last_error_html()); + EXPECT_FALSE(is_url_being_fetched()); + + // Link Doctor page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_EQ(1, error_html_update_count()); + EXPECT_EQ(0, update_count()); +} + +// The Link Doctor request fails and then the error page loads for an error that +// does not trigger DNS probes. +TEST_F(NetErrorHelperCoreTest, LinkDoctorFailsLoadNoProbes) { + // Original page starts loading. + core().set_alt_error_page_url(GURL(kLinkDoctorUrl)); + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and a Link Doctor page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_CONNECTION_FAILED), + false, &html); + EXPECT_TRUE(html.empty()); + + // The blank page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + + // Link Doctor load fails, final error page is shown. + EXPECT_TRUE(is_url_being_fetched()); + LinkDoctorLoadFailure(); + EXPECT_EQ(1, error_html_update_count()); + EXPECT_EQ(last_error_html(), NetErrorString(net::ERR_CONNECTION_FAILED)); + EXPECT_FALSE(is_url_being_fetched()); + EXPECT_EQ(0, update_count()); + + // Error page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + + // If probe statuses come in last from another page load, they should be + // ignored. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(0, update_count()); + EXPECT_EQ(1, error_html_update_count()); +} + +// The Link Doctor request fails and then the error page loads before probe +// results are received. +TEST_F(NetErrorHelperCoreTest, LinkDoctorFailsLoadBeforeProbe) { + // Original page starts loading. + core().set_alt_error_page_url(GURL(kLinkDoctorUrl)); + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and a Link Doctor page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + EXPECT_TRUE(html.empty()); + + // The blank page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + + // Link Doctor load fails, probe pending page shown. + EXPECT_TRUE(is_url_being_fetched()); + LinkDoctorLoadFailure(); + EXPECT_EQ(1, error_html_update_count()); + EXPECT_EQ(last_error_html(), + ProbeErrorString(chrome_common_net::DNS_PROBE_POSSIBLE)); + EXPECT_FALSE(is_url_being_fetched()); + EXPECT_EQ(0, update_count()); + + // Probe page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + + // Probe statuses comes in, and page is updated. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + EXPECT_EQ(1, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_STARTED), + last_error_html()); + + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(2, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN), + last_error_html()); + + // The commit results in sending a second probe status, which is ignored. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(2, update_count()); + EXPECT_EQ(1, error_html_update_count()); +} + +// The Link Doctor request fails after receiving probe results. +TEST_F(NetErrorHelperCoreTest, LinkDoctorFailsAfterProbe) { + // Original page starts loading. + core().set_alt_error_page_url(GURL(kLinkDoctorUrl)); + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and a Link Doctor page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + EXPECT_TRUE(html.empty()); + + // The blank page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + + // Results come in, but end up being ignored. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(0, update_count()); + + // Link Doctor load fails, probe pending page shown. + EXPECT_TRUE(is_url_being_fetched()); + LinkDoctorLoadFailure(); + EXPECT_EQ(1, error_html_update_count()); + EXPECT_EQ(last_error_html(), + ProbeErrorString(chrome_common_net::DNS_PROBE_POSSIBLE)); + EXPECT_FALSE(is_url_being_fetched()); + EXPECT_EQ(0, update_count()); + + // Probe page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + + // Probe statuses comes in, and page is updated. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(1, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN), + last_error_html()); + EXPECT_EQ(1, error_html_update_count()); +} + +// An error page load that would normally load the Link Doctor is interrupted +// by a new navigation before the blank page commits. +TEST_F(NetErrorHelperCoreTest, LinkDoctorInterruptedBeforeCommit) { + // Original page starts loading. + core().set_alt_error_page_url(GURL(kLinkDoctorUrl)); + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and a Link Doctor page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + EXPECT_TRUE(html.empty()); + + // The blank page starts loading. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + + // A new page load starts. + EXPECT_FALSE(is_url_being_fetched()); + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // A new page load interrupts the original load. + EXPECT_FALSE(is_url_being_fetched()); + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + EXPECT_FALSE(is_url_being_fetched()); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_FALSE(is_url_being_fetched()); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + + EXPECT_FALSE(is_url_being_fetched()); + EXPECT_EQ(0, update_count()); + EXPECT_EQ(0, error_html_update_count()); +} + +// An error page load that would normally load the Link Doctor is interrupted +// by a new navigation before the blank page finishes loading. +TEST_F(NetErrorHelperCoreTest, LinkDoctorInterruptedBeforeLoad) { + // Original page starts loading. + core().set_alt_error_page_url(GURL(kLinkDoctorUrl)); + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and a Link Doctor page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + EXPECT_TRUE(html.empty()); + + // The blank page starts loading and is committed. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + + // A new page load interrupts the original load. + EXPECT_FALSE(is_url_being_fetched()); + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + EXPECT_FALSE(is_url_being_fetched()); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_FALSE(is_url_being_fetched()); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + + EXPECT_FALSE(is_url_being_fetched()); + EXPECT_EQ(0, update_count()); + EXPECT_EQ(0, error_html_update_count()); +} + +// The Link Doctor request is cancelled due to a new navigation. The new +// navigation fails and then loads the link doctor page again (Successfully). +TEST_F(NetErrorHelperCoreTest, LinkDoctorInterrupted) { + // Original page starts loading. + core().set_alt_error_page_url(GURL(kLinkDoctorUrl)); + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and a Link Doctor page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + EXPECT_TRUE(html.empty()); + + // The blank page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_TRUE(is_url_being_fetched()); + + // Results come in, but end up being ignored. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(0, update_count()); + + // A new load appears! + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + EXPECT_FALSE(is_url_being_fetched()); + + // It fails, and a Link Doctor page is requested again once a blank page is + // loaded. + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + EXPECT_TRUE(html.empty()); + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_FALSE(is_url_being_fetched()); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_TRUE(is_url_being_fetched()); + + // Link Doctor load succeeds. + LinkDoctorLoadSuccess(); + EXPECT_EQ(1, error_html_update_count()); + EXPECT_EQ(kLinkDoctorBody, last_error_html()); + EXPECT_FALSE(is_url_being_fetched()); + + // Probe statuses come in, and are ignored. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(0, update_count()); +} + +// The Link Doctor request is cancelled due to call to Stop(). The cross +// process navigation is cancelled, and then a new load fails and tries to load +// the link doctor page again (Which fails). +TEST_F(NetErrorHelperCoreTest, LinkDoctorStopped) { + // Original page starts loading. + core().set_alt_error_page_url(GURL(kLinkDoctorUrl)); + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and a Link Doctor page is requested. + std::string html; + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + EXPECT_TRUE(html.empty()); + + // The blank page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + + EXPECT_TRUE(is_url_being_fetched()); + core().OnStop(); + EXPECT_FALSE(is_url_being_fetched()); + + // Results come in, but end up being ignored. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(0, update_count()); + + // Cross process navigation must have been cancelled, and a new load appears! + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::NON_ERROR_PAGE); + + // It fails, and a Link Doctor page is requested again. + core().GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, + NetError(net::ERR_NAME_NOT_RESOLVED), + false, &html); + EXPECT_TRUE(html.empty()); + + // The blank page loads again. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + EXPECT_TRUE(is_url_being_fetched()); + + // Link Doctor load fails, probe pending page shown. + LinkDoctorLoadFailure(); + EXPECT_EQ(1, error_html_update_count()); + EXPECT_EQ(last_error_html(), + ProbeErrorString(chrome_common_net::DNS_PROBE_POSSIBLE)); + EXPECT_FALSE(is_url_being_fetched()); + + // Probe page loads. + core().OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + core().OnCommitLoad(NetErrorHelperCore::MAIN_FRAME); + core().OnFinishLoad(NetErrorHelperCore::MAIN_FRAME); + + // Probe statuses comes in, and page is updated. + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_STARTED); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_STARTED), + last_error_html()); + EXPECT_EQ(1, update_count()); + + core().OnNetErrorInfo(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); + EXPECT_EQ(2, update_count()); + EXPECT_EQ(ProbeErrorString(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN), + last_error_html()); + EXPECT_EQ(1, error_html_update_count()); +} diff --git a/chrome/renderer/net/net_error_helper_unittest.cc b/chrome/renderer/net/net_error_helper_unittest.cc deleted file mode 100644 index 828c34e..0000000 --- a/chrome/renderer/net/net_error_helper_unittest.cc +++ /dev/null @@ -1,412 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/renderer/net/net_error_helper.h" - -#include "base/logging.h" -#include "chrome/common/net/net_error_info.h" -#include "testing/gtest/include/gtest/gtest.h" - -using chrome_common_net::DnsProbeStatus; -using chrome_common_net::DnsProbeStatusToString; - -// NetErrorHelperTest cases consist of a string of these steps. -enum TestStep { - // Simulate a provisional load start, fail, commit or a finish-load event. - // (Start and fail differentiate between normal and error pages.) - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, - LOAD_COMMIT, LOAD_FINISH, - - // Simulate an IPC from the browser with DNS_PROBE_STARTED, _NOT_RUN, or - // _FINISHED_NXDOMAIN. - STATUS_STARTED, STATUS_NOT_RUN, STATUS_FINISHED, - - // Expect that the *next* step will cause an update. (Any step that is not - // prefixed by this pseudo-step is expected *not* to cause an update.) - EXPECT_UPDATE -}; - -class TestNetErrorHelper : public NetErrorHelper { - public: - TestNetErrorHelper() - : NetErrorHelper(NULL), - mock_page_update_count_(0), - mock_displayed_probe_status_(chrome_common_net::DNS_PROBE_MAX) {} - - virtual ~TestNetErrorHelper() {} - - void StartLoad(bool is_main_frame, bool is_error_page) { - OnStartLoad(is_main_frame, is_error_page); - } - - void FailLoad(bool is_main_frame, bool is_dns_error) { - OnFailLoad(is_main_frame, is_dns_error); - } - - void CommitLoad(bool is_main_frame) { - OnCommitLoad(is_main_frame); - } - - void FinishLoad(bool is_main_frame) { - OnFinishLoad(is_main_frame); - } - - void ReceiveProbeStatus(DnsProbeStatus status) { - OnNetErrorInfo(static_cast<int>(status)); - } - - int mock_page_update_count() const { return mock_page_update_count_; } - DnsProbeStatus mock_displayed_probe_status() const { - return mock_displayed_probe_status_; - } - - protected: - virtual void UpdateErrorPage() OVERRIDE { - DVLOG(1) << "Updating error page with status " - << DnsProbeStatusToString(last_probe_status_); - mock_page_update_count_++; - mock_displayed_probe_status_ = last_probe_status_; - } - - private: - int mock_page_update_count_; - DnsProbeStatus mock_displayed_probe_status_; -}; - -class NetErrorHelperTest : public testing::Test { - protected: - enum MainFrame { SUB_FRAME, MAIN_FRAME }; - enum ErrorPage { NORMAL_PAGE, ERROR_PAGE }; - enum ErrorType { OTHER_ERROR, DNS_ERROR }; - - void StartLoad(MainFrame main_frame, ErrorPage error_page) { - helper_.StartLoad(main_frame == MAIN_FRAME, error_page == ERROR_PAGE); - } - - void FailLoad(MainFrame main_frame, ErrorType error_type) { - helper_.FailLoad(main_frame == MAIN_FRAME, error_type == DNS_ERROR); - } - - void CommitLoad(MainFrame main_frame) { - helper_.CommitLoad(main_frame == MAIN_FRAME); - } - - void FinishLoad(MainFrame main_frame) { - helper_.FinishLoad(main_frame == MAIN_FRAME); - } - - void ReceiveProbeStatus(DnsProbeStatus status) { - helper_.ReceiveProbeStatus(status); - } - - void RunTest(const TestStep steps[], int step_count); - - int page_update_count() const { return helper_.mock_page_update_count(); } - DnsProbeStatus displayed_probe_status() const { - return helper_.mock_displayed_probe_status(); - } - - private: - TestNetErrorHelper helper_; -}; - -void NetErrorHelperTest::RunTest(const TestStep steps[], int step_count) { - // Whether the next instruction is expected to cause an update (since the - // step right before it was EXPECT_UPDATE) or not. - bool update_expected = false; - int expected_update_count = page_update_count(); - // The last status that the test simulated receiving from the browser. - // When an update is expected, the status is expected to match this. - chrome_common_net::DnsProbeStatus last_status_received = - chrome_common_net::DNS_PROBE_POSSIBLE; - - for (int i = 0; i < step_count; i++) { - switch (steps[i]) { - case LOAD_NORMAL_START: - StartLoad(MAIN_FRAME, NORMAL_PAGE); - break; - case LOAD_NORMAL_FAIL: - FailLoad(MAIN_FRAME, DNS_ERROR); - break; - case LOAD_ERROR_START: - StartLoad(MAIN_FRAME, ERROR_PAGE); - break; - case LOAD_COMMIT: - CommitLoad(MAIN_FRAME); - break; - case LOAD_FINISH: - FinishLoad(MAIN_FRAME); - break; - case STATUS_STARTED: - ReceiveProbeStatus(chrome_common_net::DNS_PROBE_STARTED); - last_status_received = chrome_common_net::DNS_PROBE_STARTED; - break; - case STATUS_NOT_RUN: - ReceiveProbeStatus(chrome_common_net::DNS_PROBE_NOT_RUN); - last_status_received = chrome_common_net::DNS_PROBE_NOT_RUN; - break; - case STATUS_FINISHED: - ReceiveProbeStatus(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); - last_status_received = chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN; - break; - case EXPECT_UPDATE: - ASSERT_FALSE(update_expected); - update_expected = true; - // Skip to next step to see if it updates the status, instead of - // checking whether EXPECT_UPDATE itself caused an update. - continue; - } - - if (update_expected) { - DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, last_status_received); - ++expected_update_count; - - EXPECT_EQ(last_status_received, displayed_probe_status()); - if (displayed_probe_status() != last_status_received) { - LOG(ERROR) << "Unexpected status at step " << i << "."; - return; - } - } - - EXPECT_EQ(expected_update_count, page_update_count()); - if (page_update_count() != expected_update_count) { - LOG(ERROR) << (update_expected ? "Missing" : "Spurious") - << " update at step " << i << "."; - return; - } - - update_expected = false; - } - - DCHECK(!update_expected); -} - -TEST_F(NetErrorHelperTest, Null) { - // Test that we can simply create and destroy a NetErrorHelper. -} - -TEST_F(NetErrorHelperTest, SuccessfulPageLoad) { - StartLoad(MAIN_FRAME, NORMAL_PAGE); - CommitLoad(MAIN_FRAME); - FinishLoad(MAIN_FRAME); - - // Ignore spurious status. - ReceiveProbeStatus(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); - EXPECT_EQ(0, page_update_count()); -} - -TEST_F(NetErrorHelperTest, MainFrameNonDnsError) { - StartLoad(MAIN_FRAME, NORMAL_PAGE); - FailLoad(MAIN_FRAME, OTHER_ERROR); - StartLoad(MAIN_FRAME, ERROR_PAGE); - CommitLoad(MAIN_FRAME); - FinishLoad(MAIN_FRAME); - - // Ignore spurious status. - ReceiveProbeStatus(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); - EXPECT_EQ(0, page_update_count()); -} - -TEST_F(NetErrorHelperTest, SubFrameDnsError) { - StartLoad(SUB_FRAME, NORMAL_PAGE); - FailLoad(SUB_FRAME, DNS_ERROR); - StartLoad(SUB_FRAME, ERROR_PAGE); - CommitLoad(SUB_FRAME); - FinishLoad(SUB_FRAME); - - // Ignore spurious status. - ReceiveProbeStatus(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); - EXPECT_EQ(0, page_update_count()); -} - -TEST_F(NetErrorHelperTest, FinishedAfterFail) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, STATUS_FINISHED, LOAD_ERROR_START, - LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH - }; - RunTest(steps, arraysize(steps)); -} - -TEST_F(NetErrorHelperTest, FinishedAfterFail_StartedAfterFail) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, STATUS_STARTED, STATUS_FINISHED, - LOAD_ERROR_START, LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH - }; - RunTest(steps, arraysize(steps)); -} - -TEST_F(NetErrorHelperTest, FinishedAfterStart) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, STATUS_FINISHED, - LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH - }; - RunTest(steps, arraysize(steps)); -} - -TEST_F(NetErrorHelperTest, FinishedAfterStart_StartedAfterFail) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, STATUS_STARTED, LOAD_ERROR_START, - STATUS_FINISHED, LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH - }; - RunTest(steps, arraysize(steps)); -} - -TEST_F(NetErrorHelperTest, FinishedAfterStart_StartedAfterStart) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, STATUS_STARTED, LOAD_ERROR_START, - STATUS_FINISHED, LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH - }; - RunTest(steps, arraysize(steps)); -} - -TEST_F(NetErrorHelperTest, FinishedAfterCommit) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT, - STATUS_FINISHED, EXPECT_UPDATE, LOAD_FINISH - }; - RunTest(steps, arraysize(steps)); -} - -TEST_F(NetErrorHelperTest, FinishedAfterCommit_StartedAfterFail) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, STATUS_STARTED, LOAD_ERROR_START, - LOAD_COMMIT, STATUS_FINISHED, EXPECT_UPDATE, LOAD_FINISH - }; - RunTest(steps, arraysize(steps)); -} - -TEST_F(NetErrorHelperTest, FinishedAfterCommit_StartedAfterStart) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, STATUS_STARTED, - LOAD_ERROR_START, LOAD_COMMIT, STATUS_FINISHED, EXPECT_UPDATE, LOAD_FINISH - }; - RunTest(steps, arraysize(steps)); -} - -TEST_F(NetErrorHelperTest, FinishedAfterCommit_StartedAfterCommit) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT, - STATUS_STARTED, STATUS_FINISHED, EXPECT_UPDATE, LOAD_FINISH - }; - RunTest(steps, arraysize(steps)); -} - -TEST_F(NetErrorHelperTest, FinishedAfterFinish) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT, - LOAD_FINISH, EXPECT_UPDATE, STATUS_FINISHED - }; - RunTest(steps, arraysize(steps)); -} - -TEST_F(NetErrorHelperTest, FinishedAfterFinish_StartAfterFail) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, STATUS_STARTED, LOAD_ERROR_START, - LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH, EXPECT_UPDATE, STATUS_FINISHED - }; - RunTest(steps, arraysize(steps)); -} - -TEST_F(NetErrorHelperTest, FinishedAfterFinish_StartAfterStart) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, STATUS_STARTED, - LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH, EXPECT_UPDATE, STATUS_FINISHED - }; - RunTest(steps, arraysize(steps)); -} - -TEST_F(NetErrorHelperTest, FinishedAfterFinish_StartAfterCommit) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT, - STATUS_STARTED, EXPECT_UPDATE, LOAD_FINISH, EXPECT_UPDATE, STATUS_FINISHED - }; - RunTest(steps, arraysize(steps)); -} - -TEST_F(NetErrorHelperTest, FinishedAfterFinish_StartAfterFinish) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT, - LOAD_FINISH, EXPECT_UPDATE, STATUS_STARTED, EXPECT_UPDATE, STATUS_FINISHED - }; - RunTest(steps, arraysize(steps)); -} - -TEST_F(NetErrorHelperTest, FinishedAfterNewStart) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT, - LOAD_FINISH, LOAD_NORMAL_START, EXPECT_UPDATE, STATUS_FINISHED, - LOAD_COMMIT, LOAD_FINISH - }; - RunTest(steps, arraysize(steps)); -} - -TEST_F(NetErrorHelperTest, NotRunAfterFail) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, STATUS_NOT_RUN, LOAD_ERROR_START, - LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH - }; - RunTest(steps, arraysize(steps)); -} - -TEST_F(NetErrorHelperTest, NotRunAfterStart) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, STATUS_NOT_RUN, - LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH - }; - RunTest(steps, arraysize(steps)); -} - -TEST_F(NetErrorHelperTest, NotRunAfterCommit) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT, - STATUS_NOT_RUN, EXPECT_UPDATE, LOAD_FINISH - }; - RunTest(steps, arraysize(steps)); -} - -TEST_F(NetErrorHelperTest, NotRunAfterFinish) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT, - LOAD_FINISH, EXPECT_UPDATE, STATUS_NOT_RUN - }; - RunTest(steps, arraysize(steps)); -} - -TEST_F(NetErrorHelperTest, FinishedAfterNewCommit) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT, - LOAD_FINISH, LOAD_NORMAL_START, LOAD_COMMIT, STATUS_FINISHED, LOAD_FINISH - }; - RunTest(steps, arraysize(steps)); -} - -TEST_F(NetErrorHelperTest, FinishedAfterNewFinish) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT, - LOAD_FINISH, LOAD_NORMAL_START, LOAD_COMMIT, LOAD_FINISH, STATUS_FINISHED - }; - RunTest(steps, arraysize(steps)); -} - -// Two iterations of FinishedAfterStart_StartAfterFail -TEST_F(NetErrorHelperTest, TwoProbes_FinishedAfterStart_StartAfterFail) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, STATUS_STARTED, LOAD_ERROR_START, - STATUS_FINISHED, LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH, - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, STATUS_STARTED, LOAD_ERROR_START, - STATUS_FINISHED, LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH - }; - RunTest(steps, arraysize(steps)); -} - -// Two iterations of FinishedAfterFinish -TEST_F(NetErrorHelperTest, TwoProbes_FinishedAfterFinish) { - const TestStep steps[] = { - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT, - LOAD_FINISH, EXPECT_UPDATE, STATUS_FINISHED, - LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT, - LOAD_FINISH, EXPECT_UPDATE, STATUS_FINISHED - }; - RunTest(steps, arraysize(steps)); -} |