summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorjhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-16 02:59:24 +0000
committerjhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-16 02:59:24 +0000
commita44e6102cd74889a4394516db97a2d7bddd1255d (patch)
treeb49dd494d28f297d2ad44788d34ea66de787b7de /chrome
parent224e723f497c53daa28657b8bfb98d45b8fc1d78 (diff)
downloadchromium_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.cc30
-rw-r--r--chrome/renderer/form_manager_unittest.cc217
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