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