Home | History | Annotate | Download | only in captive_portal
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef CHROME_BROWSER_CAPTIVE_PORTAL_CAPTIVE_PORTAL_SERVICE_H_
      6 #define CHROME_BROWSER_CAPTIVE_PORTAL_CAPTIVE_PORTAL_SERVICE_H_
      7 
      8 #include "base/basictypes.h"
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/prefs/pref_member.h"
     11 #include "base/threading/non_thread_safe.h"
     12 #include "base/time/time.h"
     13 #include "base/timer/timer.h"
     14 #include "chrome/browser/captive_portal/captive_portal_detector.h"
     15 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
     16 #include "net/base/backoff_entry.h"
     17 #include "url/gurl.h"
     18 
     19 class Profile;
     20 
     21 namespace captive_portal {
     22 
     23 // Service that checks for captive portals when queried, and sends a
     24 // NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT with the Profile as the source and
     25 // a CaptivePortalService::Results as the details.
     26 //
     27 // Captive portal checks are rate-limited.  The CaptivePortalService may only
     28 // be accessed on the UI thread.
     29 // Design doc: https://docs.google.com/document/d/1k-gP2sswzYNvryu9NcgN7q5XrsMlUdlUdoW9WRaEmfM/edit
     30 class CaptivePortalService : public BrowserContextKeyedService,
     31                              public base::NonThreadSafe {
     32  public:
     33   enum TestingState {
     34     NOT_TESTING,
     35     DISABLED_FOR_TESTING,  // The service is always disabled.
     36     SKIP_OS_CHECK_FOR_TESTING  // The service can be enabled even if the OS has
     37                                // native captive portal detection.
     38   };
     39 
     40   // The details sent via a NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT.
     41   struct Results {
     42     // The result of the second most recent captive portal check.
     43     Result previous_result;
     44     // The result of the most recent captive portal check.
     45     Result result;
     46   };
     47 
     48   explicit CaptivePortalService(Profile* profile);
     49   virtual ~CaptivePortalService();
     50 
     51   // Triggers a check for a captive portal.  If there's already a check in
     52   // progress, does nothing.  Throttles the rate at which requests are sent.
     53   // Always sends the result notification asynchronously.
     54   void DetectCaptivePortal();
     55 
     56   // Returns the URL used for captive portal testing.  When a captive portal is
     57   // detected, this URL will take us to the captive portal landing page.
     58   const GURL& test_url() const { return test_url_; }
     59 
     60   // Result of the most recent captive portal check.
     61   Result last_detection_result() const { return last_detection_result_; }
     62 
     63   // Whether or not the CaptivePortalService is enabled.  When disabled, all
     64   // checks return INTERNET_CONNECTED.
     65   bool enabled() const { return enabled_; }
     66 
     67   // Used to disable captive portal detection so it doesn't interfere with
     68   // tests.  Should be called before the service is created.
     69   static void set_state_for_testing(TestingState testing_state) {
     70     testing_state_ = testing_state;
     71   }
     72   static TestingState get_state_for_testing() { return testing_state_; }
     73 
     74  private:
     75   friend class CaptivePortalServiceTest;
     76   friend class CaptivePortalBrowserTest;
     77 
     78   // Subclass of BackoffEntry that uses the CaptivePortalService's
     79   // GetCurrentTime function, for unit testing.
     80   class RecheckBackoffEntry;
     81 
     82   enum State {
     83     // No check is running or pending.
     84     STATE_IDLE,
     85     // The timer to check for a captive portal is running.
     86     STATE_TIMER_RUNNING,
     87     // There's an outstanding HTTP request to check for a captive portal.
     88     STATE_CHECKING_FOR_PORTAL,
     89   };
     90 
     91   // Contains all the information about the minimum time allowed between two
     92   // consecutive captive portal checks.
     93   struct RecheckPolicy {
     94     // Constructor initializes all values to defaults.
     95     RecheckPolicy();
     96 
     97     // The minimum amount of time between two captive portal checks, when the
     98     // last check found no captive portal.
     99     int initial_backoff_no_portal_ms;
    100 
    101     // The minimum amount of time between two captive portal checks, when the
    102     // last check found a captive portal.  This is expected to be less than
    103     // |initial_backoff_no_portal_ms|.  Also used when the service is disabled.
    104     int initial_backoff_portal_ms;
    105 
    106     net::BackoffEntry::Policy backoff_policy;
    107   };
    108 
    109   // Initiates a captive portal check, without any throttling.  If the service
    110   // is disabled, just acts like there's an Internet connection.
    111   void DetectCaptivePortalInternal();
    112 
    113   // Called by CaptivePortalDetector when detection completes.
    114   void OnPortalDetectionCompleted(
    115       const CaptivePortalDetector::Results& results);
    116 
    117   // BrowserContextKeyedService:
    118   virtual void Shutdown() OVERRIDE;
    119 
    120   // Called when a captive portal check completes.  Passes the result to all
    121   // observers.
    122   void OnResult(Result result);
    123 
    124   // Updates BackoffEntry::Policy and creates a new BackoffEntry, which
    125   // resets the count used for throttling.
    126   void ResetBackoffEntry(Result result);
    127 
    128   // Updates |enabled_| based on command line flags and Profile preferences,
    129   // and sets |state_| to STATE_NONE if it's false.
    130   // TODO(mmenke): Figure out on which platforms, if any, should not use
    131   //               automatic captive portal detection.  Currently it's enabled
    132   //               on all platforms, though this code is not compiled on
    133   //               Android, since it lacks the Browser class.
    134   void UpdateEnabledState();
    135 
    136   // Returns the current TimeTicks.
    137   base::TimeTicks GetCurrentTimeTicks() const;
    138 
    139   bool DetectionInProgress() const;
    140 
    141   // Returns true if the timer to try and detect a captive portal is running.
    142   bool TimerRunning() const;
    143 
    144   State state() const { return state_; }
    145 
    146   RecheckPolicy& recheck_policy() { return recheck_policy_; }
    147 
    148   void set_test_url(const GURL& test_url) { test_url_ = test_url; }
    149 
    150   // Sets current test time ticks. Used by unit tests.
    151   void set_time_ticks_for_testing(const base::TimeTicks& time_ticks) {
    152     time_ticks_for_testing_ = time_ticks;
    153   }
    154 
    155   // Advances current test time ticks. Used by unit tests.
    156   void advance_time_ticks_for_testing(const base::TimeDelta& delta) {
    157     time_ticks_for_testing_ += delta;
    158   }
    159 
    160   // The profile that owns this CaptivePortalService.
    161   Profile* profile_;
    162 
    163   State state_;
    164 
    165   // Detector for checking active network for a portal state.
    166   CaptivePortalDetector captive_portal_detector_;
    167 
    168   // True if the service is enabled.  When not enabled, all checks will return
    169   // RESULT_INTERNET_CONNECTED.
    170   bool enabled_;
    171 
    172   // The result of the most recent captive portal check.
    173   Result last_detection_result_;
    174 
    175   // Number of sequential checks with the same captive portal result.
    176   int num_checks_with_same_result_;
    177 
    178   // Time when |last_detection_result_| was first received.
    179   base::TimeTicks first_check_time_with_same_result_;
    180 
    181   // Time the last captive portal check completed.
    182   base::TimeTicks last_check_time_;
    183 
    184   // Policy for throttling portal checks.
    185   RecheckPolicy recheck_policy_;
    186 
    187   // Implements behavior needed by |recheck_policy_|.  Whenever there's a new
    188   // captive_portal::Result, BackoffEntry::Policy is updated and
    189   // |backoff_entry_| is recreated.  Each check that returns the same Result
    190   // is considered a "failure", to trigger throttling.
    191   scoped_ptr<net::BackoffEntry> backoff_entry_;
    192 
    193   // URL that returns a 204 response code when connected to the Internet.
    194   GURL test_url_;
    195 
    196   // The pref member for whether navigation errors should be resolved with a web
    197   // service.  Actually called "alternate_error_pages", since it's also used for
    198   // the Link Doctor.
    199   BooleanPrefMember resolve_errors_with_web_service_;
    200 
    201   base::OneShotTimer<CaptivePortalService> check_captive_portal_timer_;
    202 
    203   static TestingState testing_state_;
    204 
    205   // Test time ticks used by unit tests.
    206   base::TimeTicks time_ticks_for_testing_;
    207 
    208   DISALLOW_COPY_AND_ASSIGN(CaptivePortalService);
    209 };
    210 
    211 }  // namespace captive_portal
    212 
    213 #endif  // CHROME_BROWSER_CAPTIVE_PORTAL_CAPTIVE_PORTAL_SERVICE_H_
    214