diff options
author | jhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-16 02:59:24 +0000 |
---|---|---|
committer | jhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-16 02:59:24 +0000 |
commit | a44e6102cd74889a4394516db97a2d7bddd1255d (patch) | |
tree | b49dd494d28f297d2ad44788d34ea66de787b7de /chrome | |
parent | 224e723f497c53daa28657b8bfb98d45b8fc1d78 (diff) | |
download | chromium_src-a44e6102cd74889a4394516db97a2d7bddd1255d.zip chromium_src-a44e6102cd74889a4394516db97a2d7bddd1255d.tar.gz chromium_src-a44e6102cd74889a4394516db97a2d7bddd1255d.tar.bz2 |
AutoFill: Skip past non-matching fields when filling out a form where the number
of FormData fields does not match the number of cached control elements.
BUG=41573
TEST=FormManager.FillForm*
Review URL: http://codereview.chromium.org/1629020
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@44748 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/renderer/form_manager.cc | 30 | ||||
-rw-r--r-- | chrome/renderer/form_manager_unittest.cc | 217 |
2 files changed, 241 insertions, 6 deletions
diff --git a/chrome/renderer/form_manager.cc b/chrome/renderer/form_manager.cc index 1feab24..144e23d 100644 --- a/chrome/renderer/form_manager.cc +++ b/chrome/renderer/form_manager.cc @@ -391,31 +391,49 @@ bool FormManager::FillForm(const FormData& form) { // one case in the wild where this happens, paypal.com signup form, the fields // are appended to the end of the form and are not visible. - for (size_t i = 0; i < form_element->control_elements.size(); ++i) { + for (size_t i = 0, j = 0; + i < form_element->control_elements.size() && j < form.fields.size(); + ++i, ++j) { + // We assume that the intersection of the fields in + // |form_element->control_elements| and |form.fields| is ordered, but it's + // possible that one or the other sets may have more fields than the other, + // so loop past non-matching fields in the set with more elements. + while (form_element->control_elements[i].nameForAutofill() != + form.fields[j].name()) { + if (form_element->control_elements.size() > form.fields.size()) + ++i; + else if (form.fields.size() > form_element->control_elements.size()) + ++j; + else + NOTREACHED(); + + continue; + } + WebFormControlElement* element = &form_element->control_elements[i]; // It's possible that nameForAutofill() is empty if the form control element // has no name or ID. In that case, iter->nameForAutofill() must also be // empty. - if (form.fields[i].name().empty()) + if (form.fields[j].name().empty()) DCHECK(element->nameForAutofill().isEmpty()); else - DCHECK_EQ(form.fields[i].name(), element->nameForAutofill()); + DCHECK_EQ(form.fields[j].name(), element->nameForAutofill()); - if (!form.fields[i].value().empty() && + if (!form.fields[j].value().empty() && element->formControlType() != WebString::fromUTF8("submit")) { if (element->formControlType() == WebString::fromUTF8("text")) { WebInputElement input_element = element->toElement<WebInputElement>(); // If the maxlength attribute contains a negative value, maxLength() // returns the default maxlength value. input_element.setValue( - form.fields[i].value().substr(0, input_element.maxLength())); + form.fields[j].value().substr(0, input_element.maxLength())); input_element.setAutofilled(true); } else if (element->formControlType() == WebString::fromUTF8("select-one")) { WebSelectElement select_element = element->toElement<WebSelectElement>(); - select_element.setValue(form.fields[i].value()); + select_element.setValue(form.fields[j].value()); } } } diff --git a/chrome/renderer/form_manager_unittest.cc b/chrome/renderer/form_manager_unittest.cc index 4da73aa..316822d 100644 --- a/chrome/renderer/form_manager_unittest.cc +++ b/chrome/renderer/form_manager_unittest.cc @@ -896,6 +896,7 @@ TEST_F(FormManagerTest, FillFormNegativeMaxLength) { // TODO(jhawkins): We don't actually compare the value of the field in // FormField::operator==()! const std::vector<FormField>& fields2 = form2.fields; + ASSERT_EQ(3U, fields2.size()); EXPECT_EQ(FormField(string16(), ASCIIToUTF16("firstname"), ASCIIToUTF16("Brother"), @@ -915,4 +916,220 @@ TEST_F(FormManagerTest, FillFormNegativeMaxLength) { fields2[2]); } +// This test sends a FormData object to FillForm with more fields than are in +// the cached WebFormElement. In this case, we only fill out the fields that +// match between the FormData object and the WebFormElement. +TEST_F(FormManagerTest, FillFormMoreFormDataFields) { + LoadHTML("<FORM name=\"TestForm\" action=\"http://buh.com\" method=\"post\">" + " <INPUT type=\"text\" id=\"firstname\"/>" + " <INPUT type=\"text\" id=\"middlename\"/>" + " <INPUT type=\"text\" id=\"lastname\"/>" + " <INPUT type=\"submit\" name=\"reply-send\" value=\"Send\"/>" + "</FORM>"); + + WebFrame* web_frame = GetMainFrame(); + ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + + FormManager form_manager; + form_manager.ExtractForms(web_frame); + + // Verify that we have the form. + std::vector<FormData> forms; + form_manager.GetForms(FormManager::REQUIRE_NONE, &forms); + ASSERT_EQ(1U, forms.size()); + + // After the field modification, the fields in |form| will look like: + // prefix + // firstname + // hidden + // middlename + // second + // lastname + // postfix + FormData* form = &forms[0]; + + FormField field1(string16(), + ASCIIToUTF16("prefix"), + string16(), + ASCIIToUTF16("text")); + form->fields.insert(form->fields.begin(), field1); + + FormField field2(string16(), + ASCIIToUTF16("hidden"), + string16(), + ASCIIToUTF16("text")); + form->fields.insert(form->fields.begin() + 2, field2); + + FormField field3(string16(), + ASCIIToUTF16("second"), + string16(), + ASCIIToUTF16("text")); + form->fields.insert(form->fields.begin() + 4, field3); + + FormField field4(string16(), + ASCIIToUTF16("postfix"), + string16(), + ASCIIToUTF16("text")); + form->fields.insert(form->fields.begin() + 6, field4); + + // Fill the form. + form->fields[0].set_value(ASCIIToUTF16("Alpha")); + form->fields[1].set_value(ASCIIToUTF16("Brother")); + form->fields[2].set_value(ASCIIToUTF16("Abracadabra")); + form->fields[3].set_value(ASCIIToUTF16("Joseph")); + form->fields[4].set_value(ASCIIToUTF16("Beta")); + form->fields[5].set_value(ASCIIToUTF16("Jonathan")); + form->fields[6].set_value(ASCIIToUTF16("Omega")); + EXPECT_TRUE(form_manager.FillForm(*form)); + + // Get the input element we want to find. + WebElement element = + web_frame->document().getElementById(WebString::fromUTF8("firstname")); + WebInputElement input_element = element.toElement<WebInputElement>(); + + // Find the newly-filled form that contains the input element. + FormData form2; + EXPECT_TRUE(form_manager.FindFormWithFormControlElement( + input_element, FormManager::REQUIRE_NONE, &form2)); + EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name); + EXPECT_EQ(GURL(web_frame->url()), form2.origin); + EXPECT_EQ(GURL("http://buh.com"), form2.action); + + // TODO(jhawkins): We don't actually compare the value of the field in + // FormField::operator==()! + const std::vector<FormField>& fields = form2.fields; + ASSERT_EQ(4U, fields.size()); + EXPECT_EQ(FormField(string16(), + ASCIIToUTF16("firstname"), + ASCIIToUTF16("Brother"), + ASCIIToUTF16("text")), + fields[0]); + EXPECT_EQ(ASCIIToUTF16("Brother"), fields[0].value()); + EXPECT_EQ(FormField(string16(), + ASCIIToUTF16("middlename"), + ASCIIToUTF16("Joseph"), + ASCIIToUTF16("text")), + fields[1]); + EXPECT_EQ(ASCIIToUTF16("Joseph"), fields[1].value()); + EXPECT_EQ(FormField(string16(), + ASCIIToUTF16("lastname"), + ASCIIToUTF16("Jonathan"), + ASCIIToUTF16("text")), + fields[2]); + EXPECT_EQ(ASCIIToUTF16("Jonathan"), fields[2].value()); + EXPECT_EQ(FormField(string16(), + ASCIIToUTF16("reply-send"), + ASCIIToUTF16("Send"), + ASCIIToUTF16("submit")), + fields[3]); +} + +// This test sends a FormData object to FillForm with fewer fields than are in +// the cached WebFormElement. In this case, we only fill out the fields that +// match between the FormData object and the WebFormElement. +TEST_F(FormManagerTest, FillFormFewerFormDataFields) { + LoadHTML("<FORM name=\"TestForm\" action=\"http://buh.com\" method=\"post\">" + " <INPUT type=\"text\" id=\"prefix\"/>" + " <INPUT type=\"text\" id=\"firstname\"/>" + " <INPUT type=\"text\" id=\"hidden\"/>" + " <INPUT type=\"text\" id=\"middlename\"/>" + " <INPUT type=\"text\" id=\"second\"/>" + " <INPUT type=\"text\" id=\"lastname\"/>" + " <INPUT type=\"text\" id=\"postfix\"/>" + " <INPUT type=\"submit\" name=\"reply-send\" value=\"Send\"/>" + "</FORM>"); + + WebFrame* web_frame = GetMainFrame(); + ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + + FormManager form_manager; + form_manager.ExtractForms(web_frame); + + // Verify that we have the form. + std::vector<FormData> forms; + form_manager.GetForms(FormManager::REQUIRE_NONE, &forms); + ASSERT_EQ(1U, forms.size()); + + // After the field modification, the fields in |form| will look like: + // firstname + // middlename + // lastname + FormData* form = &forms[0]; + form->fields.erase(form->fields.begin()); + form->fields.erase(form->fields.begin() + 1); + form->fields.erase(form->fields.begin() + 2); + form->fields.erase(form->fields.begin() + 3); + + // Fill the form. + form->fields[0].set_value(ASCIIToUTF16("Brother")); + form->fields[1].set_value(ASCIIToUTF16("Joseph")); + form->fields[2].set_value(ASCIIToUTF16("Jonathan")); + EXPECT_TRUE(form_manager.FillForm(*form)); + + // Get the input element we want to find. + WebElement element = + web_frame->document().getElementById(WebString::fromUTF8("firstname")); + WebInputElement input_element = element.toElement<WebInputElement>(); + + // Find the newly-filled form that contains the input element. + FormData form2; + EXPECT_TRUE(form_manager.FindFormWithFormControlElement( + input_element, FormManager::REQUIRE_NONE, &form2)); + EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name); + EXPECT_EQ(GURL(web_frame->url()), form2.origin); + EXPECT_EQ(GURL("http://buh.com"), form2.action); + + // TODO(jhawkins): We don't actually compare the value of the field in + // FormField::operator==()! + const std::vector<FormField>& fields = form2.fields; + ASSERT_EQ(8U, fields.size()); + EXPECT_EQ(FormField(string16(), + ASCIIToUTF16("prefix"), + string16(), + ASCIIToUTF16("text")), + fields[0]); + EXPECT_EQ(string16(), fields[0].value()); + EXPECT_EQ(FormField(string16(), + ASCIIToUTF16("firstname"), + ASCIIToUTF16("Brother"), + ASCIIToUTF16("text")), + fields[1]); + EXPECT_EQ(ASCIIToUTF16("Brother"), fields[1].value()); + EXPECT_EQ(FormField(string16(), + ASCIIToUTF16("hidden"), + string16(), + ASCIIToUTF16("text")), + fields[2]); + EXPECT_EQ(string16(), fields[2].value()); + EXPECT_EQ(FormField(string16(), + ASCIIToUTF16("middlename"), + ASCIIToUTF16("Joseph"), + ASCIIToUTF16("text")), + fields[3]); + EXPECT_EQ(ASCIIToUTF16("Joseph"), fields[3].value()); + EXPECT_EQ(FormField(string16(), + ASCIIToUTF16("second"), + string16(), + ASCIIToUTF16("text")), + fields[4]); + EXPECT_EQ(string16(), fields[4].value()); + EXPECT_EQ(FormField(string16(), + ASCIIToUTF16("lastname"), + ASCIIToUTF16("Jonathan"), + ASCIIToUTF16("text")), + fields[5]); + EXPECT_EQ(ASCIIToUTF16("Jonathan"), fields[5].value()); + EXPECT_EQ(FormField(string16(), + ASCIIToUTF16("postfix"), + string16(), + ASCIIToUTF16("text")), + fields[6]); + EXPECT_EQ(string16(), fields[6].value()); + EXPECT_EQ(FormField(string16(), + ASCIIToUTF16("reply-send"), + ASCIIToUTF16("Send"), + ASCIIToUTF16("submit")), + fields[7]); +} + } // namespace |