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