diff options
19 files changed, 1207 insertions, 705 deletions
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc index f30f26b..d3acb3a 100644 --- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc +++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc @@ -641,7 +641,7 @@ void ChromeBrowserMainPartsChromeos::PostProfileInit() { // NetworkLibrary about changes in the NetworkManager and initiates // captive portal detection for active networks. NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance(); - if (NetworkPortalDetector::IsEnabled() && detector) { + if (NetworkPortalDetector::IsEnabledInCommandLine() && detector) { detector->Init(); #if defined(GOOGLE_CHROME_BUILD) bool is_official_build = true; @@ -651,7 +651,7 @@ void ChromeBrowserMainPartsChromeos::PostProfileInit() { // Enable portal detector if EULA was previously accepted or if // this is an unofficial build. if (!is_official_build || WizardController::IsEulaAccepted()) - detector->set_enabled(true); + detector->Enable(true); } display_configuration_observer_.reset( @@ -724,10 +724,9 @@ void ChromeBrowserMainPartsChromeos::PostMainMessageLoopRun() { if (NetworkChangeNotifierFactoryChromeos::GetInstance()) NetworkChangeNotifierFactoryChromeos::GetInstance()->Shutdown(); - if (NetworkPortalDetector::IsEnabled() && - NetworkPortalDetector::GetInstance()) { - NetworkPortalDetector::GetInstance()->Shutdown(); - } + NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance(); + if (NetworkPortalDetector::IsEnabledInCommandLine() && detector) + detector->Shutdown(); // Tell DeviceSettingsService to stop talking to session_manager. DeviceSettingsService::Get()->Shutdown(); diff --git a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.cc b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.cc index 55110a6..78639ce 100644 --- a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.cc +++ b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.cc @@ -4,6 +4,7 @@ #include "chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.h" +#include "chrome/browser/chromeos/cros/network_library.h" #include "chrome/browser/chromeos/login/error_screen.h" #include "chrome/browser/chromeos/login/existing_user_controller.h" #include "chrome/browser/chromeos/login/managed/locally_managed_user_controller.h" @@ -80,10 +81,8 @@ void LocallyManagedUserCreationScreen::Show() { } NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance(); - if (detector && !on_error_screen_) { - detector->AddObserver(this); - detector->ForcePortalDetection(); - } + if (detector && !on_error_screen_) + detector->AddAndFireObserver(this); on_error_screen_ = false; } diff --git a/chrome/browser/chromeos/login/mock_error_screen.cc b/chrome/browser/chromeos/login/mock_error_screen.cc new file mode 100644 index 0000000..aac54f9 --- /dev/null +++ b/chrome/browser/chromeos/login/mock_error_screen.cc @@ -0,0 +1,23 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/login/mock_error_screen.h" + +namespace chromeos { + +MockErrorScreen::MockErrorScreen(ScreenObserver* screen_observer, + ErrorScreenActor* actor) + : ErrorScreen(screen_observer, actor) { +} + +MockErrorScreen::~MockErrorScreen() { +} + +MockErrorScreenActor::MockErrorScreenActor() { +} + +MockErrorScreenActor::~MockErrorScreenActor() { +} + +} // namespace chromeosx diff --git a/chrome/browser/chromeos/login/mock_error_screen.h b/chrome/browser/chromeos/login/mock_error_screen.h new file mode 100644 index 0000000..03d270c --- /dev/null +++ b/chrome/browser/chromeos/login/mock_error_screen.h @@ -0,0 +1,40 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_ERROR_SCREEN_H_ +#define CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_ERROR_SCREEN_H_ + +#include "chrome/browser/chromeos/login/error_screen.h" +#include "chrome/browser/chromeos/login/error_screen_actor.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace chromeos { + +class MockErrorScreen : public ErrorScreen { + public: + MockErrorScreen(ScreenObserver* screen_observer, ErrorScreenActor* actor); + virtual ~MockErrorScreen(); +}; + +class MockErrorScreenActor : public ErrorScreenActor { + public: + MockErrorScreenActor(); + virtual ~MockErrorScreenActor(); + + MOCK_METHOD2(Show, void(OobeDisplay::Screen parent_screen, + base::DictionaryValue* params)); + MOCK_METHOD0(Hide, void(void)); + MOCK_METHOD0(FixCaptivePortal, void(void)); + MOCK_METHOD0(ShowCaptivePortal, void(void)); + MOCK_METHOD0(HideCaptivePortal, void(void)); + MOCK_METHOD1(SetUIState, void(ErrorScreen::UIState ui_state)); + MOCK_METHOD2(SetErrorState, void(ErrorScreen::ErrorState error_state, + const std::string& network)); + MOCK_METHOD1(AllowGuestSignin, void(bool allowed)); + MOCK_METHOD1(AllowOfflineLogin, void(bool allowed)); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_ERROR_SCREEN_H_ diff --git a/chrome/browser/chromeos/login/update_screen.cc b/chrome/browser/chromeos/login/update_screen.cc index 2a62a0d..99a470c 100644 --- a/chrome/browser/chromeos/login/update_screen.cc +++ b/chrome/browser/chromeos/login/update_screen.cc @@ -76,6 +76,12 @@ void StartUpdateCallback(UpdateScreen* screen, } } +// Returns true if blocking AU is enabled in command line. +bool IsBlockingUpdateEnabledInCommandLine() { + return CommandLine::ForCurrentProcess()->HasSwitch( + chromeos::switches::kEnableOOBEBlockingUpdate); +} + } // anonymous namespace // static @@ -266,15 +272,13 @@ void UpdateScreen::StartNetworkCheck() { // If portal detector is enabled and portal detection before AU is // allowed, initiate network state check. Otherwise, directly // proceed to update. - if (!NetworkPortalDetector::IsEnabled() || !detector || - !CommandLine::ForCurrentProcess()->HasSwitch( - chromeos::switches::kEnableOOBEBlockingUpdate)) { + if (!NetworkPortalDetector::IsEnabledInCommandLine() || !detector || + !IsBlockingUpdateEnabledInCommandLine()) { StartUpdateCheck(); return; } state_ = STATE_FIRST_PORTAL_CHECK; - detector->AddObserver(this); - detector->ForcePortalDetection(); + detector->AddAndFireObserver(this); } void UpdateScreen::CancelUpdate() { @@ -307,6 +311,8 @@ void UpdateScreen::PrepareToShow() { void UpdateScreen::ExitUpdate(UpdateScreen::ExitReason reason) { DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this); + if (NetworkPortalDetector::GetInstance()) + NetworkPortalDetector::GetInstance()->RemoveObserver(this); switch (reason) { case REASON_UPDATE_CANCELED: diff --git a/chrome/browser/chromeos/login/update_screen_browsertest.cc b/chrome/browser/chromeos/login/update_screen_browsertest.cc index 12d8b6c..c373467d 100644 --- a/chrome/browser/chromeos/login/update_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/update_screen_browsertest.cc @@ -2,12 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/command_line.h" #include "base/memory/scoped_ptr.h" #include "chrome/browser/chromeos/cros/mock_network_library.h" +#include "chrome/browser/chromeos/login/mock_error_screen.h" #include "chrome/browser/chromeos/login/mock_screen_observer.h" #include "chrome/browser/chromeos/login/update_screen.h" #include "chrome/browser/chromeos/login/wizard_controller.h" #include "chrome/browser/chromeos/login/wizard_in_process_browser_test.h" +#include "chrome/browser/chromeos/net/network_portal_detector.h" +#include "chrome/browser/chromeos/net/network_portal_detector_stub.h" +#include "chromeos/chromeos_switches.h" #include "chromeos/dbus/mock_dbus_thread_manager.h" #include "chromeos/dbus/mock_session_manager_client.h" #include "chromeos/dbus/mock_update_engine_client.h" @@ -24,6 +29,9 @@ namespace chromeos { namespace { +const char kDefaultEthernetServicePath[] = "eth0"; +const char kDefaultWifiServicePath[] = "wlan0"; + static void RequestUpdateCheckSuccess( UpdateEngineClient::UpdateCheckCallback callback) { callback.Run(UpdateEngineClient::UPDATE_RESULT_SUCCESS); @@ -35,10 +43,15 @@ class UpdateScreenTest : public WizardInProcessBrowserTest { public: UpdateScreenTest() : WizardInProcessBrowserTest("update"), mock_update_engine_client_(NULL), - mock_network_library_(NULL) {} + mock_network_library_(NULL), + network_portal_detector_stub_(NULL) { + } protected: virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { + CommandLine::ForCurrentProcess()->AppendSwitch( + chromeos::switches::kEnableOOBEBlockingUpdate); + MockDBusThreadManager* mock_dbus_thread_manager = new MockDBusThreadManager; EXPECT_CALL(*mock_dbus_thread_manager, GetSystemBus()) @@ -68,6 +81,8 @@ class UpdateScreenTest : public WizardInProcessBrowserTest { .WillOnce(Invoke(RequestUpdateCheckSuccess)); mock_network_library_ = cros_mock_->mock_network_library(); + stub_ethernet_.reset(new EthernetNetwork(kDefaultEthernetServicePath)); + stub_wifi_.reset(new WifiNetwork(kDefaultWifiServicePath)); EXPECT_CALL(*mock_network_library_, SetDefaultCheckPortalList()) .Times(1); EXPECT_CALL(*mock_network_library_, Connected()) @@ -85,11 +100,43 @@ class UpdateScreenTest : public WizardInProcessBrowserTest { .Times(AnyNumber()); EXPECT_CALL(*mock_network_library_, LoadOncNetworks(_, _, _, _)) .WillRepeatedly(Return(true)); + EXPECT_CALL(*mock_network_library_, + FindNetworkByPath(kDefaultEthernetServicePath)) + .Times(AnyNumber()) + .WillRepeatedly((Return(stub_ethernet_.get()))); + EXPECT_CALL(*mock_network_library_, + FindNetworkByPath(kDefaultWifiServicePath)) + .Times(AnyNumber()) + .WillRepeatedly((Return(stub_wifi_.get()))); + + // Setup network portal detector to return online state for both + // ethernet and wifi networks. Ethernet is an active network by + // default. + network_portal_detector_stub_ = + static_cast<NetworkPortalDetectorStub*>( + NetworkPortalDetector::GetInstance()); + NetworkPortalDetector::CaptivePortalState online_state; + online_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE; + online_state.response_code = 204; + SetActiveNetwork(stub_ethernet_.get()); + SetDetectionResults(stub_ethernet_.get(), online_state); + SetDetectionResults(stub_wifi_.get(), online_state); } virtual void SetUpOnMainThread() OVERRIDE { WizardInProcessBrowserTest::SetUpOnMainThread(); + mock_screen_observer_.reset(new MockScreenObserver()); + mock_error_screen_actor_.reset(new MockErrorScreenActor()); + mock_error_screen_.reset( + new MockErrorScreen(mock_screen_observer_.get(), + mock_error_screen_actor_.get())); + EXPECT_CALL(*mock_screen_observer_, ShowCurrentScreen()) + .Times(AnyNumber()); + EXPECT_CALL(*mock_screen_observer_, GetErrorScreen()) + .Times(AnyNumber()) + .WillRepeatedly(Return(mock_error_screen_.get())); + ASSERT_TRUE(WizardController::default_controller() != NULL); update_screen_ = WizardController::default_controller()->GetUpdateScreen(); ASSERT_TRUE(update_screen_ != NULL); @@ -103,11 +150,33 @@ class UpdateScreenTest : public WizardInProcessBrowserTest { DBusThreadManager::Shutdown(); } + void SetActiveNetwork(const Network* network) { + DCHECK(network_portal_detector_stub_); + network_portal_detector_stub_->SetActiveNetworkForTesting(network); + } + + void SetDetectionResults( + const Network* network, + const NetworkPortalDetector::CaptivePortalState& state) { + DCHECK(network_portal_detector_stub_); + network_portal_detector_stub_->SetDetectionResultsForTesting(network, + state); + } + + void NotifyPortalDetectionCompleted() { + DCHECK(network_portal_detector_stub_); + network_portal_detector_stub_->NotifyObserversForTesting(); + } + MockUpdateEngineClient* mock_update_engine_client_; MockNetworkLibrary* mock_network_library_; - + scoped_ptr<Network> stub_ethernet_; + scoped_ptr<Network> stub_wifi_; scoped_ptr<MockScreenObserver> mock_screen_observer_; + scoped_ptr<MockErrorScreenActor> mock_error_screen_actor_; + scoped_ptr<MockErrorScreen> mock_error_screen_; UpdateScreen* update_screen_; + NetworkPortalDetectorStub* network_portal_detector_stub_; private: DISALLOW_COPY_AND_ASSIGN(UpdateScreenTest); @@ -229,4 +298,94 @@ IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestErrorUpdating) { update_screen_->UpdateStatusChanged(status); } +IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestTemproraryOfflineNetwork) { + EXPECT_CALL(*mock_screen_observer_, + OnExit(ScreenObserver::UPDATE_NOUPDATE)) + .Times(1); + update_screen_->CancelUpdate(); + + // Change ethernet state to portal. + NetworkPortalDetector::CaptivePortalState portal_state; + portal_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL; + portal_state.response_code = 200; + SetDetectionResults(stub_ethernet_.get(), portal_state); + + // Update screen will show error message about portal state because + // ethernet is behind captive portal. + EXPECT_CALL(*mock_error_screen_actor_, + SetUIState(ErrorScreen::UI_STATE_UPDATE)) + .Times(1); + EXPECT_CALL(*mock_error_screen_actor_, + SetErrorState(ErrorScreen::ERROR_STATE_PORTAL, std::string())) + .Times(1); + EXPECT_CALL(*mock_error_screen_actor_, FixCaptivePortal()) + .Times(1); + EXPECT_CALL(*mock_screen_observer_, ShowErrorScreen()) + .Times(1); + + update_screen_->StartNetworkCheck(); + + NetworkPortalDetector::CaptivePortalState online_state; + online_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE; + online_state.response_code = 204; + SetDetectionResults(stub_ethernet_.get(), online_state); + + // Second notification from portal detector will be about online state, + // so update screen will hide error message and proceed to update. + EXPECT_CALL(*mock_screen_observer_, HideErrorScreen(update_screen_)) + .Times(1); + EXPECT_CALL(*mock_update_engine_client_, RequestUpdateCheck(_)) + .Times(1) + .WillOnce(Invoke(RequestUpdateCheckFail)); + EXPECT_CALL(*mock_screen_observer_, + OnExit(ScreenObserver::UPDATE_ERROR_CHECKING_FOR_UPDATE)) + .Times(1); + + NotifyPortalDetectionCompleted(); +} + +IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestTwoOfflineNetworks) { + EXPECT_CALL(*mock_screen_observer_, + OnExit(ScreenObserver::UPDATE_NOUPDATE)) + .Times(1); + update_screen_->CancelUpdate(); + + // Change ethernet state to portal. + NetworkPortalDetector::CaptivePortalState portal_state; + portal_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL; + portal_state.response_code = 200; + SetDetectionResults(stub_ethernet_.get(), portal_state); + + // Update screen will show error message about portal state because + // ethernet is behind captive portal. + EXPECT_CALL(*mock_error_screen_actor_, + SetUIState(ErrorScreen::UI_STATE_UPDATE)) + .Times(1); + EXPECT_CALL(*mock_error_screen_actor_, + SetErrorState(ErrorScreen::ERROR_STATE_PORTAL, std::string())) + .Times(1); + EXPECT_CALL(*mock_error_screen_actor_, FixCaptivePortal()) + .Times(1); + EXPECT_CALL(*mock_screen_observer_, ShowErrorScreen()) + .Times(1); + + update_screen_->StartNetworkCheck(); + + // Change active network to the wifi behind proxy. + NetworkPortalDetector::CaptivePortalState proxy_state; + proxy_state.status = + NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED; + proxy_state.response_code = -1; + SetActiveNetwork(stub_wifi_.get()); + SetDetectionResults(stub_wifi_.get(), proxy_state); + + // Update screen will show message about proxy error because wifie + // network requires proxy authentication. + EXPECT_CALL(*mock_error_screen_actor_, + SetErrorState(ErrorScreen::ERROR_STATE_PROXY, std::string())) + .Times(1); + + NotifyPortalDetectionCompleted(); +} + } // namespace chromeos diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc index a31858a..9d2a1a4 100644 --- a/chrome/browser/chromeos/login/wizard_controller.cc +++ b/chrome/browser/chromeos/login/wizard_controller.cc @@ -603,8 +603,8 @@ void WizardController::PerformPostEulaActions() { SetDefaultCheckPortalList(); host_->CheckForAutoEnrollment(); NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance(); - if (detector) - detector->set_enabled(true); + if (NetworkPortalDetector::IsEnabledInCommandLine() && detector) + detector->Enable(true); } void WizardController::PerformPostUpdateActions() { diff --git a/chrome/browser/chromeos/net/network_portal_detector.cc b/chrome/browser/chromeos/net/network_portal_detector.cc index 70d1c7f..90cb853 100644 --- a/chrome/browser/chromeos/net/network_portal_detector.cc +++ b/chrome/browser/chromeos/net/network_portal_detector.cc @@ -1,253 +1,52 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/chromeos/net/network_portal_detector.h" -#include "base/bind.h" #include "base/command_line.h" #include "base/logging.h" -#include "base/message_loop.h" -#include "base/metrics/histogram.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/chromeos/cros/cros_library.h" -#include "chrome/common/chrome_notification_types.h" +#include "chrome/browser/chromeos/net/network_portal_detector_impl.h" +#include "chrome/browser/chromeos/net/network_portal_detector_stub.h" #include "chrome/common/chrome_switches.h" -#include "content/public/browser/notification_service.h" -#include "grit/generated_resources.h" -#include "net/http/http_status_code.h" -#include "ui/base/l10n/l10n_util.h" - -using captive_portal::CaptivePortalDetector; namespace chromeos { namespace { -// Maximum number of portal detections for the same active network -// after network change. -const int kMaxRequestAttempts = 3; - -// Minimum timeout between consecutive portal checks for the same -// network. -const int kMinTimeBetweenAttemptsSec = 3; - -// Timeout for a portal check. -const int kRequestTimeoutSec = 5; - -// Delay before portal detection caused by changes in proxy settings. -const int kProxyChangeDelaySec = 1; - -// Delay between consecutive portal checks for a network in lazy mode. -const int kLazyCheckIntervalSec = 5; +NetworkPortalDetector* g_network_portal_detector = NULL; -std::string CaptivePortalStatusString( - NetworkPortalDetector::CaptivePortalStatus status) { - switch (status) { - case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN: - return l10n_util::GetStringUTF8( - IDS_CHROMEOS_CAPTIVE_PORTAL_STATUS_UNKNOWN); - case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE: - return l10n_util::GetStringUTF8( - IDS_CHROMEOS_CAPTIVE_PORTAL_STATUS_OFFLINE); - case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE: - return l10n_util::GetStringUTF8( - IDS_CHROMEOS_CAPTIVE_PORTAL_STATUS_ONLINE); - case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL: - return l10n_util::GetStringUTF8( - IDS_CHROMEOS_CAPTIVE_PORTAL_STATUS_PORTAL); - case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED: - return l10n_util::GetStringUTF8( - IDS_CHROMEOS_CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED); - case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT: - NOTREACHED(); - } - return l10n_util::GetStringUTF8( - IDS_CHROMEOS_CAPTIVE_PORTAL_STATUS_UNRECOGNIZED); +bool IsTestMode() { + return CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType); } -NetworkPortalDetector* g_network_portal_detector = NULL; - } // namespace -NetworkPortalDetector::NetworkPortalDetector( - const scoped_refptr<net::URLRequestContextGetter>& request_context) - : active_connection_state_(STATE_UNKNOWN), - test_url_(CaptivePortalDetector::kDefaultURL), - enabled_(false), - weak_ptr_factory_(this), - attempt_count_(0), - lazy_detection_enabled_(false), - lazy_check_interval_(base::TimeDelta::FromSeconds(kLazyCheckIntervalSec)), - min_time_between_attempts_( - base::TimeDelta::FromSeconds(kMinTimeBetweenAttemptsSec)), - request_timeout_(base::TimeDelta::FromSeconds(kRequestTimeoutSec)) { - captive_portal_detector_.reset(new CaptivePortalDetector(request_context)); - - registrar_.Add(this, - chrome::NOTIFICATION_LOGIN_PROXY_CHANGED, - content::NotificationService::AllSources()); - registrar_.Add(this, - chrome::NOTIFICATION_AUTH_SUPPLIED, - content::NotificationService::AllSources()); - registrar_.Add(this, - chrome::NOTIFICATION_AUTH_CANCELLED, - content::NotificationService::AllSources()); +NetworkPortalDetector::NetworkPortalDetector() { } NetworkPortalDetector::~NetworkPortalDetector() { } -void NetworkPortalDetector::Init() { - DCHECK(CalledOnValidThread()); - DCHECK(chromeos::CrosLibrary::Get()); - - state_ = STATE_IDLE; - chromeos::NetworkLibrary* network_library = - chromeos::CrosLibrary::Get()->GetNetworkLibrary(); - DCHECK(network_library); - network_library->AddNetworkManagerObserver(this); - network_library->RemoveObserverForAllNetworks(this); -} - -void NetworkPortalDetector::Shutdown() { - DCHECK(CalledOnValidThread()); - DCHECK(chromeos::CrosLibrary::Get()); - - detection_task_.Cancel(); - detection_timeout_.Cancel(); - - captive_portal_detector_->Cancel(); - captive_portal_detector_.reset(); - observers_.Clear(); - chromeos::NetworkLibrary* network_library = - chromeos::CrosLibrary::Get()->GetNetworkLibrary(); - if (network_library) - network_library->RemoveNetworkManagerObserver(this); -} - -void NetworkPortalDetector::AddObserver(Observer* observer) { - DCHECK(CalledOnValidThread()); - - if (!observers_.HasObserver(observer)) - observers_.AddObserver(observer); -} - -void NetworkPortalDetector::RemoveObserver(Observer* observer) { - DCHECK(CalledOnValidThread()); - - observers_.RemoveObserver(observer); -} - -NetworkPortalDetector::CaptivePortalState -NetworkPortalDetector::GetCaptivePortalState(const Network* network) { - DCHECK(CalledOnValidThread()); - - if (!network) - return CaptivePortalState(); - CaptivePortalStateMap::const_iterator it = - portal_state_map_.find(network->service_path()); - if (it == portal_state_map_.end()) - return CaptivePortalState(); - return it->second; -} - -void NetworkPortalDetector::OnNetworkManagerChanged(NetworkLibrary* cros) { - DCHECK(CalledOnValidThread()); - - const Network* active_network = cros->active_network(); - if (!active_network) - return; - - active_network_id_ = active_network->unique_id(); - - bool network_changed = - (active_service_path_ != active_network->service_path()); - if (network_changed) { - if (!active_service_path_.empty()) - cros->RemoveNetworkObserver(active_service_path_, this); - active_service_path_ = active_network->service_path(); - cros->AddNetworkObserver(active_service_path_, this); - } - - bool connection_state_changed = - (active_connection_state_ != active_network->connection_state()); - active_connection_state_ = active_network->connection_state(); - - if (network_changed || connection_state_changed) { - attempt_count_ = 0; - CancelPortalDetection(); - } - - if (!IsCheckingForPortal() && !IsPortalCheckPending() && - Network::IsConnectedState(active_connection_state_) && - (attempt_count_ < kMaxRequestAttempts || lazy_detection_enabled_)) { - DCHECK(active_network); - - // Initiate Captive Portal detection if network's captive - // portal state is unknown (e.g. for freshly created networks), - // offline or if network connection state was changed. - CaptivePortalState state = GetCaptivePortalState(active_network); - if (state.status == CAPTIVE_PORTAL_STATUS_UNKNOWN || - state.status == CAPTIVE_PORTAL_STATUS_OFFLINE || - (!network_changed && connection_state_changed)) { - DetectCaptivePortal(base::TimeDelta()); - } - } -} - -void NetworkPortalDetector::OnNetworkChanged(chromeos::NetworkLibrary* cros, - const chromeos::Network* network) { - DCHECK(CalledOnValidThread()); - OnNetworkManagerChanged(cros); -} - -void NetworkPortalDetector::EnableLazyDetection() { - if (lazy_detection_enabled_) - return; - VLOG(1) << "Lazy detection mode enabled."; - lazy_detection_enabled_ = true; - if (!IsPortalCheckPending() && !IsCheckingForPortal()) - DetectCaptivePortal(base::TimeDelta()); -} - -void NetworkPortalDetector::DisableLazyDetection() { - if (!lazy_detection_enabled_) - return; - VLOG(1) << "Lazy detection mode disabled."; - lazy_detection_enabled_ = false; -} - -void NetworkPortalDetector::ForcePortalDetection() { - DCHECK(CalledOnValidThread()); - - if (IsPortalCheckPending() || IsCheckingForPortal()) - return; - DCHECK(!lazy_detection_enabled_); - NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); - if (!cros) - return; - const Network* active_network = cros->active_network(); - if (!active_network) - return; - state_ = STATE_IDLE; - attempt_count_ = 0; - portal_state_map_.erase(active_network->service_path()); - DetectCaptivePortal(base::TimeDelta()); -} - // static NetworkPortalDetector* NetworkPortalDetector::CreateInstance() { - CHECK(!g_network_portal_detector); - CHECK(NetworkPortalDetector::IsEnabled()); - g_network_portal_detector = new NetworkPortalDetector( - g_browser_process->system_request_context()); + DCHECK(!g_network_portal_detector); + CHECK(NetworkPortalDetector::IsEnabledInCommandLine()); + if (IsTestMode()) { + g_network_portal_detector = new NetworkPortalDetectorStub(); + } else { + CHECK(g_browser_process); + CHECK(g_browser_process->system_request_context()); + g_network_portal_detector = new NetworkPortalDetectorImpl( + g_browser_process->system_request_context()); + } return g_network_portal_detector; } // static NetworkPortalDetector* NetworkPortalDetector::GetInstance() { - if (!NetworkPortalDetector::IsEnabled()) + if (!NetworkPortalDetector::IsEnabledInCommandLine()) return NULL; if (!g_network_portal_detector) return CreateInstance(); @@ -255,230 +54,9 @@ NetworkPortalDetector* NetworkPortalDetector::GetInstance() { } // static -bool NetworkPortalDetector::IsEnabled() { +bool NetworkPortalDetector::IsEnabledInCommandLine() { return !CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableChromeCaptivePortalDetector); } -void NetworkPortalDetector::DetectCaptivePortal(const base::TimeDelta& delay) { - DCHECK(!IsPortalCheckPending()); - DCHECK(!IsCheckingForPortal()); - DCHECK(attempt_count_ < kMaxRequestAttempts || lazy_detection_enabled_); - - if (!enabled()) - return; - - detection_task_.Cancel(); - detection_timeout_.Cancel(); - state_ = STATE_PORTAL_CHECK_PENDING; - - next_attempt_delay_ = delay; - if (attempt_count_ > 0) { - base::TimeTicks now = GetCurrentTimeTicks(); - base::TimeDelta elapsed_time; - - base::TimeDelta delay_between_attempts = min_time_between_attempts_; - if (attempt_count_ == kMaxRequestAttempts) { - DCHECK(lazy_detection_enabled_); - delay_between_attempts = lazy_check_interval_; - } - if (now > attempt_start_time_) - elapsed_time = now - attempt_start_time_; - if (elapsed_time < delay_between_attempts && - delay_between_attempts - elapsed_time > next_attempt_delay_) { - next_attempt_delay_ = delay_between_attempts - elapsed_time; - } - } else { - detection_start_time_ = GetCurrentTimeTicks(); - } - detection_task_.Reset( - base::Bind(&NetworkPortalDetector::DetectCaptivePortalTask, - weak_ptr_factory_.GetWeakPtr())); - MessageLoop::current()->PostDelayedTask(FROM_HERE, - detection_task_.callback(), - next_attempt_delay_); -} - -void NetworkPortalDetector::DetectCaptivePortalTask() { - DCHECK(IsPortalCheckPending()); - - state_ = STATE_CHECKING_FOR_PORTAL; - - attempt_start_time_ = GetCurrentTimeTicks(); - - if (attempt_count_ < kMaxRequestAttempts) { - ++attempt_count_; - VLOG(1) << "Portal detection started: " - << "network=" << active_network_id_ << ", " - << "attempt=" << attempt_count_ << " of " << kMaxRequestAttempts; - } else { - DCHECK(lazy_detection_enabled_); - VLOG(1) << "Lazy portal detection attempt started"; - } - - captive_portal_detector_->DetectCaptivePortal( - test_url_, - base::Bind(&NetworkPortalDetector::OnPortalDetectionCompleted, - weak_ptr_factory_.GetWeakPtr())); - detection_timeout_.Reset( - base::Bind(&NetworkPortalDetector::PortalDetectionTimeout, - weak_ptr_factory_.GetWeakPtr())); - MessageLoop::current()->PostDelayedTask(FROM_HERE, - detection_timeout_.callback(), - request_timeout_); -} - -void NetworkPortalDetector::PortalDetectionTimeout() { - DCHECK(CalledOnValidThread()); - DCHECK(IsCheckingForPortal()); - - VLOG(1) << "Portal detection timeout: network=" << active_network_id_; - - captive_portal_detector_->Cancel(); - CaptivePortalDetector::Results results; - results.result = captive_portal::RESULT_NO_RESPONSE; - OnPortalDetectionCompleted(results); -} - -void NetworkPortalDetector::CancelPortalDetection() { - if (IsPortalCheckPending()) - detection_task_.Cancel(); - else if (IsCheckingForPortal()) - captive_portal_detector_->Cancel(); - detection_timeout_.Cancel(); - state_ = STATE_IDLE; -} - -void NetworkPortalDetector::OnPortalDetectionCompleted( - const CaptivePortalDetector::Results& results) { - DCHECK(CalledOnValidThread()); - DCHECK(IsCheckingForPortal()); - - VLOG(1) << "Portal detection completed: " - << "network=" << active_network_id_ << ", " - << "result=" << CaptivePortalDetector::CaptivePortalResultToString( - results.result) << ", " - << "response_code=" << results.response_code; - - state_ = STATE_IDLE; - detection_timeout_.Cancel(); - - NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); - const Network* active_network = cros->active_network(); - if (!active_network) { - TryLazyDetection(); - return; - } - - CaptivePortalState state; - state.response_code = results.response_code; - switch (results.result) { - case captive_portal::RESULT_NO_RESPONSE: - if (attempt_count_ >= kMaxRequestAttempts) { - if (state.response_code == net::HTTP_PROXY_AUTHENTICATION_REQUIRED) { - state.status = CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED; - } else if (active_network->restricted_pool()) { - // Take into account shill's detection results. - state.status = CAPTIVE_PORTAL_STATUS_PORTAL; - LOG(WARNING) << "Network " << active_network->unique_id() << " " - << "is marked as " - << CaptivePortalStatusString(state.status) << " " - << "despite the fact that CaptivePortalDetector " - << "received no response"; - } else { - state.status = CAPTIVE_PORTAL_STATUS_OFFLINE; - } - SetCaptivePortalState(active_network, state); - } else { - DetectCaptivePortal(results.retry_after_delta); - } - break; - case captive_portal::RESULT_INTERNET_CONNECTED: - state.status = CAPTIVE_PORTAL_STATUS_ONLINE; - SetCaptivePortalState(active_network, state); - break; - case captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL: - state.status = CAPTIVE_PORTAL_STATUS_PORTAL; - SetCaptivePortalState(active_network, state); - break; - default: - break; - } - - TryLazyDetection(); -} - -void NetworkPortalDetector::TryLazyDetection() { - if (!IsPortalCheckPending() && !IsCheckingForPortal() && - lazy_detection_enabled_) { - DetectCaptivePortal(base::TimeDelta()); - } -} - -void NetworkPortalDetector::Observe( - int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - if (type == chrome::NOTIFICATION_LOGIN_PROXY_CHANGED || - type == chrome::NOTIFICATION_AUTH_SUPPLIED || - type == chrome::NOTIFICATION_AUTH_CANCELLED) { - VLOG(1) << "Restarting portal detection due to proxy change."; - attempt_count_ = 0; - if (IsPortalCheckPending()) - return; - CancelPortalDetection(); - DetectCaptivePortal(base::TimeDelta::FromSeconds(kProxyChangeDelaySec)); - } -} - -bool NetworkPortalDetector::IsPortalCheckPending() const { - return state_ == STATE_PORTAL_CHECK_PENDING; -} - -bool NetworkPortalDetector::IsCheckingForPortal() const { - return state_ == STATE_CHECKING_FOR_PORTAL; -} - -void NetworkPortalDetector::SetCaptivePortalState( - const Network* network, - const CaptivePortalState& state) { - DCHECK(network); - - if (!detection_start_time_.is_null()) { - UMA_HISTOGRAM_TIMES("CaptivePortal.OOBE.DetectionDuration", - GetCurrentTimeTicks() - detection_start_time_); - } - - CaptivePortalStateMap::const_iterator it = - portal_state_map_.find(network->service_path()); - if (it == portal_state_map_.end() || - it->second.status != state.status || - it->second.response_code != state.response_code) { - VLOG(1) << "Updating Chrome Captive Portal state: " - << "network=" << network->unique_id() << ", " - << "status=" << CaptivePortalStatusString(state.status) << ", " - << "response_code=" << state.response_code; - portal_state_map_[network->service_path()] = state; - } - NotifyPortalDetectionCompleted(network, state); -} - -void NetworkPortalDetector::NotifyPortalDetectionCompleted( - const Network* network, - const CaptivePortalState& state) { - FOR_EACH_OBSERVER(Observer, observers_, - OnPortalDetectionCompleted(network, state)); -} - -base::TimeTicks NetworkPortalDetector::GetCurrentTimeTicks() const { - if (time_ticks_for_testing_.is_null()) - return base::TimeTicks::Now(); - else - return time_ticks_for_testing_; -} - -bool NetworkPortalDetector::DetectionTimeoutIsCancelledForTesting() const { - return detection_timeout_.IsCancelled(); -} - } // namespace chromeos diff --git a/chrome/browser/chromeos/net/network_portal_detector.h b/chrome/browser/chromeos/net/network_portal_detector.h index 6435777..92bc443 100644 --- a/chrome/browser/chromeos/net/network_portal_detector.h +++ b/chrome/browser/chromeos/net/network_portal_detector.h @@ -1,43 +1,21 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_BROWSER_CHROMEOS_NET_NETWORK_PORTAL_DETECTOR_H_ #define CHROME_BROWSER_CHROMEOS_NET_NETWORK_PORTAL_DETECTOR_H_ -#include <string> - #include "base/basictypes.h" -#include "base/cancelable_callback.h" -#include "base/compiler_specific.h" -#include "base/hash_tables.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" -#include "base/observer_list.h" -#include "base/threading/non_thread_safe.h" -#include "base/time.h" -#include "chrome/browser/captive_portal/captive_portal_detector.h" -#include "chrome/browser/chromeos/cros/network_library.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" -#include "googleurl/src/gurl.h" #include "net/url_request/url_fetcher.h" -namespace net { -class URLRequestContextGetter; -} - namespace chromeos { +class Network; + // This class handles all notifications about network changes from // NetworkLibrary and delegates portal detection for the active // network to CaptivePortalService. -class NetworkPortalDetector - : public base::NonThreadSafe, - public chromeos::NetworkLibrary::NetworkManagerObserver, - public chromeos::NetworkLibrary::NetworkObserver, - public content::NotificationObserver { +class NetworkPortalDetector { public: enum CaptivePortalStatus { CAPTIVE_PORTAL_STATUS_UNKNOWN = 0, @@ -69,36 +47,33 @@ class NetworkPortalDetector virtual ~Observer() {} }; - virtual ~NetworkPortalDetector(); + virtual void Init() = 0; + virtual void Shutdown() = 0; - void Init(); - void Shutdown(); - - void AddObserver(Observer* observer); - void RemoveObserver(Observer* observer); + virtual void AddObserver(Observer* observer) = 0; + virtual void AddAndFireObserver(Observer* observer) = 0; + virtual void RemoveObserver(Observer* observer) = 0; // Returns Captive Portal state for a given |network|. - CaptivePortalState GetCaptivePortalState(const chromeos::Network* network); - - // NetworkLibrary::NetworkManagerObserver implementation: - virtual void OnNetworkManagerChanged(chromeos::NetworkLibrary* cros) OVERRIDE; + virtual CaptivePortalState GetCaptivePortalState( + const chromeos::Network* network) = 0; - // NetworkLibrary::NetworkObserver implementation: - virtual void OnNetworkChanged(chromeos::NetworkLibrary* cros, - const chromeos::Network* network) OVERRIDE; + // Returns true if portal detection is enabled. + virtual bool IsEnabled() = 0; - bool enabled() const { return enabled_; } - void set_enabled(bool enabled) { enabled_ = enabled; } + // Enable portal detection. This method is needed because we can't + // check current network for portal state unless user accepts EULA. + // If |start_detection| is true and NetworkPortalDetector was + // disabled previously, portal detection for the active network is + // initiated by this method. + virtual void Enable(bool start_detection) = 0; // Enables lazy detection mode. In this mode portal detection after // first 3 consecutive attemps will be performed once in 30 seconds. - void EnableLazyDetection(); + virtual void EnableLazyDetection() = 0; // Dizables lazy detection mode. - void DisableLazyDetection(); - - // Forces detection attempt for active network. - void ForcePortalDetection(); + virtual void DisableLazyDetection() = 0; // Creates an instance of the NetworkPortalDetector. static NetworkPortalDetector* CreateInstance(); @@ -106,169 +81,14 @@ class NetworkPortalDetector // Gets the instance of the NetworkPortalDetector. static NetworkPortalDetector* GetInstance(); - // Returns true is NetworkPortalDetector service is enabled. - static bool IsEnabled(); - - private: - friend class NetworkPortalDetectorTest; - - typedef std::string NetworkId; - typedef base::hash_map<NetworkId, CaptivePortalState> CaptivePortalStateMap; - - enum State { - // No portal check is running. - STATE_IDLE = 0, - // Waiting for portal check. - STATE_PORTAL_CHECK_PENDING, - // Portal check is in progress. - STATE_CHECKING_FOR_PORTAL, - }; - - explicit NetworkPortalDetector( - const scoped_refptr<net::URLRequestContextGetter>& request_context); - - // Initiates Captive Portal detection after |delay|. - void DetectCaptivePortal(const base::TimeDelta& delay); - - void DetectCaptivePortalTask(); - - // Called when portal check is timed out. Cancels portal check and - // calls OnPortalDetectionCompleted() with RESULT_NO_RESPONSE as - // a result. - void PortalDetectionTimeout(); - - void CancelPortalDetection(); - - // Called by CaptivePortalDetector when detection completes. - void OnPortalDetectionCompleted( - const captive_portal::CaptivePortalDetector::Results& results); - - // Tries to perform portal detection in "lazy" mode. Does nothing in - // the case of already pending/processing detection request. - void TryLazyDetection(); - - // content::NotificationObserver implementation: - virtual void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) OVERRIDE; - - // Returns true if we're waiting for portal check. - bool IsPortalCheckPending() const; - - // Returns true if portal check is in progress. - bool IsCheckingForPortal() const; - - // Stores captive portal state for a |network|. - void SetCaptivePortalState(const Network* network, - const CaptivePortalState& results); - - // Notifies observers that portal detection is completed for a |network|. - void NotifyPortalDetectionCompleted(const Network* network, - const CaptivePortalState& state); - - // Returns the current TimeTicks. - base::TimeTicks GetCurrentTimeTicks() const; - - State state() { return state_; } - - // Returns current number of portal detection attempts. - // Used by unit tests. - int attempt_count_for_testing() { return attempt_count_; } + // Returns true is NetworkPortalDetector service is enabled in command line. + static bool IsEnabledInCommandLine(); - // Sets minimum time between consecutive portal checks for the same - // network. Used by unit tests. - void set_min_time_between_attempts_for_testing(const base::TimeDelta& delta) { - min_time_between_attempts_ = delta; - } - - // Sets default interval between consecutive portal checks for a - // network in portal state. Used by unit tests. - void set_lazy_check_interval_for_testing(const base::TimeDelta& delta) { - lazy_check_interval_ = delta; - } - - // Sets portal detection timeout. Used by unit tests. - void set_request_timeout_for_testing(const base::TimeDelta& timeout) { - request_timeout_ = timeout; - } - - // Returns delay before next portal check. Used by unit tests. - const base::TimeDelta& next_attempt_delay_for_testing() { - return next_attempt_delay_; - } - - // Sets current test time ticks. Used by unit tests. - void set_time_ticks_for_testing(const base::TimeTicks& time_ticks) { - time_ticks_for_testing_ = time_ticks; - } - - // Advances current test time ticks. Used by unit tests. - void advance_time_ticks_for_testing(const base::TimeDelta& delta) { - time_ticks_for_testing_ += delta; - } - - // Returns true if detection timeout callback isn't fired or - // cancelled. - bool DetectionTimeoutIsCancelledForTesting() const; - - // Unique identifier of the active network. - std::string active_network_id_; - - // Service path of the active network. - std::string active_service_path_; - - // Connection state of the active network. - ConnectionState active_connection_state_; - - State state_; - CaptivePortalStateMap portal_state_map_; - ObserverList<Observer> observers_; - - base::CancelableClosure detection_task_; - base::CancelableClosure detection_timeout_; - - // URL that returns a 204 response code when connected to the Internet. - GURL test_url_; - - // Detector for checking active network for a portal state. - scoped_ptr<captive_portal::CaptivePortalDetector> captive_portal_detector_; - - // True if the NetworkPortalDetector is enabled. - bool enabled_; - - base::WeakPtrFactory<NetworkPortalDetector> weak_ptr_factory_; - - // Number of portal detection attemps for an active network. - int attempt_count_; - - // True if lazy detection is enabled. - bool lazy_detection_enabled_; - - // Time between consecutive portal checks for a network in lazy - // mode. - base::TimeDelta lazy_check_interval_; - - // Minimum time between consecutive portal checks for the same - // active network. - base::TimeDelta min_time_between_attempts_; - - // Start time of portal detection. - base::TimeTicks detection_start_time_; - - // Start time of portal detection attempt. - base::TimeTicks attempt_start_time_; - - // Timeout for a portal detection. - base::TimeDelta request_timeout_; - - // Delay before next portal detection. - base::TimeDelta next_attempt_delay_; - - // Test time ticks used by unit tests. - base::TimeTicks time_ticks_for_testing_; - - content::NotificationRegistrar registrar_; + protected: + NetworkPortalDetector(); + virtual ~NetworkPortalDetector(); + private: DISALLOW_COPY_AND_ASSIGN(NetworkPortalDetector); }; diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl.cc b/chrome/browser/chromeos/net/network_portal_detector_impl.cc new file mode 100644 index 0000000..5e96093 --- /dev/null +++ b/chrome/browser/chromeos/net/network_portal_detector_impl.cc @@ -0,0 +1,491 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/net/network_portal_detector_impl.h" + +#include "base/bind.h" +#include "base/command_line.h" +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/metrics/histogram.h" +#include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/chrome_switches.h" +#include "content/public/browser/notification_service.h" +#include "grit/generated_resources.h" +#include "net/http/http_status_code.h" +#include "ui/base/l10n/l10n_util.h" + +using captive_portal::CaptivePortalDetector; + +namespace chromeos { + +namespace { + +// Maximum number of portal detections for the same active network +// after network change. +const int kMaxRequestAttempts = 3; + +// Minimum timeout between consecutive portal checks for the same +// network. +const int kMinTimeBetweenAttemptsSec = 3; + +// Timeout for a portal check. +const int kRequestTimeoutSec = 5; + +// Delay before portal detection caused by changes in proxy settings. +const int kProxyChangeDelaySec = 1; + +// Delay between consecutive portal checks for a network in lazy mode. +const int kLazyCheckIntervalSec = 5; + +std::string CaptivePortalStatusString( + NetworkPortalDetectorImpl::CaptivePortalStatus status) { + switch (status) { + case NetworkPortalDetectorImpl::CAPTIVE_PORTAL_STATUS_UNKNOWN: + return l10n_util::GetStringUTF8( + IDS_CHROMEOS_CAPTIVE_PORTAL_STATUS_UNKNOWN); + case NetworkPortalDetectorImpl::CAPTIVE_PORTAL_STATUS_OFFLINE: + return l10n_util::GetStringUTF8( + IDS_CHROMEOS_CAPTIVE_PORTAL_STATUS_OFFLINE); + case NetworkPortalDetectorImpl::CAPTIVE_PORTAL_STATUS_ONLINE: + return l10n_util::GetStringUTF8( + IDS_CHROMEOS_CAPTIVE_PORTAL_STATUS_ONLINE); + case NetworkPortalDetectorImpl::CAPTIVE_PORTAL_STATUS_PORTAL: + return l10n_util::GetStringUTF8( + IDS_CHROMEOS_CAPTIVE_PORTAL_STATUS_PORTAL); + case NetworkPortalDetectorImpl::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED: + return l10n_util::GetStringUTF8( + IDS_CHROMEOS_CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED); + case NetworkPortalDetectorImpl::CAPTIVE_PORTAL_STATUS_COUNT: + NOTREACHED(); + } + return l10n_util::GetStringUTF8( + IDS_CHROMEOS_CAPTIVE_PORTAL_STATUS_UNRECOGNIZED); +} + +NetworkLibrary* GetNetworkLibrary() { + CHECK(CrosLibrary::Get()); + return CrosLibrary::Get()->GetNetworkLibrary(); +} + +const Network* GetActiveNetwork() { + NetworkLibrary* cros = GetNetworkLibrary(); + if (!cros) + return NULL; + return cros->active_network(); +} + +const Network* FindNetworkByPath(const std::string& service_path) { + NetworkLibrary* cros = GetNetworkLibrary(); + if (!cros) + return NULL; + return cros->FindNetworkByPath(service_path); +} + +} // namespace + +NetworkPortalDetectorImpl::NetworkPortalDetectorImpl( + const scoped_refptr<net::URLRequestContextGetter>& request_context) + : active_connection_state_(STATE_UNKNOWN), + test_url_(CaptivePortalDetector::kDefaultURL), + enabled_(false), + weak_ptr_factory_(this), + attempt_count_(0), + lazy_detection_enabled_(false), + lazy_check_interval_(base::TimeDelta::FromSeconds(kLazyCheckIntervalSec)), + min_time_between_attempts_( + base::TimeDelta::FromSeconds(kMinTimeBetweenAttemptsSec)), + request_timeout_(base::TimeDelta::FromSeconds(kRequestTimeoutSec)) { + captive_portal_detector_.reset(new CaptivePortalDetector(request_context)); + + registrar_.Add(this, + chrome::NOTIFICATION_LOGIN_PROXY_CHANGED, + content::NotificationService::AllSources()); + registrar_.Add(this, + chrome::NOTIFICATION_AUTH_SUPPLIED, + content::NotificationService::AllSources()); + registrar_.Add(this, + chrome::NOTIFICATION_AUTH_CANCELLED, + content::NotificationService::AllSources()); +} + +NetworkPortalDetectorImpl::~NetworkPortalDetectorImpl() { +} + +void NetworkPortalDetectorImpl::Init() { + DCHECK(CalledOnValidThread()); + + state_ = STATE_IDLE; + chromeos::NetworkLibrary* network_library = GetNetworkLibrary(); + DCHECK(network_library); + network_library->AddNetworkManagerObserver(this); + network_library->RemoveObserverForAllNetworks(this); +} + +void NetworkPortalDetectorImpl::Shutdown() { + DCHECK(CalledOnValidThread()); + + detection_task_.Cancel(); + detection_timeout_.Cancel(); + + captive_portal_detector_->Cancel(); + captive_portal_detector_.reset(); + observers_.Clear(); + chromeos::NetworkLibrary* network_library = GetNetworkLibrary(); + if (network_library) + network_library->RemoveNetworkManagerObserver(this); +} + +void NetworkPortalDetectorImpl::AddObserver(Observer* observer) { + DCHECK(CalledOnValidThread()); + if (!observer || observers_.HasObserver(observer)) + return; + observers_.AddObserver(observer); +} + +void NetworkPortalDetectorImpl::AddAndFireObserver(Observer* observer) { + AddObserver(observer); + if (observer) { + observer->OnPortalDetectionCompleted( + FindNetworkByPath(last_reported_network_service_path_), + last_reported_state_); + } +} + +void NetworkPortalDetectorImpl::RemoveObserver(Observer* observer) { + DCHECK(CalledOnValidThread()); + if (observer) + observers_.RemoveObserver(observer); +} + +bool NetworkPortalDetectorImpl::IsEnabled() { + return enabled_; +} + +void NetworkPortalDetectorImpl::Enable(bool start_detection) { + DCHECK(CalledOnValidThread()); + if (enabled_) + return; + enabled_ = true; + DCHECK(!IsPortalCheckPending()); + DCHECK(!IsCheckingForPortal()); + DCHECK(!lazy_detection_enabled_); + if (!start_detection) + return; + state_ = STATE_IDLE; + attempt_count_ = 0; + const Network* active_network = GetActiveNetwork(); + if (!active_network) + return; + portal_state_map_.erase(active_network->service_path()); + DetectCaptivePortal(base::TimeDelta()); +} + +NetworkPortalDetectorImpl::CaptivePortalState +NetworkPortalDetectorImpl::GetCaptivePortalState(const Network* network) { + DCHECK(CalledOnValidThread()); + if (!network) + return CaptivePortalState(); + CaptivePortalStateMap::const_iterator it = + portal_state_map_.find(network->service_path()); + if (it == portal_state_map_.end()) + return CaptivePortalState(); + return it->second; +} + +void NetworkPortalDetectorImpl::EnableLazyDetection() { + if (lazy_detection_enabled_) + return; + VLOG(1) << "Lazy detection mode enabled."; + lazy_detection_enabled_ = true; + if (!IsPortalCheckPending() && !IsCheckingForPortal()) + DetectCaptivePortal(base::TimeDelta()); +} + +void NetworkPortalDetectorImpl::DisableLazyDetection() { + if (!lazy_detection_enabled_) + return; + VLOG(1) << "Lazy detection mode disabled."; + lazy_detection_enabled_ = false; +} + +void NetworkPortalDetectorImpl::OnNetworkManagerChanged(NetworkLibrary* cros) { + DCHECK(CalledOnValidThread()); + CHECK(cros); + const Network* active_network = cros->active_network(); + if (!active_network) + return; + + active_network_id_ = active_network->unique_id(); + + bool network_changed = + (active_service_path_ != active_network->service_path()); + if (network_changed) { + if (!active_service_path_.empty()) + cros->RemoveNetworkObserver(active_service_path_, this); + active_service_path_ = active_network->service_path(); + cros->AddNetworkObserver(active_service_path_, this); + } + + bool connection_state_changed = + (active_connection_state_ != active_network->connection_state()); + active_connection_state_ = active_network->connection_state(); + + if (network_changed || connection_state_changed) { + attempt_count_ = 0; + CancelPortalDetection(); + } + + if (!IsCheckingForPortal() && !IsPortalCheckPending() && + Network::IsConnectedState(active_connection_state_) && + (attempt_count_ < kMaxRequestAttempts || lazy_detection_enabled_)) { + DCHECK(active_network); + + // Initiate Captive Portal detection if network's captive + // portal state is unknown (e.g. for freshly created networks), + // offline or if network connection state was changed. + CaptivePortalState state = GetCaptivePortalState(active_network); + if (state.status == CAPTIVE_PORTAL_STATUS_UNKNOWN || + state.status == CAPTIVE_PORTAL_STATUS_OFFLINE || + (!network_changed && connection_state_changed)) { + DetectCaptivePortal(base::TimeDelta()); + } + } +} + +void NetworkPortalDetectorImpl::OnNetworkChanged( + chromeos::NetworkLibrary* cros, + const chromeos::Network* network) { + DCHECK(CalledOnValidThread()); + OnNetworkManagerChanged(cros); +} + +void NetworkPortalDetectorImpl::DetectCaptivePortal( + const base::TimeDelta& delay) { + DCHECK(!IsPortalCheckPending()); + DCHECK(!IsCheckingForPortal()); + DCHECK(attempt_count_ < kMaxRequestAttempts || lazy_detection_enabled_); + + if (!IsEnabled()) + return; + + detection_task_.Cancel(); + detection_timeout_.Cancel(); + state_ = STATE_PORTAL_CHECK_PENDING; + + next_attempt_delay_ = delay; + if (attempt_count_ > 0) { + base::TimeTicks now = GetCurrentTimeTicks(); + base::TimeDelta elapsed_time; + + base::TimeDelta delay_between_attempts = min_time_between_attempts_; + if (attempt_count_ == kMaxRequestAttempts) { + DCHECK(lazy_detection_enabled_); + delay_between_attempts = lazy_check_interval_; + } + if (now > attempt_start_time_) + elapsed_time = now - attempt_start_time_; + if (elapsed_time < delay_between_attempts && + delay_between_attempts - elapsed_time > next_attempt_delay_) { + next_attempt_delay_ = delay_between_attempts - elapsed_time; + } + } else { + detection_start_time_ = GetCurrentTimeTicks(); + } + detection_task_.Reset( + base::Bind(&NetworkPortalDetectorImpl::DetectCaptivePortalTask, + weak_ptr_factory_.GetWeakPtr())); + MessageLoop::current()->PostDelayedTask(FROM_HERE, + detection_task_.callback(), + next_attempt_delay_); +} + +void NetworkPortalDetectorImpl::DetectCaptivePortalTask() { + DCHECK(IsPortalCheckPending()); + + state_ = STATE_CHECKING_FOR_PORTAL; + attempt_start_time_ = GetCurrentTimeTicks(); + + if (attempt_count_ < kMaxRequestAttempts) { + ++attempt_count_; + VLOG(1) << "Portal detection started: " + << "network=" << active_network_id_ << ", " + << "attempt=" << attempt_count_ << " of " << kMaxRequestAttempts; + } else { + DCHECK(lazy_detection_enabled_); + VLOG(1) << "Lazy portal detection attempt started"; + } + + captive_portal_detector_->DetectCaptivePortal( + test_url_, + base::Bind(&NetworkPortalDetectorImpl::OnPortalDetectionCompleted, + weak_ptr_factory_.GetWeakPtr())); + detection_timeout_.Reset( + base::Bind(&NetworkPortalDetectorImpl::PortalDetectionTimeout, + weak_ptr_factory_.GetWeakPtr())); + MessageLoop::current()->PostDelayedTask(FROM_HERE, + detection_timeout_.callback(), + request_timeout_); +} + +void NetworkPortalDetectorImpl::PortalDetectionTimeout() { + DCHECK(CalledOnValidThread()); + DCHECK(IsCheckingForPortal()); + + VLOG(1) << "Portal detection timeout: network=" << active_network_id_; + + captive_portal_detector_->Cancel(); + CaptivePortalDetector::Results results; + results.result = captive_portal::RESULT_NO_RESPONSE; + OnPortalDetectionCompleted(results); +} + +void NetworkPortalDetectorImpl::CancelPortalDetection() { + if (IsPortalCheckPending()) + detection_task_.Cancel(); + else if (IsCheckingForPortal()) + captive_portal_detector_->Cancel(); + detection_timeout_.Cancel(); + state_ = STATE_IDLE; +} + +void NetworkPortalDetectorImpl::OnPortalDetectionCompleted( + const CaptivePortalDetector::Results& results) { + DCHECK(CalledOnValidThread()); + DCHECK(IsCheckingForPortal()); + + VLOG(1) << "Portal detection completed: " + << "network=" << active_network_id_ << ", " + << "result=" << CaptivePortalDetector::CaptivePortalResultToString( + results.result) << ", " + << "response_code=" << results.response_code; + + state_ = STATE_IDLE; + detection_timeout_.Cancel(); + + NetworkLibrary* cros = GetNetworkLibrary(); + const Network* active_network = cros->active_network(); + if (!active_network) { + TryLazyDetection(); + return; + } + + CaptivePortalState state; + state.response_code = results.response_code; + switch (results.result) { + case captive_portal::RESULT_NO_RESPONSE: + if (attempt_count_ >= kMaxRequestAttempts) { + if (state.response_code == net::HTTP_PROXY_AUTHENTICATION_REQUIRED) { + state.status = CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED; + } else if (active_network->restricted_pool()) { + // Take into account shill's detection results. + state.status = CAPTIVE_PORTAL_STATUS_PORTAL; + LOG(WARNING) << "Network " << active_network->unique_id() << " " + << "is marked as " + << CaptivePortalStatusString(state.status) << " " + << "despite the fact that CaptivePortalDetector " + << "received no response"; + } else { + state.status = CAPTIVE_PORTAL_STATUS_OFFLINE; + } + SetCaptivePortalState(active_network, state); + } else { + DetectCaptivePortal(results.retry_after_delta); + } + break; + case captive_portal::RESULT_INTERNET_CONNECTED: + state.status = CAPTIVE_PORTAL_STATUS_ONLINE; + SetCaptivePortalState(active_network, state); + break; + case captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL: + state.status = CAPTIVE_PORTAL_STATUS_PORTAL; + SetCaptivePortalState(active_network, state); + break; + default: + break; + } + + TryLazyDetection(); +} + +void NetworkPortalDetectorImpl::TryLazyDetection() { + if (!IsPortalCheckPending() && !IsCheckingForPortal() && + lazy_detection_enabled_) { + DetectCaptivePortal(base::TimeDelta()); + } +} + +void NetworkPortalDetectorImpl::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + if (type == chrome::NOTIFICATION_LOGIN_PROXY_CHANGED || + type == chrome::NOTIFICATION_AUTH_SUPPLIED || + type == chrome::NOTIFICATION_AUTH_CANCELLED) { + VLOG(1) << "Restarting portal detection due to proxy change."; + attempt_count_ = 0; + if (IsPortalCheckPending()) + return; + CancelPortalDetection(); + DetectCaptivePortal(base::TimeDelta::FromSeconds(kProxyChangeDelaySec)); + } +} + +bool NetworkPortalDetectorImpl::IsPortalCheckPending() const { + return state_ == STATE_PORTAL_CHECK_PENDING; +} + +bool NetworkPortalDetectorImpl::IsCheckingForPortal() const { + return state_ == STATE_CHECKING_FOR_PORTAL; +} + +void NetworkPortalDetectorImpl::SetCaptivePortalState( + const Network* network, + const CaptivePortalState& state) { + DCHECK(network); + + if (!detection_start_time_.is_null()) { + UMA_HISTOGRAM_TIMES("CaptivePortal.OOBE.DetectionDuration", + GetCurrentTimeTicks() - detection_start_time_); + } + + CaptivePortalStateMap::const_iterator it = + portal_state_map_.find(network->service_path()); + if (it == portal_state_map_.end() || + it->second.status != state.status || + it->second.response_code != state.response_code) { + VLOG(1) << "Updating Chrome Captive Portal state: " + << "network=" << network->unique_id() << ", " + << "status=" << CaptivePortalStatusString(state.status) << ", " + << "response_code=" << state.response_code; + portal_state_map_[network->service_path()] = state; + } + NotifyPortalDetectionCompleted(network, state); +} + +void NetworkPortalDetectorImpl::NotifyPortalDetectionCompleted( + const Network* network, + const CaptivePortalState& state) { + if (network) + last_reported_network_service_path_ = network->service_path(); + else + last_reported_network_service_path_ = std::string(); + last_reported_state_ = state; + FOR_EACH_OBSERVER(Observer, observers_, + OnPortalDetectionCompleted(network, state)); +} + +base::TimeTicks NetworkPortalDetectorImpl::GetCurrentTimeTicks() const { + if (time_ticks_for_testing_.is_null()) + return base::TimeTicks::Now(); + else + return time_ticks_for_testing_; +} + +bool NetworkPortalDetectorImpl::DetectionTimeoutIsCancelledForTesting() const { + return detection_timeout_.IsCancelled(); +} + +} // namespace chromeos diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl.h b/chrome/browser/chromeos/net/network_portal_detector_impl.h new file mode 100644 index 0000000..bb2c1d8 --- /dev/null +++ b/chrome/browser/chromeos/net/network_portal_detector_impl.h @@ -0,0 +1,235 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_NET_NETWORK_PORTAL_DETECTOR_IMPL_H_ +#define CHROME_BROWSER_CHROMEOS_NET_NETWORK_PORTAL_DETECTOR_IMPL_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/cancelable_callback.h" +#include "base/compiler_specific.h" +#include "base/hash_tables.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/observer_list.h" +#include "base/threading/non_thread_safe.h" +#include "base/time.h" +#include "chrome/browser/captive_portal/captive_portal_detector.h" +#include "chrome/browser/chromeos/cros/network_library.h" +#include "chrome/browser/chromeos/net/network_portal_detector.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" +#include "googleurl/src/gurl.h" +#include "net/url_request/url_fetcher.h" + +namespace net { +class URLRequestContextGetter; +} + +namespace chromeos { + +// This class handles all notifications about network changes from +// NetworkLibrary and delegates portal detection for the active +// network to CaptivePortalService. +class NetworkPortalDetectorImpl + : public NetworkPortalDetector, + public base::NonThreadSafe, + public chromeos::NetworkLibrary::NetworkManagerObserver, + public chromeos::NetworkLibrary::NetworkObserver, + public content::NotificationObserver { + public: + explicit NetworkPortalDetectorImpl( + const scoped_refptr<net::URLRequestContextGetter>& request_context); + virtual ~NetworkPortalDetectorImpl(); + + // NetworkPortalDetector implementation: + virtual void Init() OVERRIDE; + virtual void Shutdown() OVERRIDE; + virtual void AddObserver(Observer* observer) OVERRIDE; + virtual void AddAndFireObserver(Observer* observer) OVERRIDE; + virtual void RemoveObserver(Observer* observer) OVERRIDE; + virtual CaptivePortalState GetCaptivePortalState( + const chromeos::Network* network) OVERRIDE; + virtual bool IsEnabled() OVERRIDE; + virtual void Enable(bool start_detection) OVERRIDE; + virtual void EnableLazyDetection() OVERRIDE; + virtual void DisableLazyDetection() OVERRIDE; + + // NetworkLibrary::NetworkManagerObserver implementation: + virtual void OnNetworkManagerChanged(chromeos::NetworkLibrary* cros) OVERRIDE; + + // NetworkLibrary::NetworkObserver implementation: + virtual void OnNetworkChanged(chromeos::NetworkLibrary* cros, + const chromeos::Network* network) OVERRIDE; + + private: + friend class NetworkPortalDetectorImplTest; + + typedef std::string NetworkId; + typedef base::hash_map<NetworkId, CaptivePortalState> CaptivePortalStateMap; + enum State { + // No portal check is running. + STATE_IDLE = 0, + // Waiting for portal check. + STATE_PORTAL_CHECK_PENDING, + // Portal check is in progress. + STATE_CHECKING_FOR_PORTAL, + }; + + // Initiates Captive Portal detection after |delay|. + void DetectCaptivePortal(const base::TimeDelta& delay); + + void DetectCaptivePortalTask(); + + // Called when portal check is timed out. Cancels portal check and + // calls OnPortalDetectionCompleted() with RESULT_NO_RESPONSE as + // a result. + void PortalDetectionTimeout(); + + void CancelPortalDetection(); + + // Called by CaptivePortalDetector when detection completes. + void OnPortalDetectionCompleted( + const captive_portal::CaptivePortalDetector::Results& results); + + // Tries to perform portal detection in "lazy" mode. Does nothing in + // the case of already pending/processing detection request. + void TryLazyDetection(); + + // content::NotificationObserver implementation: + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + // Returns true if we're waiting for portal check. + bool IsPortalCheckPending() const; + + // Returns true if portal check is in progress. + bool IsCheckingForPortal() const; + + // Stores captive portal state for a |network|. + void SetCaptivePortalState(const Network* network, + const CaptivePortalState& results); + + // Notifies observers that portal detection is completed for a |network|. + void NotifyPortalDetectionCompleted(const Network* network, + const CaptivePortalState& state); + + // Returns the current TimeTicks. + base::TimeTicks GetCurrentTimeTicks() const; + + State state() { return state_; } + + // Returns current number of portal detection attempts. + // Used by unit tests. + int attempt_count_for_testing() { return attempt_count_; } + + // Sets minimum time between consecutive portal checks for the same + // network. Used by unit tests. + void set_min_time_between_attempts_for_testing(const base::TimeDelta& delta) { + min_time_between_attempts_ = delta; + } + + // Sets default interval between consecutive portal checks for a + // network in portal state. Used by unit tests. + void set_lazy_check_interval_for_testing(const base::TimeDelta& delta) { + lazy_check_interval_ = delta; + } + + // Sets portal detection timeout. Used by unit tests. + void set_request_timeout_for_testing(const base::TimeDelta& timeout) { + request_timeout_ = timeout; + } + + // Returns delay before next portal check. Used by unit tests. + const base::TimeDelta& next_attempt_delay_for_testing() { + return next_attempt_delay_; + } + + // Sets current test time ticks. Used by unit tests. + void set_time_ticks_for_testing(const base::TimeTicks& time_ticks) { + time_ticks_for_testing_ = time_ticks; + } + + // Advances current test time ticks. Used by unit tests. + void advance_time_ticks_for_testing(const base::TimeDelta& delta) { + time_ticks_for_testing_ += delta; + } + + // Returns true if detection timeout callback isn't fired or + // cancelled. + bool DetectionTimeoutIsCancelledForTesting() const; + + // Unique identifier of the active network. + std::string active_network_id_; + + // Service path of the active network. + std::string active_service_path_; + + // Connection state of the active network. + ConnectionState active_connection_state_; + + // Service path to the latest reported Network. + std::string last_reported_network_service_path_; + + // Latest reported captive portal state. + CaptivePortalState last_reported_state_; + + State state_; + CaptivePortalStateMap portal_state_map_; + ObserverList<Observer> observers_; + + base::CancelableClosure detection_task_; + base::CancelableClosure detection_timeout_; + + // URL that returns a 204 response code when connected to the Internet. + GURL test_url_; + + // Detector for checking active network for a portal state. + scoped_ptr<captive_portal::CaptivePortalDetector> captive_portal_detector_; + + // True if the NetworkPortalDetector is enabled. + bool enabled_; + + base::WeakPtrFactory<NetworkPortalDetectorImpl> weak_ptr_factory_; + + // Number of portal detection attemps for an active network. + int attempt_count_; + + // True if lazy detection is enabled. + bool lazy_detection_enabled_; + + // Time between consecutive portal checks for a network in lazy + // mode. + base::TimeDelta lazy_check_interval_; + + // Minimum time between consecutive portal checks for the same + // active network. + base::TimeDelta min_time_between_attempts_; + + // Start time of portal detection. + base::TimeTicks detection_start_time_; + + // Start time of portal detection attempt. + base::TimeTicks attempt_start_time_; + + // Timeout for a portal detection. + base::TimeDelta request_timeout_; + + // Delay before next portal detection. + base::TimeDelta next_attempt_delay_; + + // Test time ticks used by unit tests. + base::TimeTicks time_ticks_for_testing_; + + content::NotificationRegistrar registrar_; + + DISALLOW_COPY_AND_ASSIGN(NetworkPortalDetectorImpl); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_NET_NETWORK_PORTAL_DETECTOR_IMPL_H_ diff --git a/chrome/browser/chromeos/net/network_portal_detector_unittest.cc b/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc index 3a4854c..5b28e7e 100644 --- a/chrome/browser/chromeos/net/network_portal_detector_unittest.cc +++ b/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc @@ -1,9 +1,7 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "testing/gtest/include/gtest/gtest.h" - #include "base/compiler_specific.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" @@ -13,18 +11,19 @@ #include "chrome/browser/chromeos/cros/cros_library.h" #include "chrome/browser/chromeos/cros/network_library.h" #include "chrome/browser/chromeos/cros/network_library_impl_base.h" -#include "chrome/browser/chromeos/net/network_portal_detector.h" +#include "chrome/browser/chromeos/net/network_portal_detector_impl.h" #include "chrome/test/base/testing_profile.h" #include "net/base/net_errors.h" +#include "testing/gtest/include/gtest/gtest.h" namespace chromeos { -class NetworkPortalDetectorTest +class NetworkPortalDetectorImplTest : public testing::Test, public captive_portal::CaptivePortalDetectorTestBase { public: - NetworkPortalDetectorTest() {} - virtual ~NetworkPortalDetectorTest() {} + NetworkPortalDetectorImplTest() {} + virtual ~NetworkPortalDetectorImplTest() {} virtual void SetUp() { CrosLibrary::Initialize(true); @@ -42,9 +41,9 @@ class NetworkPortalDetectorTest profile_.reset(new TestingProfile()); network_portal_detector_.reset( - new NetworkPortalDetector(profile_->GetRequestContext())); + new NetworkPortalDetectorImpl(profile_->GetRequestContext())); network_portal_detector_->Init(); - network_portal_detector_->set_enabled(true); + network_portal_detector_->Enable(false); set_detector(network_portal_detector_->captive_portal_detector_.get()); @@ -73,11 +72,11 @@ class NetworkPortalDetectorTest Profile* profile() { return profile_.get(); } - NetworkPortalDetector* network_portal_detector() { + NetworkPortalDetectorImpl* network_portal_detector() { return network_portal_detector_.get(); } - NetworkPortalDetector::State state() { + NetworkPortalDetectorImpl::State state() { return network_portal_detector()->state(); } @@ -99,15 +98,15 @@ class NetworkPortalDetectorTest } bool is_state_idle() { - return (NetworkPortalDetector::STATE_IDLE == state()); + return (NetworkPortalDetectorImpl::STATE_IDLE == state()); } bool is_state_portal_detection_pending() { - return (NetworkPortalDetector::STATE_PORTAL_CHECK_PENDING == state()); + return (NetworkPortalDetectorImpl::STATE_PORTAL_CHECK_PENDING == state()); } bool is_state_checking_for_portal() { - return (NetworkPortalDetector::STATE_CHECKING_FOR_PORTAL == state()); + return (NetworkPortalDetectorImpl::STATE_CHECKING_FOR_PORTAL == state()); } void set_request_timeout(const base::TimeDelta& timeout) { @@ -165,10 +164,10 @@ class NetworkPortalDetectorTest MessageLoop message_loop_; scoped_ptr<TestingProfile> profile_; - scoped_ptr<NetworkPortalDetector> network_portal_detector_; + scoped_ptr<NetworkPortalDetectorImpl> network_portal_detector_; }; -TEST_F(NetworkPortalDetectorTest, NoPortal) { +TEST_F(NetworkPortalDetectorImplTest, NoPortal) { ASSERT_TRUE(is_state_idle()); SetConnected(wifi1_network()); @@ -184,7 +183,7 @@ TEST_F(NetworkPortalDetectorTest, NoPortal) { wifi1_network()); } -TEST_F(NetworkPortalDetectorTest, Portal) { +TEST_F(NetworkPortalDetectorImplTest, Portal) { ASSERT_TRUE(is_state_idle()); // Check HTTP 200 response code. @@ -218,7 +217,7 @@ TEST_F(NetworkPortalDetectorTest, Portal) { ethernet_network()); } -TEST_F(NetworkPortalDetectorTest, TwoNetworks) { +TEST_F(NetworkPortalDetectorImplTest, TwoNetworks) { ASSERT_TRUE(is_state_idle()); SetConnected(wifi1_network()); @@ -240,7 +239,7 @@ TEST_F(NetworkPortalDetectorTest, TwoNetworks) { wifi1_network()); } -TEST_F(NetworkPortalDetectorTest, NetworkChanged) { +TEST_F(NetworkPortalDetectorImplTest, NetworkChanged) { ASSERT_TRUE(is_state_idle()); SetConnected(wifi1_network()); @@ -268,7 +267,7 @@ TEST_F(NetworkPortalDetectorTest, NetworkChanged) { wifi1_network()); } -TEST_F(NetworkPortalDetectorTest, NetworkStateNotChanged) { +TEST_F(NetworkPortalDetectorImplTest, NetworkStateNotChanged) { ASSERT_TRUE(is_state_idle()); SetConnected(wifi1_network()); @@ -284,7 +283,7 @@ TEST_F(NetworkPortalDetectorTest, NetworkStateNotChanged) { ASSERT_TRUE(is_state_idle()); } -TEST_F(NetworkPortalDetectorTest, NetworkStateChanged) { +TEST_F(NetworkPortalDetectorImplTest, NetworkStateChanged) { // Test for Portal -> Online -> Portal network state transitions. ASSERT_TRUE(is_state_idle()); @@ -316,7 +315,7 @@ TEST_F(NetworkPortalDetectorTest, NetworkStateChanged) { wifi1_network()); } -TEST_F(NetworkPortalDetectorTest, PortalDetectionTimeout) { +TEST_F(NetworkPortalDetectorImplTest, PortalDetectionTimeout) { ASSERT_TRUE(is_state_idle()); // For instantaneous timeout. @@ -335,7 +334,7 @@ TEST_F(NetworkPortalDetectorTest, PortalDetectionTimeout) { ASSERT_EQ(base::TimeDelta::FromSeconds(3), next_attempt_delay()); } -TEST_F(NetworkPortalDetectorTest, PortalDetectionRetryAfter) { +TEST_F(NetworkPortalDetectorImplTest, PortalDetectionRetryAfter) { ASSERT_TRUE(is_state_idle()); const char* retry_after = "HTTP/1.1 503 OK\nRetry-After: 101\n\n"; @@ -353,7 +352,7 @@ TEST_F(NetworkPortalDetectorTest, PortalDetectionRetryAfter) { ASSERT_EQ(base::TimeDelta::FromSeconds(101), next_attempt_delay()); } -TEST_F(NetworkPortalDetectorTest, PortalDetectorRetryAfterIsSmall) { +TEST_F(NetworkPortalDetectorImplTest, PortalDetectorRetryAfterIsSmall) { ASSERT_TRUE(is_state_idle()); const char* retry_after = "HTTP/1.1 503 OK\nRetry-After: 1\n\n"; @@ -372,7 +371,7 @@ TEST_F(NetworkPortalDetectorTest, PortalDetectorRetryAfterIsSmall) { ASSERT_EQ(base::TimeDelta::FromSeconds(3), next_attempt_delay()); } -TEST_F(NetworkPortalDetectorTest, FirstAttemptFailed) { +TEST_F(NetworkPortalDetectorImplTest, FirstAttemptFailed) { ASSERT_TRUE(is_state_idle()); set_min_time_between_attempts(base::TimeDelta()); @@ -398,7 +397,7 @@ TEST_F(NetworkPortalDetectorTest, FirstAttemptFailed) { wifi1_network()); } -TEST_F(NetworkPortalDetectorTest, AllAttemptsFailed) { +TEST_F(NetworkPortalDetectorImplTest, AllAttemptsFailed) { ASSERT_TRUE(is_state_idle()); set_min_time_between_attempts(base::TimeDelta()); @@ -432,7 +431,7 @@ TEST_F(NetworkPortalDetectorTest, AllAttemptsFailed) { wifi1_network()); } -TEST_F(NetworkPortalDetectorTest, ProxyAuthRequired) { +TEST_F(NetworkPortalDetectorImplTest, ProxyAuthRequired) { ASSERT_TRUE(is_state_idle()); set_min_time_between_attempts(base::TimeDelta()); @@ -463,7 +462,7 @@ TEST_F(NetworkPortalDetectorTest, ProxyAuthRequired) { wifi1_network()); } -TEST_F(NetworkPortalDetectorTest, NoResponseButBehindPortal) { +TEST_F(NetworkPortalDetectorImplTest, NoResponseButBehindPortal) { ASSERT_TRUE(is_state_idle()); set_min_time_between_attempts(base::TimeDelta()); @@ -499,7 +498,7 @@ TEST_F(NetworkPortalDetectorTest, NoResponseButBehindPortal) { wifi1_network()); } -TEST_F(NetworkPortalDetectorTest, LazyDetectionForOnlineNetwork) { +TEST_F(NetworkPortalDetectorImplTest, LazyDetectionForOnlineNetwork) { ASSERT_TRUE(is_state_idle()); set_min_time_between_attempts(base::TimeDelta()); set_lazy_check_interval(base::TimeDelta()); @@ -540,7 +539,7 @@ TEST_F(NetworkPortalDetectorTest, LazyDetectionForOnlineNetwork) { wifi1_network()); } -TEST_F(NetworkPortalDetectorTest, LazyDetectionForPortalNetwork) { +TEST_F(NetworkPortalDetectorImplTest, LazyDetectionForPortalNetwork) { ASSERT_TRUE(is_state_idle()); set_min_time_between_attempts(base::TimeDelta()); set_lazy_check_interval(base::TimeDelta()); @@ -590,7 +589,7 @@ TEST_F(NetworkPortalDetectorTest, LazyDetectionForPortalNetwork) { wifi1_network()); } -TEST_F(NetworkPortalDetectorTest, DetectionTimeoutIsCancelled) { +TEST_F(NetworkPortalDetectorImplTest, DetectionTimeoutIsCancelled) { ASSERT_TRUE(is_state_idle()); set_min_time_between_attempts(base::TimeDelta()); diff --git a/chrome/browser/chromeos/net/network_portal_detector_stub.cc b/chrome/browser/chromeos/net/network_portal_detector_stub.cc new file mode 100644 index 0000000..aa848b8 --- /dev/null +++ b/chrome/browser/chromeos/net/network_portal_detector_stub.cc @@ -0,0 +1,91 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/net/network_portal_detector_stub.h" + +#include "chrome/browser/chromeos/cros/network_library.h" + +namespace chromeos { + +NetworkPortalDetectorStub::NetworkPortalDetectorStub() : active_network_(NULL) { +} + +NetworkPortalDetectorStub::~NetworkPortalDetectorStub() { +} + +void NetworkPortalDetectorStub::Init() { +} + +void NetworkPortalDetectorStub::Shutdown() { +} + +void NetworkPortalDetectorStub::AddObserver(Observer* observer) { + if (observer && !observers_.HasObserver(observer)) + observers_.AddObserver(observer); +} + +void NetworkPortalDetectorStub::AddAndFireObserver(Observer* observer) { + AddObserver(observer); + if (!observer) + return; + if (!active_network_ || + !portal_state_map_.count(active_network_->service_path())) { + observer->OnPortalDetectionCompleted(active_network_, CaptivePortalState()); + } else { + observer->OnPortalDetectionCompleted( + active_network_, + portal_state_map_[active_network_->service_path()]); + } +} + +void NetworkPortalDetectorStub::RemoveObserver(Observer* observer) { + if (observer) + observers_.RemoveObserver(observer); +} + +NetworkPortalDetector::CaptivePortalState +NetworkPortalDetectorStub::GetCaptivePortalState( + const chromeos::Network* network) { + if (!network || !portal_state_map_.count(network->service_path())) + return CaptivePortalState(); + return portal_state_map_[network->service_path()]; +} + +bool NetworkPortalDetectorStub::IsEnabled() { + return true; +} + +void NetworkPortalDetectorStub::Enable(bool start_detection) { +} + +void NetworkPortalDetectorStub::EnableLazyDetection() { +} + +void NetworkPortalDetectorStub::DisableLazyDetection() { +} + +void NetworkPortalDetectorStub::SetActiveNetworkForTesting( + const Network* network) { + active_network_ = network; +} + +void NetworkPortalDetectorStub::SetDetectionResultsForTesting( + const Network* network, + const CaptivePortalState& state) { + if (!network) + return; + portal_state_map_[network->service_path()] = state; +} + +void NetworkPortalDetectorStub::NotifyObserversForTesting() { + CaptivePortalState state; + if (active_network_ && + portal_state_map_.count(active_network_->service_path())) { + state = portal_state_map_[active_network_->service_path()]; + } + FOR_EACH_OBSERVER(Observer, observers_, + OnPortalDetectionCompleted(active_network_, state)); +} + +} // namespace chromeos diff --git a/chrome/browser/chromeos/net/network_portal_detector_stub.h b/chrome/browser/chromeos/net/network_portal_detector_stub.h new file mode 100644 index 0000000..dae5776 --- /dev/null +++ b/chrome/browser/chromeos/net/network_portal_detector_stub.h @@ -0,0 +1,56 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_NET_NETWORK_PORTAL_DETECTOR_STUB_H_ +#define CHROME_BROWSER_CHROMEOS_NET_NETWORK_PORTAL_DETECTOR_STUB_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/hash_tables.h" +#include "base/observer_list.h" +#include "chrome/browser/chromeos/net/network_portal_detector.h" + +namespace chromeos { + +class NetworkPortalDetectorStub : public NetworkPortalDetector { + public: + NetworkPortalDetectorStub(); + virtual ~NetworkPortalDetectorStub(); + + // NetworkPortalDetector implementation: + virtual void Init() OVERRIDE; + virtual void Shutdown() OVERRIDE; + virtual void AddObserver(Observer* observer) OVERRIDE; + virtual void AddAndFireObserver(Observer* observer) OVERRIDE; + virtual void RemoveObserver(Observer* observer) OVERRIDE; + virtual CaptivePortalState GetCaptivePortalState( + const chromeos::Network* network) OVERRIDE; + virtual bool IsEnabled() OVERRIDE; + virtual void Enable(bool start_detection) OVERRIDE; + virtual void EnableLazyDetection() OVERRIDE; + virtual void DisableLazyDetection() OVERRIDE; + + private: + friend class UpdateScreenTest; + + typedef std::string NetworkId; + typedef base::hash_map<NetworkId, CaptivePortalState> CaptivePortalStateMap; + + void SetActiveNetworkForTesting(const Network* network); + void SetDetectionResultsForTesting(const Network* network, + const CaptivePortalState& state); + void NotifyObserversForTesting(); + + ObserverList<Observer> observers_; + const Network* active_network_; + CaptivePortalStateMap portal_state_map_; + + DISALLOW_COPY_AND_ASSIGN(NetworkPortalDetectorStub); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_NET_NETWORK_PORTAL_DETECTOR_STUB_H_ diff --git a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc index adb4699..cbf60fa 100644 --- a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc @@ -25,13 +25,13 @@ namespace { void EnableLazyDetection() { NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance(); - if (NetworkPortalDetector::IsEnabled() && detector) + if (NetworkPortalDetector::IsEnabledInCommandLine() && detector) detector->EnableLazyDetection(); } void DisableLazyDetection() { NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance(); - if (NetworkPortalDetector::IsEnabled() && detector) + if (NetworkPortalDetector::IsEnabledInCommandLine() && detector) detector->DisableLazyDetection(); } diff --git a/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc b/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc index b0d7cdf..4a044de 100644 --- a/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc +++ b/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc @@ -31,7 +31,7 @@ NetworkStateInformer::NetworkStateInformer() NetworkStateInformer::~NetworkStateInformer() { CrosLibrary::Get()->GetNetworkLibrary()-> RemoveNetworkManagerObserver(this); - if (NetworkPortalDetector::IsEnabled() && + if (NetworkPortalDetector::IsEnabledInCommandLine() && NetworkPortalDetector::GetInstance()) { NetworkPortalDetector::GetInstance()->RemoveObserver(this); } @@ -42,9 +42,9 @@ void NetworkStateInformer::Init() { UpdateState(cros); cros->AddNetworkManagerObserver(this); - if (NetworkPortalDetector::IsEnabled() && + if (NetworkPortalDetector::IsEnabledInCommandLine() && NetworkPortalDetector::GetInstance()) { - NetworkPortalDetector::GetInstance()->AddObserver(this); + NetworkPortalDetector::GetInstance()->AddAndFireObserver(this); } registrar_.Add(this, @@ -172,7 +172,7 @@ void NetworkStateInformer::SendStateToObservers(const std::string& reason) { NetworkStateInformer::State NetworkStateInformer::GetNetworkState( const Network* network) { DCHECK(network); - if (NetworkPortalDetector::IsEnabled() && + if (NetworkPortalDetector::IsEnabledInCommandLine() && NetworkPortalDetector::GetInstance()) { NetworkPortalDetector::CaptivePortalState state = NetworkPortalDetector::GetInstance()->GetCaptivePortalState(network); diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi index 506fdc1..adc4e57 100644 --- a/chrome/chrome_browser_chromeos.gypi +++ b/chrome/chrome_browser_chromeos.gypi @@ -535,6 +535,10 @@ 'browser/chromeos/net/network_change_notifier_network_library.h', 'browser/chromeos/net/network_portal_detector.cc', 'browser/chromeos/net/network_portal_detector.h', + 'browser/chromeos/net/network_portal_detector_impl.cc', + 'browser/chromeos/net/network_portal_detector_impl.h', + 'browser/chromeos/net/network_portal_detector_stub.cc', + 'browser/chromeos/net/network_portal_detector_stub.h', 'browser/chromeos/net/onc_utils.cc', 'browser/chromeos/net/onc_utils.h', 'browser/chromeos/network_login_observer.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index f2c045d..90a830b 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1184,6 +1184,8 @@ 'browser/chromeos/login/login_utils_browsertest.cc', 'browser/chromeos/login/mock_authenticator.cc', 'browser/chromeos/login/mock_authenticator.h', + 'browser/chromeos/login/mock_error_screen.cc', + 'browser/chromeos/login/mock_error_screen.h', 'browser/chromeos/login/mock_eula_screen.cc', 'browser/chromeos/login/mock_eula_screen.h', 'browser/chromeos/login/mock_network_screen.cc', diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index 13339dd..4606344 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -615,7 +615,7 @@ 'browser/chromeos/memory/oom_priority_manager_unittest.cc', 'browser/chromeos/mobile/mobile_activator_unittest.cc', 'browser/chromeos/mobile_config_unittest.cc', - 'browser/chromeos/net/network_portal_detector_unittest.cc', + 'browser/chromeos/net/network_portal_detector_impl_unittest.cc', 'browser/chromeos/net/onc_utils_unittest.cc', 'browser/chromeos/offline/offline_load_page_unittest.cc', 'browser/chromeos/policy/auto_enrollment_client_unittest.cc', |