autofill_download.cc revision 3f50c38dc070f4bb515c1b64450dae14f316474e
1// Copyright (c) 2010 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 <vector> 9 10#include "base/logging.h" 11#include "base/rand_util.h" 12#include "base/stl_util-inl.h" 13#include "chrome/browser/autofill/autofill_metrics.h" 14#include "chrome/browser/autofill/autofill_xml_parser.h" 15#include "chrome/browser/prefs/pref_service.h" 16#include "chrome/browser/profiles/profile.h" 17#include "chrome/common/pref_names.h" 18#include "net/http/http_response_headers.h" 19 20#define DISABLED_REQUEST_URL "http://disabled" 21 22#if defined(GOOGLE_CHROME_BUILD) || (defined(ANDROID) && defined(HAVE_AUTOFILL_DOWNLOAD_INTERNAL_H) && HAVE_AUTOFILL_DOWNLOAD_INTERNAL_H) 23#include "chrome/browser/autofill/internal/autofill_download_internal.h" 24#else 25#define AUTO_FILL_QUERY_SERVER_REQUEST_URL DISABLED_REQUEST_URL 26#define AUTO_FILL_UPLOAD_SERVER_REQUEST_URL DISABLED_REQUEST_URL 27#define AUTO_FILL_QUERY_SERVER_NAME_START_IN_HEADER "SOMESERVER/" 28#endif 29 30struct AutoFillDownloadManager::FormRequestData { 31 std::vector<std::string> form_signatures; 32 AutoFillRequestType request_type; 33}; 34 35AutoFillDownloadManager::AutoFillDownloadManager(Profile* profile) 36 : profile_(profile), 37 observer_(NULL), 38 next_query_request_(base::Time::Now()), 39 next_upload_request_(base::Time::Now()), 40 positive_upload_rate_(0), 41 negative_upload_rate_(0), 42 fetcher_id_for_unittest_(0), 43 is_testing_(false) { 44 // |profile_| could be NULL in some unit-tests. 45 if (profile_) { 46 PrefService* preferences = profile_->GetPrefs(); 47 positive_upload_rate_ = 48 preferences->GetReal(prefs::kAutoFillPositiveUploadRate); 49 negative_upload_rate_ = 50 preferences->GetReal(prefs::kAutoFillNegativeUploadRate); 51 } 52} 53 54AutoFillDownloadManager::~AutoFillDownloadManager() { 55 STLDeleteContainerPairFirstPointers(url_fetchers_.begin(), 56 url_fetchers_.end()); 57} 58 59void AutoFillDownloadManager::SetObserver( 60 AutoFillDownloadManager::Observer *observer) { 61 if (observer) { 62 DCHECK(!observer_); 63 observer_ = observer; 64 } else { 65 observer_ = NULL; 66 } 67} 68 69bool AutoFillDownloadManager::StartQueryRequest( 70 const ScopedVector<FormStructure>& forms, 71 const AutoFillMetrics& metric_logger) { 72 if (next_query_request_ > base::Time::Now()) { 73 // We are in back-off mode: do not do the request. 74 return false; 75 } 76 std::string form_xml; 77 FormRequestData request_data; 78 if (!FormStructure::EncodeQueryRequest(forms, &request_data.form_signatures, 79 &form_xml)) 80 return false; 81 82 request_data.request_type = AutoFillDownloadManager::REQUEST_QUERY; 83 metric_logger.Log(AutoFillMetrics::QUERY_SENT); 84 85 return StartRequest(form_xml, request_data); 86} 87 88bool AutoFillDownloadManager::StartUploadRequest( 89 const FormStructure& form, bool form_was_matched) { 90 if (next_upload_request_ > base::Time::Now()) { 91 // We are in back-off mode: do not do the request. 92 return false; 93 } 94 95 // Check if we need to upload form. 96 double upload_rate = form_was_matched ? GetPositiveUploadRate() : 97 GetNegativeUploadRate(); 98 if (base::RandDouble() > upload_rate) { 99 VLOG(1) << "AutoFillDownloadManager: Upload request is ignored"; 100 // If we ever need notification that upload was skipped, add it here. 101 return false; 102 } 103 std::string form_xml; 104 if (!form.EncodeUploadRequest(form_was_matched, &form_xml)) 105 return false; 106 107 FormRequestData request_data; 108 request_data.form_signatures.push_back(form.FormSignature()); 109 request_data.request_type = AutoFillDownloadManager::REQUEST_UPLOAD; 110 111 return StartRequest(form_xml, request_data); 112} 113 114bool AutoFillDownloadManager::CancelRequest( 115 const std::string& form_signature, 116 AutoFillDownloadManager::AutoFillRequestType request_type) { 117 for (std::map<URLFetcher *, FormRequestData>::iterator it = 118 url_fetchers_.begin(); 119 it != url_fetchers_.end(); 120 ++it) { 121 if (std::find(it->second.form_signatures.begin(), 122 it->second.form_signatures.end(), form_signature) != 123 it->second.form_signatures.end() && 124 it->second.request_type == request_type) { 125 delete it->first; 126 url_fetchers_.erase(it); 127 return true; 128 } 129 } 130 return false; 131} 132 133double AutoFillDownloadManager::GetPositiveUploadRate() const { 134 return positive_upload_rate_; 135} 136 137double AutoFillDownloadManager::GetNegativeUploadRate() const { 138 return negative_upload_rate_; 139} 140 141void AutoFillDownloadManager::SetPositiveUploadRate(double rate) { 142 if (rate == positive_upload_rate_) 143 return; 144 positive_upload_rate_ = rate; 145 DCHECK_GE(rate, 0.0); 146 DCHECK_LE(rate, 1.0); 147 DCHECK(profile_); 148 PrefService* preferences = profile_->GetPrefs(); 149 preferences->SetReal(prefs::kAutoFillPositiveUploadRate, rate); 150} 151 152void AutoFillDownloadManager::SetNegativeUploadRate(double rate) { 153 if (rate == negative_upload_rate_) 154 return; 155 negative_upload_rate_ = rate; 156 DCHECK_GE(rate, 0.0); 157 DCHECK_LE(rate, 1.0); 158 DCHECK(profile_); 159 PrefService* preferences = profile_->GetPrefs(); 160 preferences->SetReal(prefs::kAutoFillNegativeUploadRate, rate); 161} 162 163bool AutoFillDownloadManager::StartRequest( 164 const std::string& form_xml, 165 const FormRequestData& request_data) { 166 std::string request_url; 167 if (request_data.request_type == AutoFillDownloadManager::REQUEST_QUERY) 168 request_url = AUTO_FILL_QUERY_SERVER_REQUEST_URL; 169 else 170 request_url = AUTO_FILL_UPLOAD_SERVER_REQUEST_URL; 171 172 if (!request_url.compare(DISABLED_REQUEST_URL) && !is_testing_) { 173 // We have it disabled - return true as if it succeeded, but do nothing. 174 return true; 175 } 176 177 // Id is ignored for regular chrome, in unit test id's for fake fetcher 178 // factory will be 0, 1, 2, ... 179 URLFetcher *fetcher = URLFetcher::Create(fetcher_id_for_unittest_++, 180 GURL(request_url), 181 URLFetcher::POST, 182 this); 183 url_fetchers_[fetcher] = request_data; 184 fetcher->set_automatically_retry_on_5xx(false); 185#ifdef ANDROID 186 // On Android, use the webview request context getter which was passed 187 // through in the WebAutoFill::init() method in WebKit. 188 fetcher->set_request_context(profile_->GetRequestContext()); 189#else 190 fetcher->set_request_context(Profile::GetDefaultRequestContext()); 191#endif 192 fetcher->set_upload_data("text/plain", form_xml); 193 fetcher->Start(); 194 return true; 195} 196 197void AutoFillDownloadManager::OnURLFetchComplete( 198 const URLFetcher* source, 199 const GURL& url, 200 const net::URLRequestStatus& status, 201 int response_code, 202 const ResponseCookies& cookies, 203 const std::string& data) { 204 std::map<URLFetcher *, FormRequestData>::iterator it = 205 url_fetchers_.find(const_cast<URLFetcher*>(source)); 206 if (it == url_fetchers_.end()) { 207 // Looks like crash on Mac is possibly caused with callback entering here 208 // with unknown fetcher when network is refreshed. 209 return; 210 } 211 std::string type_of_request( 212 it->second.request_type == AutoFillDownloadManager::REQUEST_QUERY ? 213 "query" : "upload"); 214 const int kHttpResponseOk = 200; 215 const int kHttpInternalServerError = 500; 216 const int kHttpBadGateway = 502; 217 const int kHttpServiceUnavailable = 503; 218 219 CHECK(it->second.form_signatures.size()); 220 if (response_code != kHttpResponseOk) { 221 bool back_off = false; 222 std::string server_header; 223 switch (response_code) { 224 case kHttpBadGateway: 225 if (!source->response_headers()->EnumerateHeader(NULL, "server", 226 &server_header) || 227 StartsWithASCII(server_header.c_str(), 228 AUTO_FILL_QUERY_SERVER_NAME_START_IN_HEADER, 229 false) != 0) 230 break; 231 // Bad getaway was received from AutoFill servers. Fall through to back 232 // off. 233 case kHttpInternalServerError: 234 case kHttpServiceUnavailable: 235 back_off = true; 236 break; 237 } 238 239 if (back_off) { 240 base::Time back_off_time(base::Time::Now() + source->backoff_delay()); 241 if (it->second.request_type == AutoFillDownloadManager::REQUEST_QUERY) { 242 next_query_request_ = back_off_time; 243 } else { 244 next_upload_request_ = back_off_time; 245 } 246 } 247 248 LOG(WARNING) << "AutoFillDownloadManager: " << type_of_request 249 << " request has failed with response " << response_code; 250 if (observer_) { 251 observer_->OnHeuristicsRequestError(it->second.form_signatures[0], 252 it->second.request_type, 253 response_code); 254 } 255 } else { 256 VLOG(1) << "AutoFillDownloadManager: " << type_of_request 257 << " request has succeeded"; 258 if (it->second.request_type == AutoFillDownloadManager::REQUEST_QUERY) { 259 if (observer_) 260 observer_->OnLoadedAutoFillHeuristics(data); 261 } else { 262 double new_positive_upload_rate = 0; 263 double new_negative_upload_rate = 0; 264 AutoFillUploadXmlParser parse_handler(&new_positive_upload_rate, 265 &new_negative_upload_rate); 266 buzz::XmlParser parser(&parse_handler); 267 parser.Parse(data.data(), data.length(), true); 268 if (parse_handler.succeeded()) { 269 SetPositiveUploadRate(new_positive_upload_rate); 270 SetNegativeUploadRate(new_negative_upload_rate); 271 } 272 273 if (observer_) 274 observer_->OnUploadedAutoFillHeuristics(it->second.form_signatures[0]); 275 } 276 } 277 delete it->first; 278 url_fetchers_.erase(it); 279} 280