blob: f0f57b4510d8842e7f7728ec474628ff108e7515 [file] [log] [blame]
// Copyright (c) 2012 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 <memory>
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "chrome/browser/captive_portal/captive_portal_service.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "content/public/common/resource_type.h"
class Profile;
namespace content {
class NavigationHandle;
class WebContents;
namespace net {
class SSLInfo;
class CaptivePortalLoginDetector;
class CaptivePortalTabReloader;
// Along with the classes it owns, responsible for detecting page loads broken
// by a captive portal, triggering captive portal checks on navigation events
// that may indicate a captive portal is present, or has been removed / logged
// in to, and taking any correcting actions. Lives on the UI thread.
// It acts as a WebContentsObserver for its CaptivePortalLoginDetector and
// CaptivePortalTabReloader. It filters out non-main-frame navigations. It is
// also needed by CaptivePortalTabReloaders to inform the tab's
// CaptivePortalLoginDetector when the tab is at a captive portal's login page.
// The TabHelper assumes that a WebContents can only have one main frame
// navigation at a time. This assumption can be violated in rare cases, for
// example, a same-site navigation interrupted by a cross-process navigation
// started from the omnibox, may commit before it can be cancelled. In these
// cases, this class may pass incorrect messages to the TabReloader, which
// will, at worst, result in not opening up a login tab until a second load
// fails or not automatically reloading a tab after logging in.
// TODO(clamy): See if this class can be made to handle these edge-cases
// following the refactor of navigation signaling to WebContentsObservers.
// For the design doc, see:
class CaptivePortalTabHelper
: public content::WebContentsObserver,
public content::NotificationObserver,
public content::WebContentsUserData<CaptivePortalTabHelper> {
~CaptivePortalTabHelper() override;
// content::WebContentsObserver:
void DidStartNavigation(
content::NavigationHandle* navigation_handle) override;
void DidRedirectNavigation(
content::NavigationHandle* navigation_handle) override;
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
void DidStopLoading() override;
// content::NotificationObserver:
void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) override;
// Called when a certificate interstitial error page is about to be shown.
void OnSSLCertError(const net::SSLInfo& ssl_info);
// A "Login Tab" is a tab that was originally at a captive portal login
// page. This is set to false when a captive portal is no longer detected.
bool IsLoginTab() const;
// Opens a login tab if the profile's active window doesn't have one already.
static void OpenLoginTabForWebContents(content::WebContents* web_contents,
bool focus);
friend class CaptivePortalBrowserTest;
friend class CaptivePortalTabHelperTest;
friend class content::WebContentsUserData<CaptivePortalTabHelper>;
explicit CaptivePortalTabHelper(content::WebContents* web_contents);
// Called by Observe in response to the corresponding event.
void OnCaptivePortalResults(
captive_portal::CaptivePortalResult previous_result,
captive_portal::CaptivePortalResult result);
// Called to indicate a tab is at, or is navigating to, the captive portal
// login page.
void SetIsLoginTab();
// |this| takes ownership of |tab_reloader|.
void SetTabReloaderForTest(CaptivePortalTabReloader* tab_reloader);
CaptivePortalTabReloader* GetTabReloaderForTest();
Profile* profile_;
// The current main frame navigation happening for the WebContents, or
// nullptr if there is none. If there are two main frame navigations
// happening at once, it's the one that started most recently.
content::NavigationHandle* navigation_handle_;
// Neither of these will ever be NULL.
std::unique_ptr<CaptivePortalTabReloader> tab_reloader_;
std::unique_ptr<CaptivePortalLoginDetector> login_detector_;
content::NotificationRegistrar registrar_;