Home | History | Annotate | Download | only in autofill
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/command_line.h"
      6 #include "base/strings/stringprintf.h"
      7 #include "base/strings/utf_string_conversions.h"
      8 #include "chrome/test/base/chrome_render_view_test.h"
      9 #include "components/autofill/content/common/autofill_messages.h"
     10 #include "components/autofill/content/renderer/autofill_agent.h"
     11 #include "components/autofill/core/common/form_data.h"
     12 #include "components/autofill/core/common/form_field_data.h"
     13 #include "content/public/common/content_switches.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 #include "third_party/WebKit/public/platform/WebString.h"
     16 #include "third_party/WebKit/public/platform/WebURLRequest.h"
     17 #include "third_party/WebKit/public/platform/WebVector.h"
     18 #include "third_party/WebKit/public/web/WebDocument.h"
     19 #include "third_party/WebKit/public/web/WebFormElement.h"
     20 #include "third_party/WebKit/public/web/WebInputElement.h"
     21 #include "third_party/WebKit/public/web/WebLocalFrame.h"
     22 
     23 using base::ASCIIToUTF16;
     24 using blink::WebDocument;
     25 using blink::WebElement;
     26 using blink::WebFormElement;
     27 using blink::WebFrame;
     28 using blink::WebLocalFrame;
     29 using blink::WebInputElement;
     30 using blink::WebString;
     31 using blink::WebURLRequest;
     32 using blink::WebVector;
     33 
     34 namespace autofill {
     35 
     36 typedef Tuple5<int,
     37                autofill::FormData,
     38                autofill::FormFieldData,
     39                gfx::RectF,
     40                bool> AutofillQueryParam;
     41 
     42 class AutofillRendererTest : public ChromeRenderViewTest {
     43  public:
     44   AutofillRendererTest() {}
     45   virtual ~AutofillRendererTest() {}
     46 
     47  protected:
     48   virtual void SetUp() OVERRIDE {
     49     ChromeRenderViewTest::SetUp();
     50 
     51     // Don't want any delay for form state sync changes. This will still post a
     52     // message so updates will get coalesced, but as soon as we spin the message
     53     // loop, it will generate an update.
     54     SendContentStateImmediately();
     55   }
     56 
     57  private:
     58   DISALLOW_COPY_AND_ASSIGN(AutofillRendererTest);
     59 };
     60 
     61 TEST_F(AutofillRendererTest, SendForms) {
     62   LoadHTML("<form method=\"POST\">"
     63            "  <input type=\"text\" id=\"firstname\"/>"
     64            "  <input type=\"text\" id=\"middlename\"/>"
     65            "  <input type=\"text\" id=\"lastname\" autoComplete=\"off\"/>"
     66            "  <input type=\"hidden\" id=\"email\"/>"
     67            "  <select id=\"state\"/>"
     68            "    <option>?</option>"
     69            "    <option>California</option>"
     70            "    <option>Texas</option>"
     71            "  </select>"
     72            "</form>");
     73 
     74   // Verify that "FormsSeen" sends the expected number of fields.
     75   const IPC::Message* message = render_thread_->sink().GetFirstMessageMatching(
     76       AutofillHostMsg_FormsSeen::ID);
     77   ASSERT_NE(static_cast<IPC::Message*>(NULL), message);
     78   AutofillHostMsg_FormsSeen::Param params;
     79   AutofillHostMsg_FormsSeen::Read(message, &params);
     80   std::vector<FormData> forms = params.a;
     81   ASSERT_EQ(1UL, forms.size());
     82   ASSERT_EQ(4UL, forms[0].fields.size());
     83 
     84   FormFieldData expected;
     85 
     86   expected.name = ASCIIToUTF16("firstname");
     87   expected.value = base::string16();
     88   expected.form_control_type = "text";
     89   expected.max_length = WebInputElement::defaultMaxLength();
     90   EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[0]);
     91 
     92   expected.name = ASCIIToUTF16("middlename");
     93   expected.value = base::string16();
     94   expected.form_control_type = "text";
     95   expected.max_length = WebInputElement::defaultMaxLength();
     96   EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[1]);
     97 
     98   expected.name = ASCIIToUTF16("lastname");
     99   expected.value = base::string16();
    100   expected.form_control_type = "text";
    101   expected.autocomplete_attribute = "off";
    102   expected.max_length = WebInputElement::defaultMaxLength();
    103   EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[2]);
    104   expected.autocomplete_attribute = std::string();  // reset
    105 
    106   expected.name = ASCIIToUTF16("state");
    107   expected.value = ASCIIToUTF16("?");
    108   expected.form_control_type = "select-one";
    109   expected.max_length = 0;
    110   EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[3]);
    111 
    112   render_thread_->sink().ClearMessages();
    113 
    114   // Dynamically create a new form. A new message should be sent for it, but
    115   // not for the previous form.
    116   ExecuteJavaScript(
    117       "var newForm=document.createElement('form');"
    118       "newForm.id='new_testform';"
    119       "newForm.action='http://google.com';"
    120       "newForm.method='post';"
    121       "var newFirstname=document.createElement('input');"
    122       "newFirstname.setAttribute('type', 'text');"
    123       "newFirstname.setAttribute('id', 'second_firstname');"
    124       "newFirstname.value = 'Bob';"
    125       "var newLastname=document.createElement('input');"
    126       "newLastname.setAttribute('type', 'text');"
    127       "newLastname.setAttribute('id', 'second_lastname');"
    128       "newLastname.value = 'Hope';"
    129       "var newEmail=document.createElement('input');"
    130       "newEmail.setAttribute('type', 'text');"
    131       "newEmail.setAttribute('id', 'second_email');"
    132       "newEmail.value = 'bobhope (at) example.com';"
    133       "newForm.appendChild(newFirstname);"
    134       "newForm.appendChild(newLastname);"
    135       "newForm.appendChild(newEmail);"
    136       "document.body.appendChild(newForm);");
    137   msg_loop_.RunUntilIdle();
    138 
    139   message = render_thread_->sink().GetFirstMessageMatching(
    140       AutofillHostMsg_FormsSeen::ID);
    141   ASSERT_NE(static_cast<IPC::Message*>(NULL), message);
    142   AutofillHostMsg_FormsSeen::Read(message, &params);
    143   forms = params.a;
    144   ASSERT_EQ(1UL, forms.size());
    145   ASSERT_EQ(3UL, forms[0].fields.size());
    146 
    147   expected.form_control_type = "text";
    148   expected.max_length = WebInputElement::defaultMaxLength();
    149 
    150   expected.name = ASCIIToUTF16("second_firstname");
    151   expected.value = ASCIIToUTF16("Bob");
    152   EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[0]);
    153 
    154   expected.name = ASCIIToUTF16("second_lastname");
    155   expected.value = ASCIIToUTF16("Hope");
    156   EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[1]);
    157 
    158   expected.name = ASCIIToUTF16("second_email");
    159   expected.value = ASCIIToUTF16("bobhope (at) example.com");
    160   EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[2]);
    161 }
    162 
    163 TEST_F(AutofillRendererTest, EnsureNoFormSeenIfTooFewFields) {
    164   LoadHTML("<form method=\"POST\">"
    165            "  <input type=\"text\" id=\"firstname\"/>"
    166            "  <input type=\"text\" id=\"middlename\"/>"
    167            "</form>");
    168 
    169   // Verify that "FormsSeen" isn't sent, as there are too few fields.
    170   const IPC::Message* message = render_thread_->sink().GetFirstMessageMatching(
    171       AutofillHostMsg_FormsSeen::ID);
    172   ASSERT_NE(static_cast<IPC::Message*>(NULL), message);
    173   AutofillHostMsg_FormsSeen::Param params;
    174   AutofillHostMsg_FormsSeen::Read(message, &params);
    175   const std::vector<FormData>& forms = params.a;
    176   ASSERT_EQ(0UL, forms.size());
    177 }
    178 
    179 TEST_F(AutofillRendererTest, ShowAutofillWarning) {
    180   LoadHTML("<form method=\"POST\" autocomplete=\"Off\">"
    181            "  <input id=\"firstname\" autocomplete=\"OFF\"/>"
    182            "  <input id=\"middlename\"/>"
    183            "  <input id=\"lastname\"/>"
    184            "</form>");
    185 
    186   // Verify that "QueryFormFieldAutofill" isn't sent prior to a user
    187   // interaction.
    188   const IPC::Message* message0 = render_thread_->sink().GetFirstMessageMatching(
    189       AutofillHostMsg_QueryFormFieldAutofill::ID);
    190   EXPECT_EQ(static_cast<IPC::Message*>(NULL), message0);
    191 
    192   WebFrame* web_frame = GetMainFrame();
    193   WebDocument document = web_frame->document();
    194   WebInputElement firstname =
    195       document.getElementById("firstname").to<WebInputElement>();
    196   WebInputElement middlename =
    197       document.getElementById("middlename").to<WebInputElement>();
    198 
    199   // Simulate attempting to Autofill the form from the first element, which
    200   // specifies autocomplete="off".  This should still trigger an IPC which
    201   // shouldn't display warnings.
    202   autofill_agent_->FormControlElementClicked(firstname, true);
    203   const IPC::Message* message1 = render_thread_->sink().GetFirstMessageMatching(
    204       AutofillHostMsg_QueryFormFieldAutofill::ID);
    205   EXPECT_NE(static_cast<IPC::Message*>(NULL), message1);
    206 
    207   AutofillQueryParam query_param;
    208   AutofillHostMsg_QueryFormFieldAutofill::Read(message1, &query_param);
    209   EXPECT_FALSE(query_param.e);
    210   render_thread_->sink().ClearMessages();
    211 
    212   // Simulate attempting to Autofill the form from the second element, which
    213   // does not specify autocomplete="off".  This should trigger an IPC that will
    214   // show warnings, as we *do* show warnings for elements that don't themselves
    215   // set autocomplete="off", but for which the form does.
    216   autofill_agent_->FormControlElementClicked(middlename, true);
    217   const IPC::Message* message2 = render_thread_->sink().GetFirstMessageMatching(
    218       AutofillHostMsg_QueryFormFieldAutofill::ID);
    219   ASSERT_NE(static_cast<IPC::Message*>(NULL), message2);
    220 
    221   AutofillHostMsg_QueryFormFieldAutofill::Read(message2, &query_param);
    222   EXPECT_TRUE(query_param.e);
    223 }
    224 
    225 // Regression test for [ http://crbug.com/346010 ].
    226 TEST_F(AutofillRendererTest, DontCrashWhileAssociatingForms) {
    227   LoadHTML("<form id='form'>"
    228            "<foo id='foo'>"
    229            "<script id='script'>"
    230            "document.documentElement.appendChild(foo);"
    231            "newDoc = document.implementation.createDocument("
    232            "    \"http://www.w3.org/1999/xhtml\", \"html\");"
    233            "foo.insertBefore(form, script);"
    234            "newDoc.adoptNode(foo);"
    235            "</script>");
    236 
    237   // Shouldn't crash.
    238 }
    239 
    240 class RequestAutocompleteRendererTest : public AutofillRendererTest {
    241  public:
    242   RequestAutocompleteRendererTest()
    243       : invoking_frame_(NULL), sibling_frame_(NULL) {}
    244   virtual ~RequestAutocompleteRendererTest() {}
    245 
    246  protected:
    247   virtual void SetUp() OVERRIDE {
    248     AutofillRendererTest::SetUp();
    249 
    250     // Bypass the HTTPS-only restriction to show requestAutocomplete.
    251     CommandLine* command_line = CommandLine::ForCurrentProcess();
    252     command_line->AppendSwitch(::switches::kReduceSecurityForTesting);
    253 
    254     GURL url("data:text/html;charset=utf-8,"
    255              "<form><input autocomplete=cc-number></form>");
    256     const char kDoubleIframeHtml[] = "<iframe id=subframe src=\"%s\"></iframe>"
    257                                      "<iframe id=sibling></iframe>";
    258     LoadHTML(base::StringPrintf(kDoubleIframeHtml, url.spec().c_str()).c_str());
    259 
    260     WebElement subframe = GetMainFrame()->document().getElementById("subframe");
    261     ASSERT_FALSE(subframe.isNull());
    262     invoking_frame_ = WebLocalFrame::fromFrameOwnerElement(subframe);
    263     ASSERT_TRUE(invoking_frame());
    264     ASSERT_EQ(GetMainFrame(), invoking_frame()->parent());
    265 
    266     WebElement sibling = GetMainFrame()->document().getElementById("sibling");
    267     ASSERT_FALSE(sibling.isNull());
    268     sibling_frame_ = WebLocalFrame::fromFrameOwnerElement(sibling);
    269     ASSERT_TRUE(sibling_frame());
    270 
    271     WebVector<WebFormElement> forms;
    272     invoking_frame()->document().forms(forms);
    273     ASSERT_EQ(1U, forms.size());
    274     invoking_form_ = forms[0];
    275     ASSERT_FALSE(invoking_form().isNull());
    276 
    277     render_thread_->sink().ClearMessages();
    278 
    279     // Invoke requestAutocomplete to show the dialog.
    280     autofill_agent_->didRequestAutocomplete(invoking_form());
    281     ASSERT_TRUE(render_thread_->sink().GetFirstMessageMatching(
    282         AutofillHostMsg_RequestAutocomplete::ID));
    283 
    284     render_thread_->sink().ClearMessages();
    285   }
    286 
    287   virtual void TearDown() OVERRIDE {
    288     invoking_form_.reset();
    289     AutofillRendererTest::TearDown();
    290   }
    291 
    292   void NavigateFrame(WebFrame* frame) {
    293     frame->loadRequest(WebURLRequest(GURL("about:blank")));
    294     ProcessPendingMessages();
    295   }
    296 
    297   const WebFormElement& invoking_form() const { return invoking_form_; }
    298   WebLocalFrame* invoking_frame() { return invoking_frame_; }
    299   WebFrame* sibling_frame() { return sibling_frame_; }
    300 
    301  private:
    302   WebFormElement invoking_form_;
    303   WebLocalFrame* invoking_frame_;
    304   WebFrame* sibling_frame_;
    305 
    306   DISALLOW_COPY_AND_ASSIGN(RequestAutocompleteRendererTest);
    307 };
    308 
    309 TEST_F(RequestAutocompleteRendererTest, SiblingNavigateIgnored) {
    310   // Pretend that a sibling frame navigated. No cancel should be sent.
    311   NavigateFrame(sibling_frame());
    312   EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
    313       AutofillHostMsg_CancelRequestAutocomplete::ID));
    314 }
    315 
    316 TEST_F(RequestAutocompleteRendererTest, SubframeNavigateCancels) {
    317   // Pretend that the invoking frame navigated. A cancel should be sent.
    318   NavigateFrame(invoking_frame());
    319   EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching(
    320       AutofillHostMsg_CancelRequestAutocomplete::ID));
    321 }
    322 
    323 TEST_F(RequestAutocompleteRendererTest, MainFrameNavigateCancels) {
    324   // Pretend that the top-level frame navigated. A cancel should be sent.
    325   NavigateFrame(GetMainFrame());
    326   EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching(
    327       AutofillHostMsg_CancelRequestAutocomplete::ID));
    328 }
    329 
    330 TEST_F(RequestAutocompleteRendererTest, NoCancelOnSubframeNavigateAfterDone) {
    331   // Pretend that the dialog was cancelled.
    332   autofill_agent_->OnRequestAutocompleteResult(
    333       WebFormElement::AutocompleteResultErrorCancel,
    334       base::ASCIIToUTF16("Print me to the console"),
    335       FormData());
    336 
    337   // Additional navigations should not crash nor send cancels.
    338   NavigateFrame(invoking_frame());
    339   EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
    340       AutofillHostMsg_CancelRequestAutocomplete::ID));
    341 }
    342 
    343 TEST_F(RequestAutocompleteRendererTest, NoCancelOnMainFrameNavigateAfterDone) {
    344   // Pretend that the dialog was cancelled.
    345   autofill_agent_->OnRequestAutocompleteResult(
    346       WebFormElement::AutocompleteResultErrorCancel,
    347       base::ASCIIToUTF16("Print me to the console"),
    348       FormData());
    349 
    350   // Additional navigations should not crash nor send cancels.
    351   NavigateFrame(GetMainFrame());
    352   EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
    353       AutofillHostMsg_CancelRequestAutocomplete::ID));
    354 }
    355 
    356 TEST_F(RequestAutocompleteRendererTest, InvokingTwiceOnlyShowsOnce) {
    357   // Attempting to show the requestAutocomplete dialog again should be ignored.
    358   autofill_agent_->didRequestAutocomplete(invoking_form());
    359   EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
    360       AutofillHostMsg_RequestAutocomplete::ID));
    361 }
    362 
    363 }  // namespace autofill
    364