OLD | NEW |
---|---|
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/content/renderer/renderer_save_password_progress_l ogger.h" |
16 #include "components/autofill/core/common/form_field_data.h" | 16 #include "components/autofill/core/common/form_field_data.h" |
17 #include "components/autofill/core/common/password_form.h" | 17 #include "components/autofill/core/common/password_form.h" |
18 #include "components/autofill/core/common/password_form_fill_data.h" | 18 #include "components/autofill/core/common/password_form_fill_data.h" |
19 #include "content/public/renderer/document_state.h" | 19 #include "content/public/renderer/document_state.h" |
20 #include "content/public/renderer/navigation_state.h" | 20 #include "content/public/renderer/navigation_state.h" |
21 #include "content/public/renderer/render_frame.h" | |
21 #include "content/public/renderer/render_view.h" | 22 #include "content/public/renderer/render_view.h" |
22 #include "third_party/WebKit/public/platform/WebVector.h" | 23 #include "third_party/WebKit/public/platform/WebVector.h" |
23 #include "third_party/WebKit/public/web/WebAutofillClient.h" | 24 #include "third_party/WebKit/public/web/WebAutofillClient.h" |
24 #include "third_party/WebKit/public/web/WebDocument.h" | 25 #include "third_party/WebKit/public/web/WebDocument.h" |
25 #include "third_party/WebKit/public/web/WebElement.h" | 26 #include "third_party/WebKit/public/web/WebElement.h" |
26 #include "third_party/WebKit/public/web/WebFormElement.h" | 27 #include "third_party/WebKit/public/web/WebFormElement.h" |
27 #include "third_party/WebKit/public/web/WebInputEvent.h" | 28 #include "third_party/WebKit/public/web/WebInputEvent.h" |
28 #include "third_party/WebKit/public/web/WebLocalFrame.h" | 29 #include "third_party/WebKit/public/web/WebLocalFrame.h" |
29 #include "third_party/WebKit/public/web/WebNode.h" | 30 #include "third_party/WebKit/public/web/WebNode.h" |
30 #include "third_party/WebKit/public/web/WebNodeList.h" | 31 #include "third_party/WebKit/public/web/WebNodeList.h" |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
123 // |data|, and add results to |result|. | 124 // |data|, and add results to |result|. |
124 bool FindFormInputElements(blink::WebFormElement* form_element, | 125 bool FindFormInputElements(blink::WebFormElement* form_element, |
125 const PasswordFormFillData& data, | 126 const PasswordFormFillData& data, |
126 FormElements* result) { | 127 FormElements* result) { |
127 return FindFormInputElement(form_element, data.password_field, result) && | 128 return FindFormInputElement(form_element, data.password_field, result) && |
128 (!FillDataContainsUsername(data) || | 129 (!FillDataContainsUsername(data) || |
129 FindFormInputElement(form_element, data.username_field, result)); | 130 FindFormInputElement(form_element, data.username_field, result)); |
130 } | 131 } |
131 | 132 |
132 // Helper to locate form elements identified by |data|. | 133 // Helper to locate form elements identified by |data|. |
133 void FindFormElements(blink::WebView* view, | 134 void FindFormElements(content::RenderFrame* render_frame, |
134 const PasswordFormFillData& data, | 135 const PasswordFormFillData& data, |
135 FormElementsList* results) { | 136 FormElementsList* results) { |
136 DCHECK(view); | |
137 DCHECK(results); | 137 DCHECK(results); |
138 blink::WebFrame* main_frame = view->mainFrame(); | |
139 if (!main_frame) | |
140 return; | |
141 | 138 |
142 GURL::Replacements rep; | 139 GURL::Replacements rep; |
143 rep.ClearQuery(); | 140 rep.ClearQuery(); |
144 rep.ClearRef(); | 141 rep.ClearRef(); |
145 | 142 |
146 // Loop through each frame. | 143 blink::WebDocument doc = render_frame->GetWebFrame()->document(); |
147 for (blink::WebFrame* f = main_frame; f; f = f->traverseNext(false)) { | 144 if (!doc.isHTMLDocument()) |
148 blink::WebDocument doc = f->document(); | 145 return; |
149 if (!doc.isHTMLDocument()) | 146 |
147 GURL full_origin(doc.url()); | |
148 if (data.origin != full_origin.ReplaceComponents(rep)) | |
149 return; | |
150 | |
151 blink::WebVector<blink::WebFormElement> forms; | |
152 doc.forms(forms); | |
153 | |
154 for (size_t i = 0; i < forms.size(); ++i) { | |
155 blink::WebFormElement fe = forms[i]; | |
156 | |
157 GURL full_action(doc.completeURL(fe.action())); | |
158 if (full_action.is_empty()) { | |
159 // The default action URL is the form's origin. | |
160 full_action = full_origin; | |
161 } | |
162 | |
163 // Action URL must match. | |
164 if (data.action != full_action.ReplaceComponents(rep)) | |
150 continue; | 165 continue; |
151 | 166 |
152 GURL full_origin(doc.url()); | 167 scoped_ptr<FormElements> curr_elements(new FormElements); |
153 if (data.origin != full_origin.ReplaceComponents(rep)) | 168 if (!FindFormInputElements(&fe, data, curr_elements.get())) |
154 continue; | 169 continue; |
155 | 170 |
156 blink::WebVector<blink::WebFormElement> forms; | 171 // We found the right element. |
157 doc.forms(forms); | 172 // Note: this assignment adds a reference to |fe|. |
158 | 173 curr_elements->form_element = fe; |
159 for (size_t i = 0; i < forms.size(); ++i) { | 174 results->push_back(curr_elements.release()); |
160 blink::WebFormElement fe = forms[i]; | |
161 | |
162 GURL full_action(f->document().completeURL(fe.action())); | |
163 if (full_action.is_empty()) { | |
164 // The default action URL is the form's origin. | |
165 full_action = full_origin; | |
166 } | |
167 | |
168 // Action URL must match. | |
169 if (data.action != full_action.ReplaceComponents(rep)) | |
170 continue; | |
171 | |
172 scoped_ptr<FormElements> curr_elements(new FormElements); | |
173 if (!FindFormInputElements(&fe, data, curr_elements.get())) | |
174 continue; | |
175 | |
176 // We found the right element. | |
177 // Note: this assignment adds a reference to |fe|. | |
178 curr_elements->form_element = fe; | |
179 results->push_back(curr_elements.release()); | |
180 } | |
181 } | 175 } |
182 } | 176 } |
183 | 177 |
184 bool IsElementEditable(const blink::WebInputElement& element) { | 178 bool IsElementEditable(const blink::WebInputElement& element) { |
185 return element.isEnabled() && !element.isReadOnly(); | 179 return element.isEnabled() && !element.isReadOnly(); |
186 } | 180 } |
187 | 181 |
188 bool DoUsernamesMatch(const base::string16& username1, | 182 bool DoUsernamesMatch(const base::string16& username1, |
189 const base::string16& username2, | 183 const base::string16& username2, |
190 bool exact_match) { | 184 bool exact_match) { |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
426 return false; | 420 return false; |
427 auto it = map.find(key); | 421 auto it = map.find(key); |
428 return it != map.end() && it->second.get(); | 422 return it != map.end() && it->second.get(); |
429 } | 423 } |
430 | 424 |
431 } // namespace | 425 } // namespace |
432 | 426 |
433 //////////////////////////////////////////////////////////////////////////////// | 427 //////////////////////////////////////////////////////////////////////////////// |
434 // PasswordAutofillAgent, public: | 428 // PasswordAutofillAgent, public: |
435 | 429 |
436 PasswordAutofillAgent::PasswordAutofillAgent(content::RenderView* render_view) | 430 PasswordAutofillAgent::PasswordAutofillAgent(content::RenderFrame* render_frame) |
437 : content::RenderViewObserver(render_view), | 431 : content::RenderFrameObserver(render_frame), |
432 legacy_(render_frame->GetRenderView(), this), | |
438 usernames_usage_(NOTHING_TO_AUTOFILL), | 433 usernames_usage_(NOTHING_TO_AUTOFILL), |
439 web_view_(render_view->GetWebView()), | |
440 logging_state_active_(false), | 434 logging_state_active_(false), |
441 was_username_autofilled_(false), | 435 was_username_autofilled_(false), |
442 was_password_autofilled_(false), | 436 was_password_autofilled_(false), |
443 username_selection_start_(0), | 437 username_selection_start_(0), |
444 did_stop_loading_(false), | 438 did_stop_loading_(false), |
445 weak_ptr_factory_(this) { | 439 weak_ptr_factory_(this) { |
446 Send(new AutofillHostMsg_PasswordAutofillAgentConstructed(routing_id())); | 440 Send(new AutofillHostMsg_PasswordAutofillAgentConstructed(routing_id())); |
447 } | 441 } |
448 | 442 |
449 PasswordAutofillAgent::~PasswordAutofillAgent() { | 443 PasswordAutofillAgent::~PasswordAutofillAgent() { |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
524 usernames_usage_ = OTHER_POSSIBLE_USERNAME_SELECTED; | 518 usernames_usage_ = OTHER_POSSIBLE_USERNAME_SELECTED; |
525 } | 519 } |
526 return true; | 520 return true; |
527 } | 521 } |
528 | 522 |
529 bool PasswordAutofillAgent::TextDidChangeInTextField( | 523 bool PasswordAutofillAgent::TextDidChangeInTextField( |
530 const blink::WebInputElement& element) { | 524 const blink::WebInputElement& element) { |
531 // TODO(vabr): Get a mutable argument instead. http://crbug.com/397083 | 525 // TODO(vabr): Get a mutable argument instead. http://crbug.com/397083 |
532 blink::WebInputElement mutable_element = element; // We need a non-const. | 526 blink::WebInputElement mutable_element = element; // We need a non-const. |
533 | 527 |
528 DCHECK_EQ(element.document().frame(), render_frame()->GetWebFrame()); | |
529 | |
534 if (element.isPasswordField()) { | 530 if (element.isPasswordField()) { |
535 // Some login forms have event handlers that put a hash of the password into | 531 // Some login forms have event handlers that put a hash of the password into |
536 // a hidden field and then clear the password (http://crbug.com/28910, | 532 // a hidden field and then clear the password (http://crbug.com/28910, |
537 // http://crbug.com/391693). This method gets called before any of those | 533 // http://crbug.com/391693). This method gets called before any of those |
538 // handlers run, so save away a copy of the password in case it gets lost. | 534 // handlers run, so save away a copy of the password in case it gets lost. |
539 // To honor the user having explicitly cleared the password, even an empty | 535 // To honor the user having explicitly cleared the password, even an empty |
540 // password will be saved here. | 536 // password will be saved here. |
541 if (blink::WebLocalFrame* element_frame = element.document().frame()) { | 537 ProvisionallySavePassword(element.form(), RESTRICTION_NONE); |
542 ProvisionallySavePassword( | |
543 element_frame, element.form(), RESTRICTION_NONE); | |
544 } | |
545 | 538 |
546 PasswordToLoginMap::iterator iter = password_to_username_.find(element); | 539 PasswordToLoginMap::iterator iter = password_to_username_.find(element); |
547 if (iter != password_to_username_.end()) { | 540 if (iter != password_to_username_.end()) { |
548 login_to_password_info_[iter->second].password_was_edited_last = true; | 541 login_to_password_info_[iter->second].password_was_edited_last = true; |
549 // Note that the suggested value of |mutable_element| was reset when its | 542 // Note that the suggested value of |mutable_element| was reset when its |
550 // value changed. | 543 // value changed. |
551 mutable_element.setAutofilled(false); | 544 mutable_element.setAutofilled(false); |
552 } | 545 } |
553 return false; | 546 return false; |
554 } | 547 } |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
695 return true; | 688 return true; |
696 | 689 |
697 return ShowSuggestionPopup(iter->second.fill_data, element, show_all); | 690 return ShowSuggestionPopup(iter->second.fill_data, element, show_all); |
698 } | 691 } |
699 | 692 |
700 bool PasswordAutofillAgent::OriginCanAccessPasswordManager( | 693 bool PasswordAutofillAgent::OriginCanAccessPasswordManager( |
701 const blink::WebSecurityOrigin& origin) { | 694 const blink::WebSecurityOrigin& origin) { |
702 return origin.canAccessPasswordManager(); | 695 return origin.canAccessPasswordManager(); |
703 } | 696 } |
704 | 697 |
705 void PasswordAutofillAgent::OnDynamicFormsSeen(blink::WebFrame* frame) { | 698 void PasswordAutofillAgent::OnDynamicFormsSeen() { |
706 SendPasswordForms(frame, false /* only_visible */); | 699 SendPasswordForms(false /* only_visible */); |
707 } | 700 } |
708 | 701 |
709 void PasswordAutofillAgent::FirstUserGestureObserved() { | 702 void PasswordAutofillAgent::FirstUserGestureObserved() { |
710 gatekeeper_.OnUserGesture(); | 703 gatekeeper_.OnUserGesture(); |
711 } | 704 } |
712 | 705 |
713 void PasswordAutofillAgent::SendPasswordForms(blink::WebFrame* frame, | 706 void PasswordAutofillAgent::SendPasswordForms(bool only_visible) { |
714 bool only_visible) { | |
715 scoped_ptr<RendererSavePasswordProgressLogger> logger; | 707 scoped_ptr<RendererSavePasswordProgressLogger> logger; |
716 if (logging_state_active_) { | 708 if (logging_state_active_) { |
717 logger.reset(new RendererSavePasswordProgressLogger(this, routing_id())); | 709 logger.reset(new RendererSavePasswordProgressLogger(this, routing_id())); |
718 logger->LogMessage(Logger::STRING_SEND_PASSWORD_FORMS_METHOD); | 710 logger->LogMessage(Logger::STRING_SEND_PASSWORD_FORMS_METHOD); |
719 logger->LogBoolean(Logger::STRING_ONLY_VISIBLE, only_visible); | 711 logger->LogBoolean(Logger::STRING_ONLY_VISIBLE, only_visible); |
720 } | 712 } |
721 | 713 |
714 blink::WebFrame* frame = render_frame()->GetWebFrame(); | |
722 // Make sure that this security origin is allowed to use password manager. | 715 // Make sure that this security origin is allowed to use password manager. |
723 blink::WebSecurityOrigin origin = frame->document().securityOrigin(); | 716 blink::WebSecurityOrigin origin = frame->document().securityOrigin(); |
724 if (logger) { | 717 if (logger) { |
725 logger->LogURL(Logger::STRING_SECURITY_ORIGIN, | 718 logger->LogURL(Logger::STRING_SECURITY_ORIGIN, |
726 GURL(origin.toString().utf8())); | 719 GURL(origin.toString().utf8())); |
727 } | 720 } |
728 if (!OriginCanAccessPasswordManager(origin)) { | 721 if (!OriginCanAccessPasswordManager(origin)) { |
729 if (logger) { | 722 if (logger) { |
730 logger->LogMessage(Logger::STRING_SECURITY_ORIGIN_FAILURE); | 723 logger->LogMessage(Logger::STRING_SECURITY_ORIGIN_FAILURE); |
731 } | 724 } |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
788 bool PasswordAutofillAgent::OnMessageReceived(const IPC::Message& message) { | 781 bool PasswordAutofillAgent::OnMessageReceived(const IPC::Message& message) { |
789 bool handled = true; | 782 bool handled = true; |
790 IPC_BEGIN_MESSAGE_MAP(PasswordAutofillAgent, message) | 783 IPC_BEGIN_MESSAGE_MAP(PasswordAutofillAgent, message) |
791 IPC_MESSAGE_HANDLER(AutofillMsg_FillPasswordForm, OnFillPasswordForm) | 784 IPC_MESSAGE_HANDLER(AutofillMsg_FillPasswordForm, OnFillPasswordForm) |
792 IPC_MESSAGE_HANDLER(AutofillMsg_SetLoggingState, OnSetLoggingState) | 785 IPC_MESSAGE_HANDLER(AutofillMsg_SetLoggingState, OnSetLoggingState) |
793 IPC_MESSAGE_UNHANDLED(handled = false) | 786 IPC_MESSAGE_UNHANDLED(handled = false) |
794 IPC_END_MESSAGE_MAP() | 787 IPC_END_MESSAGE_MAP() |
795 return handled; | 788 return handled; |
796 } | 789 } |
797 | 790 |
791 void PasswordAutofillAgent::DidFinishDocumentLoad() { | |
792 // The |frame| contents have been parsed, but not yet rendered. Let the | |
793 // PasswordManager know that forms are loaded, even though we can't yet tell | |
794 // whether they're visible. | |
795 SendPasswordForms(false); | |
796 } | |
797 | |
798 void PasswordAutofillAgent::DidFinishLoad() { | |
799 // The |frame| contents have been rendered. Let the PasswordManager know | |
800 // which of the loaded frames are actually visible to the user. This also | |
801 // triggers the "Save password?" infobar if the user just submitted a password | |
802 // form. | |
803 SendPasswordForms(true); | |
804 } | |
805 | |
806 void PasswordAutofillAgent::FrameWillClose() { | |
807 FrameClosing(); | |
808 } | |
809 | |
798 void PasswordAutofillAgent::DidStartLoading() { | 810 void PasswordAutofillAgent::DidStartLoading() { |
799 did_stop_loading_ = false; | 811 did_stop_loading_ = false; |
800 if (usernames_usage_ != NOTHING_TO_AUTOFILL) { | 812 if (usernames_usage_ != NOTHING_TO_AUTOFILL) { |
801 UMA_HISTOGRAM_ENUMERATION("PasswordManager.OtherPossibleUsernamesUsage", | 813 UMA_HISTOGRAM_ENUMERATION("PasswordManager.OtherPossibleUsernamesUsage", |
802 usernames_usage_, | 814 usernames_usage_, OTHER_POSSIBLE_USERNAMES_MAX); |
803 OTHER_POSSIBLE_USERNAMES_MAX); | |
804 usernames_usage_ = NOTHING_TO_AUTOFILL; | 815 usernames_usage_ = NOTHING_TO_AUTOFILL; |
805 } | 816 } |
806 } | 817 } |
807 | 818 |
808 void PasswordAutofillAgent::DidFinishDocumentLoad(blink::WebLocalFrame* frame) { | |
809 // The |frame| contents have been parsed, but not yet rendered. Let the | |
810 // PasswordManager know that forms are loaded, even though we can't yet tell | |
811 // whether they're visible. | |
812 SendPasswordForms(frame, false); | |
813 } | |
814 | |
815 void PasswordAutofillAgent::DidFinishLoad(blink::WebLocalFrame* frame) { | |
816 // The |frame| contents have been rendered. Let the PasswordManager know | |
817 // which of the loaded frames are actually visible to the user. This also | |
818 // triggers the "Save password?" infobar if the user just submitted a password | |
819 // form. | |
820 SendPasswordForms(frame, true); | |
821 } | |
822 | |
823 void PasswordAutofillAgent::DidStopLoading() { | 819 void PasswordAutofillAgent::DidStopLoading() { |
824 did_stop_loading_ = true; | 820 did_stop_loading_ = true; |
825 } | 821 } |
826 | 822 |
827 void PasswordAutofillAgent::FrameDetached(blink::WebFrame* frame) { | 823 void PasswordAutofillAgent::FrameDetached(blink::WebFrame* frame) { |
828 FrameClosing(frame); | 824 if (frame == render_frame()->GetWebFrame()) |
829 } | 825 FrameClosing(); |
830 | |
831 void PasswordAutofillAgent::FrameWillClose(blink::WebFrame* frame) { | |
832 FrameClosing(frame); | |
833 } | 826 } |
834 | 827 |
835 void PasswordAutofillAgent::WillSendSubmitEvent( | 828 void PasswordAutofillAgent::WillSendSubmitEvent( |
836 blink::WebLocalFrame* frame, | 829 blink::WebLocalFrame* frame, |
837 const blink::WebFormElement& form) { | 830 const blink::WebFormElement& form) { |
831 if (frame != render_frame()->GetWebFrame()) | |
832 return; | |
838 // Forms submitted via XHR are not seen by WillSubmitForm if the default | 833 // Forms submitted via XHR are not seen by WillSubmitForm if the default |
839 // onsubmit handler is overridden. Such submission first gets detected in | 834 // onsubmit handler is overridden. Such submission first gets detected in |
840 // DidStartProvisionalLoad, which no longer knows about the particular form, | 835 // DidStartProvisionalLoad, which no longer knows about the particular form, |
841 // and uses the candidate stored in |provisionally_saved_forms_|. | 836 // and uses the candidate stored in |provisionally_saved_form_|. |
842 // | 837 // |
843 // User-typed password will get stored to |provisionally_saved_forms_| in | 838 // User-typed password will get stored to |provisionally_saved_form_| in |
844 // TextDidChangeInTextField. Autofilled or JavaScript-copied passwords need to | 839 // TextDidChangeInTextField. Autofilled or JavaScript-copied passwords need to |
845 // be saved here. | 840 // be saved here. |
846 // | 841 // |
847 // Only non-empty passwords are saved here. Empty passwords were likely | 842 // Only non-empty passwords are saved here. Empty passwords were likely |
848 // cleared by some scripts (http://crbug.com/28910, http://crbug.com/391693). | 843 // cleared by some scripts (http://crbug.com/28910, http://crbug.com/391693). |
849 // Had the user cleared the password, |provisionally_saved_forms_| would | 844 // Had the user cleared the password, |provisionally_saved_form_| would |
850 // already have been updated in TextDidChangeInTextField. | 845 // already have been updated in TextDidChangeInTextField. |
851 ProvisionallySavePassword(frame, form, RESTRICTION_NON_EMPTY_PASSWORD); | 846 ProvisionallySavePassword(form, RESTRICTION_NON_EMPTY_PASSWORD); |
852 } | 847 } |
853 | 848 |
854 void PasswordAutofillAgent::WillSubmitForm(blink::WebLocalFrame* frame, | 849 void PasswordAutofillAgent::WillSubmitForm(blink::WebLocalFrame* frame, |
855 const blink::WebFormElement& form) { | 850 const blink::WebFormElement& form) { |
856 DCHECK(frame); | 851 if (frame != render_frame()->GetWebFrame()) |
852 return; | |
853 | |
857 scoped_ptr<RendererSavePasswordProgressLogger> logger; | 854 scoped_ptr<RendererSavePasswordProgressLogger> logger; |
858 if (logging_state_active_) { | 855 if (logging_state_active_) { |
859 logger.reset(new RendererSavePasswordProgressLogger(this, routing_id())); | 856 logger.reset(new RendererSavePasswordProgressLogger(this, routing_id())); |
860 logger->LogMessage(Logger::STRING_WILL_SUBMIT_FORM_METHOD); | 857 logger->LogMessage(Logger::STRING_WILL_SUBMIT_FORM_METHOD); |
861 LogHTMLForm(logger.get(), Logger::STRING_HTML_FORM_FOR_SUBMIT, form); | 858 LogHTMLForm(logger.get(), Logger::STRING_HTML_FORM_FOR_SUBMIT, form); |
862 } | 859 } |
863 | 860 |
864 scoped_ptr<PasswordForm> submitted_form = CreatePasswordForm(form); | 861 scoped_ptr<PasswordForm> submitted_form = CreatePasswordForm(form); |
865 | 862 |
866 // If there is a provisionally saved password, copy over the previous | 863 // If there is a provisionally saved password, copy over the previous |
867 // password value so we get the user's typed password, not the value that | 864 // password value so we get the user's typed password, not the value that |
868 // may have been transformed for submit. | 865 // may have been transformed for submit. |
869 // TODO(gcasto): Do we need to have this action equality check? Is it trying | 866 // TODO(gcasto): Do we need to have this action equality check? Is it trying |
870 // to prevent accidentally copying over passwords from a different form? | 867 // to prevent accidentally copying over passwords from a different form? |
871 if (submitted_form) { | 868 if (submitted_form) { |
872 if (logger) { | 869 if (logger) { |
873 logger->LogPasswordForm(Logger::STRING_CREATED_PASSWORD_FORM, | 870 logger->LogPasswordForm(Logger::STRING_CREATED_PASSWORD_FORM, |
874 *submitted_form); | 871 *submitted_form); |
875 } | 872 } |
876 if (ContainsNonNullEntryForNonNullKey( | 873 if (provisionally_saved_form_ && |
877 provisionally_saved_forms_, static_cast<blink::WebFrame*>(frame)) && | 874 submitted_form->action == provisionally_saved_form_->action) { |
878 submitted_form->action == provisionally_saved_forms_[frame]->action) { | |
879 if (logger) | 875 if (logger) |
880 logger->LogMessage(Logger::STRING_SUBMITTED_PASSWORD_REPLACED); | 876 logger->LogMessage(Logger::STRING_SUBMITTED_PASSWORD_REPLACED); |
881 submitted_form->password_value = | 877 submitted_form->password_value = |
882 provisionally_saved_forms_[frame]->password_value; | 878 provisionally_saved_form_->password_value; |
883 submitted_form->new_password_value = | 879 submitted_form->new_password_value = |
884 provisionally_saved_forms_[frame]->new_password_value; | 880 provisionally_saved_form_->new_password_value; |
885 } | 881 } |
886 | 882 |
887 // Some observers depend on sending this information now instead of when | 883 // Some observers depend on sending this information now instead of when |
888 // the frame starts loading. If there are redirects that cause a new | 884 // the frame starts loading. If there are redirects that cause a new |
889 // RenderView to be instantiated (such as redirects to the WebStore) | 885 // RenderView to be instantiated (such as redirects to the WebStore) |
890 // we will never get to finish the load. | 886 // we will never get to finish the load. |
891 Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(), | 887 Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(), |
892 *submitted_form)); | 888 *provisionally_saved_form_)); |
893 // Remove reference since we have already submitted this form. | 889 provisionally_saved_form_.reset(); |
894 provisionally_saved_forms_.erase(frame); | |
895 } else if (logger) { | 890 } else if (logger) { |
896 logger->LogMessage(Logger::STRING_FORM_IS_NOT_PASSWORD); | 891 logger->LogMessage(Logger::STRING_FORM_IS_NOT_PASSWORD); |
897 } | 892 } |
898 } | 893 } |
899 | 894 |
900 blink::WebFrame* PasswordAutofillAgent::CurrentOrChildFrameWithSavedForms( | 895 void PasswordAutofillAgent::DidStartProvisionalLoad() { |
901 const blink::WebFrame* current_frame) { | |
902 for (FrameToPasswordFormMap::const_iterator it = | |
903 provisionally_saved_forms_.begin(); | |
904 it != provisionally_saved_forms_.end(); | |
905 ++it) { | |
906 blink::WebFrame* form_frame = it->first; | |
907 // The check that the returned frame is related to |current_frame| is mainly | |
908 // for double-checking. There should not be any unrelated frames in | |
909 // |provisionally_saved_forms_|, because the map is cleared after | |
910 // navigation. If there are reasons to remove this check in the future and | |
911 // keep just the first frame found, it might be a good idea to add a UMA | |
912 // statistic or a similar check on how many frames are here to choose from. | |
913 if (current_frame == form_frame || | |
914 current_frame->findChildByName(form_frame->assignedName())) { | |
915 return form_frame; | |
916 } | |
917 } | |
918 return NULL; | |
919 } | |
920 | |
921 void PasswordAutofillAgent::DidStartProvisionalLoad( | |
922 blink::WebLocalFrame* frame) { | |
923 scoped_ptr<RendererSavePasswordProgressLogger> logger; | 896 scoped_ptr<RendererSavePasswordProgressLogger> logger; |
924 if (logging_state_active_) { | 897 if (logging_state_active_) { |
925 logger.reset(new RendererSavePasswordProgressLogger(this, routing_id())); | 898 logger.reset(new RendererSavePasswordProgressLogger(this, routing_id())); |
926 logger->LogMessage(Logger::STRING_DID_START_PROVISIONAL_LOAD_METHOD); | 899 logger->LogMessage(Logger::STRING_DID_START_PROVISIONAL_LOAD_METHOD); |
927 } | 900 } |
928 | 901 |
929 if (!frame->parent()) { | 902 blink::WebFrame* frame = render_frame()->GetWebFrame(); |
930 // If the navigation is not triggered by a user gesture, e.g. by some ajax | 903 |
931 // callback, then inherit the submitted password form from the previous | 904 if (frame->parent()) { |
932 // state. This fixes the no password save issue for ajax login, tracked in | 905 if (logger) |
933 // [http://crbug/43219]. Note that this still fails for sites that use | 906 logger->LogMessage(Logger::STRING_FRAME_NOT_MAIN_FRAME); |
934 // synchonous XHR as isProcessingUserGesture() will return true. | 907 return; |
935 blink::WebFrame* form_frame = CurrentOrChildFrameWithSavedForms(frame); | 908 } |
936 if (logger) { | 909 |
937 logger->LogBoolean(Logger::STRING_FORM_FRAME_EQ_FRAME, | 910 // Bug fix for crbug.com/368690. isProcessingUserGesture() is false when |
vabr (Chromium)
2014/11/21 09:31:52
Please remove STRING_FORM_FRAME_EQ_FRAME also from
| |
938 form_frame == frame); | 911 // the user is performing actions outside the page (e.g. typed url, |
939 } | 912 // history navigation). We don't want to trigger saving in these cases. |
940 // Bug fix for crbug.com/368690. isProcessingUserGesture() is false when | 913 content::DocumentState* document_state = |
941 // the user is performing actions outside the page (e.g. typed url, | 914 content::DocumentState::FromDataSource(frame->provisionalDataSource()); |
942 // history navigation). We don't want to trigger saving in these cases. | 915 content::NavigationState* navigation_state = |
943 content::DocumentState* document_state = | 916 document_state->navigation_state(); |
944 content::DocumentState::FromDataSource( | 917 if (ui::PageTransitionIsWebTriggerable(navigation_state->transition_type()) && |
945 frame->provisionalDataSource()); | 918 !blink::WebUserGestureIndicator::isProcessingUserGesture()) { |
946 content::NavigationState* navigation_state = | 919 // If onsubmit has been called, try and save that form. |
947 document_state->navigation_state(); | 920 if (provisionally_saved_form_) { |
948 if (ui::PageTransitionIsWebTriggerable( | 921 if (logger) { |
949 navigation_state->transition_type()) && | 922 logger->LogPasswordForm( |
950 !blink::WebUserGestureIndicator::isProcessingUserGesture()) { | 923 Logger::STRING_PROVISIONALLY_SAVED_FORM_FOR_FRAME, |
951 // If onsubmit has been called, try and save that form. | 924 *provisionally_saved_form_); |
952 if (ContainsNonNullEntryForNonNullKey(provisionally_saved_forms_, | 925 } |
953 form_frame)) { | 926 Send(new AutofillHostMsg_PasswordFormSubmitted( |
927 routing_id(), *provisionally_saved_form_)); | |
928 provisionally_saved_form_.reset(); | |
929 } else { | |
930 // Loop through the forms on the page looking for one that has been | |
931 // filled out. If one exists, try and save the credentials. | |
932 blink::WebVector<blink::WebFormElement> forms; | |
933 frame->document().forms(forms); | |
934 | |
935 bool password_forms_found = false; | |
936 for (size_t i = 0; i < forms.size(); ++i) { | |
937 blink::WebFormElement form_element = forms[i]; | |
954 if (logger) { | 938 if (logger) { |
955 logger->LogPasswordForm( | 939 LogHTMLForm(logger.get(), Logger::STRING_FORM_FOUND_ON_PAGE, |
956 Logger::STRING_PROVISIONALLY_SAVED_FORM_FOR_FRAME, | 940 form_element); |
957 *provisionally_saved_forms_[form_frame]); | |
958 } | 941 } |
959 Send(new AutofillHostMsg_PasswordFormSubmitted( | 942 scoped_ptr<PasswordForm> password_form( |
960 routing_id(), *provisionally_saved_forms_[form_frame])); | 943 CreatePasswordForm(form_element)); |
961 provisionally_saved_forms_.erase(form_frame); | 944 if (password_form.get() && !password_form->username_value.empty() && |
962 } else { | 945 FormContainsNonDefaultPasswordValue( |
963 // Loop through the forms on the page looking for one that has been | 946 *password_form, form_element)) { |
964 // filled out. If one exists, try and save the credentials. | 947 password_forms_found = true; |
965 blink::WebVector<blink::WebFormElement> forms; | |
966 frame->document().forms(forms); | |
967 | |
968 bool password_forms_found = false; | |
969 for (size_t i = 0; i < forms.size(); ++i) { | |
970 blink::WebFormElement form_element = forms[i]; | |
971 if (logger) { | 948 if (logger) { |
972 LogHTMLForm( | 949 logger->LogPasswordForm( |
973 logger.get(), Logger::STRING_FORM_FOUND_ON_PAGE, form_element); | 950 Logger::STRING_PASSWORD_FORM_FOUND_ON_PAGE, *password_form); |
974 } | 951 } |
975 scoped_ptr<PasswordForm> password_form( | 952 Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(), |
976 CreatePasswordForm(form_element)); | 953 *password_form)); |
977 if (password_form.get() && !password_form->username_value.empty() && | |
978 FormContainsNonDefaultPasswordValue( | |
979 *password_form, form_element)) { | |
980 password_forms_found = true; | |
981 if (logger) { | |
982 logger->LogPasswordForm( | |
983 Logger::STRING_PASSWORD_FORM_FOUND_ON_PAGE, *password_form); | |
984 } | |
985 Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(), | |
986 *password_form)); | |
987 } | |
988 } | |
989 if (!password_forms_found && logger) { | |
990 logger->LogMessage(Logger::STRING_PASSWORD_FORM_NOT_FOUND_ON_PAGE); | |
991 } | 954 } |
992 } | 955 } |
956 if (!password_forms_found && logger) | |
957 logger->LogMessage(Logger::STRING_PASSWORD_FORM_NOT_FOUND_ON_PAGE); | |
993 } | 958 } |
994 // Clear the whole map during main frame navigation. | 959 } |
995 provisionally_saved_forms_.clear(); | |
996 | 960 |
997 // This is a new navigation, so require a new user gesture before filling in | 961 // This is a new navigation, so require a new user gesture before filling in |
998 // passwords. | 962 // passwords. |
999 gatekeeper_.Reset(); | 963 gatekeeper_.Reset(); |
1000 } else { | |
1001 if (logger) | |
1002 logger->LogMessage(Logger::STRING_FRAME_NOT_MAIN_FRAME); | |
1003 } | |
1004 } | 964 } |
1005 | 965 |
1006 void PasswordAutofillAgent::OnFillPasswordForm( | 966 void PasswordAutofillAgent::OnFillPasswordForm( |
1007 int key, | 967 int key, |
1008 const PasswordFormFillData& form_data) { | 968 const PasswordFormFillData& form_data) { |
1009 if (usernames_usage_ == NOTHING_TO_AUTOFILL) { | 969 if (usernames_usage_ == NOTHING_TO_AUTOFILL) { |
1010 if (form_data.other_possible_usernames.size()) | 970 if (form_data.other_possible_usernames.size()) |
1011 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_PRESENT; | 971 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_PRESENT; |
1012 else if (usernames_usage_ == NOTHING_TO_AUTOFILL) | 972 else if (usernames_usage_ == NOTHING_TO_AUTOFILL) |
1013 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_ABSENT; | 973 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_ABSENT; |
1014 } | 974 } |
1015 | 975 |
1016 FormElementsList forms; | 976 FormElementsList forms; |
1017 // We own the FormElements* in forms. | 977 // We own the FormElements* in forms. |
1018 FindFormElements(render_view()->GetWebView(), form_data, &forms); | 978 FindFormElements(render_frame(), form_data, &forms); |
1019 FormElementsList::iterator iter; | 979 FormElementsList::iterator iter; |
1020 for (iter = forms.begin(); iter != forms.end(); ++iter) { | 980 for (iter = forms.begin(); iter != forms.end(); ++iter) { |
1021 scoped_ptr<FormElements> form_elements(*iter); | 981 scoped_ptr<FormElements> form_elements(*iter); |
1022 | 982 |
1023 // Attach autocomplete listener to enable selecting alternate logins. | 983 // Attach autocomplete listener to enable selecting alternate logins. |
1024 blink::WebInputElement username_element, password_element; | 984 blink::WebInputElement username_element, password_element; |
1025 | 985 |
1026 // Check whether the password form has a username input field. | 986 // Check whether the password form has a username input field. |
1027 bool form_contains_username_field = FillDataContainsUsername(form_data); | 987 bool form_contains_username_field = FillDataContainsUsername(form_data); |
1028 if (form_contains_username_field) { | 988 if (form_contains_username_field) { |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1093 FindFormAndFieldForFormControlElement( | 1053 FindFormAndFieldForFormControlElement( |
1094 user_input, &form, &field, REQUIRE_NONE); | 1054 user_input, &form, &field, REQUIRE_NONE); |
1095 | 1055 |
1096 blink::WebInputElement selected_element = user_input; | 1056 blink::WebInputElement selected_element = user_input; |
1097 gfx::Rect bounding_box(selected_element.boundsInViewportSpace()); | 1057 gfx::Rect bounding_box(selected_element.boundsInViewportSpace()); |
1098 | 1058 |
1099 LoginToPasswordInfoKeyMap::const_iterator key_it = | 1059 LoginToPasswordInfoKeyMap::const_iterator key_it = |
1100 login_to_password_info_key_.find(user_input); | 1060 login_to_password_info_key_.find(user_input); |
1101 DCHECK(key_it != login_to_password_info_key_.end()); | 1061 DCHECK(key_it != login_to_password_info_key_.end()); |
1102 | 1062 |
1103 float scale = web_view_->pageScaleFactor(); | 1063 float scale = |
1064 render_frame()->GetRenderView()->GetWebView()->pageScaleFactor(); | |
1104 gfx::RectF bounding_box_scaled(bounding_box.x() * scale, | 1065 gfx::RectF bounding_box_scaled(bounding_box.x() * scale, |
1105 bounding_box.y() * scale, | 1066 bounding_box.y() * scale, |
1106 bounding_box.width() * scale, | 1067 bounding_box.width() * scale, |
1107 bounding_box.height() * scale); | 1068 bounding_box.height() * scale); |
1108 Send(new AutofillHostMsg_ShowPasswordSuggestions( | 1069 Send(new AutofillHostMsg_ShowPasswordSuggestions( |
1109 routing_id(), key_it->second, field.text_direction, user_input.value(), | 1070 routing_id(), key_it->second, field.text_direction, user_input.value(), |
1110 show_all, bounding_box_scaled)); | 1071 show_all, bounding_box_scaled)); |
1111 | 1072 |
1112 bool suggestions_present = false; | 1073 bool suggestions_present = false; |
1113 if (GetSuggestionsStats(fill_data, user_input.value(), show_all, | 1074 if (GetSuggestionsStats(fill_data, user_input.value(), show_all, |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1146 fill_data, | 1107 fill_data, |
1147 false /* exact_username_match */, | 1108 false /* exact_username_match */, |
1148 true /* set_selection */, | 1109 true /* set_selection */, |
1149 base::Bind(&PasswordValueGatekeeper::RegisterElement, | 1110 base::Bind(&PasswordValueGatekeeper::RegisterElement, |
1150 base::Unretained(&gatekeeper_)))) { | 1111 base::Unretained(&gatekeeper_)))) { |
1151 usernames_usage_ = OTHER_POSSIBLE_USERNAME_SELECTED; | 1112 usernames_usage_ = OTHER_POSSIBLE_USERNAME_SELECTED; |
1152 } | 1113 } |
1153 #endif | 1114 #endif |
1154 } | 1115 } |
1155 | 1116 |
1156 void PasswordAutofillAgent::FrameClosing(const blink::WebFrame* frame) { | 1117 void PasswordAutofillAgent::FrameClosing() { |
1157 for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin(); | 1118 for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin(); |
1158 iter != login_to_password_info_.end();) { | 1119 iter != login_to_password_info_.end();) { |
1159 // There may not be a username field, so get the frame from the password | 1120 // There may not be a username field, so get the frame from the password |
1160 // field. | 1121 // field. |
1161 if (iter->second.password_field.document().frame() == frame) { | 1122 DCHECK_EQ(iter->second.password_field.document().frame(), |
1162 login_to_password_info_key_.erase(iter->first); | 1123 render_frame()->GetWebFrame()); |
1163 password_to_username_.erase(iter->second.password_field); | 1124 login_to_password_info_key_.erase(iter->first); |
1164 login_to_password_info_.erase(iter++); | 1125 password_to_username_.erase(iter->second.password_field); |
1165 } else { | 1126 login_to_password_info_.erase(iter++); |
1166 ++iter; | |
1167 } | |
1168 } | 1127 } |
1169 for (FrameToPasswordFormMap::iterator iter = | 1128 provisionally_saved_form_.reset(); |
1170 provisionally_saved_forms_.begin(); | |
1171 iter != provisionally_saved_forms_.end();) { | |
1172 if (iter->first == frame) | |
1173 provisionally_saved_forms_.erase(iter++); | |
1174 else | |
1175 ++iter; | |
1176 } | |
1177 } | 1129 } |
1178 | 1130 |
1179 bool PasswordAutofillAgent::FindLoginInfo(const blink::WebNode& node, | 1131 bool PasswordAutofillAgent::FindLoginInfo(const blink::WebNode& node, |
1180 blink::WebInputElement* found_input, | 1132 blink::WebInputElement* found_input, |
1181 PasswordInfo** found_password) { | 1133 PasswordInfo** found_password) { |
1182 if (!node.isElementNode()) | 1134 if (!node.isElementNode()) |
1183 return false; | 1135 return false; |
1184 | 1136 |
1185 blink::WebElement element = node.toConst<blink::WebElement>(); | 1137 blink::WebElement element = node.toConst<blink::WebElement>(); |
1186 if (!element.hasHTMLTagName("input")) | 1138 if (!element.hasHTMLTagName("input")) |
(...skipping 18 matching lines...) Expand all Loading... | |
1205 username->setSelectionRange(username_selection_start_, | 1157 username->setSelectionRange(username_selection_start_, |
1206 username->value().length()); | 1158 username->value().length()); |
1207 } | 1159 } |
1208 if (!password->suggestedValue().isEmpty()) { | 1160 if (!password->suggestedValue().isEmpty()) { |
1209 password->setSuggestedValue(blink::WebString()); | 1161 password->setSuggestedValue(blink::WebString()); |
1210 password->setAutofilled(was_password_autofilled_); | 1162 password->setAutofilled(was_password_autofilled_); |
1211 } | 1163 } |
1212 } | 1164 } |
1213 | 1165 |
1214 void PasswordAutofillAgent::ProvisionallySavePassword( | 1166 void PasswordAutofillAgent::ProvisionallySavePassword( |
1215 blink::WebLocalFrame* frame, | |
1216 const blink::WebFormElement& form, | 1167 const blink::WebFormElement& form, |
1217 ProvisionallySaveRestriction restriction) { | 1168 ProvisionallySaveRestriction restriction) { |
1218 // TODO(vabr): This is just to stop getting a NULL frame in | |
1219 // |provisionally_saved_forms_|. Cases where we try to save password for a | |
1220 // form in a NULL frame should not happen, and it's currently unclear how they | |
1221 // happen (http://crbug.com/420519). This thing will be hopefully solved by | |
1222 // migrating the PasswordAutofillAgent to observe frames directly | |
1223 // (http://crbug.com/400186). | |
1224 if (!frame) | |
1225 return; | |
1226 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); | 1169 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); |
1227 if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD && | 1170 if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD && |
1228 password_form->password_value.empty() && | 1171 password_form->password_value.empty() && |
1229 password_form->new_password_value.empty())) { | 1172 password_form->new_password_value.empty())) { |
1230 return; | 1173 return; |
1231 } | 1174 } |
1232 provisionally_saved_forms_[frame].reset(password_form.release()); | 1175 provisionally_saved_form_ = password_form.Pass(); |
1176 } | |
1177 | |
1178 // LegacyPasswordAutofillAgent ------------------------------------------------- | |
1179 | |
1180 PasswordAutofillAgent::LegacyPasswordAutofillAgent::LegacyPasswordAutofillAgent( | |
1181 content::RenderView* render_view, | |
1182 PasswordAutofillAgent* agent) | |
1183 : content::RenderViewObserver(render_view), agent_(agent) { | |
1184 } | |
1185 | |
1186 PasswordAutofillAgent::LegacyPasswordAutofillAgent:: | |
1187 ~LegacyPasswordAutofillAgent() { | |
1188 } | |
1189 | |
1190 void PasswordAutofillAgent::LegacyPasswordAutofillAgent::OnDestruct() { | |
1191 // No op. Do not delete |this|. | |
1192 } | |
1193 | |
1194 void PasswordAutofillAgent::LegacyPasswordAutofillAgent::DidStartLoading() { | |
1195 agent_->DidStartLoading(); | |
1196 } | |
1197 | |
1198 void PasswordAutofillAgent::LegacyPasswordAutofillAgent::DidStopLoading() { | |
1199 agent_->DidStopLoading(); | |
1200 } | |
1201 | |
1202 void PasswordAutofillAgent::LegacyPasswordAutofillAgent::FrameDetached( | |
1203 blink::WebFrame* frame) { | |
1204 agent_->FrameDetached(frame); | |
1205 } | |
1206 | |
1207 void PasswordAutofillAgent::LegacyPasswordAutofillAgent::WillSendSubmitEvent( | |
1208 blink::WebLocalFrame* frame, | |
1209 const blink::WebFormElement& form) { | |
1210 agent_->WillSendSubmitEvent(frame, form); | |
1211 } | |
1212 | |
1213 void PasswordAutofillAgent::LegacyPasswordAutofillAgent::WillSubmitForm( | |
1214 blink::WebLocalFrame* frame, | |
1215 const blink::WebFormElement& form) { | |
1216 agent_->WillSubmitForm(frame, form); | |
1233 } | 1217 } |
1234 | 1218 |
1235 } // namespace autofill | 1219 } // namespace autofill |
OLD | NEW |