Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(103)

Side by Side Diff: components/autofill/content/renderer/password_autofill_agent.cc

Issue 231283003: Password manager: introduce logging for the internals page (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Comments addressed Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/autofill/content/renderer/password_autofill_agent.h" 5 #include "components/autofill/content/renderer/password_autofill_agent.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/memory/scoped_ptr.h" 8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h" 9 #include "base/message_loop/message_loop.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
11 #include "base/strings/utf_string_conversions.h" 11 #include "base/strings/utf_string_conversions.h"
12 #include "components/autofill/content/common/autofill_messages.h" 12 #include "components/autofill/content/common/autofill_messages.h"
13 #include "components/autofill/content/renderer/form_autofill_util.h" 13 #include "components/autofill/content/renderer/form_autofill_util.h"
14 #include "components/autofill/content/renderer/password_form_conversion_utils.h" 14 #include "components/autofill/content/renderer/password_form_conversion_utils.h"
15 #include "components/autofill/content/renderer/renderer_save_password_progress_l ogger.h"
15 #include "components/autofill/core/common/form_field_data.h" 16 #include "components/autofill/core/common/form_field_data.h"
16 #include "components/autofill/core/common/password_autofill_util.h" 17 #include "components/autofill/core/common/password_autofill_util.h"
17 #include "components/autofill/core/common/password_form.h" 18 #include "components/autofill/core/common/password_form.h"
18 #include "components/autofill/core/common/password_form_fill_data.h" 19 #include "components/autofill/core/common/password_form_fill_data.h"
19 #include "content/public/renderer/render_view.h" 20 #include "content/public/renderer/render_view.h"
20 #include "third_party/WebKit/public/platform/WebVector.h" 21 #include "third_party/WebKit/public/platform/WebVector.h"
21 #include "third_party/WebKit/public/web/WebAutofillClient.h" 22 #include "third_party/WebKit/public/web/WebAutofillClient.h"
22 #include "third_party/WebKit/public/web/WebDocument.h" 23 #include "third_party/WebKit/public/web/WebDocument.h"
23 #include "third_party/WebKit/public/web/WebElement.h" 24 #include "third_party/WebKit/public/web/WebElement.h"
24 #include "third_party/WebKit/public/web/WebFormElement.h" 25 #include "third_party/WebKit/public/web/WebFormElement.h"
25 #include "third_party/WebKit/public/web/WebInputEvent.h" 26 #include "third_party/WebKit/public/web/WebInputEvent.h"
26 #include "third_party/WebKit/public/web/WebLocalFrame.h" 27 #include "third_party/WebKit/public/web/WebLocalFrame.h"
27 #include "third_party/WebKit/public/web/WebNode.h" 28 #include "third_party/WebKit/public/web/WebNode.h"
28 #include "third_party/WebKit/public/web/WebNodeList.h" 29 #include "third_party/WebKit/public/web/WebNodeList.h"
29 #include "third_party/WebKit/public/web/WebPasswordFormData.h" 30 #include "third_party/WebKit/public/web/WebPasswordFormData.h"
30 #include "third_party/WebKit/public/web/WebSecurityOrigin.h" 31 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
31 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h" 32 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
32 #include "third_party/WebKit/public/web/WebView.h" 33 #include "third_party/WebKit/public/web/WebView.h"
33 #include "ui/events/keycodes/keyboard_codes.h" 34 #include "ui/events/keycodes/keyboard_codes.h"
35 #include "url/gurl.h"
34 36
35 namespace autofill { 37 namespace autofill {
36 namespace { 38 namespace {
37 39
38 // The size above which we stop triggering autocomplete. 40 // The size above which we stop triggering autocomplete.
39 static const size_t kMaximumTextSizeForAutocomplete = 1000; 41 static const size_t kMaximumTextSizeForAutocomplete = 1000;
40 42
41 // Maps element names to the actual elements to simplify form filling. 43 // Maps element names to the actual elements to simplify form filling.
42 typedef std::map<base::string16, blink::WebInputElement> 44 typedef std::map<base::string16, blink::WebInputElement> FormInputElementMap;
43 FormInputElementMap; 45
46 // Shorten the name to spare line breaks. The code provides enough context
47 // already.
48 typedef SavePasswordProgressLogger Logger;
44 49
45 // Utility struct for form lookup and autofill. When we parse the DOM to look up 50 // Utility struct for form lookup and autofill. When we parse the DOM to look up
46 // a form, in addition to action and origin URL's we have to compare all 51 // a form, in addition to action and origin URL's we have to compare all
47 // necessary form elements. To avoid having to look these up again when we want 52 // necessary form elements. To avoid having to look these up again when we want
48 // to fill the form, the FindFormElements function stores the pointers 53 // to fill the form, the FindFormElements function stores the pointers
49 // in a FormElements* result, referenced to ensure they are safe to use. 54 // in a FormElements* result, referenced to ensure they are safe to use.
50 struct FormElements { 55 struct FormElements {
51 blink::WebFormElement form_element; 56 blink::WebFormElement form_element;
52 FormInputElementMap input_elements; 57 FormInputElementMap input_elements;
53 }; 58 };
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 // appropriately named elements match the element to be saved. Currently 199 // appropriately named elements match the element to be saved. Currently
195 // we ignore filling passwords where naming is ambigious anyway. 200 // we ignore filling passwords where naming is ambigious anyway.
196 for (size_t i = 0; i < temp_elements.size(); ++i) { 201 for (size_t i = 0; i < temp_elements.size(); ++i) {
197 if (temp_elements[i].to<blink::WebElement>().getAttribute("value") == 202 if (temp_elements[i].to<blink::WebElement>().getAttribute("value") ==
198 form.password_value) 203 form.password_value)
199 return true; 204 return true;
200 } 205 }
201 return false; 206 return false;
202 } 207 }
203 208
209 // Log a message including the name, method and action of |form|.
210 void LogHTMLForm(Logger* logger,
Ilya Sherman 2014/04/23 20:21:44 Optional nit: I'd prefer to still use the full cla
vabr (Chromium) 2014/04/24 10:59:27 Sounds reasonable. I changed this and checked that
211 Logger::StringID message_id,
212 const blink::WebFormElement& form) {
213 logger->LogHTMLForm(message_id,
214 form.name().utf8(),
215 form.method().utf8(),
216 GURL(form.action().utf8()));
217 }
218
204 } // namespace 219 } // namespace
205 220
206 //////////////////////////////////////////////////////////////////////////////// 221 ////////////////////////////////////////////////////////////////////////////////
207 // PasswordAutofillAgent, public: 222 // PasswordAutofillAgent, public:
208 223
209 PasswordAutofillAgent::PasswordAutofillAgent(content::RenderView* render_view) 224 PasswordAutofillAgent::PasswordAutofillAgent(content::RenderView* render_view)
210 : content::RenderViewObserver(render_view), 225 : content::RenderViewObserver(render_view),
211 usernames_usage_(NOTHING_TO_AUTOFILL), 226 usernames_usage_(NOTHING_TO_AUTOFILL),
212 web_view_(render_view->GetWebView()), 227 web_view_(render_view->GetWebView()),
228 logging_state_active_(false),
213 weak_ptr_factory_(this) { 229 weak_ptr_factory_(this) {
214 } 230 }
215 231
216 PasswordAutofillAgent::~PasswordAutofillAgent() {} 232 PasswordAutofillAgent::~PasswordAutofillAgent() {
233 }
217 234
218 PasswordAutofillAgent::PasswordValueGatekeeper::PasswordValueGatekeeper() 235 PasswordAutofillAgent::PasswordValueGatekeeper::PasswordValueGatekeeper()
219 : was_user_gesture_seen_(false) {} 236 : was_user_gesture_seen_(false) {
237 }
220 238
221 PasswordAutofillAgent::PasswordValueGatekeeper::~PasswordValueGatekeeper() {} 239 PasswordAutofillAgent::PasswordValueGatekeeper::~PasswordValueGatekeeper() {
240 }
222 241
223 void PasswordAutofillAgent::PasswordValueGatekeeper::RegisterElement( 242 void PasswordAutofillAgent::PasswordValueGatekeeper::RegisterElement(
224 blink::WebInputElement* element) { 243 blink::WebInputElement* element) {
225 if (was_user_gesture_seen_) 244 if (was_user_gesture_seen_)
226 ShowValue(element); 245 ShowValue(element);
227 else 246 else
228 elements_.push_back(*element); 247 elements_.push_back(*element);
229 } 248 }
230 249
231 void PasswordAutofillAgent::PasswordValueGatekeeper::OnUserGesture() { 250 void PasswordAutofillAgent::PasswordValueGatekeeper::OnUserGesture() {
(...skipping 19 matching lines...) Expand all
251 element->setValue(element->suggestedValue(), true); 270 element->setValue(element->suggestedValue(), true);
252 } 271 }
253 272
254 bool PasswordAutofillAgent::TextFieldDidEndEditing( 273 bool PasswordAutofillAgent::TextFieldDidEndEditing(
255 const blink::WebInputElement& element) { 274 const blink::WebInputElement& element) {
256 LoginToPasswordInfoMap::const_iterator iter = 275 LoginToPasswordInfoMap::const_iterator iter =
257 login_to_password_info_.find(element); 276 login_to_password_info_.find(element);
258 if (iter == login_to_password_info_.end()) 277 if (iter == login_to_password_info_.end())
259 return false; 278 return false;
260 279
261 const PasswordFormFillData& fill_data = 280 const PasswordFormFillData& fill_data = iter->second.fill_data;
Ilya Sherman 2014/04/23 20:21:44 The clang-format changes look fine, but I'd prefer
vabr (Chromium) 2014/04/24 10:59:27 Done as https://codereview.chromium.org/254573005/
262 iter->second.fill_data;
263 281
264 // If wait_for_username is false, we should have filled when the text changed. 282 // If wait_for_username is false, we should have filled when the text changed.
265 if (!fill_data.wait_for_username) 283 if (!fill_data.wait_for_username)
266 return false; 284 return false;
267 285
268 blink::WebInputElement password = iter->second.password_field; 286 blink::WebInputElement password = iter->second.password_field;
269 if (!IsElementEditable(password)) 287 if (!IsElementEditable(password))
270 return false; 288 return false;
271 289
272 blink::WebInputElement username = element; // We need a non-const. 290 blink::WebInputElement username = element; // We need a non-const.
273 291
274 // Do not set selection when ending an editing session, otherwise it can 292 // Do not set selection when ending an editing session, otherwise it can
275 // mess with focus. 293 // mess with focus.
276 FillUserNameAndPassword(&username, &password, fill_data, 294 FillUserNameAndPassword(&username,
295 &password,
296 fill_data,
277 true /* exact_username_match */, 297 true /* exact_username_match */,
278 false /* set_selection */); 298 false /* set_selection */);
279 return true; 299 return true;
280 } 300 }
281 301
282 bool PasswordAutofillAgent::TextDidChangeInTextField( 302 bool PasswordAutofillAgent::TextDidChangeInTextField(
283 const blink::WebInputElement& element) { 303 const blink::WebInputElement& element) {
284 LoginToPasswordInfoMap::const_iterator iter = 304 LoginToPasswordInfoMap::const_iterator iter =
285 login_to_password_info_.find(element); 305 login_to_password_info_.find(element);
286 if (iter == login_to_password_info_.end()) 306 if (iter == login_to_password_info_.end())
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 const blink::WebNode& node, 368 const blink::WebNode& node,
349 const blink::WebString& username) { 369 const blink::WebString& username) {
350 blink::WebInputElement input; 370 blink::WebInputElement input;
351 PasswordInfo password; 371 PasswordInfo password;
352 if (!FindLoginInfo(node, &input, &password)) 372 if (!FindLoginInfo(node, &input, &password))
353 return false; 373 return false;
354 374
355 // Set the incoming |username| in the text field and |FillUserNameAndPassword| 375 // Set the incoming |username| in the text field and |FillUserNameAndPassword|
356 // will do the rest. 376 // will do the rest.
357 input.setValue(username, true); 377 input.setValue(username, true);
358 return FillUserNameAndPassword(&input, &password.password_field, 378 return FillUserNameAndPassword(&input,
379 &password.password_field,
359 password.fill_data, 380 password.fill_data,
360 true /* exact_username_match */, 381 true /* exact_username_match */,
361 true /* set_selection */); 382 true /* set_selection */);
362 } 383 }
363 384
364 bool PasswordAutofillAgent::DidClearAutofillSelection( 385 bool PasswordAutofillAgent::DidClearAutofillSelection(
365 const blink::WebNode& node) { 386 const blink::WebNode& node) {
366 blink::WebInputElement input; 387 blink::WebInputElement input;
367 PasswordInfo password; 388 PasswordInfo password;
368 return FindLoginInfo(node, &input, &password); 389 return FindLoginInfo(node, &input, &password);
(...skipping 25 matching lines...) Expand all
394 void PasswordAutofillAgent::OnDynamicFormsSeen(blink::WebFrame* frame) { 415 void PasswordAutofillAgent::OnDynamicFormsSeen(blink::WebFrame* frame) {
395 SendPasswordForms(frame, false /* only_visible */); 416 SendPasswordForms(frame, false /* only_visible */);
396 } 417 }
397 418
398 void PasswordAutofillAgent::FirstUserGestureObserved() { 419 void PasswordAutofillAgent::FirstUserGestureObserved() {
399 gatekeeper_.OnUserGesture(); 420 gatekeeper_.OnUserGesture();
400 } 421 }
401 422
402 void PasswordAutofillAgent::SendPasswordForms(blink::WebFrame* frame, 423 void PasswordAutofillAgent::SendPasswordForms(blink::WebFrame* frame,
403 bool only_visible) { 424 bool only_visible) {
425 scoped_ptr<RendererSavePasswordProgressLogger> logger;
426 // From the perspective of saving passwords, only calls with |only_visible|
427 // being true are important -- the decision whether to save the password is
428 // only made after visible forms are known, for failed login detection. Calls
429 // with |only_visible| false are important for password form autofill, which
430 // is currently not part of the logging.
431 if (only_visible && logging_state_active_) {
432 logger.reset(new RendererSavePasswordProgressLogger(this, routing_id()));
433 logger->LogMessage(Logger::STRING_SEND_PASSWORD_FORMS_METHOD);
434 }
435
404 // Make sure that this security origin is allowed to use password manager. 436 // Make sure that this security origin is allowed to use password manager.
405 blink::WebSecurityOrigin origin = frame->document().securityOrigin(); 437 blink::WebSecurityOrigin origin = frame->document().securityOrigin();
406 if (!OriginCanAccessPasswordManager(origin)) 438 if (logger) {
439 logger->LogURL(Logger::STRING_SECURITY_ORIGIN,
440 GURL(origin.toString().utf8()));
441 }
442 if (!OriginCanAccessPasswordManager(origin)) {
443 if (logger) {
444 logger->LogMessage(Logger::STRING_SECURITY_ORIGIN_FAILURE);
445 logger->LogMessage(Logger::STRING_DECISION_DROP);
446 }
407 return; 447 return;
448 }
408 449
409 // Checks whether the webpage is a redirect page or an empty page. 450 // Checks whether the webpage is a redirect page or an empty page.
410 if (IsWebpageEmpty(frame)) 451 if (IsWebpageEmpty(frame)) {
452 if (logger) {
453 logger->LogMessage(Logger::STRING_WEBPAGE_EMPTY);
454 logger->LogMessage(Logger::STRING_DECISION_DROP);
455 }
411 return; 456 return;
457 }
412 458
413 blink::WebVector<blink::WebFormElement> forms; 459 blink::WebVector<blink::WebFormElement> forms;
414 frame->document().forms(forms); 460 frame->document().forms(forms);
461 if (logger)
462 logger->LogNumber(Logger::STRING_NUMBER_OF_ALL_FORMS, forms.size());
415 463
416 std::vector<PasswordForm> password_forms; 464 std::vector<PasswordForm> password_forms;
417 for (size_t i = 0; i < forms.size(); ++i) { 465 for (size_t i = 0; i < forms.size(); ++i) {
418 const blink::WebFormElement& form = forms[i]; 466 const blink::WebFormElement& form = forms[i];
467 bool is_form_visible = IsWebNodeVisible(form);
468 if (logger) {
469 LogHTMLForm(logger.get(), Logger::STRING_FORM_FOUND_ON_PAGE, form);
470 logger->LogBoolean(Logger::STRING_FORM_IS_VISIBLE, is_form_visible);
471 }
419 472
420 // If requested, ignore non-rendered forms, e.g. those styled with 473 // If requested, ignore non-rendered forms, e.g. those styled with
421 // display:none. 474 // display:none.
422 if (only_visible && !IsWebNodeVisible(form)) 475 if (only_visible && !is_form_visible)
423 continue; 476 continue;
424 477
425 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); 478 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form));
426 if (password_form.get()) 479 if (password_form.get()) {
480 if (logger) {
481 logger->LogPasswordForm(Logger::STRING_FORM_IS_PASSWORD,
482 *password_form);
483 }
427 password_forms.push_back(*password_form); 484 password_forms.push_back(*password_form);
485 }
428 } 486 }
429 487
430 if (password_forms.empty() && !only_visible) { 488 if (password_forms.empty() && !only_visible) {
431 // We need to send the PasswordFormsRendered message regardless of whether 489 // We need to send the PasswordFormsRendered message regardless of whether
432 // there are any forms visible, as this is also the code path that triggers 490 // there are any forms visible, as this is also the code path that triggers
433 // showing the infobar. 491 // showing the infobar.
434 return; 492 return;
435 } 493 }
436 494
437 if (only_visible) { 495 if (only_visible) {
438 Send(new AutofillHostMsg_PasswordFormsRendered(routing_id(), 496 Send(new AutofillHostMsg_PasswordFormsRendered(routing_id(),
439 password_forms)); 497 password_forms));
440 } else { 498 } else {
441 Send(new AutofillHostMsg_PasswordFormsParsed(routing_id(), password_forms)); 499 Send(new AutofillHostMsg_PasswordFormsParsed(routing_id(), password_forms));
442 } 500 }
443 } 501 }
444 502
445 bool PasswordAutofillAgent::OnMessageReceived(const IPC::Message& message) { 503 bool PasswordAutofillAgent::OnMessageReceived(const IPC::Message& message) {
446 bool handled = true; 504 bool handled = true;
447 IPC_BEGIN_MESSAGE_MAP(PasswordAutofillAgent, message) 505 IPC_BEGIN_MESSAGE_MAP(PasswordAutofillAgent, message)
448 IPC_MESSAGE_HANDLER(AutofillMsg_FillPasswordForm, OnFillPasswordForm) 506 IPC_MESSAGE_HANDLER(AutofillMsg_FillPasswordForm, OnFillPasswordForm)
507 IPC_MESSAGE_HANDLER(AutofillMsg_ChangeLoggingState, OnChangeLoggingState)
449 IPC_MESSAGE_UNHANDLED(handled = false) 508 IPC_MESSAGE_UNHANDLED(handled = false)
450 IPC_END_MESSAGE_MAP() 509 IPC_END_MESSAGE_MAP()
451 return handled; 510 return handled;
452 } 511 }
453 512
454 void PasswordAutofillAgent::DidStartLoading() { 513 void PasswordAutofillAgent::DidStartLoading() {
455 if (usernames_usage_ != NOTHING_TO_AUTOFILL) { 514 if (usernames_usage_ != NOTHING_TO_AUTOFILL) {
456 UMA_HISTOGRAM_ENUMERATION("PasswordManager.OtherPossibleUsernamesUsage", 515 UMA_HISTOGRAM_ENUMERATION("PasswordManager.OtherPossibleUsernamesUsage",
457 usernames_usage_, OTHER_POSSIBLE_USERNAMES_MAX); 516 usernames_usage_,
517 OTHER_POSSIBLE_USERNAMES_MAX);
458 usernames_usage_ = NOTHING_TO_AUTOFILL; 518 usernames_usage_ = NOTHING_TO_AUTOFILL;
459 } 519 }
460 } 520 }
461 521
462 void PasswordAutofillAgent::DidFinishDocumentLoad(blink::WebLocalFrame* frame) { 522 void PasswordAutofillAgent::DidFinishDocumentLoad(blink::WebLocalFrame* frame) {
463 // The |frame| contents have been parsed, but not yet rendered. Let the 523 // The |frame| contents have been parsed, but not yet rendered. Let the
464 // PasswordManager know that forms are loaded, even though we can't yet tell 524 // PasswordManager know that forms are loaded, even though we can't yet tell
465 // whether they're visible. 525 // whether they're visible.
466 SendPasswordForms(frame, false); 526 SendPasswordForms(frame, false);
467 } 527 }
(...skipping 21 matching lines...) Expand all
489 // into a hidden field and then clear the password (http://crbug.com/28910). 549 // into a hidden field and then clear the password (http://crbug.com/28910).
490 // This method gets called before any of those handlers run, so save away 550 // This method gets called before any of those handlers run, so save away
491 // a copy of the password in case it gets lost. 551 // a copy of the password in case it gets lost.
492 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); 552 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form));
493 if (password_form) 553 if (password_form)
494 provisionally_saved_forms_[frame].reset(password_form.release()); 554 provisionally_saved_forms_[frame].reset(password_form.release());
495 } 555 }
496 556
497 void PasswordAutofillAgent::WillSubmitForm(blink::WebLocalFrame* frame, 557 void PasswordAutofillAgent::WillSubmitForm(blink::WebLocalFrame* frame,
498 const blink::WebFormElement& form) { 558 const blink::WebFormElement& form) {
559 scoped_ptr<RendererSavePasswordProgressLogger> logger;
560 if (logging_state_active_) {
561 logger.reset(new RendererSavePasswordProgressLogger(this, routing_id()));
562 logger->LogMessage(Logger::STRING_WILL_SUBMIT_FORM_METHOD);
563 LogHTMLForm(logger.get(), Logger::STRING_HTML_FORM_FOR_SUBMIT, form);
564 }
565
499 scoped_ptr<PasswordForm> submitted_form = CreatePasswordForm(form); 566 scoped_ptr<PasswordForm> submitted_form = CreatePasswordForm(form);
500 567
501 // If there is a provisionally saved password, copy over the previous 568 // If there is a provisionally saved password, copy over the previous
502 // password value so we get the user's typed password, not the value that 569 // password value so we get the user's typed password, not the value that
503 // may have been transformed for submit. 570 // may have been transformed for submit.
504 // TODO(gcasto): Do we need to have this action equality check? Is it trying 571 // TODO(gcasto): Do we need to have this action equality check? Is it trying
505 // to prevent accidentally copying over passwords from a different form? 572 // to prevent accidentally copying over passwords from a different form?
506 if (submitted_form) { 573 if (submitted_form) {
574 if (logger) {
575 logger->LogPasswordForm(Logger::STRING_CREATED_PASSWORD_FORM,
576 *submitted_form);
577 }
507 if (provisionally_saved_forms_[frame].get() && 578 if (provisionally_saved_forms_[frame].get() &&
508 submitted_form->action == provisionally_saved_forms_[frame]->action) { 579 submitted_form->action == provisionally_saved_forms_[frame]->action) {
580 if (logger)
581 logger->LogMessage(Logger::STRING_SUBMITTED_PASSWORD_REPLACED);
509 submitted_form->password_value = 582 submitted_form->password_value =
510 provisionally_saved_forms_[frame]->password_value; 583 provisionally_saved_forms_[frame]->password_value;
511 } 584 }
512 585
513 // Some observers depend on sending this information now instead of when 586 // Some observers depend on sending this information now instead of when
514 // the frame starts loading. If there are redirects that cause a new 587 // the frame starts loading. If there are redirects that cause a new
515 // RenderView to be instantiated (such as redirects to the WebStore) 588 // RenderView to be instantiated (such as redirects to the WebStore)
516 // we will never get to finish the load. 589 // we will never get to finish the load.
517 Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(), 590 Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(),
518 *submitted_form)); 591 *submitted_form));
519 // Remove reference since we have already submitted this form. 592 // Remove reference since we have already submitted this form.
520 provisionally_saved_forms_.erase(frame); 593 provisionally_saved_forms_.erase(frame);
594 } else if (logger) {
595 logger->LogMessage(Logger::STRING_DECISION_DROP);
521 } 596 }
522 } 597 }
523 598
524 blink::WebFrame* PasswordAutofillAgent::CurrentOrChildFrameWithSavedForms( 599 blink::WebFrame* PasswordAutofillAgent::CurrentOrChildFrameWithSavedForms(
525 const blink::WebFrame* current_frame) { 600 const blink::WebFrame* current_frame) {
526 for (FrameToPasswordFormMap::const_iterator it = 601 for (FrameToPasswordFormMap::const_iterator it =
527 provisionally_saved_forms_.begin(); 602 provisionally_saved_forms_.begin();
528 it != provisionally_saved_forms_.end(); 603 it != provisionally_saved_forms_.end();
529 ++it) { 604 ++it) {
530 blink::WebFrame* form_frame = it->first; 605 blink::WebFrame* form_frame = it->first;
531 // The check that the returned frame is related to |current_frame| is mainly 606 // The check that the returned frame is related to |current_frame| is mainly
532 // for double-checking. There should not be any unrelated frames in 607 // for double-checking. There should not be any unrelated frames in
533 // |provisionally_saved_forms_|, because the map is cleared after 608 // |provisionally_saved_forms_|, because the map is cleared after
534 // navigation. If there are reasons to remove this check in the future and 609 // navigation. If there are reasons to remove this check in the future and
535 // keep just the first frame found, it might be a good idea to add a UMA 610 // keep just the first frame found, it might be a good idea to add a UMA
536 // statistic or a similar check on how many frames are here to choose from. 611 // statistic or a similar check on how many frames are here to choose from.
537 if (current_frame == form_frame || 612 if (current_frame == form_frame ||
538 current_frame->findChildByName(form_frame->assignedName())) { 613 current_frame->findChildByName(form_frame->assignedName())) {
539 return form_frame; 614 return form_frame;
540 } 615 }
541 } 616 }
542 return NULL; 617 return NULL;
543 } 618 }
544 619
545 void PasswordAutofillAgent::DidStartProvisionalLoad( 620 void PasswordAutofillAgent::DidStartProvisionalLoad(
546 blink::WebLocalFrame* frame) { 621 blink::WebLocalFrame* frame) {
622 scoped_ptr<RendererSavePasswordProgressLogger> logger;
623 if (logging_state_active_) {
624 logger.reset(new RendererSavePasswordProgressLogger(this, routing_id()));
625 logger->LogMessage(Logger::STRING_DID_START_PROVISIONAL_LOAD_METHOD);
626 }
627
547 if (!frame->parent()) { 628 if (!frame->parent()) {
548 // If the navigation is not triggered by a user gesture, e.g. by some ajax 629 // If the navigation is not triggered by a user gesture, e.g. by some ajax
549 // callback, then inherit the submitted password form from the previous 630 // callback, then inherit the submitted password form from the previous
550 // state. This fixes the no password save issue for ajax login, tracked in 631 // state. This fixes the no password save issue for ajax login, tracked in
551 // [http://crbug/43219]. Note that this still fails for sites that use 632 // [http://crbug/43219]. Note that this still fails for sites that use
552 // synchonous XHR as isProcessingUserGesture() will return true. 633 // synchonous XHR as isProcessingUserGesture() will return true.
553 blink::WebFrame* form_frame = CurrentOrChildFrameWithSavedForms(frame); 634 blink::WebFrame* form_frame = CurrentOrChildFrameWithSavedForms(frame);
635 if (logger) {
636 logger->LogBoolean(Logger::STRING_FORM_FRAME_EQ_FRAME,
637 form_frame == frame);
638 }
554 if (!blink::WebUserGestureIndicator::isProcessingUserGesture()) { 639 if (!blink::WebUserGestureIndicator::isProcessingUserGesture()) {
555 // If onsubmit has been called, try and save that form. 640 // If onsubmit has been called, try and save that form.
556 if (provisionally_saved_forms_[form_frame].get()) { 641 if (provisionally_saved_forms_[form_frame].get()) {
642 if (logger) {
643 logger->LogPasswordForm(
644 Logger::STRING_PROVISIONALLY_SAVED_FORM_FOR_FRAME,
645 *provisionally_saved_forms_[form_frame]);
646 }
557 Send(new AutofillHostMsg_PasswordFormSubmitted( 647 Send(new AutofillHostMsg_PasswordFormSubmitted(
558 routing_id(), 648 routing_id(), *provisionally_saved_forms_[form_frame]));
559 *provisionally_saved_forms_[form_frame]));
560 provisionally_saved_forms_.erase(form_frame); 649 provisionally_saved_forms_.erase(form_frame);
561 } else { 650 } else {
562 // Loop through the forms on the page looking for one that has been 651 // Loop through the forms on the page looking for one that has been
563 // filled out. If one exists, try and save the credentials. 652 // filled out. If one exists, try and save the credentials.
564 blink::WebVector<blink::WebFormElement> forms; 653 blink::WebVector<blink::WebFormElement> forms;
565 frame->document().forms(forms); 654 frame->document().forms(forms);
566 655
656 bool password_forms_found = false;
567 for (size_t i = 0; i < forms.size(); ++i) { 657 for (size_t i = 0; i < forms.size(); ++i) {
568 blink::WebFormElement form_element= forms[i]; 658 blink::WebFormElement form_element = forms[i];
659 if (logger) {
660 LogHTMLForm(
661 logger.get(), Logger::STRING_FORM_FOUND_ON_PAGE, form_element);
662 }
569 scoped_ptr<PasswordForm> password_form( 663 scoped_ptr<PasswordForm> password_form(
570 CreatePasswordForm(form_element)); 664 CreatePasswordForm(form_element));
571 if (password_form.get() && 665 if (password_form.get() && !password_form->username_value.empty() &&
572 !password_form->username_value.empty() &&
573 !password_form->password_value.empty() && 666 !password_form->password_value.empty() &&
574 !PasswordValueIsDefault(*password_form, form_element)) { 667 !PasswordValueIsDefault(*password_form, form_element)) {
575 Send(new AutofillHostMsg_PasswordFormSubmitted( 668 password_forms_found = true;
576 routing_id(), *password_form)); 669 if (logger) {
670 logger->LogPasswordForm(
671 Logger::STRING_PASSWORD_FORM_FOUND_ON_PAGE, *password_form);
672 }
673 Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(),
674 *password_form));
577 } 675 }
578 } 676 }
677 if (!password_forms_found && logger) {
678 logger->LogMessage(Logger::STRING_DECISION_DROP);
679 }
579 } 680 }
580 } 681 }
581 // Clear the whole map during main frame navigation. 682 // Clear the whole map during main frame navigation.
582 provisionally_saved_forms_.clear(); 683 provisionally_saved_forms_.clear();
583 684
584 // This is a new navigation, so require a new user gesture before filling in 685 // This is a new navigation, so require a new user gesture before filling in
585 // passwords. 686 // passwords.
586 gatekeeper_.Reset(); 687 gatekeeper_.Reset();
688 } else {
689 if (logger)
690 logger->LogMessage(Logger::STRING_DECISION_DROP);
587 } 691 }
588 } 692 }
589 693
590 void PasswordAutofillAgent::OnFillPasswordForm( 694 void PasswordAutofillAgent::OnFillPasswordForm(
591 const PasswordFormFillData& form_data) { 695 const PasswordFormFillData& form_data) {
592 if (usernames_usage_ == NOTHING_TO_AUTOFILL) { 696 if (usernames_usage_ == NOTHING_TO_AUTOFILL) {
593 if (form_data.other_possible_usernames.size()) 697 if (form_data.other_possible_usernames.size())
594 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_PRESENT; 698 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_PRESENT;
595 else if (usernames_usage_ == NOTHING_TO_AUTOFILL) 699 else if (usernames_usage_ == NOTHING_TO_AUTOFILL)
596 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_ABSENT; 700 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_ABSENT;
(...skipping 30 matching lines...) Expand all
627 PasswordInfo password_info; 731 PasswordInfo password_info;
628 password_info.fill_data = form_data; 732 password_info.fill_data = form_data;
629 password_info.password_field = password_element; 733 password_info.password_field = password_element;
630 login_to_password_info_[username_element] = password_info; 734 login_to_password_info_[username_element] = password_info;
631 735
632 FormData form; 736 FormData form;
633 FormFieldData field; 737 FormFieldData field;
634 FindFormAndFieldForFormControlElement( 738 FindFormAndFieldForFormControlElement(
635 username_element, &form, &field, REQUIRE_NONE); 739 username_element, &form, &field, REQUIRE_NONE);
636 Send(new AutofillHostMsg_AddPasswordFormMapping( 740 Send(new AutofillHostMsg_AddPasswordFormMapping(
637 routing_id(), 741 routing_id(), field, form_data));
638 field,
639 form_data));
640 } 742 }
641 } 743 }
642 744
745 void PasswordAutofillAgent::OnChangeLoggingState(bool active) {
746 logging_state_active_ = active;
747 }
748
643 //////////////////////////////////////////////////////////////////////////////// 749 ////////////////////////////////////////////////////////////////////////////////
644 // PasswordAutofillAgent, private: 750 // PasswordAutofillAgent, private:
645 751
646 void PasswordAutofillAgent::GetSuggestions( 752 void PasswordAutofillAgent::GetSuggestions(
647 const PasswordFormFillData& fill_data, 753 const PasswordFormFillData& fill_data,
648 const base::string16& input, 754 const base::string16& input,
649 std::vector<base::string16>* suggestions, 755 std::vector<base::string16>* suggestions,
650 std::vector<base::string16>* realms) { 756 std::vector<base::string16>* realms) {
651 if (StartsWith(fill_data.basic_data.fields[0].value, input, false)) { 757 if (StartsWith(fill_data.basic_data.fields[0].value, input, false)) {
652 suggestions->push_back(fill_data.basic_data.fields[0].value); 758 suggestions->push_back(fill_data.basic_data.fields[0].value);
653 realms->push_back(base::UTF8ToUTF16(fill_data.preferred_realm)); 759 realms->push_back(base::UTF8ToUTF16(fill_data.preferred_realm));
654 } 760 }
655 761
656 for (PasswordFormFillData::LoginCollection::const_iterator iter = 762 for (PasswordFormFillData::LoginCollection::const_iterator iter =
657 fill_data.additional_logins.begin(); 763 fill_data.additional_logins.begin();
658 iter != fill_data.additional_logins.end(); ++iter) { 764 iter != fill_data.additional_logins.end();
765 ++iter) {
659 if (StartsWith(iter->first, input, false)) { 766 if (StartsWith(iter->first, input, false)) {
660 suggestions->push_back(iter->first); 767 suggestions->push_back(iter->first);
661 realms->push_back(base::UTF8ToUTF16(iter->second.realm)); 768 realms->push_back(base::UTF8ToUTF16(iter->second.realm));
662 } 769 }
663 } 770 }
664 771
665 for (PasswordFormFillData::UsernamesCollection::const_iterator iter = 772 for (PasswordFormFillData::UsernamesCollection::const_iterator iter =
666 fill_data.other_possible_usernames.begin(); 773 fill_data.other_possible_usernames.begin();
667 iter != fill_data.other_possible_usernames.end(); ++iter) { 774 iter != fill_data.other_possible_usernames.end();
775 ++iter) {
668 for (size_t i = 0; i < iter->second.size(); ++i) { 776 for (size_t i = 0; i < iter->second.size(); ++i) {
669 if (StartsWith(iter->second[i], input, false)) { 777 if (StartsWith(iter->second[i], input, false)) {
670 usernames_usage_ = OTHER_POSSIBLE_USERNAME_SHOWN; 778 usernames_usage_ = OTHER_POSSIBLE_USERNAME_SHOWN;
671 suggestions->push_back(iter->second[i]); 779 suggestions->push_back(iter->second[i]);
672 realms->push_back(base::UTF8ToUTF16(iter->first.realm)); 780 realms->push_back(base::UTF8ToUTF16(iter->first.realm));
673 } 781 }
674 } 782 }
675 } 783 }
676 } 784 }
677 785
(...skipping 19 matching lines...) Expand all
697 user_input, &form, &field, REQUIRE_NONE); 805 user_input, &form, &field, REQUIRE_NONE);
698 806
699 blink::WebInputElement selected_element = user_input; 807 blink::WebInputElement selected_element = user_input;
700 gfx::Rect bounding_box(selected_element.boundsInViewportSpace()); 808 gfx::Rect bounding_box(selected_element.boundsInViewportSpace());
701 809
702 float scale = web_view_->pageScaleFactor(); 810 float scale = web_view_->pageScaleFactor();
703 gfx::RectF bounding_box_scaled(bounding_box.x() * scale, 811 gfx::RectF bounding_box_scaled(bounding_box.x() * scale,
704 bounding_box.y() * scale, 812 bounding_box.y() * scale,
705 bounding_box.width() * scale, 813 bounding_box.width() * scale,
706 bounding_box.height() * scale); 814 bounding_box.height() * scale);
707 Send(new AutofillHostMsg_ShowPasswordSuggestions(routing_id(), 815 Send(new AutofillHostMsg_ShowPasswordSuggestions(
708 field, 816 routing_id(), field, bounding_box_scaled, suggestions, realms));
709 bounding_box_scaled,
710 suggestions,
711 realms));
712 return !suggestions.empty(); 817 return !suggestions.empty();
713 } 818 }
714 819
715 void PasswordAutofillAgent::FillFormOnPasswordRecieved( 820 void PasswordAutofillAgent::FillFormOnPasswordRecieved(
716 const PasswordFormFillData& fill_data, 821 const PasswordFormFillData& fill_data,
717 blink::WebInputElement username_element, 822 blink::WebInputElement username_element,
718 blink::WebInputElement password_element) { 823 blink::WebInputElement password_element) {
719 // Do not fill if the password field is in an iframe. 824 // Do not fill if the password field is in an iframe.
720 DCHECK(password_element.document().frame()); 825 DCHECK(password_element.document().frame());
721 if (password_element.document().frame()->parent()) 826 if (password_element.document().frame()->parent())
(...skipping 10 matching lines...) Expand all
732 // Try to set the username to the preferred name, but only if the field 837 // Try to set the username to the preferred name, but only if the field
733 // can be set and isn't prefilled. 838 // can be set and isn't prefilled.
734 if (IsElementAutocompletable(username_element) && 839 if (IsElementAutocompletable(username_element) &&
735 username_element.value().isEmpty()) { 840 username_element.value().isEmpty()) {
736 // TODO(tkent): Check maxlength and pattern. 841 // TODO(tkent): Check maxlength and pattern.
737 username_element.setValue(fill_data.basic_data.fields[0].value, true); 842 username_element.setValue(fill_data.basic_data.fields[0].value, true);
738 } 843 }
739 844
740 // Fill if we have an exact match for the username. Note that this sets 845 // Fill if we have an exact match for the username. Note that this sets
741 // username to autofilled. 846 // username to autofilled.
742 FillUserNameAndPassword(&username_element, &password_element, fill_data, 847 FillUserNameAndPassword(&username_element,
848 &password_element,
849 fill_data,
743 true /* exact_username_match */, 850 true /* exact_username_match */,
744 false /* set_selection */); 851 false /* set_selection */);
745 } 852 }
746 853
747 bool PasswordAutofillAgent::FillUserNameAndPassword( 854 bool PasswordAutofillAgent::FillUserNameAndPassword(
748 blink::WebInputElement* username_element, 855 blink::WebInputElement* username_element,
749 blink::WebInputElement* password_element, 856 blink::WebInputElement* password_element,
750 const PasswordFormFillData& fill_data, 857 const PasswordFormFillData& fill_data,
751 bool exact_username_match, 858 bool exact_username_match,
752 bool set_selection) { 859 bool set_selection) {
753 base::string16 current_username = username_element->value(); 860 base::string16 current_username = username_element->value();
754 // username and password will contain the match found if any. 861 // username and password will contain the match found if any.
755 base::string16 username; 862 base::string16 username;
756 base::string16 password; 863 base::string16 password;
757 864
758 // Look for any suitable matches to current field text. 865 // Look for any suitable matches to current field text.
759 if (DoUsernamesMatch(fill_data.basic_data.fields[0].value, current_username, 866 if (DoUsernamesMatch(fill_data.basic_data.fields[0].value,
867 current_username,
760 exact_username_match)) { 868 exact_username_match)) {
761 username = fill_data.basic_data.fields[0].value; 869 username = fill_data.basic_data.fields[0].value;
762 password = fill_data.basic_data.fields[1].value; 870 password = fill_data.basic_data.fields[1].value;
763 } else { 871 } else {
764 // Scan additional logins for a match. 872 // Scan additional logins for a match.
765 PasswordFormFillData::LoginCollection::const_iterator iter; 873 PasswordFormFillData::LoginCollection::const_iterator iter;
766 for (iter = fill_data.additional_logins.begin(); 874 for (iter = fill_data.additional_logins.begin();
767 iter != fill_data.additional_logins.end(); ++iter) { 875 iter != fill_data.additional_logins.end();
768 if (DoUsernamesMatch(iter->first, current_username, 876 ++iter) {
769 exact_username_match)) { 877 if (DoUsernamesMatch(
878 iter->first, current_username, exact_username_match)) {
770 username = iter->first; 879 username = iter->first;
771 password = iter->second.password; 880 password = iter->second.password;
772 break; 881 break;
773 } 882 }
774 } 883 }
775 884
776 // Check possible usernames. 885 // Check possible usernames.
777 if (username.empty() && password.empty()) { 886 if (username.empty() && password.empty()) {
778 for (PasswordFormFillData::UsernamesCollection::const_iterator iter = 887 for (PasswordFormFillData::UsernamesCollection::const_iterator iter =
779 fill_data.other_possible_usernames.begin(); 888 fill_data.other_possible_usernames.begin();
780 iter != fill_data.other_possible_usernames.end(); ++iter) { 889 iter != fill_data.other_possible_usernames.end();
890 ++iter) {
781 for (size_t i = 0; i < iter->second.size(); ++i) { 891 for (size_t i = 0; i < iter->second.size(); ++i) {
782 if (DoUsernamesMatch(iter->second[i], current_username, 892 if (DoUsernamesMatch(
783 exact_username_match)) { 893 iter->second[i], current_username, exact_username_match)) {
784 usernames_usage_ = OTHER_POSSIBLE_USERNAME_SELECTED; 894 usernames_usage_ = OTHER_POSSIBLE_USERNAME_SELECTED;
785 username = iter->second[i]; 895 username = iter->second[i];
786 password = iter->first.password; 896 password = iter->first.password;
787 break; 897 break;
788 } 898 }
789 } 899 }
790 if (!username.empty() && !password.empty()) 900 if (!username.empty() && !password.empty())
791 break; 901 break;
792 } 902 }
793 } 903 }
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
841 // Don't inline autocomplete if the caret is not at the end. 951 // Don't inline autocomplete if the caret is not at the end.
842 // TODO(jcivelli): is there a better way to test the caret location? 952 // TODO(jcivelli): is there a better way to test the caret location?
843 if (username.selectionStart() != username.selectionEnd() || 953 if (username.selectionStart() != username.selectionEnd() ||
844 username.selectionEnd() != static_cast<int>(username.value().length())) { 954 username.selectionEnd() != static_cast<int>(username.value().length())) {
845 return; 955 return;
846 } 956 }
847 957
848 // Show the popup with the list of available usernames. 958 // Show the popup with the list of available usernames.
849 ShowSuggestionPopup(fill_data, username); 959 ShowSuggestionPopup(fill_data, username);
850 960
851
852 #if !defined(OS_ANDROID) 961 #if !defined(OS_ANDROID)
853 // Fill the user and password field with the most relevant match. Android 962 // Fill the user and password field with the most relevant match. Android
854 // only fills in the fields after the user clicks on the suggestion popup. 963 // only fills in the fields after the user clicks on the suggestion popup.
855 FillUserNameAndPassword(&username, &password, fill_data, 964 FillUserNameAndPassword(&username,
965 &password,
966 fill_data,
856 false /* exact_username_match */, 967 false /* exact_username_match */,
857 true /* set_selection */); 968 true /* set_selection */);
858 #endif 969 #endif
859 } 970 }
860 971
861 void PasswordAutofillAgent::FrameClosing(const blink::WebFrame* frame) { 972 void PasswordAutofillAgent::FrameClosing(const blink::WebFrame* frame) {
862 for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin(); 973 for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin();
863 iter != login_to_password_info_.end();) { 974 iter != login_to_password_info_.end();) {
864 if (iter->first.document().frame() == frame) 975 if (iter->first.document().frame() == frame)
865 login_to_password_info_.erase(iter++); 976 login_to_password_info_.erase(iter++);
(...skipping 24 matching lines...) Expand all
890 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(input); 1001 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(input);
891 if (iter == login_to_password_info_.end()) 1002 if (iter == login_to_password_info_.end())
892 return false; 1003 return false;
893 1004
894 *found_input = input; 1005 *found_input = input;
895 *found_password = iter->second; 1006 *found_password = iter->second;
896 return true; 1007 return true;
897 } 1008 }
898 1009
899 } // namespace autofill 1010 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698