Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(308)

Side by Side Diff: tools/clang/traffic_annotation_extractor/tests/inputs/autofill_download_manager.cc

Issue 2448133006: Tool added to extract network traffic annotations. (Closed)
Patch Set: nits Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
battre 2017/04/07 08:42:27 I would suggest to reduce this file significantly
Ramin Halavati 2017/04/07 11:33:32 I am not sure if this is the correct way to add te
battre 2017/04/10 10:58:31 SGTM. Keep in mind that the current style of testi
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698