OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |