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

Side by Side Diff: components/autofill/content/renderer/password_autofill_agent.cc

Issue 614023002: [Password manager] Relplace the FormFieldData vector from autofill::FormData with named fields… (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Removed FormData from PasswordFormFillData. Created 6 years, 1 month 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
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/autofill/content/renderer/password_autofill_agent.h" 5 #include "components/autofill/content/renderer/password_autofill_agent.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/memory/scoped_ptr.h" 8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h" 9 #include "base/message_loop/message_loop.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
55 // necessary form elements. To avoid having to look these up again when we want 55 // necessary form elements. To avoid having to look these up again when we want
56 // to fill the form, the FindFormElements function stores the pointers 56 // to fill the form, the FindFormElements function stores the pointers
57 // in a FormElements* result, referenced to ensure they are safe to use. 57 // in a FormElements* result, referenced to ensure they are safe to use.
58 struct FormElements { 58 struct FormElements {
59 blink::WebFormElement form_element; 59 blink::WebFormElement form_element;
60 FormInputElementMap input_elements; 60 FormInputElementMap input_elements;
61 }; 61 };
62 62
63 typedef std::vector<FormElements*> FormElementsList; 63 typedef std::vector<FormElements*> FormElementsList;
64 64
65 enum FieldType { PASSWORD_FIELD, TEXT_FIELD };
66
67 // Utility function to find the unique entry of the |form_element| for the
68 // specified input |field_name|. On successful find, adds it to |result|
69 // and returns |true|. Otherwise clears the references from each
vabr (Chromium) 2014/11/04 21:28:33 This function can return true with an empty |resul
Pritam Nikam 2014/11/05 05:58:13 Done.
vabr (Chromium) 2014/11/05 08:23:40 I don't see this comment addressed. The function c
Pritam Nikam 2014/11/05 10:53:00 Done. Sorry! I've missed to incorporate changes.
70 // |HTMLInputElement| from |result| and returns |false|.
71 bool FillInputField(blink::WebFormElement* form_element,
Ilya Sherman 2014/11/04 23:05:30 What does "Fill" refer to in this function name?
Pritam Nikam 2014/11/05 05:58:13 Done. Rephrased to AddInputElementToResultWithMat
72 const base::string16& field_name,
73 FormElements* result,
74 FieldType field_type) {
75 blink::WebVector<blink::WebNode> temp_elements;
76 size_t field_match_counter = 0;
77 // Fill the username input field.
Ilya Sherman 2014/11/04 23:05:30 What does this comment mean?
Pritam Nikam 2014/11/05 05:58:14 Done. Rephrased it to express the below excerpt.
78 form_element->getNamedElements(field_name, temp_elements);
79 for (size_t i = 0; i < temp_elements.size(); ++i) {
Ilya Sherman 2014/11/04 23:05:31 nit: Please use a C++11 range-based for loop.
Pritam Nikam 2014/11/05 05:58:13 I think we cannot use C++11 range-based for loop h
Ilya Sherman 2014/11/07 20:19:25 Yes, you're right -- my bad.
80 if (temp_elements[i].to<blink::WebElement>().hasHTMLTagName("input")) {
81 // Check for a non-unique match.
82 if (++field_match_counter > 1)
Ilya Sherman 2014/11/04 23:05:30 Please use the boolean style that was used before.
Pritam Nikam 2014/11/05 05:58:14 Done.
83 break;
84
85 // Only fill saved passwords into password fields and usernames into
86 // text fields.
87 blink::WebInputElement input_element =
88 temp_elements[i].to<blink::WebInputElement>();
89 if (input_element.isPasswordField() != (field_type == PASSWORD_FIELD))
90 continue;
91
92 // This |input_element| matched, add it to our temporary |result|. It's
93 // possible there are multiple matches, but for purposes of identifying
94 // the form one suffices and if some function needs to deal with multiple
95 // matching |input_elements| it can get at them through the
96 // |FormElement*|. Note: This assignment adds a reference to the
97 // |HTMLInputElement|.
98 result->input_elements[field_name] = input_element;
99 }
100 }
101
102 // A required |input_element| was not found. This is not the right form. Make
103 // sure no |input_elements| from a partially matched form in this iteration
104 // remain in the |result| set. Note: Clear will remove a reference from each
Ilya Sherman 2014/11/04 23:05:30 Why did you change the case of "Clear"? The funct
Pritam Nikam 2014/11/05 05:58:13 Done.
105 // |HTMLInputElement|.
106 if (field_match_counter > 1) {
107 result->input_elements.clear();
108 return false;
109 }
110
111 return true;
112 }
113
65 // Helper to search the given form element for the specified input elements 114 // Helper to search the given form element for the specified input elements
66 // in |data|, and add results to |result|. 115 // in |data|, and add results to |result|.
67 static bool FindFormInputElements(blink::WebFormElement* fe, 116 bool FindFormInputElements(blink::WebFormElement* form_element,
68 const FormData& data, 117 const PasswordFormFillData& data,
69 FormElements* result) { 118 FormElements* result) {
70 const bool username_is_present = !data.fields[0].name.empty(); 119 bool password_found = FillInputField(form_element, data.password_field.name,
120 result, PASSWORD_FIELD);
Ilya Sherman 2014/11/04 23:05:31 nit: I think it would be clearer to inline this co
Pritam Nikam 2014/11/05 05:58:14 Done.
71 121
72 // Loop through the list of elements we need to find on the form in order to 122 return password_found &&
73 // autofill it. If we don't find any one of them, abort processing this 123 (data.username_field.name.empty() ||
74 // form; it can't be the right one. 124 FillInputField(form_element, data.username_field.name, result,
75 // First field is the username, skip it if not present. 125 TEXT_FIELD));
76 for (size_t j = (username_is_present ? 0 : 1); j < data.fields.size(); ++j) {
77 blink::WebVector<blink::WebNode> temp_elements;
78 fe->getNamedElements(data.fields[j].name, temp_elements);
79
80 // Match the first input element, if any.
81 // |getNamedElements| may return non-input elements where the names match,
82 // so the results are filtered for input elements.
83 // If more than one match is made, then we have ambiguity (due to misuse
84 // of "name" attribute) so is it considered not found.
85 bool found_input = false;
86 for (size_t i = 0; i < temp_elements.size(); ++i) {
87 if (temp_elements[i].to<blink::WebElement>().hasHTMLTagName("input")) {
88 // Check for a non-unique match.
89 if (found_input) {
90 found_input = false;
91 break;
92 }
93
94 // Only fill saved passwords into password fields and usernames into
95 // text fields.
96 blink::WebInputElement input_element =
97 temp_elements[i].to<blink::WebInputElement>();
98 if (input_element.isPasswordField() !=
99 (data.fields[j].form_control_type == "password"))
100 continue;
101
102 // This element matched, add it to our temporary result. It's possible
103 // there are multiple matches, but for purposes of identifying the form
104 // one suffices and if some function needs to deal with multiple
105 // matching elements it can get at them through the FormElement*.
106 // Note: This assignment adds a reference to the InputElement.
107 result->input_elements[data.fields[j].name] = input_element;
108 found_input = true;
109 }
110 }
111
112 // A required element was not found. This is not the right form.
113 // Make sure no input elements from a partially matched form in this
114 // iteration remain in the result set.
115 // Note: clear will remove a reference from each InputElement.
116 if (!found_input) {
117 result->input_elements.clear();
118 return false;
119 }
120 }
121 return true;
122 } 126 }
123 127
124 // Helper to locate form elements identified by |data|. 128 // Helper to locate form elements identified by |data|.
125 void FindFormElements(blink::WebView* view, 129 void FindFormElements(blink::WebView* view,
126 const FormData& data, 130 const PasswordFormFillData& data,
127 FormElementsList* results) { 131 FormElementsList* results) {
128 DCHECK(view); 132 DCHECK(view);
129 DCHECK(results); 133 DCHECK(results);
130 blink::WebFrame* main_frame = view->mainFrame(); 134 blink::WebFrame* main_frame = view->mainFrame();
131 if (!main_frame) 135 if (!main_frame)
132 return; 136 return;
133 137
134 GURL::Replacements rep; 138 GURL::Replacements rep;
135 rep.ClearQuery(); 139 rep.ClearQuery();
136 rep.ClearRef(); 140 rep.ClearRef();
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 // Log a message including the name, method and action of |form|. 234 // Log a message including the name, method and action of |form|.
231 void LogHTMLForm(SavePasswordProgressLogger* logger, 235 void LogHTMLForm(SavePasswordProgressLogger* logger,
232 SavePasswordProgressLogger::StringID message_id, 236 SavePasswordProgressLogger::StringID message_id,
233 const blink::WebFormElement& form) { 237 const blink::WebFormElement& form) {
234 logger->LogHTMLForm(message_id, 238 logger->LogHTMLForm(message_id,
235 form.name().utf8(), 239 form.name().utf8(),
236 GURL(form.action().utf8())); 240 GURL(form.action().utf8()));
237 } 241 }
238 242
239 bool FillDataContainsUsername(const PasswordFormFillData& fill_data) { 243 bool FillDataContainsUsername(const PasswordFormFillData& fill_data) {
240 return !fill_data.basic_data.fields[0].name.empty(); 244 return !fill_data.username_field.name.empty();
241 } 245 }
242 246
243 // This function attempts to fill |suggestions| and |realms| form |fill_data| 247 // This function attempts to fill |suggestions| and |realms| form |fill_data|
244 // based on |current_username|. Returns true when |suggestions| gets filled 248 // based on |current_username|. Returns true when |suggestions| gets filled
245 // from |fill_data.other_possible_usernames|, else returns false. 249 // from |fill_data.other_possible_usernames|, else returns false.
246 bool GetSuggestions(const PasswordFormFillData& fill_data, 250 bool GetSuggestions(const PasswordFormFillData& fill_data,
247 const base::string16& current_username, 251 const base::string16& current_username,
248 std::vector<base::string16>* suggestions, 252 std::vector<base::string16>* suggestions,
249 std::vector<base::string16>* realms, 253 std::vector<base::string16>* realms,
250 bool show_all) { 254 bool show_all) {
251 bool other_possible_username_shown = false; 255 bool other_possible_username_shown = false;
252 if (show_all || 256 if (show_all ||
253 StartsWith( 257 StartsWith(fill_data.username_field.value, current_username, false)) {
254 fill_data.basic_data.fields[0].value, current_username, false)) { 258 suggestions->push_back(fill_data.username_field.value);
255 suggestions->push_back(fill_data.basic_data.fields[0].value);
256 realms->push_back(base::UTF8ToUTF16(fill_data.preferred_realm)); 259 realms->push_back(base::UTF8ToUTF16(fill_data.preferred_realm));
257 } 260 }
258 261
259 for (PasswordFormFillData::LoginCollection::const_iterator iter = 262 for (PasswordFormFillData::LoginCollection::const_iterator iter =
260 fill_data.additional_logins.begin(); 263 fill_data.additional_logins.begin();
261 iter != fill_data.additional_logins.end(); 264 iter != fill_data.additional_logins.end();
262 ++iter) { 265 ++iter) {
263 if (show_all || StartsWith(iter->first, current_username, false)) { 266 if (show_all || StartsWith(iter->first, current_username, false)) {
264 suggestions->push_back(iter->first); 267 suggestions->push_back(iter->first);
265 realms->push_back(base::UTF8ToUTF16(iter->second.realm)); 268 realms->push_back(base::UTF8ToUTF16(iter->second.realm));
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
301 base::string16 current_username; 304 base::string16 current_username;
302 if (!username_element->isNull()) { 305 if (!username_element->isNull()) {
303 current_username = username_element->value(); 306 current_username = username_element->value();
304 } 307 }
305 308
306 // username and password will contain the match found if any. 309 // username and password will contain the match found if any.
307 base::string16 username; 310 base::string16 username;
308 base::string16 password; 311 base::string16 password;
309 312
310 // Look for any suitable matches to current field text. 313 // Look for any suitable matches to current field text.
311 if (DoUsernamesMatch(fill_data.basic_data.fields[0].value, 314 if (DoUsernamesMatch(fill_data.username_field.value, current_username,
Ilya Sherman 2014/11/04 23:05:30 nit: Please run "git cl format" over your changes.
Pritam Nikam 2014/11/05 05:58:14 Done. Formatting here is after "git cl format" on
Ilya Sherman 2014/11/07 20:19:25 Thanks for checking that, and sorry for the false
312 current_username,
313 exact_username_match)) { 315 exact_username_match)) {
314 username = fill_data.basic_data.fields[0].value; 316 username = fill_data.username_field.value;
315 password = fill_data.basic_data.fields[1].value; 317 password = fill_data.password_field.value;
316 } else { 318 } else {
317 // Scan additional logins for a match. 319 // Scan additional logins for a match.
318 PasswordFormFillData::LoginCollection::const_iterator iter; 320 PasswordFormFillData::LoginCollection::const_iterator iter;
319 for (iter = fill_data.additional_logins.begin(); 321 for (iter = fill_data.additional_logins.begin();
320 iter != fill_data.additional_logins.end(); 322 iter != fill_data.additional_logins.end();
321 ++iter) { 323 ++iter) {
322 if (DoUsernamesMatch( 324 if (DoUsernamesMatch(
323 iter->first, current_username, exact_username_match)) { 325 iter->first, current_username, exact_username_match)) {
324 username = iter->first; 326 username = iter->first;
325 password = iter->second.password; 327 password = iter->second.password;
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
405 // If we can't modify the password, don't try to set the username 407 // If we can't modify the password, don't try to set the username
406 if (!IsElementAutocompletable(password_element)) 408 if (!IsElementAutocompletable(password_element))
407 return false; 409 return false;
408 410
409 // Try to set the username to the preferred name, but only if the field 411 // Try to set the username to the preferred name, but only if the field
410 // can be set and isn't prefilled. 412 // can be set and isn't prefilled.
411 if (form_contains_username_field && 413 if (form_contains_username_field &&
412 IsElementAutocompletable(username_element) && 414 IsElementAutocompletable(username_element) &&
413 username_element.value().isEmpty()) { 415 username_element.value().isEmpty()) {
414 // TODO(tkent): Check maxlength and pattern. 416 // TODO(tkent): Check maxlength and pattern.
415 username_element.setValue(fill_data.basic_data.fields[0].value, true); 417 username_element.setValue(fill_data.username_field.value, true);
416 } 418 }
417 419
418 // Fill if we have an exact match for the username. Note that this sets 420 // Fill if we have an exact match for the username. Note that this sets
419 // username to autofilled. 421 // username to autofilled.
420 return FillUserNameAndPassword(&username_element, 422 return FillUserNameAndPassword(&username_element,
421 &password_element, 423 &password_element,
422 fill_data, 424 fill_data,
423 true /* exact_username_match */, 425 true /* exact_username_match */,
424 false /* set_selection */, 426 false /* set_selection */,
425 registration_callback); 427 registration_callback);
(...skipping 593 matching lines...) Expand 10 before | Expand all | Expand 10 after
1019 const PasswordFormFillData& form_data) { 1021 const PasswordFormFillData& form_data) {
1020 if (usernames_usage_ == NOTHING_TO_AUTOFILL) { 1022 if (usernames_usage_ == NOTHING_TO_AUTOFILL) {
1021 if (form_data.other_possible_usernames.size()) 1023 if (form_data.other_possible_usernames.size())
1022 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_PRESENT; 1024 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_PRESENT;
1023 else if (usernames_usage_ == NOTHING_TO_AUTOFILL) 1025 else if (usernames_usage_ == NOTHING_TO_AUTOFILL)
1024 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_ABSENT; 1026 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_ABSENT;
1025 } 1027 }
1026 1028
1027 FormElementsList forms; 1029 FormElementsList forms;
1028 // We own the FormElements* in forms. 1030 // We own the FormElements* in forms.
1029 FindFormElements(render_view()->GetWebView(), form_data.basic_data, &forms); 1031 FindFormElements(render_view()->GetWebView(), form_data, &forms);
1030 FormElementsList::iterator iter; 1032 FormElementsList::iterator iter;
1031 for (iter = forms.begin(); iter != forms.end(); ++iter) { 1033 for (iter = forms.begin(); iter != forms.end(); ++iter) {
1032 scoped_ptr<FormElements> form_elements(*iter); 1034 scoped_ptr<FormElements> form_elements(*iter);
1033 1035
1034 // Attach autocomplete listener to enable selecting alternate logins. 1036 // Attach autocomplete listener to enable selecting alternate logins.
1035 blink::WebInputElement username_element, password_element; 1037 blink::WebInputElement username_element, password_element;
1036 1038
1037 // Check whether the password form has a username input field. 1039 // Check whether the password form has a username input field.
1038 bool form_contains_username_field = FillDataContainsUsername(form_data); 1040 bool form_contains_username_field = FillDataContainsUsername(form_data);
1039 if (form_contains_username_field) { 1041 if (form_contains_username_field) {
1040 username_element = 1042 username_element =
1041 form_elements->input_elements[form_data.basic_data.fields[0].name]; 1043 form_elements->input_elements[form_data.username_field.name];
1042 } 1044 }
1043 1045
1044 // No password field, bail out. 1046 // No password field, bail out.
1045 if (form_data.basic_data.fields[1].name.empty()) 1047 if (form_data.password_field.name.empty())
1046 break; 1048 break;
1047 1049
1048 // Get pointer to password element. (We currently only support single 1050 // Get pointer to password element. (We currently only support single
1049 // password forms). 1051 // password forms).
1050 password_element = 1052 password_element =
1051 form_elements->input_elements[form_data.basic_data.fields[1].name]; 1053 form_elements->input_elements[form_data.password_field.name];
1052 1054
1053 // If wait_for_username is true, we don't want to initially fill the form 1055 // If wait_for_username is true, we don't want to initially fill the form
1054 // until the user types in a valid username. 1056 // until the user types in a valid username.
1055 if (!form_data.wait_for_username && 1057 if (!form_data.wait_for_username &&
1056 FillFormOnPasswordRecieved( 1058 FillFormOnPasswordRecieved(
1057 form_data, 1059 form_data,
1058 username_element, 1060 username_element,
1059 password_element, 1061 password_element,
1060 base::Bind(&PasswordValueGatekeeper::RegisterElement, 1062 base::Bind(&PasswordValueGatekeeper::RegisterElement,
1061 base::Unretained(&gatekeeper_)))) { 1063 base::Unretained(&gatekeeper_)))) {
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
1243 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); 1245 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form));
1244 if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD && 1246 if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD &&
1245 password_form->password_value.empty() && 1247 password_form->password_value.empty() &&
1246 password_form->new_password_value.empty())) { 1248 password_form->new_password_value.empty())) {
1247 return; 1249 return;
1248 } 1250 }
1249 provisionally_saved_forms_[frame].reset(password_form.release()); 1251 provisionally_saved_forms_[frame].reset(password_form.release());
1250 } 1252 }
1251 1253
1252 } // namespace autofill 1254 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698