1 // Copyright (c) 2011 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 "chrome/browser/autofill/autofill_download.h" 6 7 #include <algorithm> 8 #include <ostream> 9 #include <vector> 10 11 #ifdef ANDROID 12 #include "android/jni/autofill_request_url.h" 13 #endif 14 #include "base/logging.h" 15 #include "base/rand_util.h" 16 #include "base/stl_util-inl.h" 17 #include "base/string_util.h" 18 #include "chrome/browser/autofill/autofill_metrics.h" 19 #include "chrome/browser/autofill/autofill_xml_parser.h" 20 #include "chrome/browser/autofill/form_structure.h" 21 #include "chrome/browser/prefs/pref_service.h" 22 #include "chrome/browser/profiles/profile.h" 23 #include "chrome/common/pref_names.h" 24 #include "googleurl/src/gurl.h" 25 #include "net/http/http_response_headers.h" 26 #include "third_party/libjingle/source/talk/xmllite/xmlparser.h" 27 28 #define AUTO_FILL_QUERY_SERVER_REQUEST_URL \ 29 "http://toolbarqueries.clients.google.com:80/tbproxy/af/query" 30 #define AUTO_FILL_UPLOAD_SERVER_REQUEST_URL \ 31 "http://toolbarqueries.clients.google.com:80/tbproxy/af/upload" 32 #define AUTO_FILL_QUERY_SERVER_NAME_START_IN_HEADER "GFE/" 33 #ifdef ANDROID 34 #define ANDROID_AUTOFILL_CLIENT_PARAM "?client=AndroidBrowser" 35 #endif 36 37 namespace { 38 const size_t kMaxFormCacheSize = 16; 39 }; 40 41 struct AutofillDownloadManager::FormRequestData { 42 std::vector<std::string> form_signatures; 43 AutofillRequestType request_type; 44 }; 45 46 #ifdef ANDROID 47 // Taken from autofill_manager.cc 48 const double kAutoFillPositiveUploadRateDefaultValue = 0.01; 49 const double kAutoFillNegativeUploadRateDefaultValue = 0.01; 50 #endif 51 52 AutofillDownloadManager::AutofillDownloadManager(Profile* profile) 53 : profile_(profile), 54 observer_(NULL), 55 max_form_cache_size_(kMaxFormCacheSize), 56 next_query_request_(base::Time::Now()), 57 next_upload_request_(base::Time::Now()), 58 positive_upload_rate_(0), 59 negative_upload_rate_(0), 60 fetcher_id_for_unittest_(0) { 61 // |profile_| could be NULL in some unit-tests. 62 #ifdef ANDROID 63 positive_upload_rate_ = kAutoFillPositiveUploadRateDefaultValue; 64 negative_upload_rate_ = kAutoFillNegativeUploadRateDefaultValue; 65 #else 66 if (profile_) { 67 PrefService* preferences = profile_->GetPrefs(); 68 positive_upload_rate_ = 69 preferences->GetDouble(prefs::kAutofillPositiveUploadRate); 70 negative_upload_rate_ = 71 preferences->GetDouble(prefs::kAutofillNegativeUploadRate); 72 } 73 #endif 74 } 75 76 AutofillDownloadManager::~AutofillDownloadManager() { 77 STLDeleteContainerPairFirstPointers(url_fetchers_.begin(), 78 url_fetchers_.end()); 79 } 80 81 void AutofillDownloadManager::SetObserver( 82 AutofillDownloadManager::Observer *observer) { 83 if (observer) { 84 DCHECK(!observer_); 85 observer_ = observer; 86 } else { 87 observer_ = NULL; 88 } 89 } 90 91 bool AutofillDownloadManager::StartQueryRequest( 92 const ScopedVector<FormStructure>& forms, 93 const AutofillMetrics& metric_logger) { 94 if (next_query_request_ > base::Time::Now()) { 95 // We are in back-off mode: do not do the request. 96 return false; 97 } 98 std::string form_xml; 99 FormRequestData request_data; 100 if (!FormStructure::EncodeQueryRequest(forms, &request_data.form_signatures, 101 &form_xml)) { 102 return false; 103 } 104 105 request_data.request_type = AutofillDownloadManager::REQUEST_QUERY; 106 metric_logger.Log(AutofillMetrics::QUERY_SENT); 107 108 std::string query_data; 109 if (CheckCacheForQueryRequest(request_data.form_signatures, &query_data)) { 110 VLOG(1) << "AutofillDownloadManager: query request has been retrieved from" 111 << "the cache"; 112 if (observer_) 113 observer_->OnLoadedAutofillHeuristics(query_data); 114 return true; 115 } 116 117 return StartRequest(form_xml, request_data); 118 } 119 120 bool AutofillDownloadManager::StartUploadRequest( 121 const FormStructure& form, bool form_was_matched) { 122 if (next_upload_request_ > base::Time::Now()) { 123 // We are in back-off mode: do not do the request. 124 return false; 125 } 126 127 // Check if we need to upload form. 128 double upload_rate = form_was_matched ? GetPositiveUploadRate() : 129 GetNegativeUploadRate(); 130 if (base::RandDouble() > upload_rate) { 131 VLOG(1) << "AutofillDownloadManager: Upload request is ignored"; 132 // If we ever need notification that upload was skipped, add it here. 133 return false; 134 } 135 std::string form_xml; 136 if (!form.EncodeUploadRequest(form_was_matched, &form_xml)) 137 return false; 138 139 FormRequestData request_data; 140 request_data.form_signatures.push_back(form.FormSignature()); 141 request_data.request_type = AutofillDownloadManager::REQUEST_UPLOAD; 142 143 return StartRequest(form_xml, request_data); 144 } 145 146 bool AutofillDownloadManager::CancelRequest( 147 const std::string& form_signature, 148 AutofillDownloadManager::AutofillRequestType request_type) { 149 for (std::map<URLFetcher *, FormRequestData>::iterator it = 150 url_fetchers_.begin(); 151 it != url_fetchers_.end(); 152 ++it) { 153 if (std::find(it->second.form_signatures.begin(), 154 it->second.form_signatures.end(), form_signature) != 155 it->second.form_signatures.end() && 156 it->second.request_type == request_type) { 157 delete it->first; 158 url_fetchers_.erase(it); 159 return true; 160 } 161 } 162 return false; 163 } 164 165 double AutofillDownloadManager::GetPositiveUploadRate() const { 166 return positive_upload_rate_; 167 } 168 169 double AutofillDownloadManager::GetNegativeUploadRate() const { 170 return negative_upload_rate_; 171 } 172 173 void AutofillDownloadManager::SetPositiveUploadRate(double rate) { 174 if (rate == positive_upload_rate_) 175 return; 176 positive_upload_rate_ = rate; 177 DCHECK_GE(rate, 0.0); 178 DCHECK_LE(rate, 1.0); 179 DCHECK(profile_); 180 #ifndef ANDROID 181 PrefService* preferences = profile_->GetPrefs(); 182 preferences->SetDouble(prefs::kAutofillPositiveUploadRate, rate); 183 #endif 184 } 185 186 void AutofillDownloadManager::SetNegativeUploadRate(double rate) { 187 if (rate == negative_upload_rate_) 188 return; 189 negative_upload_rate_ = rate; 190 DCHECK_GE(rate, 0.0); 191 DCHECK_LE(rate, 1.0); 192 DCHECK(profile_); 193 #ifndef ANDROID 194 PrefService* preferences = profile_->GetPrefs(); 195 preferences->SetDouble(prefs::kAutofillNegativeUploadRate, rate); 196 #endif 197 } 198 199 bool AutofillDownloadManager::StartRequest( 200 const std::string& form_xml, 201 const FormRequestData& request_data) { 202 net::URLRequestContextGetter* request_context = 203 #ifdef ANDROID 204 // On Android, use the webview request context getter which was passed 205 // through in the WebAutoFill::init() method in WebKit. 206 profile_->GetRequestContext(); 207 #else 208 Profile::GetDefaultRequestContext(); 209 #endif 210 // Check if default request context is NULL: this very rarely happens, 211 // I think, this could happen only if user opens chrome with some pages 212 // loading the forms immediately; I cannot reproduce this even in that 213 // scenario, but bug 74492 shows it happened at least once. In that case bail 214 // out and fall back on our own heuristics. 215 if (!request_context) 216 return false; 217 std::string request_url; 218 if (request_data.request_type == AutofillDownloadManager::REQUEST_QUERY) 219 request_url = AUTO_FILL_QUERY_SERVER_REQUEST_URL; 220 else 221 request_url = AUTO_FILL_UPLOAD_SERVER_REQUEST_URL; 222 223 #ifdef ANDROID 224 if (request_data.request_type == AutofillDownloadManager::REQUEST_QUERY) { 225 // Ask the platform what URL to use for Autofill. If the 226 // platform doesn't know, bail and rely on the heuristics 227 // we've gathered. 228 request_url = android::AutofillRequestUrl::GetQueryUrl(); 229 if (request_url.empty()) 230 return false; 231 request_url += ANDROID_AUTOFILL_CLIENT_PARAM; 232 233 } 234 #endif 235 236 // Id is ignored for regular chrome, in unit test id's for fake fetcher 237 // factory will be 0, 1, 2, ... 238 URLFetcher *fetcher = URLFetcher::Create(fetcher_id_for_unittest_++, 239 GURL(request_url), 240 URLFetcher::POST, 241 this); 242 url_fetchers_[fetcher] = request_data; 243 fetcher->set_automatically_retry_on_5xx(false); 244 fetcher->set_request_context(request_context); 245 fetcher->set_upload_data("text/plain", form_xml); 246 fetcher->Start(); 247 return true; 248 } 249 250 void AutofillDownloadManager::CacheQueryRequest( 251 const std::vector<std::string>& forms_in_query, 252 const std::string& query_data) { 253 std::string signature = GetCombinedSignature(forms_in_query); 254 for (QueryRequestCache::iterator it = cached_forms_.begin(); 255 it != cached_forms_.end(); ++it) { 256 if (it->first == signature) { 257 // We hit the cache, move to the first position and return. 258 std::pair<std::string, std::string> data = *it; 259 cached_forms_.erase(it); 260 cached_forms_.push_front(data); 261 return; 262 } 263 } 264 std::pair<std::string, std::string> data; 265 data.first = signature; 266 data.second = query_data; 267 cached_forms_.push_front(data); 268 while (cached_forms_.size() > max_form_cache_size_) 269 cached_forms_.pop_back(); 270 } 271 272 bool AutofillDownloadManager::CheckCacheForQueryRequest( 273 const std::vector<std::string>& forms_in_query, 274 std::string* query_data) const { 275 std::string signature = GetCombinedSignature(forms_in_query); 276 for (QueryRequestCache::const_iterator it = cached_forms_.begin(); 277 it != cached_forms_.end(); ++it) { 278 if (it->first == signature) { 279 // We hit the cache, fill the data and return. 280 *query_data = it->second; 281 return true; 282 } 283 } 284 return false; 285 } 286 287 std::string AutofillDownloadManager::GetCombinedSignature( 288 const std::vector<std::string>& forms_in_query) const { 289 size_t total_size = forms_in_query.size(); 290 for (size_t i = 0; i < forms_in_query.size(); ++i) 291 total_size += forms_in_query[i].length(); 292 std::string signature; 293 294 signature.reserve(total_size); 295 296 for (size_t i = 0; i < forms_in_query.size(); ++i) { 297 if (i) 298 signature.append(","); 299 signature.append(forms_in_query[i]); 300 } 301 return signature; 302 } 303 304 void AutofillDownloadManager::OnURLFetchComplete( 305 const URLFetcher* source, 306 const GURL& url, 307 const net::URLRequestStatus& status, 308 int response_code, 309 const ResponseCookies& cookies, 310 const std::string& data) { 311 std::map<URLFetcher *, FormRequestData>::iterator it = 312 url_fetchers_.find(const_cast<URLFetcher*>(source)); 313 if (it == url_fetchers_.end()) { 314 // Looks like crash on Mac is possibly caused with callback entering here 315 // with unknown fetcher when network is refreshed. 316 return; 317 } 318 std::string type_of_request( 319 it->second.request_type == AutofillDownloadManager::REQUEST_QUERY ? 320 "query" : "upload"); 321 const int kHttpResponseOk = 200; 322 const int kHttpInternalServerError = 500; 323 const int kHttpBadGateway = 502; 324 const int kHttpServiceUnavailable = 503; 325 326 CHECK(it->second.form_signatures.size()); 327 if (response_code != kHttpResponseOk) { 328 bool back_off = false; 329 std::string server_header; 330 switch (response_code) { 331 case kHttpBadGateway: 332 if (!source->response_headers()->EnumerateHeader(NULL, "server", 333 &server_header) || 334 StartsWithASCII(server_header.c_str(), 335 AUTO_FILL_QUERY_SERVER_NAME_START_IN_HEADER, 336 false) != 0) 337 break; 338 // Bad gateway was received from Autofill servers. Fall through to back 339 // off. 340 case kHttpInternalServerError: 341 case kHttpServiceUnavailable: 342 back_off = true; 343 break; 344 } 345 346 if (back_off) { 347 base::Time back_off_time(base::Time::Now() + source->backoff_delay()); 348 if (it->second.request_type == AutofillDownloadManager::REQUEST_QUERY) { 349 next_query_request_ = back_off_time; 350 } else { 351 next_upload_request_ = back_off_time; 352 } 353 } 354 355 LOG(WARNING) << "AutofillDownloadManager: " << type_of_request 356 << " request has failed with response " << response_code; 357 if (observer_) { 358 observer_->OnHeuristicsRequestError(it->second.form_signatures[0], 359 it->second.request_type, 360 response_code); 361 } 362 } else { 363 VLOG(1) << "AutofillDownloadManager: " << type_of_request 364 << " request has succeeded"; 365 if (it->second.request_type == AutofillDownloadManager::REQUEST_QUERY) { 366 CacheQueryRequest(it->second.form_signatures, data); 367 if (observer_) 368 observer_->OnLoadedAutofillHeuristics(data); 369 } else { 370 double new_positive_upload_rate = 0; 371 double new_negative_upload_rate = 0; 372 AutofillUploadXmlParser parse_handler(&new_positive_upload_rate, 373 &new_negative_upload_rate); 374 buzz::XmlParser parser(&parse_handler); 375 parser.Parse(data.data(), data.length(), true); 376 if (parse_handler.succeeded()) { 377 SetPositiveUploadRate(new_positive_upload_rate); 378 SetNegativeUploadRate(new_negative_upload_rate); 379 } 380 381 if (observer_) 382 observer_->OnUploadedAutofillHeuristics(it->second.form_signatures[0]); 383 } 384 } 385 delete it->first; 386 url_fetchers_.erase(it); 387 } 388