errorpage_browsertest.cc 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/memory/raw_ptr.h"
  5. #include "weblayer/test/weblayer_browser_test.h"
  6. #include "base/test/bind.h"
  7. #include "base/test/scoped_feature_list.h"
  8. #include "build/build_config.h"
  9. #include "components/embedder_support/switches.h"
  10. #include "components/error_page/content/browser/net_error_auto_reloader.h"
  11. #include "content/public/test/browser_test_utils.h"
  12. #include "content/public/test/url_loader_interceptor.h"
  13. #include "net/test/url_request/url_request_failed_job.h"
  14. #include "weblayer/browser/tab_impl.h"
  15. #include "weblayer/public/navigation_controller.h"
  16. #include "weblayer/shell/browser/shell.h"
  17. #include "weblayer/test/weblayer_browser_test_utils.h"
  18. #if BUILDFLAG(IS_ANDROID)
  19. #include "components/strings/grit/components_strings.h"
  20. #include "ui/base/l10n/l10n_util.h"
  21. #endif
  22. namespace weblayer {
  23. using ErrorPageBrowserTest = WebLayerBrowserTest;
  24. IN_PROC_BROWSER_TEST_F(ErrorPageBrowserTest, NameNotResolved) {
  25. GURL error_page_url =
  26. net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED);
  27. NavigateAndWaitForFailure(error_page_url, shell());
  28. // Currently, interstitials for error pages are displayed only on Android.
  29. #if BUILDFLAG(IS_ANDROID)
  30. std::u16string expected_title =
  31. l10n_util::GetStringUTF16(IDS_ANDROID_ERROR_PAGE_WEBPAGE_NOT_AVAILABLE);
  32. EXPECT_EQ(expected_title, GetTitle(shell()));
  33. #endif
  34. }
  35. // Verifies that navigating to a URL that returns a 404 with an empty body
  36. // results in the navigation failing.
  37. IN_PROC_BROWSER_TEST_F(ErrorPageBrowserTest, 404WithEmptyBody) {
  38. EXPECT_TRUE(embedded_test_server()->Start());
  39. GURL error_page_url = embedded_test_server()->GetURL("/empty404.html");
  40. NavigateAndWaitForFailure(error_page_url, shell());
  41. }
  42. class ErrorPageReloadBrowserTest : public ErrorPageBrowserTest {
  43. public:
  44. ErrorPageReloadBrowserTest() = default;
  45. void SetUpCommandLine(base::CommandLine* command_line) override {
  46. command_line->AppendSwitch(embedder_support::kEnableAutoReload);
  47. ErrorPageBrowserTest::SetUpCommandLine(command_line);
  48. }
  49. // Helper to perform navigations, whether successful or intercepted for
  50. // simulated failure. Note that this asynchronously initiates the navigation
  51. // and then waits only for the *navigation* to finish; this is in contrast to
  52. // common test utilities which wait for loading to finish. It matters because
  53. // most of NetErrorAutoReloader's interesting behavior is triggered at
  54. // navigation completion and tests may want to observe the immediate side
  55. // effects, such as the scheduling of an auto-reload timer.
  56. //
  57. // Return true if the navigation was successful, or false if it failed.
  58. [[nodiscard]] bool Navigate(const GURL& url,
  59. bool disable_network_error_auto_reload = false) {
  60. content::TestNavigationManager navigation(web_contents(), url);
  61. NavigationController::NavigateParams params;
  62. auto* navigation_controller = shell()->tab()->GetNavigationController();
  63. std::unique_ptr<DisableAutoReload> disable_auto_reload;
  64. if (disable_network_error_auto_reload)
  65. disable_auto_reload =
  66. std::make_unique<DisableAutoReload>(navigation_controller);
  67. navigation_controller->Navigate(url, params);
  68. navigation.WaitForNavigationFinished();
  69. return navigation.was_successful();
  70. }
  71. // Returns the time-delay of the currently scheduled auto-reload task, if one
  72. // is scheduled. If no auto-reload is scheduled, this returns null.
  73. absl::optional<base::TimeDelta> GetCurrentAutoReloadDelay() {
  74. auto* auto_reloader =
  75. error_page::NetErrorAutoReloader::FromWebContents(web_contents());
  76. if (!auto_reloader)
  77. return absl::nullopt;
  78. const absl::optional<base::OneShotTimer>& timer =
  79. auto_reloader->next_reload_timer_for_testing();
  80. if (!timer)
  81. return absl::nullopt;
  82. return timer->GetCurrentDelay();
  83. }
  84. content::WebContents* web_contents() {
  85. return static_cast<TabImpl*>(shell()->tab())->web_contents();
  86. }
  87. private:
  88. class DisableAutoReload : public NavigationObserver {
  89. public:
  90. explicit DisableAutoReload(NavigationController* controller)
  91. : controller_(controller) {
  92. controller_->AddObserver(this);
  93. }
  94. ~DisableAutoReload() override { controller_->RemoveObserver(this); }
  95. // NavigationObserver implementation:
  96. void NavigationStarted(Navigation* navigation) override {
  97. navigation->DisableNetworkErrorAutoReload();
  98. }
  99. private:
  100. raw_ptr<NavigationController> controller_;
  101. };
  102. };
  103. IN_PROC_BROWSER_TEST_F(ErrorPageReloadBrowserTest, ReloadOnNetworkChanged) {
  104. ASSERT_TRUE(embedded_test_server()->Start());
  105. // Ensure that the NetErrorAutoReloader believes it's online, otherwise it
  106. // does not attempt auto-reload on error pages.
  107. error_page::NetErrorAutoReloader::CreateForWebContents(web_contents());
  108. auto* reloader =
  109. error_page::NetErrorAutoReloader::FromWebContents(web_contents());
  110. reloader->DisableConnectionChangeObservationForTesting();
  111. reloader->OnConnectionChanged(network::mojom::ConnectionType::CONNECTION_4G);
  112. GURL url = embedded_test_server()->GetURL("/error_page");
  113. // We send net::ERR_NETWORK_CHANGED on the first load, and the reload should
  114. // get a net::OK response.
  115. bool first_try = true;
  116. content::URLLoaderInterceptor interceptor(base::BindLambdaForTesting(
  117. [&url, &first_try](content::URLLoaderInterceptor::RequestParams* params) {
  118. if (params->url_request.url == url) {
  119. if (first_try) {
  120. first_try = false;
  121. params->client->OnComplete(
  122. network::URLLoaderCompletionStatus(net::ERR_NETWORK_CHANGED));
  123. } else {
  124. content::URLLoaderInterceptor::WriteResponse(
  125. "weblayer/test/data/simple_page.html", params->client.get());
  126. }
  127. return true;
  128. }
  129. return false;
  130. }));
  131. NavigateAndWaitForCompletion(url, shell());
  132. }
  133. // By default auto reload is enabled.
  134. IN_PROC_BROWSER_TEST_F(ErrorPageReloadBrowserTest, AutoReloadDefault) {
  135. ASSERT_TRUE(embedded_test_server()->Start());
  136. // Ensure that the NetErrorAutoReloader believes it's online, otherwise it
  137. // does not attempt auto-reload on error pages.
  138. error_page::NetErrorAutoReloader::CreateForWebContents(web_contents());
  139. auto* reloader =
  140. error_page::NetErrorAutoReloader::FromWebContents(web_contents());
  141. reloader->DisableConnectionChangeObservationForTesting();
  142. reloader->OnConnectionChanged(network::mojom::ConnectionType::CONNECTION_4G);
  143. GURL url = embedded_test_server()->GetURL("/error_page");
  144. content::URLLoaderInterceptor interceptor(base::BindLambdaForTesting(
  145. [&url](content::URLLoaderInterceptor::RequestParams* params) {
  146. if (params->url_request.url == url) {
  147. params->client->OnComplete(
  148. network::URLLoaderCompletionStatus(net::ERR_NETWORK_CHANGED));
  149. return true;
  150. }
  151. return false;
  152. }));
  153. EXPECT_FALSE(Navigate(url));
  154. EXPECT_EQ(error_page::NetErrorAutoReloader::GetNextReloadDelayForTesting(0),
  155. GetCurrentAutoReloadDelay());
  156. }
  157. IN_PROC_BROWSER_TEST_F(ErrorPageReloadBrowserTest, AutoReloadDisabled) {
  158. ASSERT_TRUE(embedded_test_server()->Start());
  159. GURL url = embedded_test_server()->GetURL("/error_page");
  160. content::URLLoaderInterceptor interceptor(base::BindLambdaForTesting(
  161. [&url](content::URLLoaderInterceptor::RequestParams* params) {
  162. if (params->url_request.url == url) {
  163. params->client->OnComplete(
  164. network::URLLoaderCompletionStatus(net::ERR_NETWORK_CHANGED));
  165. return true;
  166. }
  167. return false;
  168. }));
  169. EXPECT_FALSE(Navigate(url, true));
  170. EXPECT_EQ(absl::nullopt, GetCurrentAutoReloadDelay());
  171. }
  172. } // namespace weblayer