Fix build break
[chromium-blink-merge.git] / chrome / browser / captive_portal / captive_portal_detector.cc
blobe1bb561195db06a7b231c54219d9b5551502412d
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.
5 #include "chrome/browser/captive_portal/captive_portal_detector.h"
7 #include "base/logging.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "net/base/load_flags.h"
11 #include "net/http/http_response_headers.h"
12 #include "net/url_request/url_request_status.h"
14 namespace captive_portal {
16 namespace {
18 const char* const kCaptivePortalResultNames[] = {
19 "InternetConnected",
20 "NoResponse",
21 "BehindCaptivePortal",
22 "NumCaptivePortalResults",
24 COMPILE_ASSERT(arraysize(kCaptivePortalResultNames) == RESULT_COUNT + 1,
25 captive_portal_result_name_count_mismatch);
27 } // namespace
29 const char CaptivePortalDetector::kDefaultURL[] =
30 "http://www.gstatic.com/generate_204";
32 CaptivePortalDetector::CaptivePortalDetector(
33 const scoped_refptr<net::URLRequestContextGetter>& request_context)
34 : request_context_(request_context) {
37 CaptivePortalDetector::~CaptivePortalDetector() {
40 // static
41 std::string CaptivePortalDetector::CaptivePortalResultToString(Result result) {
42 DCHECK_GE(result, 0);
43 DCHECK_LT(static_cast<unsigned int>(result),
44 arraysize(kCaptivePortalResultNames));
45 return kCaptivePortalResultNames[result];
48 void CaptivePortalDetector::DetectCaptivePortal(
49 const GURL& url,
50 const DetectionCallback& detection_callback) {
51 DCHECK(CalledOnValidThread());
52 DCHECK(!FetchingURL());
53 DCHECK(detection_callback_.is_null());
55 detection_callback_ = detection_callback;
57 // The first 0 means this can use a TestURLFetcherFactory in unit tests.
58 url_fetcher_.reset(net::URLFetcher::Create(0,
59 url,
60 net::URLFetcher::GET,
61 this));
62 url_fetcher_->SetAutomaticallyRetryOn5xx(false);
63 url_fetcher_->SetRequestContext(request_context_);
65 // Can't safely use net::LOAD_DISABLE_CERT_REVOCATION_CHECKING here,
66 // since then the connection may be reused without checking the cert.
67 url_fetcher_->SetLoadFlags(
68 net::LOAD_BYPASS_CACHE |
69 net::LOAD_DO_NOT_PROMPT_FOR_LOGIN |
70 net::LOAD_DO_NOT_SAVE_COOKIES |
71 net::LOAD_DO_NOT_SEND_COOKIES |
72 net::LOAD_DO_NOT_SEND_AUTH_DATA);
73 url_fetcher_->Start();
76 void CaptivePortalDetector::Cancel() {
77 url_fetcher_.reset();
78 detection_callback_.Reset();
81 void CaptivePortalDetector::OnURLFetchComplete(const net::URLFetcher* source) {
82 DCHECK(CalledOnValidThread());
83 DCHECK(FetchingURL());
84 DCHECK_EQ(url_fetcher_.get(), source);
85 DCHECK(!detection_callback_.is_null());
87 Results results;
88 GetCaptivePortalResultFromResponse(url_fetcher_.get(), &results);
89 DetectionCallback callback = detection_callback_;
90 url_fetcher_.reset();
91 detection_callback_.Reset();
92 callback.Run(results);
95 // Takes a net::URLFetcher that has finished trying to retrieve the test
96 // URL, and returns a CaptivePortalService::Result based on its result.
97 void CaptivePortalDetector::GetCaptivePortalResultFromResponse(
98 const net::URLFetcher* url_fetcher,
99 Results* results) const {
100 DCHECK(results);
101 DCHECK(!url_fetcher->GetStatus().is_io_pending());
103 results->result = RESULT_NO_RESPONSE;
104 results->response_code = url_fetcher->GetResponseCode();
105 results->retry_after_delta = base::TimeDelta();
107 // If there's a network error of some sort when fetching a file via HTTP,
108 // there may be a networking problem, rather than a captive portal.
109 // TODO(mmenke): Consider special handling for redirects that end up at
110 // errors, especially SSL certificate errors.
111 if (url_fetcher->GetStatus().status() != net::URLRequestStatus::SUCCESS)
112 return;
114 // In the case of 503 errors, look for the Retry-After header.
115 if (results->response_code == 503) {
116 net::HttpResponseHeaders* headers = url_fetcher->GetResponseHeaders();
117 std::string retry_after_string;
119 // If there's no Retry-After header, nothing else to do.
120 if (!headers->EnumerateHeader(NULL, "Retry-After", &retry_after_string))
121 return;
123 // Otherwise, try parsing it as an integer (seconds) or as an HTTP date.
124 int seconds;
125 base::Time full_date;
126 if (base::StringToInt(retry_after_string, &seconds)) {
127 results->retry_after_delta = base::TimeDelta::FromSeconds(seconds);
128 } else if (headers->GetTimeValuedHeader("Retry-After", &full_date)) {
129 base::Time now = GetCurrentTime();
130 if (full_date > now)
131 results->retry_after_delta = full_date - now;
133 return;
136 // A 511 response (Network Authentication Required) means that the user needs
137 // to login to whatever server issued the response.
138 // See: http://tools.ietf.org/html/rfc6585
139 if (results->response_code == 511) {
140 results->result = RESULT_BEHIND_CAPTIVE_PORTAL;
141 return;
144 // Other non-2xx/3xx HTTP responses may indicate server errors.
145 if (results->response_code >= 400 || results->response_code < 200)
146 return;
148 // A 204 response code indicates there's no captive portal.
149 if (results->response_code == 204) {
150 results->result = RESULT_INTERNET_CONNECTED;
151 return;
154 // Otherwise, assume it's a captive portal.
155 results->result = RESULT_BEHIND_CAPTIVE_PORTAL;
158 base::Time CaptivePortalDetector::GetCurrentTime() const {
159 if (time_for_testing_.is_null())
160 return base::Time::Now();
161 else
162 return time_for_testing_;
165 bool CaptivePortalDetector::FetchingURL() const {
166 return url_fetcher_.get() != NULL;
169 } // namespace captive_portal