#include <algorithm>
#include <atomic>
#include <iterator>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "base/base_switches.h"
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/sequence_checker.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/captive_portal/captive_portal_service_factory.h"
#include "chrome/browser/interstitials/security_interstitial_page_test_utils.h"
#include "chrome/browser/net/secure_dns_config.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/captive_portal/content/captive_portal_service.h"
#include "components/captive_portal/content/captive_portal_tab_helper.h"
#include "components/captive_portal/content/captive_portal_tab_reloader.h"
#include "components/captive_portal/core/captive_portal_types.h"
#include "components/embedder_support/pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/security_interstitials/content/captive_portal_blocking_page.h"
#include "components/security_interstitials/content/security_interstitial_page.h"
#include "components/security_interstitials/content/security_interstitial_tab_helper.h"
#include "components/security_interstitials/content/ssl_blocking_page.h"
#include "components/security_interstitials/content/ssl_error_handler.h"
#include "components/tabs/public/tab_interface.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/prerender_test_util.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/url_loader_interceptor.h"
#include "extensions/buildflags/buildflags.h"
#include "net/base/net_errors.h"
#include "net/cert/x509_certificate.h"
#include "net/dns/mock_host_resolver.h"
#include "net/http/http_util.h"
#include "net/http/transport_security_state.h"
#include "net/test/cert_test_util.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/test_data_directory.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(IS_WIN)
#include "base/win/win_util.h"
#endif
#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "base/files/file_path.h"
#include "chrome/browser/ui/web_applications/test/isolated_web_app_test_utils.h"
#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
#include "chrome/browser/web_applications/isolated_web_apps/test/isolated_web_app_builder.h"
#include "chrome/browser/web_applications/os_integration/os_integration_manager.h"
#include "content/public/common/content_features.h"
#include "extensions/browser/guest_view/web_view/web_view_guest.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/apps/app_service/browser_app_launcher.h"
#include "chrome/browser/apps/app_service/chrome_app_deprecation/chrome_app_deprecation.h"
#include "chrome/browser/apps/platform_apps/app_browsertest_util.h"
#include "chrome/browser/extensions/chrome_test_extension_loader.h"
#include "extensions/browser/app_window/app_window_registry.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/test_extension_dir.h"
#endif
#endif
using captive_portal::CaptivePortalResult;
using content::BrowserThread;
using content::WebContents;
using content::WebContentsObserver;
namespace {
const char* const kTestServerLoginPath = "/captive_portal/login.html";
const char* const kTestServerIframeTimeoutPath =
"/captive_portal/iframe_timeout.html";
const char* const kRedirectToMockHttpsPath =
"/captive_portal/redirect_to_mock_https.html";
const char* const kMockHttpsBadCertPath = "/bad_cert.html";
const char* const kMockCaptivePortalTestUrl =
"http://mock.captive.portal.test/login.html";
const char* const kMockCaptivePortal511Url =
"http://mock.captive.portal.test/page511.html";
const char* const kMockHttpsUrl =
"https://mock.captive.portal.long.timeout/title2.html";
const char* const kMockHttpsUrl2 =
"https://mock.captive.portal.long.timeout2/title2.html";
const char* const kMockHttpsQuickTimeoutUrl =
"https://mock.captive.portal.quick.timeout/title2.html";
const char* const kMockHttpConnectionTimeoutErr =
"http://mock.captive.portal.quick.error/timeout";
const char* const kMockHttpsConnectionTimeoutErr =
"https://mock.captive.portal.quick.error/timeout";
const char* const kMockHttpsConnectionUnexpectedErr =
"https://mock.captive.portal.quick.error/unexpected";
const char* const kMockHttpConnectionConnectionClosedErr =
"http://mock.captive.portal.quick.error/connection_closed";
const char* const kMockHttpConnectionSecureDnsErr =
"http://mock.captive.portal.quick.error/secure_dns";
const char* const kMockHttpsConnectionSecureDnsErr =
"https://mock.captive.portal.quick.error/secure_dns";
const char* const kInternetConnectedTitle = "Title Of Awesomeness";
const char* const kLoginSecureDnsDisabledTitle =
"Fake Login Page Secure Dns Disabled";
std::string CreateServerRedirect(const std::string& dest_url) {
const char* const kServerRedirectBase = "/server-redirect?";
return kServerRedirectBase + dest_url;
}
int NumTabs() {
int count = 0;
tabs::ForEachTabInterface([&count](tabs::TabInterface* tab) {
++count;
return true;
});
return count;
}
int NumLoadingTabs() {
int count = 0;
tabs::ForEachTabInterface([&count](tabs::TabInterface* tab) {
if (tab->GetContents()->IsLoading()) {
++count;
}
return true;
});
return count;
}
bool IsLoginTab(WebContents* web_contents) {
return captive_portal::CaptivePortalTabHelper::FromWebContents(web_contents)
->IsLoginTab();
}
#if BUILDFLAG(ENABLE_EXTENSIONS)
content::WebContents* GetWebViewContents(content::RenderFrameHost* app_frame) {
extensions::WebViewGuest* web_view_guest = nullptr;
app_frame->ForEachRenderFrameHostWithAction(
[&web_view_guest](content::RenderFrameHost* rfh) {
if (auto* web_view =
extensions::WebViewGuest::FromRenderFrameHost(rfh)) {
web_view_guest = web_view;
return content::RenderFrameHost::FrameIterationAction::kStop;
}
return content::RenderFrameHost::FrameIterationAction::kContinue;
});
CHECK(web_view_guest);
content::WebContents* web_contents = web_view_guest->web_contents();
CHECK(web_contents);
return web_contents;
}
#endif
struct LoadObserver : public WebContentsObserver {
public:
class Observer {
public:
virtual ~Observer() = default;
virtual void OnWebContentsDestroyed(WebContents*) = 0;
virtual void OnDidStopLoading(WebContents*) = 0;
};
LoadObserver(Observer* observer, WebContents* web_contents)
: WebContentsObserver(web_contents), observer_(observer) {}
void WebContentsDestroyed() override {
observer_->OnWebContentsDestroyed(web_contents());
}
void DidStopLoading() override {
observer_->OnDidStopLoading(web_contents());
}
private:
raw_ptr<Observer> observer_ = nullptr;
};
class MultiNavigationObserver : public ui_test_utils::AllTabsObserver,
public LoadObserver::Observer {
public:
MultiNavigationObserver();
~MultiNavigationObserver() override;
void WaitForNavigations(int num_navigations_to_wait_for);
int NumNavigationsForTab(WebContents* web_contents) const;
int num_navigations() const { return num_navigations_; }
private:
std::unique_ptr<base::CheckedObserver> ProcessOneContents(
WebContents* web_contents) override;
void OnWebContentsDestroyed(WebContents* web_contents) override;
void OnDidStopLoading(WebContents* web_contents) override;
using TabNavigationMap = std::map<const WebContents*, int>;
int num_navigations_ = 0;
TabNavigationMap tab_navigation_map_;
std::optional<int> num_navigations_to_wait_for_;
};
MultiNavigationObserver::MultiNavigationObserver() {
AddAllBrowsers();
}
MultiNavigationObserver::~MultiNavigationObserver() = default;
std::unique_ptr<base::CheckedObserver>
MultiNavigationObserver::ProcessOneContents(WebContents* web_contents) {
tab_navigation_map_[web_contents] = 0;
return std::make_unique<LoadObserver>(this, web_contents);
}
void MultiNavigationObserver::OnWebContentsDestroyed(
WebContents* web_contents) {
auto iter = tab_navigation_map_.find(web_contents);
CHECK(iter != tab_navigation_map_.end());
tab_navigation_map_.erase(iter);
}
void MultiNavigationObserver::OnDidStopLoading(WebContents* web_contents) {
auto iter = tab_navigation_map_.find(web_contents);
CHECK(iter != tab_navigation_map_.end());
++(iter->second);
++num_navigations_;
if (num_navigations_to_wait_for_ &&
*num_navigations_to_wait_for_ == num_navigations_) {
ConditionMet();
}
}
void MultiNavigationObserver::WaitForNavigations(
int num_navigations_to_wait_for) {
EXPECT_LT(0, num_navigations_to_wait_for);
if (num_navigations_ < num_navigations_to_wait_for) {
num_navigations_to_wait_for_ = num_navigations_to_wait_for;
Wait();
}
EXPECT_EQ(num_navigations_, num_navigations_to_wait_for);
}
int MultiNavigationObserver::NumNavigationsForTab(
WebContents* web_contents) const {
auto tab_navigations = tab_navigation_map_.find(web_contents);
if (tab_navigations == tab_navigation_map_.end()) {
return 0;
}
return tab_navigations->second;
}
class FailLoadsAfterLoginObserver : public LoadObserver::Observer {
public:
FailLoadsAfterLoginObserver();
FailLoadsAfterLoginObserver(const FailLoadsAfterLoginObserver&) = delete;
FailLoadsAfterLoginObserver& operator=(const FailLoadsAfterLoginObserver&) =
delete;
~FailLoadsAfterLoginObserver() override;
void WaitForNavigations();
void OnWebContentsDestroyed(WebContents* web_contents) override {}
void OnDidStopLoading(WebContents* web_contents) override;
private:
typedef std::set<raw_ptr<WebContents, SetExperimental>> TabSet;
TabSet tabs_needing_navigation_;
std::vector<std::unique_ptr<LoadObserver>> load_observers_;
TabSet tabs_navigated_to_final_destination_;
bool waiting_for_navigation_;
std::unique_ptr<base::RunLoop> run_loop_;
};
FailLoadsAfterLoginObserver::FailLoadsAfterLoginObserver()
: waiting_for_navigation_(false) {
tabs::ForEachTabInterface([this](tabs::TabInterface* tab) {
content::WebContents* const contents = tab->GetContents();
if (contents->IsLoading()) {
tabs_needing_navigation_.insert(contents);
}
return true;
});
for (WebContents* contents : tabs_needing_navigation_) {
load_observers_.push_back(std::make_unique<LoadObserver>(this, contents));
}
}
FailLoadsAfterLoginObserver::~FailLoadsAfterLoginObserver() = default;
void FailLoadsAfterLoginObserver::WaitForNavigations() {
EXPECT_FALSE(waiting_for_navigation_);
if (tabs_needing_navigation_.size() !=
tabs_navigated_to_final_destination_.size()) {
waiting_for_navigation_ = true;
run_loop_ = std::make_unique<base::RunLoop>();
run_loop_->Run();
EXPECT_FALSE(waiting_for_navigation_);
}
EXPECT_EQ(tabs_needing_navigation_.size(),
tabs_navigated_to_final_destination_.size());
}
void FailLoadsAfterLoginObserver::OnDidStopLoading(WebContents* contents) {
ASSERT_EQ(1u, tabs_needing_navigation_.count(contents));
ASSERT_EQ(0u, tabs_navigated_to_final_destination_.count(contents));
if (contents->GetTitle() != base::ASCIIToUTF16(kInternetConnectedTitle))
return;
tabs_navigated_to_final_destination_.insert(contents);
if (waiting_for_navigation_ &&
tabs_needing_navigation_.size() ==
tabs_navigated_to_final_destination_.size()) {
waiting_for_navigation_ = false;
if (run_loop_)
run_loop_->Quit();
}
}
class CaptivePortalObserver {
public:
explicit CaptivePortalObserver(Profile* profile);
CaptivePortalObserver(const CaptivePortalObserver&) = delete;
CaptivePortalObserver& operator=(const CaptivePortalObserver&) = delete;
void WaitForResults(int num_results_to_wait_for);
int num_results_received() const { return num_results_received_; }
CaptivePortalResult captive_portal_result() const {
return captive_portal_result_;
}
private:
void Observe(const captive_portal::CaptivePortalService::Results& results);
int num_results_received_;
int num_results_to_wait_for_;
bool waiting_for_result_;
std::unique_ptr<base::RunLoop> run_loop_;
raw_ptr<captive_portal::CaptivePortalService> captive_portal_service_;
base::CallbackListSubscription subscription_;
CaptivePortalResult captive_portal_result_;
};
CaptivePortalObserver::CaptivePortalObserver(Profile* profile)
: num_results_received_(0),
num_results_to_wait_for_(0),
waiting_for_result_(false),
captive_portal_service_(
CaptivePortalServiceFactory::GetForProfile(profile)),
captive_portal_result_(
captive_portal_service_->last_detection_result()) {
subscription_ = captive_portal_service_->RegisterCallback(base::BindRepeating(
&CaptivePortalObserver::Observe, base::Unretained(this)));
}
void CaptivePortalObserver::WaitForResults(int num_results_to_wait_for) {
EXPECT_LT(0, num_results_to_wait_for);
EXPECT_FALSE(waiting_for_result_);
if (num_results_received_ < num_results_to_wait_for) {
num_results_to_wait_for_ = num_results_to_wait_for;
waiting_for_result_ = true;
run_loop_ = std::make_unique<base::RunLoop>();
run_loop_->Run();
EXPECT_FALSE(waiting_for_result_);
}
EXPECT_EQ(num_results_to_wait_for, num_results_received_);
}
void CaptivePortalObserver::Observe(
const captive_portal::CaptivePortalService::Results& results) {
EXPECT_EQ(captive_portal_result_, results.previous_result);
EXPECT_EQ(captive_portal_service_->last_detection_result(), results.result);
captive_portal_result_ = results.result;
++num_results_received_;
if (waiting_for_result_ &&
num_results_to_wait_for_ == num_results_received_) {
waiting_for_result_ = false;
if (run_loop_)
run_loop_->Quit();
}
}
class SSLInterstitialTimerObserver {
public:
explicit SSLInterstitialTimerObserver(content::WebContents* web_contents);
SSLInterstitialTimerObserver(const SSLInterstitialTimerObserver&) = delete;
SSLInterstitialTimerObserver& operator=(const SSLInterstitialTimerObserver&) =
delete;
~SSLInterstitialTimerObserver();
void WaitForTimerStarted();
private:
void OnTimerStarted(content::WebContents* web_contents);
raw_ptr<const content::WebContents> web_contents_;
SSLErrorHandler::TimerStartedCallback callback_;
scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
};
SSLInterstitialTimerObserver::SSLInterstitialTimerObserver(
content::WebContents* web_contents)
: web_contents_(web_contents),
message_loop_runner_(new content::MessageLoopRunner) {
callback_ = base::BindRepeating(&SSLInterstitialTimerObserver::OnTimerStarted,
base::Unretained(this));
SSLErrorHandler::SetInterstitialTimerStartedCallbackForTesting(&callback_);
}
SSLInterstitialTimerObserver::~SSLInterstitialTimerObserver() {
SSLErrorHandler::SetInterstitialTimerStartedCallbackForTesting(nullptr);
}
void SSLInterstitialTimerObserver::WaitForTimerStarted() {
message_loop_runner_->Run();
}
void SSLInterstitialTimerObserver::OnTimerStarted(
content::WebContents* web_contents) {
if (web_contents_ == web_contents && message_loop_runner_.get())
message_loop_runner_->Quit();
}
class TabActivationWaiter : public TabStripModelObserver {
public:
explicit TabActivationWaiter(TabStripModel* tab_strip_model)
: number_of_unconsumed_active_tab_changes_(0) {
tab_strip_model->AddObserver(this);
}
TabActivationWaiter(const TabActivationWaiter&) = delete;
TabActivationWaiter& operator=(const TabActivationWaiter&) = delete;
void WaitForActiveTabChange() {
if (number_of_unconsumed_active_tab_changes_ == 0) {
message_loop_runner_ = new content::MessageLoopRunner;
message_loop_runner_->Run();
}
DCHECK_EQ(1, number_of_unconsumed_active_tab_changes_);
number_of_unconsumed_active_tab_changes_--;
}
void OnTabStripModelChanged(
TabStripModel* tab_strip_model,
const TabStripModelChange& change,
const TabStripSelectionChange& selection) override {
if (tab_strip_model->empty() || !selection.active_tab_changed())
return;
number_of_unconsumed_active_tab_changes_++;
DCHECK_EQ(1, number_of_unconsumed_active_tab_changes_);
if (message_loop_runner_)
message_loop_runner_->Quit();
}
private:
scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
int number_of_unconsumed_active_tab_changes_;
};
}
class CaptivePortalBrowserTest : public InProcessBrowserTest {
public:
CaptivePortalBrowserTest();
CaptivePortalBrowserTest(const CaptivePortalBrowserTest&) = delete;
CaptivePortalBrowserTest& operator=(const CaptivePortalBrowserTest&) = delete;
~CaptivePortalBrowserTest() override;
void SetUpOnMainThread() override;
void TearDownOnMainThread() override;
bool OnIntercept(content::URLLoaderInterceptor::RequestParams* params);
void EnableCaptivePortalDetection(Profile* profile, bool enabled);
void RespondToProbeRequests(bool enabled);
void SetUpCaptivePortalService(Profile* profile, const GURL& test_url);
bool CheckPending(Browser* browser);
security_interstitials::SecurityInterstitialPage::TypeID GetInterstitialType(
WebContents* contents) const;
bool IsShowingInterstitial(WebContents* contents);
captive_portal::CaptivePortalTabReloader::State GetStateOfTabReloader(
WebContents* web_contents) const;
captive_portal::CaptivePortalTabReloader::State GetStateOfTabReloaderAt(
Browser* browser,
int index) const;
int NumTabsWithState(
captive_portal::CaptivePortalTabReloader::State state) const;
int NumBrokenTabs() const;
int NumNeedReloadTabs() const;
void NavigateToPageExpectNoTest(Browser* browser, const GURL& url);
void SlowLoadNoCaptivePortal(Browser* browser,
CaptivePortalResult expected_result);
void FastTimeoutNoCaptivePortal(Browser* browser,
CaptivePortalResult expected_result);
void SlowLoadBehindCaptivePortal(Browser* browser,
bool expect_open_login_tab,
bool expect_new_login_browser = false,
Browser** out_login_browser = nullptr);
void SlowLoadBehindCaptivePortal(Browser* browser,
bool expect_open_login_tab,
bool expect_new_login_browser,
const GURL& hanging_url,
int expected_portal_checks,
int expected_login_tab_navigations,
Browser** out_login_browser = nullptr);
void FastTimeoutBehindCaptivePortal(Browser* browser,
bool expect_open_login_tab);
void FastErrorBehindCaptivePortal(Browser* browser,
bool expect_open_login_tab,
bool expect_new_login_browser,
const GURL& error_url,
Browser** out_login_browser = nullptr);
void FastErrorWithInterstitialTimer(Browser* browser,
const GURL& cert_error_url);
void NavigateLoginTab(Browser* browser,
int num_loading_tabs,
int num_timed_out_tabs);
void Login(Browser* captive_portal_browser,
int num_loading_tabs,
int num_timed_out_tabs,
int expected_portal_checks);
void LoginCertError(Browser* browser);
void FailLoadsAfterLogin(Browser* browser, int num_loading_tabs);
void FailLoadsWithoutLogin(Browser* browser,
int num_loading_tabs,
Browser* captive_portal_browser = nullptr);
void RunNavigateLoadingTabToTimeoutTest(Browser* browser,
const GURL& starting_url,
const GURL& interrupted_url,
const GURL& timeout_url);
void SetSlowSSLLoadTime(
captive_portal::CaptivePortalTabReloader* tab_reloader,
base::TimeDelta slow_ssl_load_time);
captive_portal::CaptivePortalTabReloader* GetTabReloader(
WebContents* web_contents) const;
void SetBehindCaptivePortal(bool behind_captive_portal) {
behind_captive_portal_ = behind_captive_portal;
}
void WaitForJobs(int num_jobs) {
if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
SetNumJobsToWaitForOnInterceptorThread(num_jobs);
} else {
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(
&CaptivePortalBrowserTest::SetNumJobsToWaitForOnInterceptorThread,
base::Unretained(this), num_jobs));
}
run_loop_ = std::make_unique<base::RunLoop>();
run_loop_->Run();
}
void SetNumJobsToWaitForOnInterceptorThread(int num_jobs) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!num_jobs_to_wait_for_);
int num_ongoing_jobs = static_cast<int>(ongoing_mock_requests_.size());
if (num_ongoing_jobs == num_jobs) {
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&CaptivePortalBrowserTest::QuitRunLoop,
base::Unretained(this)));
return;
}
EXPECT_LT(num_ongoing_jobs, num_jobs);
num_jobs_to_wait_for_ = num_jobs;
}
void FailJobs(int expected_num_jobs,
int error,
net::ResolveErrorInfo resolve_error_info) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&CaptivePortalBrowserTest::FailJobs,
base::Unretained(this), expected_num_jobs,
error, resolve_error_info));
return;
}
EXPECT_EQ(expected_num_jobs,
static_cast<int>(ongoing_mock_requests_.size()));
network::URLLoaderCompletionStatus status;
status.error_code = error;
status.resolve_error_info = resolve_error_info;
for (auto& job : ongoing_mock_requests_)
job.client->OnComplete(status);
ongoing_mock_requests_.clear();
}
void FailJobsWithCertError(int expected_num_jobs,
const net::SSLInfo& ssl_info) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&CaptivePortalBrowserTest::FailJobsWithCertError,
base::Unretained(this), expected_num_jobs, ssl_info));
return;
}
DCHECK(intercept_bad_cert_);
intercept_bad_cert_ = false;
EXPECT_EQ(expected_num_jobs,
static_cast<int>(ongoing_mock_requests_.size()));
for (auto& job : ongoing_mock_requests_) {
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&CaptivePortalBrowserTest::CreateLoader,
base::Unretained(this), std::move(job)));
}
ongoing_mock_requests_.clear();
}
void CreateLoader(content::URLLoaderInterceptor::RequestParams job) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
browser()
->profile()
->GetDefaultStoragePartition()
->GetURLLoaderFactoryForBrowserProcess()
->CreateLoaderAndStart(std::move(job.receiver), job.request_id,
job.options, std::move(job.url_request),
job.client.Unbind(), job.traffic_annotation);
}
void AbandonJobs(int expected_num_jobs) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&CaptivePortalBrowserTest::AbandonJobs,
base::Unretained(this), expected_num_jobs));
return;
}
EXPECT_EQ(expected_num_jobs,
static_cast<int>(ongoing_mock_requests_.size()));
for (auto& job : ongoing_mock_requests_) {
abandoned_client_pipes_.push_back(job.client.Unbind().PassPipe());
}
ongoing_mock_requests_.clear();
}
static std::string GetContents(const std::string& path) {
base::FilePath root_http;
base::PathService::Get(chrome::DIR_TEST_DATA, &root_http);
base::ScopedAllowBlockingForTesting allow_io;
base::FilePath file_path = root_http.AppendASCII(path);
std::string contents;
CHECK(base::ReadFileToString(file_path, &contents));
return contents;
}
void QuitRunLoop() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (run_loop_)
run_loop_->Quit();
}
#if BUILDFLAG(ENABLE_EXTENSIONS)
void CertErrorInWebAppWithEmbeddedFrameOpensCaptivePortal(
bool should_open_new_browser,
int num_navigations_to_wait_for,
base::FunctionRef<content::RenderFrameHost*()> install_and_open_web_app,
base::FunctionRef<void(content::RenderFrameHost* app_frame,
const GURL& cert_error_url)>
create_embedded_frame) {
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_MISMATCHED_NAME);
https_server.ServeFilesFromSourceDirectory(GetChromeTestDataDir());
ASSERT_TRUE(https_server.Start());
GURL cert_error_url = https_server.GetURL(kTestServerLoginPath);
content::RenderFrameHost* web_app_frame = install_and_open_web_app();
MultiNavigationObserver navigation_observer;
CaptivePortalObserver portal_observer(browser()->profile());
int initial_tab_count = 0;
if (should_open_new_browser) {
CloseBrowserSynchronously(browser());
browser_closed_ = true;
initial_tab_count = 0;
} else {
TabStripModel* tab_strip_model = browser()->tab_strip_model();
ASSERT_FALSE(tab_strip_model->GetActiveWebContents()->IsLoading());
initial_tab_count = tab_strip_model->count();
}
size_t initial_browser_count = chrome::GetTotalBrowserCount();
ui_test_utils::BrowserCreatedObserver browser_created_observer;
create_embedded_frame(web_app_frame, cert_error_url);
portal_observer.WaitForResults(1);
navigation_observer.WaitForNavigations(num_navigations_to_wait_for);
content::WebContents* embedded_frame_web_contents =
GetWebViewContents(web_app_frame);
captive_portal::CaptivePortalTabReloader* tab_reloader =
GetTabReloader(embedded_frame_web_contents);
ASSERT_TRUE(tab_reloader);
SetSlowSSLLoadTime(tab_reloader, base::Hours(1));
EXPECT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
portal_observer.captive_portal_result());
EXPECT_EQ(1, portal_observer.num_results_received());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
GetStateOfTabReloader(embedded_frame_web_contents));
TabStripModel* tab_strip_model = nullptr;
if (should_open_new_browser) {
ASSERT_EQ(initial_browser_count + 1, chrome::GetTotalBrowserCount());
BrowserWindowInterface* const new_browser =
browser_created_observer.Wait();
ASSERT_TRUE(new_browser);
tab_strip_model = new_browser->GetTabStripModel();
} else {
EXPECT_EQ(initial_browser_count, chrome::GetTotalBrowserCount());
tab_strip_model = browser()->tab_strip_model();
}
EXPECT_EQ(initial_tab_count + 1, tab_strip_model->count());
EXPECT_EQ(initial_tab_count, tab_strip_model->active_index());
WebContents* login_tab =
tab_strip_model->GetWebContentsAt(initial_tab_count);
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloader(login_tab));
EXPECT_TRUE(IsLoginTab(login_tab));
EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(login_tab));
}
#endif
protected:
std::unique_ptr<content::URLLoaderInterceptor> url_loader_interceptor_;
std::unique_ptr<base::RunLoop> run_loop_;
int num_jobs_to_wait_for_ = 0;
std::vector<content::URLLoaderInterceptor::RequestParams>
ongoing_mock_requests_;
std::vector<mojo::ScopedMessagePipeHandle> abandoned_client_pipes_;
std::atomic<bool> behind_captive_portal_;
#if BUILDFLAG(IS_WIN)
std::optional<base::win::ScopedDomainStateForTesting> scoped_domain_;
#endif
bool intercept_bad_cert_ = true;
bool browser_closed_ = false;
};
CaptivePortalBrowserTest::CaptivePortalBrowserTest()
: behind_captive_portal_(true) {
#if BUILDFLAG(IS_WIN)
scoped_domain_.emplace(false);
#endif
}
CaptivePortalBrowserTest::~CaptivePortalBrowserTest() = default;
void CaptivePortalBrowserTest::SetUpOnMainThread() {
url_loader_interceptor_ =
std::make_unique<content::URLLoaderInterceptor>(base::BindRepeating(
&CaptivePortalBrowserTest::OnIntercept, base::Unretained(this)));
EXPECT_EQ(captive_portal::CaptivePortalService::DISABLED_FOR_TESTING,
captive_portal::CaptivePortalService::get_state_for_testing());
captive_portal::CaptivePortalService::set_state_for_testing(
captive_portal::CaptivePortalService::NOT_TESTING);
EnableCaptivePortalDetection(browser()->profile(), true);
SetUpCaptivePortalService(browser()->profile(),
GURL(kMockCaptivePortalTestUrl));
SSLErrorHandler::SetInterstitialDelayForTesting(base::Hours(1));
}
bool CaptivePortalBrowserTest::OnIntercept(
content::URLLoaderInterceptor::RequestParams* params) {
if (params->url_request.url.GetPath() == kMockHttpsBadCertPath &&
intercept_bad_cert_) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
ongoing_mock_requests_.emplace_back(std::move(*params));
return true;
}
auto url_string = params->url_request.url.spec();
network::URLLoaderCompletionStatus status;
status.error_code = net::OK;
if (url_string == kMockHttpConnectionTimeoutErr ||
url_string == kMockHttpsConnectionTimeoutErr) {
status.error_code = net::ERR_CONNECTION_TIMED_OUT;
} else if (url_string == kMockHttpsConnectionUnexpectedErr) {
status.error_code = net::ERR_UNEXPECTED;
} else if (url_string == kMockHttpConnectionConnectionClosedErr) {
status.error_code = net::ERR_CONNECTION_CLOSED;
} else if (url_string == kMockHttpConnectionSecureDnsErr ||
url_string == kMockHttpsConnectionSecureDnsErr) {
status.error_code = net::ERR_NAME_NOT_RESOLVED;
status.resolve_error_info = net::ResolveErrorInfo(
net::ERR_CERT_COMMON_NAME_INVALID, true );
}
if (status.error_code != net::OK) {
params->client->OnComplete(status);
return true;
}
if (url_string == kMockHttpsUrl || url_string == kMockHttpsUrl2 ||
url_string == kMockHttpsQuickTimeoutUrl ||
params->url_request.url.GetPath() == kRedirectToMockHttpsPath) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (params->url_request.url.GetPath() == kRedirectToMockHttpsPath) {
net::RedirectInfo redirect_info;
redirect_info.new_url = GURL(kMockHttpsUrl);
redirect_info.new_method = "GET";
std::string headers;
headers = base::StringPrintf(
"HTTP/1.0 301 Moved permanently\n"
"Location: %s\n"
"Content-Type: text/html\n\n",
kMockHttpsUrl);
net::HttpResponseInfo info;
info.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
net::HttpUtil::AssembleRawHeaders(headers));
auto response = network::mojom::URLResponseHead::New();
response->headers = info.headers;
response->headers->GetMimeType(&response->mime_type);
response->encoded_data_length = 0;
params->client->OnReceiveRedirect(redirect_info, std::move(response));
}
if (behind_captive_portal_) {
if (url_string == kMockHttpsQuickTimeoutUrl) {
network::URLLoaderCompletionStatus completion_status;
completion_status.error_code = net::ERR_CONNECTION_TIMED_OUT;
params->client->OnComplete(completion_status);
} else {
ongoing_mock_requests_.emplace_back(std::move(*params));
if (num_jobs_to_wait_for_ ==
static_cast<int>(ongoing_mock_requests_.size())) {
num_jobs_to_wait_for_ = 0;
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&CaptivePortalBrowserTest::QuitRunLoop,
base::Unretained(this)));
}
}
} else {
content::URLLoaderInterceptor::WriteResponse(
"HTTP/1.1 200 OK\nContent-type: text/html\n\n",
GetContents("title2.html"), params->client.get());
}
return true;
}
std::string headers;
if (url_string == kMockCaptivePortalTestUrl ||
url_string == kMockCaptivePortal511Url) {
std::string contents;
if (behind_captive_portal_) {
if (url_string == kMockCaptivePortal511Url) {
contents = GetContents("captive_portal/page511.html");
headers = "HTTP/1.1 511 Network Authentication Required\n";
} else {
contents =
params->url_request.trusted_params->disable_secure_dns
? GetContents("captive_portal/login_secure_dns_disabled.html")
: GetContents("captive_portal/login.html");
headers = "HTTP/1.0 200 Just Peachy\n";
}
} else {
headers = "HTTP/1.0 204 No Content\nContent-Length: 0\n";
}
headers += "Content-Type: text/html\n\n";
content::URLLoaderInterceptor::WriteResponse(headers, contents,
params->client.get());
return true;
}
return false;
}
void CaptivePortalBrowserTest::TearDownOnMainThread() {
if (!browser_closed_) {
EXPECT_FALSE(CheckPending(browser()));
}
url_loader_interceptor_.reset();
abandoned_client_pipes_.clear();
}
void CaptivePortalBrowserTest::EnableCaptivePortalDetection(
Profile* profile, bool enabled) {
profile->GetPrefs()->SetBoolean(embedder_support::kAlternateErrorPagesEnabled,
enabled);
}
void CaptivePortalBrowserTest::RespondToProbeRequests(bool enabled) {
if (enabled) {
EXPECT_EQ(captive_portal::CaptivePortalService::IGNORE_REQUESTS_FOR_TESTING,
captive_portal::CaptivePortalService::get_state_for_testing());
captive_portal::CaptivePortalService::set_state_for_testing(
captive_portal::CaptivePortalService::NOT_TESTING);
} else {
EXPECT_EQ(captive_portal::CaptivePortalService::NOT_TESTING,
captive_portal::CaptivePortalService::get_state_for_testing());
captive_portal::CaptivePortalService::set_state_for_testing(
captive_portal::CaptivePortalService::IGNORE_REQUESTS_FOR_TESTING);
}
}
void CaptivePortalBrowserTest::SetUpCaptivePortalService(Profile* profile,
const GURL& test_url) {
captive_portal::CaptivePortalService* captive_portal_service =
CaptivePortalServiceFactory::GetForProfile(profile);
captive_portal_service->set_test_url(test_url);
captive_portal::CaptivePortalService::RecheckPolicy* recheck_policy =
&captive_portal_service->recheck_policy();
recheck_policy->initial_backoff_no_portal_ms = 0;
recheck_policy->initial_backoff_portal_ms = 0;
recheck_policy->backoff_policy.maximum_backoff_ms = 0;
}
bool CaptivePortalBrowserTest::CheckPending(Browser* browser) {
captive_portal::CaptivePortalService* captive_portal_service =
CaptivePortalServiceFactory::GetForProfile(browser->profile());
return captive_portal_service->DetectionInProgress() ||
captive_portal_service->TimerRunning();
}
security_interstitials::SecurityInterstitialPage::TypeID
CaptivePortalBrowserTest::GetInterstitialType(WebContents* contents) const {
security_interstitials::SecurityInterstitialTabHelper* helper =
security_interstitials::SecurityInterstitialTabHelper::FromWebContents(
contents);
if (!helper)
return nullptr;
security_interstitials::SecurityInterstitialPage* blocking_page =
helper->GetBlockingPageForCurrentlyCommittedNavigationForTesting();
if (!blocking_page)
return nullptr;
return blocking_page->GetTypeForTesting();
}
bool CaptivePortalBrowserTest::IsShowingInterstitial(WebContents* contents) {
return GetInterstitialType(contents) != nullptr;
}
captive_portal::CaptivePortalTabReloader::State
CaptivePortalBrowserTest::GetStateOfTabReloader(
WebContents* web_contents) const {
return GetTabReloader(web_contents)->state();
}
captive_portal::CaptivePortalTabReloader::State
CaptivePortalBrowserTest::GetStateOfTabReloaderAt(Browser* browser,
int index) const {
return GetStateOfTabReloader(
browser->tab_strip_model()->GetWebContentsAt(index));
}
int CaptivePortalBrowserTest::NumTabsWithState(
captive_portal::CaptivePortalTabReloader::State state) const {
int count = 0;
tabs::ForEachTabInterface([this, state, &count](tabs::TabInterface* tab) {
if (GetStateOfTabReloader(tab->GetContents()) == state) {
++count;
}
return true;
});
return count;
}
int CaptivePortalBrowserTest::NumBrokenTabs() const {
return NumTabsWithState(
captive_portal::CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL);
}
int CaptivePortalBrowserTest::NumNeedReloadTabs() const {
return NumTabsWithState(
captive_portal::CaptivePortalTabReloader::STATE_NEEDS_RELOAD);
}
void CaptivePortalBrowserTest::NavigateToPageExpectNoTest(Browser* browser,
const GURL& url) {
MultiNavigationObserver navigation_observer;
CaptivePortalObserver portal_observer(browser->profile());
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser, url));
EXPECT_EQ(0, portal_observer.num_results_received());
EXPECT_FALSE(CheckPending(browser));
EXPECT_EQ(1, browser->tab_strip_model()->count());
EXPECT_EQ(1, navigation_observer.num_navigations());
EXPECT_EQ(0, NumLoadingTabs());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser, 0));
}
void CaptivePortalBrowserTest::SlowLoadNoCaptivePortal(
Browser* browser,
CaptivePortalResult expected_result) {
captive_portal::CaptivePortalTabReloader* tab_reloader =
GetTabReloader(browser->tab_strip_model()->GetActiveWebContents());
ASSERT_TRUE(tab_reloader);
SetSlowSSLLoadTime(tab_reloader, base::TimeDelta());
MultiNavigationObserver navigation_observer;
CaptivePortalObserver portal_observer(browser->profile());
ui_test_utils::NavigateToURLWithDisposition(
browser, GURL(kMockHttpsUrl), WindowOpenDisposition::CURRENT_TAB,
ui_test_utils::BROWSER_TEST_NO_WAIT);
portal_observer.WaitForResults(1);
ASSERT_EQ(1, browser->tab_strip_model()->count());
EXPECT_EQ(expected_result, portal_observer.captive_portal_result());
EXPECT_EQ(1, portal_observer.num_results_received());
EXPECT_EQ(0, navigation_observer.num_navigations());
EXPECT_FALSE(CheckPending(browser));
EXPECT_EQ(1, NumLoadingTabs());
WaitForJobs(1);
FailJobs(1, net::ERR_CONNECTION_TIMED_OUT, net::ResolveErrorInfo(net::OK));
navigation_observer.WaitForNavigations(1);
ASSERT_EQ(1, browser->tab_strip_model()->count());
EXPECT_EQ(1, portal_observer.num_results_received());
EXPECT_FALSE(CheckPending(browser));
EXPECT_EQ(0, NumLoadingTabs());
SetSlowSSLLoadTime(tab_reloader, base::Days(1));
}
void CaptivePortalBrowserTest::FastTimeoutNoCaptivePortal(
Browser* browser,
CaptivePortalResult expected_result) {
ASSERT_NE(expected_result, captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
captive_portal::CaptivePortalTabReloader* tab_reloader =
GetTabReloader(browser->tab_strip_model()->GetActiveWebContents());
ASSERT_TRUE(tab_reloader);
SetSlowSSLLoadTime(tab_reloader, base::Hours(1));
MultiNavigationObserver navigation_observer;
CaptivePortalObserver portal_observer(browser->profile());
int active_index = browser->tab_strip_model()->active_index();
int expected_tab_count = browser->tab_strip_model()->count();
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser, GURL(kMockHttpsConnectionTimeoutErr)));
ASSERT_TRUE(portal_observer.num_results_received() > 0 ||
CheckPending(browser));
portal_observer.WaitForResults(1);
navigation_observer.WaitForNavigations(1);
EXPECT_EQ(1, portal_observer.num_results_received());
EXPECT_EQ(expected_result, portal_observer.captive_portal_result());
EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
browser->tab_strip_model()->GetWebContentsAt(active_index)));
EXPECT_EQ(0, NumLoadingTabs());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser, 0));
EXPECT_FALSE(CheckPending(browser));
EXPECT_EQ(expected_tab_count, browser->tab_strip_model()->count());
}
void CaptivePortalBrowserTest::SlowLoadBehindCaptivePortal(
Browser* browser,
bool expect_open_login_tab,
bool expect_new_login_browser,
Browser** out_login_browser) {
return SlowLoadBehindCaptivePortal(
browser, expect_open_login_tab, expect_new_login_browser,
GURL(kMockHttpsUrl), 1, 1, out_login_browser);
}
void CaptivePortalBrowserTest::SlowLoadBehindCaptivePortal(
Browser* browser,
bool expect_open_login_tab,
bool expect_new_login_browser,
const GURL& hanging_url,
int expected_portal_checks,
int expected_login_tab_navigations,
Browser** out_login_browser) {
ASSERT_GE(expected_portal_checks, 1);
TabStripModel* tab_strip_model = browser->tab_strip_model();
ASSERT_FALSE(tab_strip_model->GetActiveWebContents()->IsLoading());
captive_portal::CaptivePortalTabReloader* tab_reloader =
GetTabReloader(tab_strip_model->GetActiveWebContents());
ASSERT_TRUE(tab_reloader);
SetSlowSSLLoadTime(tab_reloader, base::TimeDelta());
int initial_tab_count = tab_strip_model->count();
int initial_active_index = tab_strip_model->active_index();
int initial_loading_tabs = NumLoadingTabs();
int expected_broken_tabs = NumBrokenTabs();
size_t initial_browser_count = chrome::GetTotalBrowserCount();
if (captive_portal::CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL !=
GetStateOfTabReloader(tab_strip_model->GetActiveWebContents())) {
++expected_broken_tabs;
}
ui_test_utils::BrowserCreatedObserver browser_created_observer;
MultiNavigationObserver navigation_observer;
CaptivePortalObserver portal_observer(browser->profile());
ui_test_utils::NavigateToURLWithDisposition(
browser, hanging_url, WindowOpenDisposition::CURRENT_TAB,
ui_test_utils::BROWSER_TEST_NO_WAIT);
portal_observer.WaitForResults(expected_portal_checks);
Browser* login_browser = nullptr;
if (expect_open_login_tab) {
ASSERT_GE(expected_login_tab_navigations, 1);
navigation_observer.WaitForNavigations(expected_login_tab_navigations);
WebContents* login_tab;
if (expect_new_login_browser) {
ASSERT_EQ(initial_browser_count + 1, chrome::GetTotalBrowserCount());
ASSERT_EQ(initial_tab_count, tab_strip_model->count());
EXPECT_EQ(initial_tab_count - 1, tab_strip_model->active_index());
login_browser = browser_created_observer.Wait();
EXPECT_EQ(Browser::TYPE_POPUP, login_browser->type());
login_tab = login_browser->GetTabStripModel()->GetWebContentsAt(0);
EXPECT_TRUE(
captive_portal::CaptivePortalTabHelper::FromWebContents(login_tab)
->is_captive_portal_window());
EXPECT_EQ(base::ASCIIToUTF16(kLoginSecureDnsDisabledTitle),
login_tab->GetTitle());
} else {
ASSERT_EQ(initial_browser_count, chrome::GetTotalBrowserCount());
ASSERT_EQ(initial_tab_count + 1, tab_strip_model->count());
EXPECT_EQ(initial_tab_count, tab_strip_model->active_index());
login_tab = tab_strip_model->GetWebContentsAt(initial_tab_count);
login_browser = browser;
}
EXPECT_EQ(expected_login_tab_navigations,
navigation_observer.NumNavigationsForTab(login_tab));
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloader(login_tab));
EXPECT_TRUE(IsLoginTab(login_tab));
} else {
ASSERT_EQ(initial_browser_count, chrome::GetTotalBrowserCount());
EXPECT_EQ(0, navigation_observer.num_navigations());
EXPECT_EQ(initial_active_index, tab_strip_model->active_index());
ASSERT_EQ(initial_tab_count, tab_strip_model->count());
EXPECT_EQ(initial_active_index, tab_strip_model->active_index());
}
WaitForJobs(initial_loading_tabs + 1);
EXPECT_EQ(initial_loading_tabs + 1, NumLoadingTabs());
EXPECT_EQ(expected_broken_tabs, NumBrokenTabs());
EXPECT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
portal_observer.captive_portal_result());
EXPECT_EQ(expected_portal_checks, portal_observer.num_results_received());
EXPECT_FALSE(CheckPending(browser));
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
GetStateOfTabReloaderAt(browser, initial_active_index));
SetSlowSSLLoadTime(tab_reloader, base::Hours(1));
if (out_login_browser)
*out_login_browser = login_browser;
}
void CaptivePortalBrowserTest::FastTimeoutBehindCaptivePortal(
Browser* browser,
bool expect_open_login_tab) {
Browser* login_browser = nullptr;
FastErrorBehindCaptivePortal(browser, expect_open_login_tab,
false ,
GURL(kMockHttpsQuickTimeoutUrl), &login_browser);
DCHECK(!login_browser || login_browser == browser);
}
void CaptivePortalBrowserTest::FastErrorBehindCaptivePortal(
Browser* browser,
bool expect_open_login_tab,
bool expect_new_login_browser,
const GURL& error_url,
Browser** out_login_browser) {
TabStripModel* tab_strip_model = browser->tab_strip_model();
ASSERT_FALSE(tab_strip_model->GetActiveWebContents()->IsLoading());
captive_portal::CaptivePortalTabReloader* tab_reloader =
GetTabReloader(tab_strip_model->GetActiveWebContents());
ASSERT_TRUE(tab_reloader);
SetSlowSSLLoadTime(tab_reloader, base::Hours(1));
int initial_tab_count = tab_strip_model->count();
int initial_active_index = tab_strip_model->active_index();
int initial_loading_tabs = NumLoadingTabs();
int expected_broken_tabs = NumBrokenTabs();
size_t initial_browser_count = chrome::GetTotalBrowserCount();
if (captive_portal::CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL !=
GetStateOfTabReloader(tab_strip_model->GetActiveWebContents())) {
++expected_broken_tabs;
}
MultiNavigationObserver navigation_observer;
CaptivePortalObserver portal_observer(browser->profile());
ui_test_utils::BrowserCreatedObserver browser_created_observer;
ui_test_utils::NavigateToURLWithDisposition(
browser, error_url, WindowOpenDisposition::CURRENT_TAB,
ui_test_utils::BROWSER_TEST_NO_WAIT);
portal_observer.WaitForResults(1);
Browser* login_browser = nullptr;
if (expect_open_login_tab) {
navigation_observer.WaitForNavigations(2);
WebContents* login_tab;
if (expect_new_login_browser) {
login_browser = browser_created_observer.Wait();
ASSERT_EQ(initial_browser_count + 1, chrome::GetTotalBrowserCount());
ASSERT_EQ(initial_tab_count, tab_strip_model->count());
EXPECT_EQ(initial_tab_count - 1, tab_strip_model->active_index());
EXPECT_EQ(Browser::TYPE_POPUP, login_browser->GetType());
login_tab = login_browser->GetTabStripModel()->GetWebContentsAt(0);
EXPECT_TRUE(
captive_portal::CaptivePortalTabHelper::FromWebContents(login_tab)
->is_captive_portal_window());
EXPECT_EQ(base::ASCIIToUTF16(kLoginSecureDnsDisabledTitle),
login_tab->GetTitle());
} else {
ASSERT_EQ(initial_browser_count, chrome::GetTotalBrowserCount());
ASSERT_EQ(initial_tab_count + 1, tab_strip_model->count());
EXPECT_EQ(initial_tab_count, tab_strip_model->active_index());
login_tab = tab_strip_model->GetWebContentsAt(initial_tab_count);
login_browser = browser;
}
EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
tab_strip_model->GetWebContentsAt(initial_active_index)));
EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(login_tab));
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloader(login_tab));
EXPECT_TRUE(IsLoginTab(login_tab));
} else {
navigation_observer.WaitForNavigations(1);
ASSERT_EQ(initial_browser_count, chrome::GetTotalBrowserCount());
EXPECT_EQ(initial_active_index, tab_strip_model->active_index());
EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
tab_strip_model->GetWebContentsAt(initial_active_index)));
ASSERT_EQ(initial_tab_count, tab_strip_model->count());
EXPECT_EQ(initial_active_index, tab_strip_model->active_index());
}
EXPECT_EQ(initial_loading_tabs, NumLoadingTabs());
EXPECT_EQ(expected_broken_tabs, NumBrokenTabs());
EXPECT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
portal_observer.captive_portal_result());
EXPECT_EQ(1, portal_observer.num_results_received());
EXPECT_FALSE(CheckPending(browser));
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
GetStateOfTabReloaderAt(browser, initial_active_index));
if (out_login_browser)
*out_login_browser = login_browser;
}
void CaptivePortalBrowserTest::FastErrorWithInterstitialTimer(
Browser* browser,
const GURL& cert_error_url) {
TabStripModel* tab_strip_model = browser->tab_strip_model();
WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
RespondToProbeRequests(false);
SSLInterstitialTimerObserver interstitial_timer_observer(broken_tab_contents);
ui_test_utils::NavigateToURLWithDisposition(
browser, cert_error_url, WindowOpenDisposition::CURRENT_TAB,
ui_test_utils::BROWSER_TEST_NO_WAIT);
interstitial_timer_observer.WaitForTimerStarted();
EXPECT_TRUE(broken_tab_contents->IsLoading());
EXPECT_EQ(1, NumLoadingTabs());
}
void CaptivePortalBrowserTest::NavigateLoginTab(Browser* browser,
int num_loading_tabs,
int num_timed_out_tabs) {
MultiNavigationObserver navigation_observer;
CaptivePortalObserver portal_observer(browser->profile());
TabStripModel* tab_strip_model = browser->tab_strip_model();
int initial_tab_count = tab_strip_model->count();
EXPECT_EQ(num_loading_tabs, NumLoadingTabs());
EXPECT_EQ(num_timed_out_tabs, NumBrokenTabs() - NumLoadingTabs());
int login_tab_index = tab_strip_model->active_index();
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloader(tab_strip_model->GetActiveWebContents()));
ASSERT_TRUE(IsLoginTab(browser->tab_strip_model()->GetActiveWebContents()));
content::ExecuteScriptAsync(tab_strip_model->GetActiveWebContents(),
"submitForm()");
portal_observer.WaitForResults(1);
navigation_observer.WaitForNavigations(1);
EXPECT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
portal_observer.captive_portal_result());
EXPECT_EQ(1, portal_observer.num_results_received());
EXPECT_FALSE(CheckPending(browser));
EXPECT_EQ(initial_tab_count, tab_strip_model->count());
EXPECT_EQ(num_loading_tabs, NumLoadingTabs());
EXPECT_EQ(num_loading_tabs + num_timed_out_tabs, NumBrokenTabs());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser, login_tab_index));
EXPECT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(login_tab_index)));
EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
tab_strip_model->GetWebContentsAt(login_tab_index)));
}
void CaptivePortalBrowserTest::Login(Browser* captive_portal_browser,
int num_loading_tabs,
int num_timed_out_tabs,
int expected_portal_checks) {
SetBehindCaptivePortal(false);
MultiNavigationObserver navigation_observer;
CaptivePortalObserver portal_observer(captive_portal_browser->profile());
TabStripModel* tab_strip_model = captive_portal_browser->tab_strip_model();
size_t initial_browser_count = chrome::GetTotalBrowserCount();
int initial_tab_count = NumTabs();
ASSERT_EQ(num_loading_tabs, NumLoadingTabs());
EXPECT_EQ(num_timed_out_tabs, NumBrokenTabs() - NumLoadingTabs());
int login_tab_index = tab_strip_model->active_index();
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(captive_portal_browser, login_tab_index));
content::WebContents* login_tab =
tab_strip_model->GetWebContentsAt(login_tab_index);
ASSERT_TRUE(IsLoginTab(login_tab));
if (chrome_browser_interstitials::IsShowingHttpsFirstModeInterstitial(
login_tab)) {
content::TestNavigationObserver nav_observer(login_tab, 1);
std::string javascript = "window.certificateErrorPageController.proceed();";
ASSERT_TRUE(content::ExecJs(login_tab, javascript));
nav_observer.Wait();
}
content::ExecuteScriptAsync(tab_strip_model->GetActiveWebContents(),
"submitForm()");
portal_observer.WaitForResults(1);
navigation_observer.WaitForNavigations(1 + num_timed_out_tabs);
portal_observer.WaitForResults(expected_portal_checks);
EXPECT_EQ(expected_portal_checks, portal_observer.num_results_received());
EXPECT_EQ(0, NumBrokenTabs());
EXPECT_EQ(num_loading_tabs, NumLoadingTabs());
EXPECT_EQ(num_loading_tabs, NumNeedReloadTabs());
EXPECT_EQ(initial_browser_count, chrome::GetTotalBrowserCount());
EXPECT_EQ(initial_tab_count, NumTabs());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(captive_portal_browser, login_tab_index));
EXPECT_FALSE(IsLoginTab(tab_strip_model->GetWebContentsAt(login_tab_index)));
EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
tab_strip_model->GetWebContentsAt(login_tab_index)));
}
void CaptivePortalBrowserTest::LoginCertError(Browser* browser) {
SetBehindCaptivePortal(false);
MultiNavigationObserver navigation_observer;
CaptivePortalObserver portal_observer(browser->profile());
TabStripModel* tab_strip_model = browser->tab_strip_model();
int login_tab_index = tab_strip_model->active_index();
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser, login_tab_index));
ASSERT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(login_tab_index)));
content::ExecuteScriptAsync(tab_strip_model->GetActiveWebContents(),
"submitForm()");
portal_observer.WaitForResults(2);
navigation_observer.WaitForNavigations(2);
EXPECT_EQ(2, portal_observer.num_results_received());
EXPECT_FALSE(CheckPending(browser));
EXPECT_EQ(captive_portal::RESULT_INTERNET_CONNECTED,
portal_observer.captive_portal_result());
ASSERT_EQ(2, tab_strip_model->count());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser, 0));
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser, login_tab_index));
EXPECT_FALSE(IsLoginTab(tab_strip_model->GetWebContentsAt(login_tab_index)));
EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
tab_strip_model->GetWebContentsAt(login_tab_index)));
}
void CaptivePortalBrowserTest::FailLoadsAfterLogin(Browser* browser,
int num_loading_tabs) {
ASSERT_EQ(num_loading_tabs, NumLoadingTabs());
ASSERT_EQ(num_loading_tabs, NumNeedReloadTabs());
EXPECT_EQ(0, NumBrokenTabs());
TabStripModel* tab_strip_model = browser->tab_strip_model();
int initial_num_tabs = tab_strip_model->count();
int initial_active_tab = tab_strip_model->active_index();
CaptivePortalObserver portal_observer(browser->profile());
FailLoadsAfterLoginObserver fail_loads_observer;
WaitForJobs(num_loading_tabs);
FailJobs(num_loading_tabs, net::ERR_CONNECTION_TIMED_OUT,
net::ResolveErrorInfo(net::OK));
fail_loads_observer.WaitForNavigations();
EXPECT_EQ(0, portal_observer.num_results_received());
EXPECT_FALSE(CheckPending(browser));
EXPECT_EQ(initial_num_tabs, tab_strip_model->count());
EXPECT_EQ(initial_active_tab, tab_strip_model->active_index());
EXPECT_EQ(0, NumNeedReloadTabs());
EXPECT_EQ(0, NumLoadingTabs());
}
void CaptivePortalBrowserTest::FailLoadsWithoutLogin(
Browser* browser,
int num_loading_tabs,
Browser* captive_portal_browser) {
if (!captive_portal_browser)
captive_portal_browser = browser;
ASSERT_EQ(num_loading_tabs, NumLoadingTabs());
ASSERT_EQ(0, NumNeedReloadTabs());
EXPECT_EQ(num_loading_tabs, NumBrokenTabs());
TabStripModel* tab_strip_model = captive_portal_browser->tab_strip_model();
int initial_num_tabs = NumTabs();
int login_tab = tab_strip_model->active_index();
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloader(tab_strip_model->GetActiveWebContents()));
ASSERT_TRUE(IsLoginTab(tab_strip_model->GetActiveWebContents()));
CaptivePortalObserver portal_observer(browser->profile());
MultiNavigationObserver navigation_observer;
FailJobs(num_loading_tabs, net::ERR_CONNECTION_TIMED_OUT,
net::ResolveErrorInfo(net::OK));
navigation_observer.WaitForNavigations(num_loading_tabs);
EXPECT_EQ(0, portal_observer.num_results_received());
EXPECT_FALSE(CheckPending(browser));
EXPECT_EQ(initial_num_tabs, NumTabs());
EXPECT_EQ(0, NumNeedReloadTabs());
EXPECT_EQ(0, NumLoadingTabs());
EXPECT_EQ(num_loading_tabs, NumBrokenTabs());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloader(tab_strip_model->GetActiveWebContents()));
EXPECT_TRUE(IsLoginTab(tab_strip_model->GetActiveWebContents()));
EXPECT_EQ(login_tab, tab_strip_model->active_index());
EXPECT_EQ(0, navigation_observer.NumNavigationsForTab(
tab_strip_model->GetWebContentsAt(login_tab)));
}
void CaptivePortalBrowserTest::RunNavigateLoadingTabToTimeoutTest(
Browser* browser,
const GURL& starting_url,
const GURL& hanging_url,
const GURL& timeout_url) {
SetBehindCaptivePortal(false);
NavigateToPageExpectNoTest(browser, starting_url);
SetBehindCaptivePortal(true);
SlowLoadBehindCaptivePortal(browser, true ,
false ,
hanging_url, 1, 1);
WaitForJobs(1);
AbandonJobs(1);
TabStripModel* tab_strip_model = browser->tab_strip_model();
captive_portal::CaptivePortalTabReloader* tab_reloader =
GetTabReloader(tab_strip_model->GetWebContentsAt(0));
ASSERT_TRUE(tab_reloader);
SetSlowSSLLoadTime(tab_reloader, base::Seconds(2));
CaptivePortalObserver portal_observer(browser->profile());
tab_strip_model->ActivateTabAt(
0, TabStripUserGestureDetails(
TabStripUserGestureDetails::GestureType::kOther));
browser->OpenURL(content::OpenURLParams(timeout_url, content::Referrer(),
WindowOpenDisposition::CURRENT_TAB,
ui::PAGE_TRANSITION_TYPED, false),
{});
portal_observer.WaitForResults(1);
EXPECT_FALSE(CheckPending(browser));
EXPECT_EQ(1, NumLoadingTabs());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
GetStateOfTabReloaderAt(browser, 0));
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser, 1));
ASSERT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(1)));
WaitForJobs(1);
tab_strip_model->ActivateTabAt(
1, TabStripUserGestureDetails(
TabStripUserGestureDetails::GestureType::kOther));
SetSlowSSLLoadTime(tab_reloader, base::Days(1));
Login(browser, 1 , 0 ,
1 );
FailLoadsAfterLogin(browser, 1);
}
void CaptivePortalBrowserTest::SetSlowSSLLoadTime(
captive_portal::CaptivePortalTabReloader* tab_reloader,
base::TimeDelta slow_ssl_load_time) {
tab_reloader->set_slow_ssl_load_time(slow_ssl_load_time);
}
captive_portal::CaptivePortalTabReloader*
CaptivePortalBrowserTest::GetTabReloader(WebContents* web_contents) const {
return captive_portal::CaptivePortalTabHelper::FromWebContents(web_contents)
->GetTabReloaderForTest();
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpTimeout) {
NavigateToPageExpectNoTest(browser(), GURL(kMockHttpConnectionTimeoutErr));
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpsNonTimeoutError) {
NavigateToPageExpectNoTest(browser(),
GURL(kMockHttpsConnectionUnexpectedErr));
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpsIframeTimeout) {
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.ServeFilesFromSourceDirectory(GetChromeTestDataDir());
ASSERT_TRUE(https_server.Start());
GURL url = https_server.GetURL(kTestServerIframeTimeoutPath);
NavigateToPageExpectNoTest(browser(), url);
}
#if BUILDFLAG(ENABLE_EXTENSIONS)
class IWACaptivePortalBrowserTest : public CaptivePortalBrowserTest {
public:
IWACaptivePortalBrowserTest() {
iwa_scoped_feature_list_.InitWithFeatures(
{features::kIsolatedWebAppDevMode, features::kIsolatedWebApps}, {});
}
content::RenderFrameHost* InstallAndOpenWebApp() {
const std::unique_ptr<web_app::BundledIsolatedWebApp> bundle =
web_app::IsolatedWebAppBuilder(
web_app::ManifestBuilder().AddPermissionsPolicyWildcard(
network::mojom::PermissionsPolicyFeature::kControlledFrame))
.BuildBundle();
web_app::IsolatedWebAppUrlInfo url_info =
bundle->InstallChecked(browser()->profile());
return web_app::OpenIsolatedWebApp(browser()->profile(), url_info.app_id());
}
void CreateControlledFrame(content::RenderFrameHost* app_frame,
const GURL& src) {
constexpr static std::string_view kCreateControlledFrame = R"(
new Promise((resolve, reject) => {
const controlledframe = document.createElement('controlledframe');
controlledframe.addEventListener('loadabort', (e) => {
resolve();
});
controlledframe.addEventListener('loadstop', (e) => {
reject('must abort load because of cert error');
});
controlledframe.src = $1;
document.body.appendChild(controlledframe);
});
)";
CHECK(ExecJs(app_frame, content::JsReplace(kCreateControlledFrame, src)));
}
base::test::ScopedFeatureList iwa_scoped_feature_list_;
web_app::OsIntegrationTestOverrideBlockingRegistration faked_os_integration_;
};
IN_PROC_BROWSER_TEST_F(IWACaptivePortalBrowserTest,
HttpsCertErrorControlledFrameNewTab) {
CertErrorInWebAppWithEmbeddedFrameOpensCaptivePortal(
false, 2,
[this]() -> content::RenderFrameHost* {
return this->InstallAndOpenWebApp();
},
[this](content::RenderFrameHost* app_frame, const GURL& cert_error_url) {
CreateControlledFrame(app_frame, cert_error_url);
});
}
IN_PROC_BROWSER_TEST_F(IWACaptivePortalBrowserTest,
HttpsCertErrorControlledFrameNewBrowser) {
CertErrorInWebAppWithEmbeddedFrameOpensCaptivePortal(
true, 2,
[this]() -> content::RenderFrameHost* {
return this->InstallAndOpenWebApp();
},
[this](content::RenderFrameHost* app_frame, const GURL& cert_error_url) {
CreateControlledFrame(app_frame, cert_error_url);
});
}
#if BUILDFLAG(IS_CHROMEOS)
class ChromeAppCaptivePortalBrowserTest : public CaptivePortalBrowserTest {
public:
ChromeAppCaptivePortalBrowserTest() = default;
void LaunchPlatformApp(const extensions::Extension* extension) {
apps::AppServiceProxyFactory::GetForProfile(GetProfile())
->BrowserAppLauncher()
->LaunchAppWithParamsForTesting(apps::AppLaunchParams(
extension->id(), apps::LaunchContainer::kLaunchContainerNone,
WindowOpenDisposition::NEW_WINDOW, apps::LaunchSource::kFromTest));
}
content::RenderFrameHost* InstallAndLaunchChromeApp() {
base::ScopedAllowBlockingForTesting allow_blocking;
extension_dir_.WriteManifest(R"({
"name": "Captive Portal WebView Test App",
"version": "1.0",
"manifest_version": 2,
"app": {
"background": {
"scripts": ["background.js"]
}
},
"permissions": ["webview"]
})");
extension_dir_.WriteFile(FILE_PATH_LITERAL("background.js"), R"(
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create('embedder.html', {
'innerBounds': {'width': 100, 'height': 100}
});
});
)");
extension_dir_.WriteFile(FILE_PATH_LITERAL("embedder.html"), R"(
<!DOCTYPE html>
<html><head><title>Test Chrome App</title></head>
<body>
<script src="embedder.js"></script>
</body></html>
)");
extension_dir_.WriteFile(FILE_PATH_LITERAL("embedder.js"), R"(
onload = function() {
chrome.test.sendMessage('Launched');
};
)");
ExtensionTestMessageListener listener("Launched");
extensions::ChromeTestExtensionLoader extension_loader(GetProfile());
extension_loader.set_pack_extension(false);
scoped_refptr<const extensions::Extension> extension =
extension_loader.LoadExtension(extension_dir_.UnpackedPath());
CHECK(extension);
apps::chrome_app_deprecation::ScopedAddAppToAllowlistForTesting allowlist(
extension->id());
LaunchPlatformApp(extension.get());
CHECK(listener.WaitUntilSatisfied());
content::RunAllPendingInMessageLoop();
extensions::AppWindowRegistry* app_registry =
extensions::AppWindowRegistry::Get(browser()->profile());
extensions::AppWindow* window =
app_registry->GetCurrentAppWindowForApp(extension->id());
CHECK(window);
return window->web_contents()->GetPrimaryMainFrame();
}
void CreateWebView(content::RenderFrameHost* app_frame, const GURL& src) {
constexpr static std::string_view kCreateWebView = R"(
new Promise((resolve, reject) => {
const webview = document.createElement('webview');
webview.addEventListener('loadabort', (e) => {
resolve();
});
webview.addEventListener('loadstop', (e) => {
reject('must abort load because of cert error');
});
webview.src = $1;
document.body.appendChild(webview);
});
)";
CHECK(ExecJs(app_frame, content::JsReplace(kCreateWebView, src)));
}
private:
extensions::TestExtensionDir extension_dir_;
};
IN_PROC_BROWSER_TEST_F(ChromeAppCaptivePortalBrowserTest,
HttpsCertErrorWebViewNewTab) {
CertErrorInWebAppWithEmbeddedFrameOpensCaptivePortal(
false, 1,
[this]() -> content::RenderFrameHost* {
return this->InstallAndLaunchChromeApp();
},
[this](content::RenderFrameHost* app_frame, const GURL& cert_error_url) {
this->CreateWebView(app_frame, cert_error_url);
});
}
IN_PROC_BROWSER_TEST_F(ChromeAppCaptivePortalBrowserTest,
HttpsCertErrorWebViewNewBrowser) {
CertErrorInWebAppWithEmbeddedFrameOpensCaptivePortal(
true, 1,
[this]() -> content::RenderFrameHost* {
return this->InstallAndLaunchChromeApp();
},
[this](content::RenderFrameHost* app_frame, const GURL& cert_error_url) {
this->CreateWebView(app_frame, cert_error_url);
});
}
#endif
#endif
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, RequestFails) {
SetUpCaptivePortalService(browser()->profile(),
GURL(kMockHttpConnectionConnectionClosedErr));
SlowLoadNoCaptivePortal(browser(), captive_portal::RESULT_NO_RESPONSE);
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, RequestFailsFastTimout) {
SetUpCaptivePortalService(browser()->profile(),
GURL(kMockHttpConnectionConnectionClosedErr));
FastTimeoutNoCaptivePortal(browser(), captive_portal::RESULT_NO_RESPONSE);
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, Disabled) {
EnableCaptivePortalDetection(browser()->profile(), false);
SlowLoadNoCaptivePortal(browser(), captive_portal::RESULT_INTERNET_CONNECTED);
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, InternetConnected) {
ASSERT_TRUE(embedded_test_server()->Start());
SetUpCaptivePortalService(browser()->profile(),
embedded_test_server()->GetURL("/nocontent"));
SlowLoadNoCaptivePortal(browser(), captive_portal::RESULT_INTERNET_CONNECTED);
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, RedirectSSLCertError) {
ASSERT_TRUE(embedded_test_server()->Start());
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_MISMATCHED_NAME);
https_server.ServeFilesFromSourceDirectory(GetChromeTestDataDir());
ASSERT_TRUE(https_server.Start());
GURL ssl_login_url = https_server.GetURL(kTestServerLoginPath);
captive_portal::CaptivePortalService* captive_portal_service =
CaptivePortalServiceFactory::GetForProfile(browser()->profile());
ASSERT_TRUE(captive_portal_service);
SetUpCaptivePortalService(browser()->profile(),
embedded_test_server()->GetURL(
CreateServerRedirect(ssl_login_url.spec())));
SlowLoadNoCaptivePortal(browser(), captive_portal::RESULT_NO_RESPONSE);
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, Login) {
SlowLoadBehindCaptivePortal(browser(), true);
Login(browser(), 1 , 0 ,
1 );
FailLoadsAfterLogin(browser(), 1);
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, LoginIncognito) {
MultiNavigationObserver navigation_observer;
CaptivePortalObserver non_incognito_portal_observer(browser()->profile());
Browser* incognito_browser = CreateIncognitoBrowser();
EnableCaptivePortalDetection(incognito_browser->profile(), true);
SetUpCaptivePortalService(incognito_browser->profile(),
GURL(kMockCaptivePortalTestUrl));
SlowLoadBehindCaptivePortal(incognito_browser, true);
TabStripModel* tab_strip_model = browser()->tab_strip_model();
EXPECT_EQ(1, tab_strip_model->count());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser(), 0));
Login(incognito_browser, 1 , 0 ,
1 );
FailLoadsAfterLogin(incognito_browser, 1);
EXPECT_EQ(1, tab_strip_model->count());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser(), 0));
EXPECT_EQ(0, navigation_observer.NumNavigationsForTab(
tab_strip_model->GetWebContentsAt(0)));
EXPECT_EQ(0, non_incognito_portal_observer.num_results_received());
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, LoginSlow) {
SlowLoadBehindCaptivePortal(browser(), true);
FailLoadsWithoutLogin(browser(), 1);
Login(browser(), 0 , 1 ,
1 );
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, LoginFastTimeout) {
FastTimeoutBehindCaptivePortal(browser(), true);
Login(browser(), 0 , 1 ,
1 );
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
ShowCaptivePortalInterstitialOnCertError) {
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_MISMATCHED_NAME);
https_server.ServeFilesFromSourceDirectory(GetChromeTestDataDir());
ASSERT_TRUE(https_server.Start());
TabStripModel* tab_strip_model = browser()->tab_strip_model();
WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
GURL cert_error_url = https_server.GetURL(kTestServerLoginPath);
int cert_error_tab_index = tab_strip_model->active_index();
FastErrorBehindCaptivePortal(browser(), true ,
false ,
cert_error_url);
EXPECT_EQ(CaptivePortalBlockingPage::kTypeForTesting,
GetInterstitialType(broken_tab_contents));
int login_tab_index = tab_strip_model->active_index();
tab_strip_model->ActivateTabAt(cert_error_tab_index);
content::RenderFrameHost* rfh;
rfh = broken_tab_contents->GetPrimaryMainFrame();
EXPECT_TRUE(WaitForRenderFrameReady(rfh));
const char kClickConnectButtonJS[] =
"document.getElementById('primary-button').click();";
{
TabActivationWaiter tab_activation_waiter(tab_strip_model);
content::ExecuteScriptAsync(rfh, kClickConnectButtonJS);
tab_activation_waiter.WaitForActiveTabChange();
}
EXPECT_EQ(login_tab_index, tab_strip_model->active_index());
EXPECT_EQ(1, login_tab_index);
content::WebContentsDestroyedWatcher destroyed_watcher(
tab_strip_model->GetActiveWebContents());
EXPECT_EQ(2, tab_strip_model->count());
tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(), 0);
EXPECT_EQ(1, tab_strip_model->count());
destroyed_watcher.Wait();
MultiNavigationObserver navigation_observer;
content::ExecuteScriptAsync(rfh, kClickConnectButtonJS);
navigation_observer.WaitForNavigations(1);
EXPECT_EQ(login_tab_index, tab_strip_model->active_index());
LoginCertError(browser());
ASSERT_TRUE(IsShowingInterstitial((broken_tab_contents)));
tab_strip_model->ActivateTabAt(cert_error_tab_index);
EXPECT_EQ(SSLBlockingPage::kTypeForTesting,
GetInterstitialType(tab_strip_model->GetActiveWebContents()));
CaptivePortalObserver portal_observer(browser()->profile());
captive_portal::CaptivePortalService* captive_portal_service =
CaptivePortalServiceFactory::GetForProfile(browser()->profile());
captive_portal_service->DetectCaptivePortal();
portal_observer.WaitForResults(1);
EXPECT_EQ(SSLBlockingPage::kTypeForTesting,
GetInterstitialType(broken_tab_contents));
SetBehindCaptivePortal(true);
CaptivePortalObserver final_portal_observer(browser()->profile());
captive_portal_service->DetectCaptivePortal();
final_portal_observer.WaitForResults(1);
EXPECT_EQ(SSLBlockingPage::kTypeForTesting,
GetInterstitialType(broken_tab_contents));
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
CertErrorOnCaptivePortalLoginShowsSSLErrorInterstitial) {
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_MISMATCHED_NAME);
https_server.ServeFilesFromSourceDirectory(GetChromeTestDataDir());
ASSERT_TRUE(https_server.Start());
SSLErrorHandler::SetOSReportsCaptivePortalForTesting(true);
TabStripModel* tab_strip_model = browser()->tab_strip_model();
WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
GURL cert_error_url = https_server.GetURL(kTestServerLoginPath);
FastErrorBehindCaptivePortal(browser(), true ,
false ,
cert_error_url);
EXPECT_EQ(CaptivePortalBlockingPage::kTypeForTesting,
GetInterstitialType(broken_tab_contents));
WebContents* login_tab_contents = tab_strip_model->GetActiveWebContents();
int login_tab_index = tab_strip_model->active_index();
EXPECT_EQ(1, login_tab_index);
EXPECT_TRUE(IsLoginTab(login_tab_contents));
ui_test_utils::NavigateToURLWithDisposition(
browser(), cert_error_url, WindowOpenDisposition::CURRENT_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
EXPECT_TRUE(IsLoginTab(login_tab_contents));
EXPECT_EQ(SSLBlockingPage::kTypeForTesting,
GetInterstitialType(login_tab_contents));
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
InterstitialTimerStopNavigationWhileLoading) {
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_MISMATCHED_NAME);
https_server.ServeFilesFromSourceDirectory(GetChromeTestDataDir());
ASSERT_TRUE(https_server.Start());
GURL cert_error_url = https_server.GetURL(kTestServerLoginPath);
TabStripModel* tab_strip_model = browser()->tab_strip_model();
WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
CaptivePortalObserver portal_observer1(browser()->profile());
FastErrorWithInterstitialTimer(browser(), cert_error_url);
MultiNavigationObserver test_navigation_observer;
broken_tab_contents->Stop();
test_navigation_observer.WaitForNavigations(1);
EXPECT_TRUE(nullptr == SSLErrorHandler::FromWebContents(broken_tab_contents));
EXPECT_FALSE(IsShowingInterstitial(broken_tab_contents));
EXPECT_FALSE(broken_tab_contents->IsLoading());
EXPECT_EQ(0, portal_observer1.num_results_received());
EXPECT_EQ(0, NumLoadingTabs());
EXPECT_FALSE(CheckPending(browser()));
EXPECT_EQ(1, browser()->tab_strip_model()->count());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser(), 0));
RespondToProbeRequests(true);
CaptivePortalObserver portal_observer2(browser()->profile());
captive_portal::CaptivePortalService* captive_portal_service =
CaptivePortalServiceFactory::GetForProfile(browser()->profile());
captive_portal_service->DetectCaptivePortal();
portal_observer2.WaitForResults(1);
EXPECT_FALSE(IsShowingInterstitial(broken_tab_contents));
EXPECT_FALSE(broken_tab_contents->IsLoading());
EXPECT_EQ(1, portal_observer2.num_results_received());
EXPECT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
portal_observer2.captive_portal_result());
EXPECT_EQ(0, NumLoadingTabs());
EXPECT_FALSE(CheckPending(browser()));
EXPECT_EQ(1, browser()->tab_strip_model()->count());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser(), 0));
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
InterstitialTimerReloadWhileLoading) {
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_MISMATCHED_NAME);
https_server.ServeFilesFromSourceDirectory(GetChromeTestDataDir());
ASSERT_TRUE(https_server.Start());
GURL cert_error_url = https_server.GetURL(kTestServerLoginPath);
TabStripModel* tab_strip_model = browser()->tab_strip_model();
WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
CaptivePortalObserver portal_observer(browser()->profile());
FastErrorWithInterstitialTimer(browser(), cert_error_url);
MultiNavigationObserver test_navigation_observer;
chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
test_navigation_observer.WaitForNavigations(1);
EXPECT_TRUE(nullptr == SSLErrorHandler::FromWebContents(broken_tab_contents));
EXPECT_FALSE(IsShowingInterstitial(broken_tab_contents));
EXPECT_FALSE(broken_tab_contents->IsLoading());
EXPECT_EQ(0, portal_observer.num_results_received());
EXPECT_EQ(0, NumLoadingTabs());
EXPECT_FALSE(CheckPending(browser()));
EXPECT_EQ(1, browser()->tab_strip_model()->count());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser(), 0));
RespondToProbeRequests(true);
CaptivePortalObserver portal_observer2(browser()->profile());
captive_portal::CaptivePortalService* captive_portal_service =
CaptivePortalServiceFactory::GetForProfile(browser()->profile());
captive_portal_service->DetectCaptivePortal();
portal_observer2.WaitForResults(1);
EXPECT_FALSE(IsShowingInterstitial(broken_tab_contents));
EXPECT_FALSE(broken_tab_contents->IsLoading());
EXPECT_EQ(1, portal_observer2.num_results_received());
EXPECT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
portal_observer2.captive_portal_result());
EXPECT_EQ(0, NumLoadingTabs());
EXPECT_FALSE(CheckPending(browser()));
EXPECT_EQ(1, browser()->tab_strip_model()->count());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser(), 0));
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
InterstitialTimerNavigateAwayWhileLoading) {
ASSERT_TRUE(embedded_test_server()->Start());
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_MISMATCHED_NAME);
https_server.ServeFilesFromSourceDirectory(GetChromeTestDataDir());
ASSERT_TRUE(https_server.Start());
GURL cert_error_url = https_server.GetURL(kTestServerLoginPath);
TabStripModel* tab_strip_model = browser()->tab_strip_model();
WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
CaptivePortalObserver portal_observer(browser()->profile());
FastErrorWithInterstitialTimer(browser(), cert_error_url);
MultiNavigationObserver test_navigation_observer;
browser()->OpenURL(
content::OpenURLParams(
embedded_test_server()->GetURL("/title2.html"), content::Referrer(),
WindowOpenDisposition::CURRENT_TAB, ui::PAGE_TRANSITION_TYPED, false),
{});
test_navigation_observer.WaitForNavigations(1);
EXPECT_TRUE(nullptr == SSLErrorHandler::FromWebContents(broken_tab_contents));
EXPECT_FALSE(IsShowingInterstitial(broken_tab_contents));
EXPECT_FALSE(broken_tab_contents->IsLoading());
EXPECT_EQ(0, portal_observer.num_results_received());
EXPECT_EQ(0, NumLoadingTabs());
EXPECT_FALSE(CheckPending(browser()));
EXPECT_EQ(1, browser()->tab_strip_model()->count());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser(), 0));
RespondToProbeRequests(true);
CaptivePortalObserver portal_observer2(browser()->profile());
captive_portal::CaptivePortalService* captive_portal_service =
CaptivePortalServiceFactory::GetForProfile(browser()->profile());
captive_portal_service->DetectCaptivePortal();
portal_observer2.WaitForResults(1);
EXPECT_FALSE(IsShowingInterstitial(broken_tab_contents));
EXPECT_FALSE(broken_tab_contents->IsLoading());
EXPECT_EQ(1, portal_observer2.num_results_received());
EXPECT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
portal_observer2.captive_portal_result());
EXPECT_EQ(0, NumLoadingTabs());
EXPECT_FALSE(CheckPending(browser()));
EXPECT_EQ(1, browser()->tab_strip_model()->count());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser(), 0));
}
IN_PROC_BROWSER_TEST_F(
CaptivePortalBrowserTest,
InterstitialTimerNavigateWhileLoading_EndWithSSLInterstitial) {
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_MISMATCHED_NAME);
https_server.ServeFilesFromSourceDirectory(GetChromeTestDataDir());
ASSERT_TRUE(https_server.Start());
GURL cert_error_url = https_server.GetURL(kTestServerLoginPath);
SetBehindCaptivePortal(false);
TabStripModel* tab_strip_model = browser()->tab_strip_model();
WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
FastErrorWithInterstitialTimer(browser(), cert_error_url);
RespondToProbeRequests(true);
CaptivePortalObserver portal_observer(browser()->profile());
MultiNavigationObserver test_navigation_observer;
browser()->OpenURL(content::OpenURLParams(cert_error_url, content::Referrer(),
WindowOpenDisposition::CURRENT_TAB,
ui::PAGE_TRANSITION_TYPED, false),
{});
test_navigation_observer.WaitForNavigations(1);
ASSERT_TRUE(IsShowingInterstitial(broken_tab_contents));
EXPECT_EQ(SSLBlockingPage::kTypeForTesting,
GetInterstitialType(broken_tab_contents));
EXPECT_FALSE(broken_tab_contents->IsLoading());
EXPECT_EQ(1, portal_observer.num_results_received());
EXPECT_EQ(captive_portal::RESULT_INTERNET_CONNECTED,
portal_observer.captive_portal_result());
EXPECT_EQ(0, NumLoadingTabs());
EXPECT_FALSE(CheckPending(browser()));
EXPECT_EQ(1, browser()->tab_strip_model()->count());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser(), 0));
}
IN_PROC_BROWSER_TEST_F(
CaptivePortalBrowserTest,
InterstitialTimerNavigateWhileLoading_EndWithCaptivePortalInterstitial) {
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_MISMATCHED_NAME);
https_server.ServeFilesFromSourceDirectory(GetChromeTestDataDir());
ASSERT_TRUE(https_server.Start());
GURL cert_error_url = https_server.GetURL(kTestServerLoginPath);
SetBehindCaptivePortal(true);
TabStripModel* tab_strip_model = browser()->tab_strip_model();
WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
int initial_tab_count = tab_strip_model->count();
FastErrorWithInterstitialTimer(browser(), cert_error_url);
RespondToProbeRequests(true);
CaptivePortalObserver portal_observer(browser()->profile());
MultiNavigationObserver test_navigation_observer;
browser()->OpenURL(content::OpenURLParams(cert_error_url, content::Referrer(),
WindowOpenDisposition::CURRENT_TAB,
ui::PAGE_TRANSITION_TYPED, false),
{});
test_navigation_observer.WaitForNavigations(2);
ASSERT_TRUE(IsShowingInterstitial(broken_tab_contents));
EXPECT_EQ(CaptivePortalBlockingPage::kTypeForTesting,
GetInterstitialType(broken_tab_contents));
ASSERT_EQ(initial_tab_count + 1, tab_strip_model->count());
EXPECT_EQ(initial_tab_count, tab_strip_model->active_index());
EXPECT_FALSE(broken_tab_contents->IsLoading());
EXPECT_EQ(1, portal_observer.num_results_received());
EXPECT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
portal_observer.captive_portal_result());
EXPECT_EQ(0, NumLoadingTabs());
EXPECT_FALSE(CheckPending(browser()));
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
GetStateOfTabReloaderAt(browser(), 0));
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser(), 1));
EXPECT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(1)));
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, SSLCertErrorLogin) {
ASSERT_TRUE(embedded_test_server()->Start());
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_MISMATCHED_NAME);
https_server.ServeFilesFromSourceDirectory(GetChromeTestDataDir());
ASSERT_TRUE(https_server.Start());
SSLErrorHandler::SetInterstitialDelayForTesting(base::TimeDelta());
TabStripModel* tab_strip_model = browser()->tab_strip_model();
WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
GURL cert_error_url = https_server.GetURL(kTestServerLoginPath);
FastErrorBehindCaptivePortal(browser(), true ,
false ,
cert_error_url);
EXPECT_EQ(SSLBlockingPage::kTypeForTesting,
GetInterstitialType(broken_tab_contents));
LoginCertError(browser());
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, LoginExtraNavigations) {
FastTimeoutBehindCaptivePortal(browser(), true);
TabStripModel* tab_strip_model = browser()->tab_strip_model();
tab_strip_model->ActivateTabAt(
0, TabStripUserGestureDetails(
TabStripUserGestureDetails::GestureType::kOther));
FastTimeoutBehindCaptivePortal(browser(), false);
tab_strip_model->ActivateTabAt(
1, TabStripUserGestureDetails(
TabStripUserGestureDetails::GestureType::kOther));
NavigateLoginTab(browser(), 0, 1);
Login(browser(), 0 , 1 ,
1 );
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, CloseLoginTab) {
SlowLoadBehindCaptivePortal(browser(), true);
FailLoadsWithoutLogin(browser(), 1);
chrome::CloseTab(browser());
SlowLoadBehindCaptivePortal(browser(), true);
Login(browser(), 1 , 0 ,
1 );
FailLoadsAfterLogin(browser(), 1);
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, TwoBrokenTabs) {
ASSERT_TRUE(embedded_test_server()->Start());
SlowLoadBehindCaptivePortal(browser(), true);
MultiNavigationObserver navigation_observer;
CaptivePortalObserver portal_observer(browser()->profile());
ui_test_utils::NavigateToURLWithDisposition(
browser(), embedded_test_server()->GetURL("/title2.html"),
WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
TabStripModel* tab_strip_model = browser()->tab_strip_model();
ASSERT_EQ(3, tab_strip_model->count());
EXPECT_FALSE(CheckPending(browser()));
EXPECT_EQ(0, portal_observer.num_results_received());
EXPECT_EQ(1, NumLoadingTabs());
EXPECT_EQ(1, navigation_observer.num_navigations());
EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
tab_strip_model->GetWebContentsAt(2)));
ASSERT_EQ(captive_portal::CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
GetStateOfTabReloaderAt(browser(), 0));
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser(), 1));
ASSERT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(1)));
ASSERT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser(), 2));
ASSERT_EQ(2, tab_strip_model->active_index());
SlowLoadBehindCaptivePortal(browser(), false);
tab_strip_model->ActivateTabAt(
1, TabStripUserGestureDetails(
TabStripUserGestureDetails::GestureType::kOther));
Login(browser(), 2 , 0 ,
1 );
FailLoadsAfterLogin(browser(), 2);
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, AbortLoad) {
SlowLoadBehindCaptivePortal(browser(), true);
WaitForJobs(1);
AbandonJobs(1);
CaptivePortalObserver portal_observer(browser()->profile());
MultiNavigationObserver navigation_observer;
TabStripModel* tab_strip_model = browser()->tab_strip_model();
tab_strip_model->ActivateTabAt(
0, TabStripUserGestureDetails(
TabStripUserGestureDetails::GestureType::kOther));
chrome::Stop(browser());
navigation_observer.WaitForNavigations(1);
EXPECT_EQ(0, NumBrokenTabs());
EXPECT_EQ(0, portal_observer.num_results_received());
EXPECT_FALSE(CheckPending(browser()));
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser(), 0));
tab_strip_model->ActivateTabAt(
1, TabStripUserGestureDetails(
TabStripUserGestureDetails::GestureType::kOther));
Login(browser(), 0 , 0 ,
1 );
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, NavigateBrokenTab) {
ASSERT_TRUE(embedded_test_server()->Start());
SlowLoadBehindCaptivePortal(browser(), true);
FailLoadsWithoutLogin(browser(), 1);
TabStripModel* tab_strip_model = browser()->tab_strip_model();
tab_strip_model->ActivateTabAt(
0, TabStripUserGestureDetails(
TabStripUserGestureDetails::GestureType::kOther));
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), embedded_test_server()->GetURL("/title2.html")));
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser(), 0));
tab_strip_model->ActivateTabAt(
1, TabStripUserGestureDetails(
TabStripUserGestureDetails::GestureType::kOther));
Login(browser(), 0 , 0 ,
1 );
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
NavigateLoadingTabToTimeoutSingleSite) {
RunNavigateLoadingTabToTimeoutTest(
browser(),
GURL(kMockHttpsUrl),
GURL(kMockHttpsUrl),
GURL(kMockHttpsUrl));
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
NavigateLoadingTabToTimeoutTwoSites) {
RunNavigateLoadingTabToTimeoutTest(
browser(),
GURL(kMockHttpsUrl),
GURL(kMockHttpsUrl),
GURL(kMockHttpsUrl2));
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
NavigateLoadingTabToTimeoutThreeSites) {
ASSERT_TRUE(embedded_test_server()->Start());
RunNavigateLoadingTabToTimeoutTest(
browser(), embedded_test_server()->GetURL("/title1.html"),
GURL(kMockHttpsUrl), GURL(kMockHttpsUrl2));
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, GoBack) {
ASSERT_TRUE(embedded_test_server()->Start());
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), embedded_test_server()->GetURL("/title2.html")));
SlowLoadBehindCaptivePortal(browser(), true);
FailLoadsWithoutLogin(browser(), 1);
CaptivePortalObserver portal_observer(browser()->profile());
MultiNavigationObserver navigation_observer;
TabStripModel* tab_strip_model = browser()->tab_strip_model();
tab_strip_model->ActivateTabAt(
0, TabStripUserGestureDetails(
TabStripUserGestureDetails::GestureType::kOther));
chrome::GoBack(browser(), WindowOpenDisposition::CURRENT_TAB);
navigation_observer.WaitForNavigations(1);
EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
tab_strip_model->GetWebContentsAt(0)));
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser(), 0));
EXPECT_EQ(0, portal_observer.num_results_received());
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, GoBackToTimeout) {
ASSERT_TRUE(embedded_test_server()->Start());
EnableCaptivePortalDetection(browser()->profile(), false);
SlowLoadNoCaptivePortal(browser(), captive_portal::RESULT_INTERNET_CONNECTED);
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), embedded_test_server()->GetURL("/title2.html")));
ASSERT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser(), 0));
EnableCaptivePortalDetection(browser()->profile(), true);
TabStripModel* tab_strip_model = browser()->tab_strip_model();
captive_portal::CaptivePortalTabReloader* tab_reloader =
GetTabReloader(tab_strip_model->GetActiveWebContents());
ASSERT_TRUE(tab_reloader);
SetSlowSSLLoadTime(tab_reloader, base::TimeDelta());
MultiNavigationObserver navigation_observer;
CaptivePortalObserver portal_observer(browser()->profile());
chrome::GoBack(browser(), WindowOpenDisposition::CURRENT_TAB);
portal_observer.WaitForResults(1);
navigation_observer.WaitForNavigations(1);
WaitForJobs(1);
EXPECT_EQ(1, portal_observer.num_results_received());
ASSERT_FALSE(CheckPending(browser()));
ASSERT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
portal_observer.captive_portal_result());
ASSERT_EQ(captive_portal::CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
GetStateOfTabReloaderAt(browser(), 0));
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser(), 1));
ASSERT_TRUE(IsLoginTab(browser()->tab_strip_model()->GetWebContentsAt(1)));
ASSERT_EQ(2, tab_strip_model->count());
EXPECT_EQ(1, tab_strip_model->active_index());
EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
tab_strip_model->GetWebContentsAt(1)));
EXPECT_EQ(1, NumLoadingTabs());
SetSlowSSLLoadTime(tab_reloader, base::Days(1));
Login(browser(), 1 , 0 ,
1 );
FailLoadsAfterLogin(browser(), 1);
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, ReloadTimeout) {
SetBehindCaptivePortal(false);
TabStripModel* tab_strip_model = browser()->tab_strip_model();
CaptivePortalObserver portal_observer(browser()->profile());
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL(kMockHttpsUrl)));
ASSERT_EQ(0, portal_observer.num_results_received());
ASSERT_EQ(1, tab_strip_model->count());
SetBehindCaptivePortal(true);
captive_portal::CaptivePortalTabReloader* tab_reloader =
GetTabReloader(tab_strip_model->GetActiveWebContents());
ASSERT_TRUE(tab_reloader);
SetSlowSSLLoadTime(tab_reloader, base::TimeDelta());
MultiNavigationObserver navigation_observer;
tab_strip_model->GetActiveWebContents()->GetController().Reload(
content::ReloadType::NORMAL, true);
portal_observer.WaitForResults(1);
navigation_observer.WaitForNavigations(1);
WaitForJobs(1);
ASSERT_EQ(1, portal_observer.num_results_received());
ASSERT_FALSE(CheckPending(browser()));
ASSERT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
portal_observer.captive_portal_result());
ASSERT_EQ(captive_portal::CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
GetStateOfTabReloaderAt(browser(), 0));
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser(), 1));
ASSERT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(1)));
ASSERT_EQ(2, tab_strip_model->count());
EXPECT_EQ(1, tab_strip_model->active_index());
EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
tab_strip_model->GetWebContentsAt(1)));
EXPECT_EQ(1, NumLoadingTabs());
SetSlowSSLLoadTime(tab_reloader, base::Days(1));
Login(browser(), 1 , 0 ,
1 );
FailLoadsAfterLogin(browser(), 1);
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, DISABLED_TwoWindows) {
Browser* browser2 =
Browser::Create(Browser::CreateParams(browser()->profile(), true));
ASSERT_TRUE(
ui_test_utils::NavigateToURL(browser2, GURL(url::kAboutBlankURL)));
Browser* active_browser =
chrome::FindTabbedBrowser(browser()->profile(), true);
Browser* inactive_browser;
if (active_browser == browser2) {
inactive_browser = browser();
} else {
ASSERT_EQ(active_browser, browser());
inactive_browser = browser2;
}
CaptivePortalObserver portal_observer(browser()->profile());
MultiNavigationObserver navigation_observer;
NavigateParams params(inactive_browser, GURL(kMockHttpsQuickTimeoutUrl),
ui::PAGE_TRANSITION_TYPED);
params.disposition = WindowOpenDisposition::NEW_BACKGROUND_TAB;
params.window_action = NavigateParams::WindowAction::kNoAction;
ui_test_utils::NavigateToURL(¶ms);
navigation_observer.WaitForNavigations(2);
ASSERT_EQ(active_browser,
chrome::FindTabbedBrowser(browser()->profile(), true));
ASSERT_EQ(1, active_browser->tab_strip_model()->active_index());
EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
inactive_browser->tab_strip_model()->GetWebContentsAt(1)));
EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
active_browser->tab_strip_model()->GetWebContentsAt(1)));
EXPECT_EQ(0, NumLoadingTabs());
portal_observer.WaitForResults(1);
ASSERT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
portal_observer.captive_portal_result());
EXPECT_EQ(1, portal_observer.num_results_received());
EXPECT_EQ(2, inactive_browser->tab_strip_model()->count());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(inactive_browser, 0));
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
GetStateOfTabReloaderAt(inactive_browser, 1));
ASSERT_EQ(2, active_browser->tab_strip_model()->count());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(active_browser, 0));
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(active_browser, 1));
EXPECT_TRUE(
IsLoginTab(active_browser->tab_strip_model()->GetWebContentsAt(1)));
Login(active_browser, 0 , 1 ,
1 );
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpToHttpsRedirectLogin) {
ASSERT_TRUE(embedded_test_server()->Start());
SlowLoadBehindCaptivePortal(
browser(), true ,
false ,
embedded_test_server()->GetURL(kRedirectToMockHttpsPath), 1, 1);
Login(browser(), 1 , 0 ,
1 );
FailLoadsAfterLogin(browser(), 1);
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpsToHttpRedirect) {
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.AddDefaultHandlers(GetChromeTestDataDir());
ASSERT_TRUE(https_server.Start());
GURL http_error_url("http://doesnt.exist/");
NavigateToPageExpectNoTest(
browser(),
https_server.GetURL(CreateServerRedirect(http_error_url.spec())));
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, Status511) {
SetUpCaptivePortalService(browser()->profile(),
GURL(kMockCaptivePortal511Url));
SlowLoadBehindCaptivePortal(browser(), true ,
false ,
GURL(kMockHttpsUrl), 2, 2);
Login(browser(), 1 , 0 ,
1 );
FailLoadsAfterLogin(browser(), 1);
}
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
DISABLED_InterstitialTimerCertErrorAfterSlowLoad) {
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
GURL cert_error_url;
https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_MISMATCHED_NAME);
https_server.ServeFilesFromSourceDirectory(GetChromeTestDataDir());
ASSERT_TRUE(https_server.Start());
cert_error_url = https_server.GetURL(kMockHttpsBadCertPath);
TabStripModel* tab_strip_model = browser()->tab_strip_model();
int broken_tab_index = tab_strip_model->active_index();
WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
SlowLoadBehindCaptivePortal(browser(), true ,
false ,
cert_error_url, 1, 1);
SetBehindCaptivePortal(false);
CaptivePortalObserver portal_observer(browser()->profile());
MultiNavigationObserver navigation_observer;
net::SSLInfo info;
info.cert_status = net::CERT_STATUS_COMMON_NAME_INVALID;
info.cert =
net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
info.unverified_cert = info.cert;
FailJobsWithCertError(1, info);
navigation_observer.WaitForNavigations(1);
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE,
GetStateOfTabReloaderAt(browser(), broken_tab_index));
ASSERT_TRUE(IsShowingInterstitial((broken_tab_contents)));
portal_observer.WaitForResults(2);
EXPECT_EQ(SSLBlockingPage::kTypeForTesting,
GetInterstitialType(broken_tab_contents));
}
#if BUILDFLAG(IS_WIN)
#define MAYBE_SecureDnsCaptivePortal DISABLED_SecureDnsCaptivePortal
#else
#define MAYBE_SecureDnsCaptivePortal SecureDnsCaptivePortal
#endif
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, MAYBE_SecureDnsCaptivePortal) {
PrefService* pref_service = g_browser_process->local_state();
#if BUILDFLAG(IS_CHROMEOS)
pref_service = browser()->profile()->GetPrefs();
#endif
pref_service->SetString(prefs::kDnsOverHttpsMode,
SecureDnsConfig::kModeSecure);
pref_service->SetString(prefs::kDnsOverHttpsTemplates,
"https://bar.test/dns-query{?dns}");
Browser* login_browser = nullptr;
SlowLoadBehindCaptivePortal(browser(), true ,
true ,
&login_browser);
ASSERT_TRUE(login_browser);
FailLoadsWithoutLogin(browser(), 1, login_browser);
SlowLoadBehindCaptivePortal(browser(), false ,
false );
Browser* second_user_browser = CreateBrowser(browser()->profile());
EXPECT_TRUE(second_user_browser->window()->IsVisible());
SlowLoadBehindCaptivePortal(second_user_browser,
false ,
false );
EXPECT_TRUE(login_browser->window()->IsVisible());
Login(login_browser, 2 , 0 ,
1 );
}
#if BUILDFLAG(IS_WIN)
#define MAYBE_SecureDnsErrorTriggersCheck DISABLED_SecureDnsErrorTriggersCheck
#else
#define MAYBE_SecureDnsErrorTriggersCheck SecureDnsErrorTriggersCheck
#endif
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
MAYBE_SecureDnsErrorTriggersCheck) {
PrefService* pref_service = g_browser_process->local_state();
#if BUILDFLAG(IS_CHROMEOS)
pref_service = browser()->profile()->GetPrefs();
#endif
pref_service->SetString(prefs::kDnsOverHttpsTemplates,
"https://bar.test/dns-query{?dns}");
pref_service->SetString(prefs::kDnsOverHttpsMode,
SecureDnsConfig::kModeSecure);
TabStripModel* tab_strip_model = browser()->tab_strip_model();
WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
Browser* login_browser = nullptr;
FastErrorBehindCaptivePortal(browser(), true ,
true ,
GURL(kMockHttpConnectionSecureDnsErr),
&login_browser);
ASSERT_TRUE(login_browser);
EXPECT_TRUE(broken_tab_contents->GetController()
.GetLastCommittedEntry()
->GetPageType() == content::PAGE_TYPE_ERROR);
Login(login_browser, 0 , 1 ,
2 );
EXPECT_TRUE(broken_tab_contents->GetController()
.GetLastCommittedEntry()
->GetPageType() == content::PAGE_TYPE_ERROR);
}
#if BUILDFLAG(IS_WIN)
#define MAYBE_SlowLoadSecureDnsErrorWithCaptivePortal \
DISABLED_SlowLoadSecureDnsErrorWithCaptivePortal
#else
#define MAYBE_SlowLoadSecureDnsErrorWithCaptivePortal \
SlowLoadSecureDnsErrorWithCaptivePortal
#endif
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
MAYBE_SlowLoadSecureDnsErrorWithCaptivePortal) {
PrefService* pref_service = g_browser_process->local_state();
#if BUILDFLAG(IS_CHROMEOS)
pref_service = browser()->profile()->GetPrefs();
#endif
pref_service->SetString(prefs::kDnsOverHttpsTemplates,
"https://bar.test/dns-query{?dns}");
pref_service->SetString(prefs::kDnsOverHttpsMode,
SecureDnsConfig::kModeSecure);
SlowLoadBehindCaptivePortal(browser(), true ,
true );
MultiNavigationObserver navigation_observer;
FailJobs(1, net::ERR_NAME_NOT_RESOLVED,
net::ResolveErrorInfo(net::ERR_CERT_COMMON_NAME_INVALID, true));
navigation_observer.WaitForNavigations(1);
WebContents* tab = browser()->tab_strip_model()->GetWebContentsAt(0);
EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(tab));
EXPECT_TRUE(tab->GetController().GetLastCommittedEntry()->GetPageType() ==
content::PAGE_TYPE_ERROR);
EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
EXPECT_EQ(2, NumTabs());
}
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
#define MAYBE_SlowLoadSecureDnsErrorAfterLogin \
DISABLED_SlowLoadSecureDnsErrorAfterLogin
#else
#define MAYBE_SlowLoadSecureDnsErrorAfterLogin SlowLoadSecureDnsErrorAfterLogin
#endif
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
MAYBE_SlowLoadSecureDnsErrorAfterLogin) {
PrefService* pref_service = g_browser_process->local_state();
#if BUILDFLAG(IS_CHROMEOS)
pref_service = browser()->profile()->GetPrefs();
#endif
pref_service->SetString(prefs::kDnsOverHttpsTemplates,
"https://bar.test/dns-query{?dns}");
pref_service->SetString(prefs::kDnsOverHttpsMode,
SecureDnsConfig::kModeSecure);
Browser* login_browser = nullptr;
SlowLoadBehindCaptivePortal(browser(), true ,
true ,
&login_browser);
ASSERT_TRUE(login_browser);
Login(login_browser, 1 , 0 ,
1 );
MultiNavigationObserver navigation_observer;
FailJobs(1, net::ERR_NAME_NOT_RESOLVED,
net::ResolveErrorInfo(net::ERR_CERT_COMMON_NAME_INVALID, true));
navigation_observer.WaitForNavigations(1);
WebContents* tab = browser()->tab_strip_model()->GetWebContentsAt(0);
EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(tab));
EXPECT_EQ(tab->GetController().GetLastCommittedEntry()->GetPageType(),
content::PAGE_TYPE_NORMAL);
EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
EXPECT_EQ(2, NumTabs());
}
class CaptivePortalForPrerenderingTest : public CaptivePortalBrowserTest {
public:
CaptivePortalForPrerenderingTest()
: prerender_helper_(base::BindRepeating(
&CaptivePortalForPrerenderingTest::GetWebContents,
base::Unretained(this))) {}
~CaptivePortalForPrerenderingTest() override = default;
void SetUp() override {
prerender_helper_.RegisterServerRequestMonitor(embedded_test_server());
CaptivePortalBrowserTest::SetUp();
}
void SetUpOnMainThread() override {
CaptivePortalBrowserTest::SetUpOnMainThread();
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(embedded_test_server()->Start());
}
void TearDownOnMainThread() override {
CaptivePortalBrowserTest::TearDownOnMainThread();
}
content::test::PrerenderTestHelper& prerender_helper() {
return prerender_helper_;
}
content::WebContents* GetWebContents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
void SetState(captive_portal::CaptivePortalTabReloader::State state) {
captive_portal::CaptivePortalTabReloader* tab_reloader =
GetTabReloader(GetWebContents());
ASSERT_TRUE(tab_reloader);
tab_reloader->SetState(state);
}
private:
content::test::PrerenderTestHelper prerender_helper_;
};
IN_PROC_BROWSER_TEST_F(CaptivePortalForPrerenderingTest,
DontFireOnLoadStartDuringPrerendering) {
GURL initial_url = embedded_test_server()->GetURL("/empty.html");
GURL prerender_url = embedded_test_server()->GetURL("/title1.html");
ASSERT_NE(ui_test_utils::NavigateToURL(browser(), initial_url), nullptr);
SetState(captive_portal::CaptivePortalTabReloader::STATE_TIMER_RUNNING);
prerender_helper().AddPrerender(prerender_url);
captive_portal::CaptivePortalTabReloader::State new_state =
GetStateOfTabReloader(GetWebContents());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_TIMER_RUNNING,
new_state);
}
IN_PROC_BROWSER_TEST_F(CaptivePortalForPrerenderingTest,
DontFireOnRedirectDuringPrerendering) {
GURL initial_url = embedded_test_server()->GetURL("/empty.html");
GURL redirect_url =
embedded_test_server()->GetURL(CreateServerRedirect(initial_url.spec()));
ASSERT_NE(ui_test_utils::NavigateToURL(browser(), initial_url), nullptr);
prerender_helper().AddPrerender(redirect_url);
SetState(captive_portal::CaptivePortalTabReloader::STATE_TIMER_RUNNING);
prerender_helper().NavigatePrimaryPage(redirect_url);
captive_portal::CaptivePortalTabReloader::State new_state =
GetStateOfTabReloader(GetWebContents());
EXPECT_EQ(captive_portal::CaptivePortalTabReloader::STATE_NONE, new_state);
}