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

Unified Diff: components/autofill/content/renderer/password_autofill_agent.cc

Issue 2865233003: Use an MutationObserver to check when a password form disappears after XHR (Closed)
Patch Set: updates Created 3 years, 7 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 side-by-side diff with in-line comments
Download patch
Index: components/autofill/content/renderer/password_autofill_agent.cc
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index e73ef7c656ae558b3f756e921fac3fe9a79c704c..6ea1c0cc7fc98171d9d70fb1284e8877437d7150 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -44,6 +44,7 @@
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebElement.h"
#include "third_party/WebKit/public/web/WebFormElement.h"
+#include "third_party/WebKit/public/web/WebFormElementObserverCallback.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebNode.h"
#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
@@ -618,6 +619,34 @@ bool HasPasswordField(const blink::WebLocalFrame& frame) {
} // namespace
+class PasswordAutofillAgent::FormElementObserver
+ : public blink::WebFormElementObserverCallback {
+ public:
+ explicit FormElementObserver(PasswordAutofillAgent* agent) : agent_(agent) {}
+ ~FormElementObserver() override { Detach(); }
+
+ void Detach() {
+ if (agent_) {
+ DCHECK_EQ(agent_->form_element_observer_, this);
+ agent_->form_element_observer_ = nullptr;
+ }
+ agent_ = nullptr;
+ }
+
+ void ElementWasHiddenOrRemoved() override {
+ if (!agent_)
+ return;
+ agent_->OnSameDocumentNavigationCompleted(
+ PasswordForm::SubmissionIndicatorEvent::DOM_MUTATION_AFTER_XHR);
+ // The above call will delete "this".
+ }
+
+ private:
+ PasswordAutofillAgent* agent_;
+
+ DISALLOW_COPY_AND_ASSIGN(FormElementObserver);
+};
+
////////////////////////////////////////////////////////////////////////////////
// PasswordAutofillAgent, public:
@@ -628,13 +657,16 @@ PasswordAutofillAgent::PasswordAutofillAgent(content::RenderFrame* render_frame)
was_password_autofilled_(false),
sent_request_to_store_(false),
checked_safe_browsing_reputation_(false),
- binding_(this) {
+ binding_(this),
+ form_element_observer_(nullptr) {
// PasswordAutofillAgent is guaranteed to outlive |render_frame|.
render_frame->GetInterfaceRegistry()->AddInterface(
base::Bind(&PasswordAutofillAgent::BindRequest, base::Unretained(this)));
}
PasswordAutofillAgent::~PasswordAutofillAgent() {
+ if (form_element_observer_)
+ form_element_observer_->Detach();
}
void PasswordAutofillAgent::BindRequest(
@@ -1032,37 +1064,53 @@ void PasswordAutofillAgent::OnDynamicFormsSeen() {
}
void PasswordAutofillAgent::AJAXSucceeded() {
- OnSameDocumentNavigationCompleted(false);
+ OnSameDocumentNavigationCompleted(
+ PasswordForm::SubmissionIndicatorEvent::XHR_SUCCEEDED);
}
void PasswordAutofillAgent::OnSameDocumentNavigationCompleted(
- bool is_inpage_navigation) {
+ PasswordForm::SubmissionIndicatorEvent event) {
if (!provisionally_saved_form_.IsPasswordValid())
return;
- provisionally_saved_form_.SetSubmissionIndicatorEvent(
- is_inpage_navigation
- ? PasswordForm::SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION
- : PasswordForm::SubmissionIndicatorEvent::XHR_SUCCEEDED);
-
// Prompt to save only if the form is now gone, either invisible or
// removed from the DOM.
blink::WebFrame* frame = render_frame()->GetWebFrame();
const auto& password_form = provisionally_saved_form_.password_form();
// TODO(crbug.com/720347): This method could be called often and checking form
// visibility could be expesive. Add performance metrics for this.
- if (form_util::IsFormVisible(frame, provisionally_saved_form_.form_element(),
- password_form.action, password_form.origin,
- password_form.form_data) ||
- (provisionally_saved_form_.form_element().IsNull() &&
- IsUnownedPasswordFormVisible(
- frame, provisionally_saved_form_.input_element(),
- password_form.action, password_form.origin, password_form.form_data,
- form_predictions_))) {
+ if (event != PasswordForm::SubmissionIndicatorEvent::DOM_MUTATION_AFTER_XHR &&
+ (form_util::IsFormVisible(frame, provisionally_saved_form_.form_element(),
+ password_form.action, password_form.origin,
+ password_form.form_data) ||
+ (provisionally_saved_form_.form_element().IsNull() &&
+ IsUnownedPasswordFormVisible(
+ frame, provisionally_saved_form_.input_element(),
+ password_form.action, password_form.origin, password_form.form_data,
+ form_predictions_)))) {
+ if (!form_element_observer_) {
+ std::unique_ptr<FormElementObserver> observer(
+ new FormElementObserver(this));
+ form_element_observer_ = observer.get();
+ if (provisionally_saved_form_.form_element().IsNull()) {
+ provisionally_saved_form_.input_element()
+ .GetDocument()
+ .ObserveFormElement(provisionally_saved_form_.input_element(),
+ std::move(observer));
+ } else {
+ provisionally_saved_form_.form_element()
+ .GetDocument()
+ .ObserveFormElement(provisionally_saved_form_.form_element(),
+ std::move(observer));
+ }
+ }
return;
}
+ provisionally_saved_form_.SetSubmissionIndicatorEvent(event);
GetPasswordManagerDriver()->InPageNavigation(password_form);
+ if (form_element_observer_)
+ form_element_observer_->Detach();
provisionally_saved_form_.Reset();
}
@@ -1217,7 +1265,8 @@ void PasswordAutofillAgent::DidCommitProvisionalLoad(
bool is_new_navigation,
bool is_same_document_navigation) {
if (is_same_document_navigation) {
- OnSameDocumentNavigationCompleted(true);
+ OnSameDocumentNavigationCompleted(
+ PasswordForm::SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION);
} else {
checked_safe_browsing_reputation_ = false;
}
@@ -1299,6 +1348,8 @@ void PasswordAutofillAgent::WillSubmitForm(const blink::WebFormElement& form) {
// RenderView to be instantiated (such as redirects to the WebStore)
// we will never get to finish the load.
GetPasswordManagerDriver()->PasswordFormSubmitted(*submitted_form);
+ if (form_element_observer_)
+ form_element_observer_->Detach();
provisionally_saved_form_.Reset();
} else if (logger) {
logger->LogMessage(Logger::STRING_FORM_IS_NOT_PASSWORD);
@@ -1346,6 +1397,8 @@ void PasswordAutofillAgent::DidStartProvisionalLoad(
}
GetPasswordManagerDriver()->PasswordFormSubmitted(
provisionally_saved_form_.password_form());
+ if (form_element_observer_)
+ form_element_observer_->Detach();
provisionally_saved_form_.Reset();
} else {
std::vector<std::unique_ptr<PasswordForm>> possible_submitted_forms;
@@ -1629,6 +1682,8 @@ void PasswordAutofillAgent::FrameClosing() {
password_to_username_.erase(iter.second.password_field);
}
web_input_to_password_info_.clear();
+ if (form_element_observer_)
+ form_element_observer_->Detach();
provisionally_saved_form_.Reset();
field_value_and_properties_map_.clear();
sent_request_to_store_ = false;

Powered by Google App Engine
This is Rietveld 408576698