Chromium Code Reviews| 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 |