OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 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/autofill/core/browser/autofill_download_manager.h" |
| 6 |
| 7 #include <utility> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/location.h" |
| 11 #include "base/logging.h" |
| 12 #include "base/numerics/safe_conversions.h" |
| 13 #include "base/rand_util.h" |
| 14 #include "base/strings/string_util.h" |
| 15 #include "base/threading/thread_task_runner_handle.h" |
| 16 #include "components/autofill/core/browser/autofill_driver.h" |
| 17 #include "components/autofill/core/browser/autofill_metrics.h" |
| 18 #include "components/autofill/core/browser/form_structure.h" |
| 19 #include "components/autofill/core/browser/proto/server.pb.h" |
| 20 #include "components/autofill/core/common/autofill_pref_names.h" |
| 21 #include "components/data_use_measurement/core/data_use_user_data.h" |
| 22 #include "components/variations/net/variations_http_headers.h" |
| 23 #include "net/base/load_flags.h" |
| 24 #include "net/http/http_request_headers.h" |
| 25 #include "net/http/http_response_headers.h" |
| 26 #include "net/http/http_status_code.h" |
| 27 #include "net/traffic_annotation/network_traffic_annotation.h" |
| 28 #include "net/url_request/url_fetcher.h" |
| 29 #include "url/gurl.h" |
| 30 |
| 31 namespace { |
| 32 |
| 33 net::NetworkTrafficAnnotationTag GetNetworkTrafficAnnotation( |
| 34 const autofill::AutofillDownloadManager::RequestType& request_type) { |
| 35 if (request_type == autofill::AutofillDownloadManager::REQUEST_QUERY) { |
| 36 return net::DefineNetworkTrafficAnnotation("autofill_query", R"( |
| 37 semantics { |
| 38 sender: "Autofill" |
| 39 description: |
| 40 "Chromium can automatically fill in web forms. If the feature is " |
| 41 "enabled, Chromium will send a non-identifying description of the " |
| 42 "form to Google's servers, which will respond with the type of " |
| 43 "data required by each of the form's fields, if known. I.e., if a " |
| 44 "field expects to receive a name, phone number, street address, " |
| 45 "etc." |
| 46 trigger: "User encounters a web form." |
| 47 data: |
| 48 "Hashed descriptions of the form and its fields. User data is not " |
| 49 "sent." |
| 50 destination: GOOGLE_OWNED_SERVICE |
| 51 } |
| 52 policy { |
| 53 cookies_allowed: false |
| 54 setting: |
| 55 "You can enable or disable this feature via 'Enable autofill to " |
| 56 "fill out web forms in a single click.' in Chromium's settings " |
| 57 "under 'Passwords and forms'. The feature is enabled by default." |
| 58 chrome_policy { |
| 59 AutofillEnabled { |
| 60 policy_options {mode: MANDATORY} |
| 61 AutofillEnabled: false |
| 62 } |
| 63 } |
| 64 })"); |
| 65 } |
| 66 |
| 67 DCHECK_EQ(request_type, autofill::AutofillDownloadManager::REQUEST_UPLOAD); |
| 68 return net::DefineNetworkTrafficAnnotation("autofill_upload", R"( |
| 69 semantics { |
| 70 sender: "Autofill" |
| 71 description: |
| 72 "Chromium relies on crowd-sourced field type classifications to " |
| 73 "help it automatically fill in web forms. If the feature is " |
| 74 "enabled, Chromium will send a non-identifying description of the " |
| 75 "form to Google's servers along with the type of data Chromium " |
| 76 "observed being given to the form. I.e., if you entered your first " |
| 77 "name into a form field, Chromium will 'vote' for that form field " |
| 78 "being a first name field." |
| 79 trigger: "User submits a web form." |
| 80 data: |
| 81 "Hashed descriptions of the form and its fields along with type of " |
| 82 "data given to each field, if recognized from the user's " |
| 83 "profile(s). User data is not sent." |
| 84 destination: GOOGLE_OWNED_SERVICE |
| 85 } |
| 86 policy { |
| 87 cookies_allowed: false |
| 88 setting: |
| 89 "You can enable or disable this feature via 'Enable autofill to " |
| 90 "fill out web forms in a single click.' in Chromium's settings " |
| 91 "under 'Passwords and forms'. The feature is enabled by default." |
| 92 chrome_policy { |
| 93 AutofillEnabled { |
| 94 policy_options {mode: MANDATORY} |
| 95 AutofillEnabled: false |
| 96 } |
| 97 } |
| 98 })"); |
| 99 } |
| 100 |
| 101 } // namespace |
| 102 |
| 103 namespace autofill { |
| 104 |
| 105 namespace { |
| 106 |
| 107 const size_t kMaxFormCacheSize = 16; |
| 108 const size_t kMaxFieldsPerQueryRequest = 100; |
| 109 |
| 110 const net::BackoffEntry::Policy kAutofillBackoffPolicy = { |
| 111 // Number of initial errors (in sequence) to ignore before applying |
| 112 // exponential back-off rules. |
| 113 0, |
| 114 |
| 115 // Initial delay for exponential back-off in ms. |
| 116 1000, // 1 second. |
| 117 |
| 118 // Factor by which the waiting time will be multiplied. |
| 119 2, |
| 120 |
| 121 // Fuzzing percentage. ex: 10% will spread requests randomly |
| 122 // between 90%-100% of the calculated time. |
| 123 0.33, // 33%. |
| 124 |
| 125 // Maximum amount of time we are willing to delay our request in ms. |
| 126 30 * 1000, // 30 seconds. |
| 127 |
| 128 // Time to keep an entry from being discarded even when it |
| 129 // has no significant state, -1 to never discard. |
| 130 -1, |
| 131 |
| 132 // Don't use initial delay unless the last request was an error. |
| 133 false, |
| 134 }; |
| 135 |
| 136 #if defined(GOOGLE_CHROME_BUILD) |
| 137 const char kClientName[] = "Google Chrome"; |
| 138 #else |
| 139 const char kClientName[] = "Chromium"; |
| 140 #endif // defined(GOOGLE_CHROME_BUILD) |
| 141 |
| 142 size_t CountActiveFieldsInForms(const std::vector<FormStructure*>& forms) { |
| 143 size_t active_field_count = 0; |
| 144 for (const auto* form : forms) |
| 145 active_field_count += form->active_field_count(); |
| 146 return active_field_count; |
| 147 } |
| 148 |
| 149 std::string RequestTypeToString(AutofillDownloadManager::RequestType type) { |
| 150 switch (type) { |
| 151 case AutofillDownloadManager::REQUEST_QUERY: |
| 152 return "query"; |
| 153 case AutofillDownloadManager::REQUEST_UPLOAD: |
| 154 return "upload"; |
| 155 } |
| 156 NOTREACHED(); |
| 157 return std::string(); |
| 158 } |
| 159 |
| 160 GURL GetRequestUrl(AutofillDownloadManager::RequestType request_type) { |
| 161 return GURL("https://clients1.google.com/tbproxy/af/" + |
| 162 RequestTypeToString(request_type) + "?client=" + kClientName); |
| 163 } |
| 164 |
| 165 std::ostream& operator<<(std::ostream& out, |
| 166 const autofill::AutofillQueryContents& query) { |
| 167 out << "client_version: " << query.client_version(); |
| 168 for (const auto& form : query.form()) { |
| 169 out << "\nForm\n signature: " << form.signature(); |
| 170 for (const auto& field : form.field()) { |
| 171 out << "\n Field\n signature: " << field.signature(); |
| 172 if (!field.name().empty()) |
| 173 out << "\n name: " << field.name(); |
| 174 if (!field.type().empty()) |
| 175 out << "\n type: " << field.type(); |
| 176 } |
| 177 } |
| 178 return out; |
| 179 } |
| 180 |
| 181 std::ostream& operator<<(std::ostream& out, |
| 182 const autofill::AutofillUploadContents& upload) { |
| 183 out << "client_version: " << upload.client_version() << "\n"; |
| 184 out << "form_signature: " << upload.form_signature() << "\n"; |
| 185 out << "data_present: " << upload.data_present() << "\n"; |
| 186 out << "submission: " << upload.submission() << "\n"; |
| 187 if (!upload.action_signature()) |
| 188 out << "action_signature: " << upload.action_signature() << "\n"; |
| 189 if (!upload.login_form_signature()) |
| 190 out << "login_form_signature: " << upload.login_form_signature() << "\n"; |
| 191 if (!upload.form_name().empty()) |
| 192 out << "form_name: " << upload.form_name() << "\n"; |
| 193 |
| 194 for (const auto& field : upload.field()) { |
| 195 out << "\n Field" |
| 196 << "\n signature: " << field.signature() |
| 197 << "\n autofill_type: " << field.autofill_type(); |
| 198 if (!field.name().empty()) |
| 199 out << "\n name: " << field.name(); |
| 200 if (!field.autocomplete().empty()) |
| 201 out << "\n autocomplete: " << field.autocomplete(); |
| 202 if (!field.type().empty()) |
| 203 out << "\n type: " << field.type(); |
| 204 if (field.generation_type()) |
| 205 out << "\n generation_type: " << field.generation_type(); |
| 206 } |
| 207 return out; |
| 208 } |
| 209 |
| 210 } // namespace |
| 211 |
| 212 struct AutofillDownloadManager::FormRequestData { |
| 213 std::vector<std::string> form_signatures; |
| 214 RequestType request_type; |
| 215 std::string payload; |
| 216 }; |
| 217 |
| 218 AutofillDownloadManager::AutofillDownloadManager(AutofillDriver* driver, |
| 219 Observer* observer) |
| 220 : driver_(driver), |
| 221 observer_(observer), |
| 222 max_form_cache_size_(kMaxFormCacheSize), |
| 223 fetcher_backoff_(&kAutofillBackoffPolicy), |
| 224 fetcher_id_for_unittest_(0), |
| 225 weak_factory_(this) { |
| 226 DCHECK(observer_); |
| 227 } |
| 228 |
| 229 AutofillDownloadManager::~AutofillDownloadManager() = default; |
| 230 |
| 231 bool AutofillDownloadManager::StartQueryRequest( |
| 232 const std::vector<FormStructure*>& forms) { |
| 233 // Do not send the request if it contains more fields than the server can |
| 234 // accept. |
| 235 if (CountActiveFieldsInForms(forms) > kMaxFieldsPerQueryRequest) |
| 236 return false; |
| 237 |
| 238 AutofillQueryContents query; |
| 239 FormRequestData request_data; |
| 240 if (!FormStructure::EncodeQueryRequest(forms, &request_data.form_signatures, |
| 241 &query)) { |
| 242 return false; |
| 243 } |
| 244 |
| 245 std::string payload; |
| 246 if (!query.SerializeToString(&payload)) |
| 247 return false; |
| 248 |
| 249 request_data.request_type = AutofillDownloadManager::REQUEST_QUERY; |
| 250 request_data.payload = payload; |
| 251 AutofillMetrics::LogServerQueryMetric(AutofillMetrics::QUERY_SENT); |
| 252 |
| 253 std::string query_data; |
| 254 if (CheckCacheForQueryRequest(request_data.form_signatures, &query_data)) { |
| 255 VLOG(1) << "AutofillDownloadManager: query request has been retrieved " |
| 256 << "from the cache, form signatures: " |
| 257 << GetCombinedSignature(request_data.form_signatures); |
| 258 observer_->OnLoadedServerPredictions(std::move(query_data), |
| 259 request_data.form_signatures); |
| 260 return true; |
| 261 } |
| 262 |
| 263 VLOG(1) << "Sending Autofill Query Request:\n" << query; |
| 264 |
| 265 return StartRequest(request_data); |
| 266 } |
| 267 |
| 268 bool AutofillDownloadManager::StartUploadRequest( |
| 269 const FormStructure& form, |
| 270 bool form_was_autofilled, |
| 271 const ServerFieldTypeSet& available_field_types, |
| 272 const std::string& login_form_signature, |
| 273 bool observed_submission) { |
| 274 AutofillUploadContents upload; |
| 275 if (!form.EncodeUploadRequest(available_field_types, form_was_autofilled, |
| 276 login_form_signature, observed_submission, |
| 277 &upload)) |
| 278 return false; |
| 279 |
| 280 std::string payload; |
| 281 if (!upload.SerializeToString(&payload)) |
| 282 return false; |
| 283 |
| 284 if (form.upload_required() == UPLOAD_NOT_REQUIRED) { |
| 285 VLOG(1) << "AutofillDownloadManager: Upload request is ignored."; |
| 286 // If we ever need notification that upload was skipped, add it here. |
| 287 return false; |
| 288 } |
| 289 |
| 290 FormRequestData request_data; |
| 291 request_data.form_signatures.push_back(form.FormSignatureAsStr()); |
| 292 request_data.request_type = AutofillDownloadManager::REQUEST_UPLOAD; |
| 293 request_data.payload = payload; |
| 294 |
| 295 VLOG(1) << "Sending Autofill Upload Request:\n" << upload; |
| 296 |
| 297 return StartRequest(request_data); |
| 298 } |
| 299 |
| 300 bool AutofillDownloadManager::StartRequest( |
| 301 const FormRequestData& request_data) { |
| 302 net::URLRequestContextGetter* request_context = |
| 303 driver_->GetURLRequestContext(); |
| 304 DCHECK(request_context); |
| 305 GURL request_url = GetRequestUrl(request_data.request_type); |
| 306 |
| 307 // Id is ignored for regular chrome, in unit test id's for fake fetcher |
| 308 // factory will be 0, 1, 2, ... |
| 309 std::unique_ptr<net::URLFetcher> owned_fetcher = net::URLFetcher::Create( |
| 310 fetcher_id_for_unittest_++, request_url, net::URLFetcher::POST, this, |
| 311 GetNetworkTrafficAnnotation(request_data.request_type)); |
| 312 net::URLFetcher* fetcher = owned_fetcher.get(); |
| 313 data_use_measurement::DataUseUserData::AttachToFetcher( |
| 314 fetcher, data_use_measurement::DataUseUserData::AUTOFILL); |
| 315 url_fetchers_[fetcher] = |
| 316 std::make_pair(std::move(owned_fetcher), request_data); |
| 317 fetcher->SetAutomaticallyRetryOn5xx(false); |
| 318 fetcher->SetRequestContext(request_context); |
| 319 fetcher->SetUploadData("text/proto", request_data.payload); |
| 320 fetcher->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES | |
| 321 net::LOAD_DO_NOT_SEND_COOKIES); |
| 322 // Add Chrome experiment state to the request headers. |
| 323 net::HttpRequestHeaders headers; |
| 324 // Note: It's OK to pass |is_signed_in| false if it's unknown, as it does |
| 325 // not affect transmission of experiments coming from the variations server. |
| 326 bool is_signed_in = false; |
| 327 variations::AppendVariationHeaders(fetcher->GetOriginalURL(), |
| 328 driver_->IsOffTheRecord(), false, |
| 329 is_signed_in, &headers); |
| 330 fetcher->SetExtraRequestHeaders(headers.ToString()); |
| 331 fetcher->Start(); |
| 332 |
| 333 return true; |
| 334 } |
| 335 |
| 336 void AutofillDownloadManager::CacheQueryRequest( |
| 337 const std::vector<std::string>& forms_in_query, |
| 338 const std::string& query_data) { |
| 339 std::string signature = GetCombinedSignature(forms_in_query); |
| 340 for (auto it = cached_forms_.begin(); it != cached_forms_.end(); ++it) { |
| 341 if (it->first == signature) { |
| 342 // We hit the cache, move to the first position and return. |
| 343 std::pair<std::string, std::string> data = *it; |
| 344 cached_forms_.erase(it); |
| 345 cached_forms_.push_front(data); |
| 346 return; |
| 347 } |
| 348 } |
| 349 std::pair<std::string, std::string> data; |
| 350 data.first = signature; |
| 351 data.second = query_data; |
| 352 cached_forms_.push_front(data); |
| 353 while (cached_forms_.size() > max_form_cache_size_) |
| 354 cached_forms_.pop_back(); |
| 355 } |
| 356 |
| 357 bool AutofillDownloadManager::CheckCacheForQueryRequest( |
| 358 const std::vector<std::string>& forms_in_query, |
| 359 std::string* query_data) const { |
| 360 std::string signature = GetCombinedSignature(forms_in_query); |
| 361 for (const auto& it : cached_forms_) { |
| 362 if (it.first == signature) { |
| 363 // We hit the cache, fill the data and return. |
| 364 *query_data = it.second; |
| 365 return true; |
| 366 } |
| 367 } |
| 368 return false; |
| 369 } |
| 370 |
| 371 std::string AutofillDownloadManager::GetCombinedSignature( |
| 372 const std::vector<std::string>& forms_in_query) const { |
| 373 size_t total_size = forms_in_query.size(); |
| 374 for (size_t i = 0; i < forms_in_query.size(); ++i) |
| 375 total_size += forms_in_query[i].length(); |
| 376 std::string signature; |
| 377 |
| 378 signature.reserve(total_size); |
| 379 |
| 380 for (size_t i = 0; i < forms_in_query.size(); ++i) { |
| 381 if (i) |
| 382 signature.append(","); |
| 383 signature.append(forms_in_query[i]); |
| 384 } |
| 385 return signature; |
| 386 } |
| 387 |
| 388 void AutofillDownloadManager::OnURLFetchComplete( |
| 389 const net::URLFetcher* source) { |
| 390 auto it = url_fetchers_.find(const_cast<net::URLFetcher*>(source)); |
| 391 if (it == url_fetchers_.end()) { |
| 392 // Looks like crash on Mac is possibly caused with callback entering here |
| 393 // with unknown fetcher when network is refreshed. |
| 394 return; |
| 395 } |
| 396 std::string request_type(RequestTypeToString(it->second.second.request_type)); |
| 397 |
| 398 CHECK(it->second.second.form_signatures.size()); |
| 399 bool success = source->GetResponseCode() == net::HTTP_OK; |
| 400 fetcher_backoff_.InformOfRequest(success); |
| 401 |
| 402 if (!success) { |
| 403 // Reschedule with the appropriate delay, ignoring return value because |
| 404 // payload is already well formed. |
| 405 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| 406 FROM_HERE, |
| 407 base::Bind(base::IgnoreResult(&AutofillDownloadManager::StartRequest), |
| 408 weak_factory_.GetWeakPtr(), it->second.second), |
| 409 fetcher_backoff_.GetTimeUntilRelease()); |
| 410 |
| 411 VLOG(1) << "AutofillDownloadManager: " << request_type |
| 412 << " request has failed with response " |
| 413 << source->GetResponseCode(); |
| 414 observer_->OnServerRequestError(it->second.second.form_signatures[0], |
| 415 it->second.second.request_type, |
| 416 source->GetResponseCode()); |
| 417 } else { |
| 418 std::string response_body; |
| 419 source->GetResponseAsString(&response_body); |
| 420 if (it->second.second.request_type == |
| 421 AutofillDownloadManager::REQUEST_QUERY) { |
| 422 CacheQueryRequest(it->second.second.form_signatures, response_body); |
| 423 observer_->OnLoadedServerPredictions(std::move(response_body), |
| 424 it->second.second.form_signatures); |
| 425 } else { |
| 426 VLOG(1) << "AutofillDownloadManager: upload request has succeeded."; |
| 427 observer_->OnUploadedPossibleFieldTypes(); |
| 428 } |
| 429 } |
| 430 url_fetchers_.erase(it); |
| 431 } |
| 432 |
| 433 } // namespace autofill |
OLD | NEW |