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 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 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, ¶ms); 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 (at) 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, ¶ms); 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 (at) example.com"); 168 EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[2]); 169 } 170 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, ¶ms); 183 const std::vector<FormData>& forms = params.a; 184 ASSERT_EQ(0UL, forms.size()); 185 } 186 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 ]. 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: 252 RequestAutocompleteRendererTest() 253 : invoking_frame_(NULL), sibling_frame_(NULL) {} 254 virtual ~RequestAutocompleteRendererTest() {} 255 256 protected: 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 298 virtual void TearDown() OVERRIDE { 299 invoking_form_.reset(); 300 AutofillRendererTest::TearDown(); 301 } 302 303 void NavigateFrame(WebFrame* frame) { 304 frame->loadRequest(WebURLRequest(GURL("about:blank"))); 305 ProcessPendingMessages(); 306 } 307 308 const WebFormElement& invoking_form() const { return invoking_form_; } 309 WebLocalFrame* invoking_frame() { return invoking_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 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 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 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 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 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 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