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

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: Incorporated review comments. Created 6 years, 2 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
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 // Helper to search the given form element for the specified input elements 65 enum FieldType { PASSWORD_FIELD, TEXT_FIELD };
66 // in |data|, and add results to |result|.
67 static bool FindFormInputElements(blink::WebFormElement* fe,
68 const FormData& data,
69 FormElements* result) {
70 const bool username_is_present = !data.fields[0].name.empty();
71 66
72 // Loop through the list of elements we need to find on the form in order to 67 // Utility function to search the unique entry of the |form_element| for the
vabr (Chromium) 2014/10/16 16:34:24 nit: search -> find Currently it sounds like the e
Pritam Nikam 2014/11/04 13:22:21 Done.
73 // autofill it. If we don't find any one of them, abort processing this 68 // specified input |field_name|. On successful search, adds it to |result|
74 // form; it can't be the right one. 69 // and returns |true|. Otherwise clears the references from each
75 // First field is the username, skip it if not present. 70 // |HTMLInputElement| from |result| and returns |false|.
76 for (size_t j = (username_is_present ? 0 : 1); j < data.fields.size(); ++j) { 71 bool FillInputField(blink::WebFormElement* form_element,
77 blink::WebVector<blink::WebNode> temp_elements; 72 const base::string16& field_name,
78 fe->getNamedElements(data.fields[j].name, temp_elements); 73 FormElements* result,
74 FieldType field_type) {
75 size_t field_match_counter = 0;
76 blink::WebVector<blink::WebNode> temp_elements;
79 77
80 // Match the first input element, if any. 78 // Fill the username input field.
81 // |getNamedElements| may return non-input elements where the names match, 79 form_element->getNamedElements(field_name, temp_elements);
82 // so the results are filtered for input elements. 80 for (size_t i = 0; i < temp_elements.size(); ++i) {
83 // If more than one match is made, then we have ambiguity (due to misuse 81 if (temp_elements[i].to<blink::WebElement>().hasHTMLTagName("input")) {
84 // of "name" attribute) so is it considered not found. 82 // Check for a non-unique match.
85 bool found_input = false; 83 if (field_match_counter > 0) {
86 for (size_t i = 0; i < temp_elements.size(); ++i) { 84 ++field_match_counter;
vabr (Chromium) 2014/10/16 16:34:24 Currently the behaviour wrt. duplicates depends on
Pritam Nikam 2014/11/04 13:22:22 Done. In my opinion, even if we would resolve th
87 if (temp_elements[i].to<blink::WebElement>().hasHTMLTagName("input")) { 85 break;
88 // Check for a non-unique match. 86 }
89 if (found_input) {
90 found_input = false;
91 break;
92 }
93 87
94 // Only fill saved passwords into password fields and usernames into 88 // Only fill saved passwords into password fields and usernames into
95 // text fields. 89 // text fields.
96 blink::WebInputElement input_element = 90 blink::WebInputElement input_element =
97 temp_elements[i].to<blink::WebInputElement>(); 91 temp_elements[i].to<blink::WebInputElement>();
98 if (input_element.isPasswordField() != 92 if (input_element.isPasswordField() != (field_type == PASSWORD_FIELD))
99 (data.fields[j].form_control_type == "password")) 93 continue;
100 continue;
101 94
102 // This element matched, add it to our temporary result. It's possible 95 // This |input_element| matched, add it to our temporary |result|. It's
103 // there are multiple matches, but for purposes of identifying the form 96 // possible there are multiple matches, but for purposes of identifying
104 // one suffices and if some function needs to deal with multiple 97 // the form one suffices and if some function needs to deal with multiple
105 // matching elements it can get at them through the FormElement*. 98 // matching |input_elements| it can get at them through the
106 // Note: This assignment adds a reference to the InputElement. 99 // |FormElement*|. Note: This assignment adds a reference to the
107 result->input_elements[data.fields[j].name] = input_element; 100 // |HTMLInputElement|.
108 found_input = true; 101 result->input_elements[field_name] = input_element;
109 } 102 ++field_match_counter;
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 } 103 }
120 } 104 }
121 return true; 105
106 // A required |input_element| was not found. This is not the right form. Make
107 // sure no |input_elements| from a partially matched form in this iteration
108 // remain in the |result| set. Note: Clear will remove a reference from each
109 // |HTMLInputElement|.
110 if (field_match_counter != 1)
111 result->input_elements.clear();
vabr (Chromium) 2014/10/16 16:34:24 optional nit: If you rephrase the last 4 lines to:
Pritam Nikam 2014/11/04 13:22:22 Done.
112
113 return (field_match_counter == 1);
114 }
115
116 // Helper to search the given |form_element| for the specified input elements in
117 // |data|, and add results to |result|.
118 bool FindFormInputElements(blink::WebFormElement* form_element,
119 const FormData& data,
120 FormElements* result) {
121 bool password_found = FillInputField(
122 form_element, data.password_field.name, result, PASSWORD_FIELD);
123 return password_found &&
124 (data.username_field.name.empty() ||
125 FillInputField(
126 form_element, data.username_field.name, result, TEXT_FIELD));
122 } 127 }
123 128
124 // Helper to locate form elements identified by |data|. 129 // Helper to locate form elements identified by |data|.
125 void FindFormElements(blink::WebView* view, 130 void FindFormElements(blink::WebView* view,
126 const FormData& data, 131 const FormData& data,
127 FormElementsList* results) { 132 FormElementsList* results) {
128 DCHECK(view); 133 DCHECK(view);
129 DCHECK(results); 134 DCHECK(results);
130 blink::WebFrame* main_frame = view->mainFrame(); 135 blink::WebFrame* main_frame = view->mainFrame();
131 if (!main_frame) 136 if (!main_frame)
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 // Log a message including the name, method and action of |form|. 220 // Log a message including the name, method and action of |form|.
216 void LogHTMLForm(SavePasswordProgressLogger* logger, 221 void LogHTMLForm(SavePasswordProgressLogger* logger,
217 SavePasswordProgressLogger::StringID message_id, 222 SavePasswordProgressLogger::StringID message_id,
218 const blink::WebFormElement& form) { 223 const blink::WebFormElement& form) {
219 logger->LogHTMLForm(message_id, 224 logger->LogHTMLForm(message_id,
220 form.name().utf8(), 225 form.name().utf8(),
221 GURL(form.action().utf8())); 226 GURL(form.action().utf8()));
222 } 227 }
223 228
224 bool FillDataContainsUsername(const PasswordFormFillData& fill_data) { 229 bool FillDataContainsUsername(const PasswordFormFillData& fill_data) {
225 return !fill_data.basic_data.fields[0].name.empty(); 230 return !fill_data.basic_data.username_field.name.empty();
226 } 231 }
227 232
228 } // namespace 233 } // namespace
229 234
230 //////////////////////////////////////////////////////////////////////////////// 235 ////////////////////////////////////////////////////////////////////////////////
231 // PasswordAutofillAgent, public: 236 // PasswordAutofillAgent, public:
232 237
233 PasswordAutofillAgent::PasswordAutofillAgent(content::RenderView* render_view) 238 PasswordAutofillAgent::PasswordAutofillAgent(content::RenderView* render_view)
234 : content::RenderViewObserver(render_view), 239 : content::RenderViewObserver(render_view),
235 usernames_usage_(NOTHING_TO_AUTOFILL), 240 usernames_usage_(NOTHING_TO_AUTOFILL),
(...skipping 572 matching lines...) Expand 10 before | Expand all | Expand 10 after
808 for (iter = forms.begin(); iter != forms.end(); ++iter) { 813 for (iter = forms.begin(); iter != forms.end(); ++iter) {
809 scoped_ptr<FormElements> form_elements(*iter); 814 scoped_ptr<FormElements> form_elements(*iter);
810 815
811 // Attach autocomplete listener to enable selecting alternate logins. 816 // Attach autocomplete listener to enable selecting alternate logins.
812 blink::WebInputElement username_element, password_element; 817 blink::WebInputElement username_element, password_element;
813 818
814 // Check whether the password form has a username input field. 819 // Check whether the password form has a username input field.
815 bool form_contains_username_field = FillDataContainsUsername(form_data); 820 bool form_contains_username_field = FillDataContainsUsername(form_data);
816 if (form_contains_username_field) { 821 if (form_contains_username_field) {
817 username_element = 822 username_element =
818 form_elements->input_elements[form_data.basic_data.fields[0].name]; 823 form_elements
824 ->input_elements[form_data.basic_data.username_field.name];
819 } 825 }
820 826
821 // No password field, bail out. 827 // No password field, bail out.
822 if (form_data.basic_data.fields[1].name.empty()) 828 if (form_data.basic_data.password_field.name.empty())
823 break; 829 break;
824 830
825 // Get pointer to password element. (We currently only support single 831 // Get pointer to password element. (We currently only support single
826 // password forms). 832 // password forms).
827 password_element = 833 password_element =
828 form_elements->input_elements[form_data.basic_data.fields[1].name]; 834 form_elements->input_elements[form_data.basic_data.password_field.name];
829 835
830 // If wait_for_username is true, we don't want to initially fill the form 836 // If wait_for_username is true, we don't want to initially fill the form
831 // until the user types in a valid username. 837 // until the user types in a valid username.
832 if (!form_data.wait_for_username) 838 if (!form_data.wait_for_username)
833 FillFormOnPasswordRecieved(form_data, username_element, password_element); 839 FillFormOnPasswordRecieved(form_data, username_element, password_element);
834 840
835 // We might have already filled this form if there are two <form> elements 841 // We might have already filled this form if there are two <form> elements
836 // with identical markup. 842 // with identical markup.
837 if (login_to_password_info_.find(username_element) != 843 if (login_to_password_info_.find(username_element) !=
838 login_to_password_info_.end()) 844 login_to_password_info_.end())
(...skipping 28 matching lines...) Expand all
867 : backspace_pressed_last(false), password_was_edited_last(false) { 873 : backspace_pressed_last(false), password_was_edited_last(false) {
868 } 874 }
869 875
870 void PasswordAutofillAgent::GetSuggestions( 876 void PasswordAutofillAgent::GetSuggestions(
871 const PasswordFormFillData& fill_data, 877 const PasswordFormFillData& fill_data,
872 const base::string16& input, 878 const base::string16& input,
873 std::vector<base::string16>* suggestions, 879 std::vector<base::string16>* suggestions,
874 std::vector<base::string16>* realms, 880 std::vector<base::string16>* realms,
875 bool show_all) { 881 bool show_all) {
876 if (show_all || 882 if (show_all ||
877 StartsWith(fill_data.basic_data.fields[0].value, input, false)) { 883 StartsWith(fill_data.basic_data.username_field.value, input, false)) {
878 suggestions->push_back(fill_data.basic_data.fields[0].value); 884 suggestions->push_back(fill_data.basic_data.username_field.value);
879 realms->push_back(base::UTF8ToUTF16(fill_data.preferred_realm)); 885 realms->push_back(base::UTF8ToUTF16(fill_data.preferred_realm));
880 } 886 }
881 887
882 for (PasswordFormFillData::LoginCollection::const_iterator iter = 888 for (PasswordFormFillData::LoginCollection::const_iterator iter =
883 fill_data.additional_logins.begin(); 889 fill_data.additional_logins.begin();
884 iter != fill_data.additional_logins.end(); 890 iter != fill_data.additional_logins.end();
885 ++iter) { 891 ++iter) {
886 if (show_all || StartsWith(iter->first, input, false)) { 892 if (show_all || StartsWith(iter->first, input, false)) {
887 suggestions->push_back(iter->first); 893 suggestions->push_back(iter->first);
888 realms->push_back(base::UTF8ToUTF16(iter->second.realm)); 894 realms->push_back(base::UTF8ToUTF16(iter->second.realm));
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
956 // If we can't modify the password, don't try to set the username 962 // If we can't modify the password, don't try to set the username
957 if (!IsElementAutocompletable(password_element)) 963 if (!IsElementAutocompletable(password_element))
958 return; 964 return;
959 965
960 // Try to set the username to the preferred name, but only if the field 966 // Try to set the username to the preferred name, but only if the field
961 // can be set and isn't prefilled. 967 // can be set and isn't prefilled.
962 if (form_contains_username_field && 968 if (form_contains_username_field &&
963 IsElementAutocompletable(username_element) && 969 IsElementAutocompletable(username_element) &&
964 username_element.value().isEmpty()) { 970 username_element.value().isEmpty()) {
965 // TODO(tkent): Check maxlength and pattern. 971 // TODO(tkent): Check maxlength and pattern.
966 username_element.setValue(fill_data.basic_data.fields[0].value, true); 972 username_element.setValue(fill_data.basic_data.username_field.value, true);
967 } 973 }
968 974
969 // Fill if we have an exact match for the username. Note that this sets 975 // Fill if we have an exact match for the username. Note that this sets
970 // username to autofilled. 976 // username to autofilled.
971 FillUserNameAndPassword(&username_element, 977 FillUserNameAndPassword(&username_element,
972 &password_element, 978 &password_element,
973 fill_data, 979 fill_data,
974 true /* exact_username_match */, 980 true /* exact_username_match */,
975 false /* set_selection */); 981 false /* set_selection */);
976 } 982 }
(...skipping 11 matching lines...) Expand all
988 base::string16 current_username; 994 base::string16 current_username;
989 if (!username_element->isNull()) { 995 if (!username_element->isNull()) {
990 current_username = username_element->value(); 996 current_username = username_element->value();
991 } 997 }
992 998
993 // username and password will contain the match found if any. 999 // username and password will contain the match found if any.
994 base::string16 username; 1000 base::string16 username;
995 base::string16 password; 1001 base::string16 password;
996 1002
997 // Look for any suitable matches to current field text. 1003 // Look for any suitable matches to current field text.
998 if (DoUsernamesMatch(fill_data.basic_data.fields[0].value, 1004 if (DoUsernamesMatch(fill_data.basic_data.username_field.value,
999 current_username, 1005 current_username,
1000 exact_username_match)) { 1006 exact_username_match)) {
1001 username = fill_data.basic_data.fields[0].value; 1007 username = fill_data.basic_data.username_field.value;
1002 password = fill_data.basic_data.fields[1].value; 1008 password = fill_data.basic_data.password_field.value;
1003 } else { 1009 } else {
1004 // Scan additional logins for a match. 1010 // Scan additional logins for a match.
1005 PasswordFormFillData::LoginCollection::const_iterator iter; 1011 PasswordFormFillData::LoginCollection::const_iterator iter;
1006 for (iter = fill_data.additional_logins.begin(); 1012 for (iter = fill_data.additional_logins.begin();
1007 iter != fill_data.additional_logins.end(); 1013 iter != fill_data.additional_logins.end();
1008 ++iter) { 1014 ++iter) {
1009 if (DoUsernamesMatch( 1015 if (DoUsernamesMatch(
1010 iter->first, current_username, exact_username_match)) { 1016 iter->first, current_username, exact_username_match)) {
1011 username = iter->first; 1017 username = iter->first;
1012 password = iter->second.password; 1018 password = iter->second.password;
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
1162 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); 1168 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form));
1163 if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD && 1169 if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD &&
1164 password_form->password_value.empty() && 1170 password_form->password_value.empty() &&
1165 password_form->new_password_value.empty())) { 1171 password_form->new_password_value.empty())) {
1166 return; 1172 return;
1167 } 1173 }
1168 provisionally_saved_forms_[frame].reset(password_form.release()); 1174 provisionally_saved_forms_[frame].reset(password_form.release());
1169 } 1175 }
1170 1176
1171 } // namespace autofill 1177 } // namespace autofill
OLDNEW
« no previous file with comments | « components/autofill/content/common/autofill_param_traits_macros.h ('k') | components/autofill/core/common/form_data.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698