• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "components/captive_portal/captive_portal_detector.h"
6 
7 #include "base/basictypes.h"
8 #include "base/bind.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/time/time.h"
14 #include "components/captive_portal/captive_portal_testing_utils.h"
15 #include "net/base/net_errors.h"
16 #include "net/url_request/url_request_test_util.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "url/gurl.h"
19 
20 namespace captive_portal {
21 
22 namespace {
23 
24 class CaptivePortalClient {
25  public:
CaptivePortalClient(CaptivePortalDetector * captive_portal_detector)26   explicit CaptivePortalClient(CaptivePortalDetector* captive_portal_detector)
27       : num_results_received_(0) {
28   }
29 
OnPortalDetectionCompleted(const CaptivePortalDetector::Results & results)30   void OnPortalDetectionCompleted(
31       const CaptivePortalDetector::Results& results) {
32     results_ = results;
33     ++num_results_received_;
34   }
35 
captive_portal_results() const36   const CaptivePortalDetector::Results& captive_portal_results() const {
37     return results_;
38   }
39 
num_results_received() const40   int num_results_received() const { return num_results_received_; }
41 
42  private:
43   CaptivePortalDetector::Results results_;
44   int num_results_received_;
45 
46   DISALLOW_COPY_AND_ASSIGN(CaptivePortalClient);
47 };
48 
49 }  // namespace
50 
51 class CaptivePortalDetectorTest : public testing::Test,
52                                   public CaptivePortalDetectorTestBase {
53  public:
CaptivePortalDetectorTest()54   CaptivePortalDetectorTest() {}
~CaptivePortalDetectorTest()55   virtual ~CaptivePortalDetectorTest() {}
56 
SetUp()57   virtual void SetUp() OVERRIDE {
58     CHECK(base::MessageLoopProxy::current().get());
59     scoped_refptr<net::URLRequestContextGetter> request_context_getter(
60         new net::TestURLRequestContextGetter(
61             base::MessageLoopProxy::current()));
62 
63     detector_.reset(new CaptivePortalDetector(request_context_getter.get()));
64     set_detector(detector_.get());
65   }
66 
TearDown()67   virtual void TearDown() OVERRIDE {
68     detector_.reset();
69   }
70 
RunTest(const CaptivePortalDetector::Results & expected_results,int net_error,int status_code,const char * response_headers)71   void RunTest(const CaptivePortalDetector::Results& expected_results,
72                int net_error,
73                int status_code,
74                const char* response_headers) {
75     ASSERT_FALSE(FetchingURL());
76 
77     GURL url(CaptivePortalDetector::kDefaultURL);
78     CaptivePortalClient client(detector());
79 
80     detector()->DetectCaptivePortal(url,
81         base::Bind(&CaptivePortalClient::OnPortalDetectionCompleted,
82                    base::Unretained(&client)));
83 
84     ASSERT_TRUE(FetchingURL());
85     base::RunLoop().RunUntilIdle();
86 
87     CompleteURLFetch(net_error, status_code, response_headers);
88 
89     EXPECT_FALSE(FetchingURL());
90     EXPECT_EQ(1, client.num_results_received());
91     EXPECT_EQ(expected_results.result, client.captive_portal_results().result);
92     EXPECT_EQ(expected_results.response_code,
93               client.captive_portal_results().response_code);
94     EXPECT_EQ(expected_results.retry_after_delta,
95               client.captive_portal_results().retry_after_delta);
96   }
97 
RunCancelTest()98   void RunCancelTest() {
99     ASSERT_FALSE(FetchingURL());
100 
101     GURL url(CaptivePortalDetector::kDefaultURL);
102     CaptivePortalClient client(detector());
103 
104     detector()->DetectCaptivePortal(url,
105         base::Bind(&CaptivePortalClient::OnPortalDetectionCompleted,
106                    base::Unretained(&client)));
107 
108     ASSERT_TRUE(FetchingURL());
109     base::RunLoop().RunUntilIdle();
110 
111     detector()->Cancel();
112 
113     ASSERT_FALSE(FetchingURL());
114     EXPECT_EQ(0, client.num_results_received());
115   }
116 
117  private:
118   base::MessageLoop message_loop_;
119   scoped_ptr<CaptivePortalDetector> detector_;
120 };
121 
122 // Test that the CaptivePortalDetector returns the expected result
123 // codes in response to a variety of probe results.
TEST_F(CaptivePortalDetectorTest,CaptivePortalResultCodes)124 TEST_F(CaptivePortalDetectorTest, CaptivePortalResultCodes) {
125   CaptivePortalDetector::Results results;
126   results.result = captive_portal::RESULT_INTERNET_CONNECTED;
127   results.response_code = 204;
128 
129   RunTest(results, net::OK, 204, NULL);
130 
131   // The server may return an HTTP error when it's acting up.
132   results.result = captive_portal::RESULT_NO_RESPONSE;
133   results.response_code = 500;
134   RunTest(results, net::OK, 500, NULL);
135 
136   // Generic network error case.
137   results.result = captive_portal::RESULT_NO_RESPONSE;
138   results.response_code = net::URLFetcher::RESPONSE_CODE_INVALID;
139   RunTest(results, net::ERR_TIMED_OUT, net::URLFetcher::RESPONSE_CODE_INVALID,
140           NULL);
141 
142   // In the general captive portal case, the portal will return a page with a
143   // 200 status.
144   results.result = captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL;
145   results.response_code = 200;
146   RunTest(results, net::OK, 200, NULL);
147 
148   // Some captive portals return 511 instead, to advertise their captive
149   // portal-ness.
150   results.result = captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL;
151   results.response_code = 511;
152   RunTest(results, net::OK, 511, NULL);
153 }
154 
155 // Check a Retry-After header that contains a delay in seconds.
TEST_F(CaptivePortalDetectorTest,CaptivePortalRetryAfterSeconds)156 TEST_F(CaptivePortalDetectorTest, CaptivePortalRetryAfterSeconds) {
157   const char* retry_after = "HTTP/1.1 503 OK\nRetry-After: 101\n\n";
158   CaptivePortalDetector::Results results;
159 
160   // Check that Retry-After headers work both on the first request to return a
161   // result and on subsequent requests.
162   results.result = captive_portal::RESULT_NO_RESPONSE;
163   results.response_code = 503;
164   results.retry_after_delta = base::TimeDelta::FromSeconds(101);
165   RunTest(results, net::OK, 503, retry_after);
166 
167   results.result = captive_portal::RESULT_INTERNET_CONNECTED;
168   results.response_code = 204;
169   results.retry_after_delta = base::TimeDelta();
170   RunTest(results, net::OK, 204, NULL);
171 }
172 
173 // Check a Retry-After header that contains a date.
TEST_F(CaptivePortalDetectorTest,CaptivePortalRetryAfterDate)174 TEST_F(CaptivePortalDetectorTest, CaptivePortalRetryAfterDate) {
175   const char* retry_after =
176       "HTTP/1.1 503 OK\nRetry-After: Tue, 17 Apr 2012 18:02:51 GMT\n\n";
177   CaptivePortalDetector::Results results;
178 
179   // base has a function to get a time in the right format from a string, but
180   // not the other way around.
181   base::Time start_time;
182   ASSERT_TRUE(base::Time::FromString("Tue, 17 Apr 2012 18:02:00 GMT",
183                                      &start_time));
184   base::Time retry_after_time;
185   ASSERT_TRUE(base::Time::FromString("Tue, 17 Apr 2012 18:02:51 GMT",
186                                      &retry_after_time));
187 
188   SetTime(start_time);
189 
190   results.result = captive_portal::RESULT_NO_RESPONSE;
191   results.response_code = 503;
192   results.retry_after_delta = retry_after_time - start_time;
193   RunTest(results, net::OK, 503, retry_after);
194 }
195 
196 // Check invalid Retry-After headers are ignored.
TEST_F(CaptivePortalDetectorTest,CaptivePortalRetryAfterInvalid)197 TEST_F(CaptivePortalDetectorTest, CaptivePortalRetryAfterInvalid) {
198   const char* retry_after = "HTTP/1.1 503 OK\nRetry-After: Christmas\n\n";
199   CaptivePortalDetector::Results results;
200 
201   results.result = captive_portal::RESULT_NO_RESPONSE;
202   results.response_code = 503;
203   RunTest(results, net::OK, 503, retry_after);
204 }
205 
TEST_F(CaptivePortalDetectorTest,Cancel)206 TEST_F(CaptivePortalDetectorTest, Cancel) {
207   RunCancelTest();
208   CaptivePortalDetector::Results results;
209   results.result = captive_portal::RESULT_INTERNET_CONNECTED;
210   results.response_code = 204;
211   RunTest(results, net::OK, 204, NULL);
212 }
213 
214 }  // namespace captive_portal
215