• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
AutofillRendererTest()44   AutofillRendererTest() {}
~AutofillRendererTest()45   virtual ~AutofillRendererTest() {}
46 
47  protected:
SetUp()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 
TEST_F(AutofillRendererTest,SendForms)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@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@example.com");
160   EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[2]);
161 }
162 
TEST_F(AutofillRendererTest,EnsureNoFormSeenIfTooFewFields)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 
TEST_F(AutofillRendererTest,ShowAutofillWarning)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 ].
TEST_F(AutofillRendererTest,DontCrashWhileAssociatingForms)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:
RequestAutocompleteRendererTest()242   RequestAutocompleteRendererTest()
243       : invoking_frame_(NULL), sibling_frame_(NULL) {}
~RequestAutocompleteRendererTest()244   virtual ~RequestAutocompleteRendererTest() {}
245 
246  protected:
SetUp()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 
TearDown()287   virtual void TearDown() OVERRIDE {
288     invoking_form_.reset();
289     AutofillRendererTest::TearDown();
290   }
291 
NavigateFrame(WebFrame * frame)292   void NavigateFrame(WebFrame* frame) {
293     frame->loadRequest(WebURLRequest(GURL("about:blank")));
294     ProcessPendingMessages();
295   }
296 
invoking_form() const297   const WebFormElement& invoking_form() const { return invoking_form_; }
invoking_frame()298   WebLocalFrame* invoking_frame() { return invoking_frame_; }
sibling_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 
TEST_F(RequestAutocompleteRendererTest,SiblingNavigateIgnored)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 
TEST_F(RequestAutocompleteRendererTest,SubframeNavigateCancels)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 
TEST_F(RequestAutocompleteRendererTest,MainFrameNavigateCancels)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 
TEST_F(RequestAutocompleteRendererTest,NoCancelOnSubframeNavigateAfterDone)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 
TEST_F(RequestAutocompleteRendererTest,NoCancelOnMainFrameNavigateAfterDone)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 
TEST_F(RequestAutocompleteRendererTest,InvokingTwiceOnlyShowsOnce)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