summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgcasto@chromium.org <gcasto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-16 01:09:12 +0000
committergcasto@chromium.org <gcasto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-16 01:09:12 +0000
commit0660a8c72b2841655ae2e0b852e7f8aca4b602b3 (patch)
treed56f2fa87ad6a35815e30f322f915b83757b0752
parentdcf99f46e7eeee2c2633d0eabb2f4dd21a5aaa79 (diff)
downloadchromium_src-0660a8c72b2841655ae2e0b852e7f8aca4b602b3.zip
chromium_src-0660a8c72b2841655ae2e0b852e7f8aca4b602b3.tar.gz
chromium_src-0660a8c72b2841655ae2e0b852e7f8aca4b602b3.tar.bz2
[password autofill] Remove references to PasswordForm from RenderViewImpl
autofill::PasswordAutofillAgent now manages submitted passwords instead. Browser side classes other than PasswordManager which want to monitor these submits do so via registering a callback with PasswordManager::AddSubmissionsCallback(). This is the first step in moving content::PasswordForm to autofill::PasswordForm. BUG=263121 Review URL: https://chromiumcodereview.appspot.com/19705013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@217900 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/android/tab_android.cc3
-rw-r--r--chrome/browser/password_manager/password_form_manager_unittest.cc4
-rw-r--r--chrome/browser/password_manager/password_manager.cc36
-rw-r--r--chrome/browser/password_manager/password_manager.h18
-rw-r--r--chrome/browser/password_manager/password_manager_browsertest.cc103
-rw-r--r--chrome/browser/password_manager/password_manager_unittest.cc101
-rw-r--r--chrome/browser/prerender/prerender_tab_helper.cc38
-rw-r--r--chrome/browser/prerender/prerender_tab_helper.h24
-rw-r--r--chrome/browser/ui/browser_tab_contents.cc6
-rw-r--r--chrome/browser/ui/sync/one_click_signin_helper.cc43
-rw-r--r--chrome/browser/ui/sync/one_click_signin_helper.h13
-rw-r--r--chrome/browser/ui/sync/one_click_signin_helper_unittest.cc6
-rw-r--r--chrome/chrome_common.gypi1
-rw-r--r--chrome/chrome_renderer.gypi2
-rw-r--r--chrome/common/common_message_generator.h1
-rw-r--r--chrome/common/one_click_signin_messages.h12
-rw-r--r--chrome/renderer/chrome_content_renderer_client.cc5
-rw-r--r--chrome/renderer/one_click_signin_agent.cc29
-rw-r--r--chrome/renderer/one_click_signin_agent.h25
-rw-r--r--chrome/test/data/password/done.html (renamed from chrome/test/data/password/password_xhr_done.html)2
-rw-r--r--chrome/test/data/password/multi_frames.html10
-rw-r--r--chrome/test/data/password/password_form.html15
-rw-r--r--chrome/test/data/password/password_xhr_submit.html2
-rw-r--r--components/autofill/content/renderer/password_autofill_agent.cc60
-rw-r--r--components/autofill/content/renderer/password_autofill_agent.h12
-rw-r--r--components/autofill/core/common/autofill_messages.h4
-rw-r--r--content/browser/renderer_host/render_view_host_impl.cc2
-rw-r--r--content/browser/renderer_host/test_render_view_host.cc3
-rw-r--r--content/common/view_messages.h1
-rw-r--r--content/public/common/frame_navigate_params.h4
-rw-r--r--content/public/renderer/document_state.cc6
-rw-r--r--content/public/renderer/document_state.h17
-rw-r--r--content/public/renderer/render_view_observer.h2
-rw-r--r--content/renderer/render_frame_impl.cc29
-rw-r--r--content/renderer/render_view_impl.cc25
-rw-r--r--content/test/test_web_contents.cc2
36 files changed, 416 insertions, 250 deletions
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
index 3b5b2b1..d4da9b7 100644
--- a/chrome/browser/android/tab_android.cc
+++ b/chrome/browser/android/tab_android.cc
@@ -78,7 +78,8 @@ void BrowserTabContents::AttachTabHelpers(WebContents* contents) {
PasswordManager::CreateForWebContentsAndDelegate(
contents, PasswordManagerDelegateImpl::FromWebContents(contents));
PrefsTabHelper::CreateForWebContents(contents);
- prerender::PrerenderTabHelper::CreateForWebContents(contents);
+ prerender::PrerenderTabHelper::CreateForWebContentsWithPasswordManager(
+ contents, PasswordManager::FromWebContents(contents));
SSLTabHelper::CreateForWebContents(contents);
TabSpecificContentSettings::CreateForWebContents(contents);
TranslateTabHelper::CreateForWebContents(contents);
diff --git a/chrome/browser/password_manager/password_form_manager_unittest.cc b/chrome/browser/password_manager/password_form_manager_unittest.cc
index f9771a2..33339e1 100644
--- a/chrome/browser/password_manager/password_form_manager_unittest.cc
+++ b/chrome/browser/password_manager/password_form_manager_unittest.cc
@@ -24,6 +24,8 @@ using content::PasswordForm;
using ::testing::Eq;
+namespace {
+
class TestPasswordManagerDelegate : public PasswordManagerDelegate {
public:
explicit TestPasswordManagerDelegate(Profile* profile) : profile_(profile) {}
@@ -51,6 +53,8 @@ class TestPasswordManager : public PasswordManager {
bool wait_for_username) const OVERRIDE {}
};
+} // namespace
+
class TestPasswordFormManager : public PasswordFormManager {
public:
TestPasswordFormManager(Profile* profile,
diff --git a/chrome/browser/password_manager/password_manager.cc b/chrome/browser/password_manager/password_manager.cc
index db7148e..b421a58 100644
--- a/chrome/browser/password_manager/password_manager.cc
+++ b/chrome/browser/password_manager/password_manager.cc
@@ -228,6 +228,11 @@ void PasswordManager::RecordFailure(ProvisionalSaveFailure failure) {
failure, MAX_FAILURE_VALUE);
}
+void PasswordManager::AddSubmissionCallback(
+ const PasswordSubmittedCallback& callback) {
+ submission_callbacks_.push_back(callback);
+}
+
void PasswordManager::AddObserver(LoginModelObserver* observer) {
observers_.AddObserver(observer);
}
@@ -236,20 +241,13 @@ void PasswordManager::RemoveObserver(LoginModelObserver* observer) {
observers_.RemoveObserver(observer);
}
-void PasswordManager::DidNavigateAnyFrame(
+void PasswordManager::DidNavigateMainFrame(
const content::LoadCommittedDetails& details,
const content::FrameNavigateParams& params) {
- bool password_form_submitted = params.password_form.origin.is_valid();
-
- // Try to save the password if one was submitted.
- if (password_form_submitted)
- ProvisionallySavePassword(params.password_form);
-
- // Clear data after submission or main frame navigation. We don't want
- // to clear data after subframe navigation as there might be password
- // forms on other frames that could be submitted.
- if (password_form_submitted || details.is_main_frame)
- pending_login_managers_.clear();
+ // Clear data after main frame navigation. We don't want to clear data after
+ // subframe navigation as there might be password forms on other frames that
+ // could be submitted.
+ pending_login_managers_.clear();
}
bool PasswordManager::OnMessageReceived(const IPC::Message& message) {
@@ -259,11 +257,23 @@ bool PasswordManager::OnMessageReceived(const IPC::Message& message) {
OnPasswordFormsParsed)
IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormsRendered,
OnPasswordFormsRendered)
+ IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormSubmitted,
+ OnPasswordFormSubmitted)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
+void PasswordManager::OnPasswordFormSubmitted(
+ const PasswordForm& password_form) {
+ ProvisionallySavePassword(password_form);
+ for (size_t i = 0; i < submission_callbacks_.size(); ++i) {
+ submission_callbacks_[i].Run(password_form);
+ }
+
+ pending_login_managers_.clear();
+}
+
void PasswordManager::OnPasswordFormsParsed(
const std::vector<PasswordForm>& forms) {
// Ask the SSLManager for current security.
@@ -391,7 +401,7 @@ void PasswordManager::Autofill(
PossiblyInitializeUsernamesExperiment(best_matches);
switch (form_for_autofill.scheme) {
case PasswordForm::SCHEME_HTML: {
- // Note the check above is required because the observer_ for a non-HTML
+ // Note the check above is required because the observers_ for a non-HTML
// schemed password form may have been freed, so we need to distinguish.
autofill::PasswordFormFillData fill_data;
InitPasswordFormFillData(form_for_autofill,
diff --git a/chrome/browser/password_manager/password_manager.h b/chrome/browser/password_manager/password_manager.h
index 7167efd..351f6e5 100644
--- a/chrome/browser/password_manager/password_manager.h
+++ b/chrome/browser/password_manager/password_manager.h
@@ -7,6 +7,7 @@
#include <vector>
+#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/observer_list.h"
@@ -42,6 +43,14 @@ class PasswordManager : public LoginModel,
PasswordManagerDelegate* delegate);
virtual ~PasswordManager();
+ typedef base::Callback<void(const content::PasswordForm&)>
+ PasswordSubmittedCallback;
+
+ // There is no corresponding remove function as currently all of the
+ // owners of these callbacks have sufficient lifetimes so that the callbacks
+ // should always be valid when called.
+ void AddSubmissionCallback(const PasswordSubmittedCallback& callback);
+
// Is saving new data for password autofill enabled for the current profile?
// For example, saving new data is disabled in Incognito mode, whereas filling
// data is not.
@@ -69,7 +78,7 @@ class PasswordManager : public LoginModel,
void ProvisionallySavePassword(const content::PasswordForm& form);
// content::WebContentsObserver overrides.
- virtual void DidNavigateAnyFrame(
+ virtual void DidNavigateMainFrame(
const content::LoadCommittedDetails& details,
const content::FrameNavigateParams& params) OVERRIDE;
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
@@ -86,6 +95,10 @@ class PasswordManager : public LoginModel,
PasswordManager(content::WebContents* web_contents,
PasswordManagerDelegate* delegate);
+ // Handle notification that a password form was submitted.
+ virtual void OnPasswordFormSubmitted(
+ const content::PasswordForm& password_form);
+
private:
friend class content::WebContentsUserData<PasswordManager>;
@@ -156,6 +169,9 @@ class PasswordManager : public LoginModel,
// notification in const member functions.
mutable ObserverList<LoginModelObserver> observers_;
+ // Callbacks to be notified when a password form has been submitted.
+ std::vector<PasswordSubmittedCallback> submission_callbacks_;
+
DISALLOW_COPY_AND_ASSIGN(PasswordManager);
};
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index 02d2cea..9d1e663 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -112,8 +112,109 @@ class PasswordManagerBrowserTest : public InProcessBrowserTest {
DISALLOW_COPY_AND_ASSIGN(PasswordManagerBrowserTest);
};
-
// Actual tests ---------------------------------------------------------------
+IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, PromptForNormalSubmit) {
+ ASSERT_TRUE(test_server()->Start());
+
+ GURL url = test_server()->GetURL("files/password/password_form.html");
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // Fill a form and submit through a <input type="submit"> button. Nothing
+ // special.
+ NavigationObserver observer(WebContents());
+ std::string fill_and_submit =
+ "document.getElementById('username_field').value = 'temp';"
+ "document.getElementById('password_field').value = 'random';"
+ "document.getElementById('input_submit_button').click()";
+ ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
+ observer.Wait();
+ EXPECT_TRUE(observer.infobar_shown());
+}
+
+IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
+ PromptForSubmitUsingJavaScript) {
+ ASSERT_TRUE(test_server()->Start());
+
+ GURL url = test_server()->GetURL("files/password/password_form.html");
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // Fill a form and submit using <button> that calls submit() on the form.
+ // This should work regardless of the type of element, as long as submit() is
+ // called.
+ NavigationObserver observer(WebContents());
+ std::string fill_and_submit =
+ "document.getElementById('username_field').value = 'temp';"
+ "document.getElementById('password_field').value = 'random';"
+ "document.getElementById('submit_button').click()";
+ ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
+ observer.Wait();
+ EXPECT_TRUE(observer.infobar_shown());
+}
+
+IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptForNavigation) {
+ ASSERT_TRUE(test_server()->Start());
+
+ GURL url = test_server()->GetURL("files/password/password_form.html");
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // Don't fill the password form, just navigate away. Shouldn't prompt.
+ NavigationObserver observer(WebContents());
+ ASSERT_TRUE(content::ExecuteScript(RenderViewHost(),
+ "window.location.href = 'done.html';"));
+ observer.Wait();
+ EXPECT_FALSE(observer.infobar_shown());
+}
+
+IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
+ NoPromptForSubFrameNavigation) {
+ ASSERT_TRUE(test_server()->Start());
+
+ GURL url = test_server()->GetURL("files/password/multi_frames.html");
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // If you are filling out a password form in one frame and a different frame
+ // navigates, this should not trigger the infobar.
+ NavigationObserver observer(WebContents());
+ std::string fill =
+ "var first_frame = document.getElementById('first_frame');"
+ "var frame_doc = first_frame.contentDocument;"
+ "frame_doc.getElementById('username_field').value = 'temp';"
+ "frame_doc.getElementById('password_field').value = 'random';";
+ std::string navigate_frame =
+ "var second_iframe = document.getElementById('second_frame');"
+ "second_iframe.contentWindow.location.href = 'done.html';";
+
+ ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill));
+ ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame));
+ observer.Wait();
+ EXPECT_FALSE(observer.infobar_shown());
+}
+
+IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
+ PromptAfterSubmitWithSubFrameNavigation) {
+ ASSERT_TRUE(test_server()->Start());
+
+ GURL url = test_server()->GetURL("files/password/multi_frames.html");
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // Make sure that we prompt to save password even if a sub-frame navigation
+ // happens first.
+ NavigationObserver observer(WebContents());
+ std::string navigate_frame =
+ "var second_iframe = document.getElementById('second_frame');"
+ "second_iframe.contentWindow.location.href = 'done.html';";
+ std::string fill_and_submit =
+ "var first_frame = document.getElementById('first_frame');"
+ "var frame_doc = first_frame.contentDocument;"
+ "frame_doc.getElementById('username_field').value = 'temp';"
+ "frame_doc.getElementById('password_field').value = 'random';"
+ "frame_doc.getElementById('input_submit_button').click();";
+
+ ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame));
+ ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
+ observer.Wait();
+ EXPECT_TRUE(observer.infobar_shown());
+}
IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, PromptForXHRSubmit) {
#if defined(OS_WIN) && defined(USE_ASH)
diff --git a/chrome/browser/password_manager/password_manager_unittest.cc b/chrome/browser/password_manager/password_manager_unittest.cc
index 45ab851..cecba4f 100644
--- a/chrome/browser/password_manager/password_manager_unittest.cc
+++ b/chrome/browser/password_manager/password_manager_unittest.cc
@@ -30,6 +30,8 @@ using testing::Exactly;
using testing::Return;
using testing::WithArg;
+namespace {
+
class MockPasswordManagerDelegate : public PasswordManagerDelegate {
public:
MOCK_METHOD1(FillPasswordForm, void(const autofill::PasswordFormFillData&));
@@ -46,6 +48,31 @@ ACTION_P(SaveToScopedPtr, scoped) {
scoped->reset(arg0);
}
+class TestPasswordManager : public PasswordManager {
+ public:
+ TestPasswordManager(content::WebContents* contents,
+ PasswordManagerDelegate* delegate)
+ : PasswordManager(contents, delegate) {}
+ virtual ~TestPasswordManager() {}
+
+ virtual void OnPasswordFormSubmitted(const PasswordForm& form) OVERRIDE {
+ PasswordManager::OnPasswordFormSubmitted(form);
+ }
+
+ static TestPasswordManager* CreateForWebContentsAndDelegate(
+ content::WebContents* contents,
+ PasswordManagerDelegate* delegate) {
+ TestPasswordManager* tpm = new TestPasswordManager(contents, delegate);
+ contents->SetUserData(UserDataKey(), tpm);
+ return tpm;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestPasswordManager);
+};
+
+} // namespace
+
class PasswordManagerTest : public ChromeRenderViewHostTestHarness {
protected:
virtual void SetUp() {
@@ -55,7 +82,7 @@ class PasswordManagerTest : public ChromeRenderViewHostTestHarness {
profile(), MockPasswordStore::Build).get());
EXPECT_CALL(delegate_, GetProfile()).WillRepeatedly(Return(profile()));
- PasswordManager::CreateForWebContentsAndDelegate(
+ manager_ = TestPasswordManager::CreateForWebContentsAndDelegate(
web_contents(), &delegate_);
EXPECT_CALL(delegate_, DidLastPageLoadEncounterSSLErrors())
.WillRepeatedly(Return(false));
@@ -81,12 +108,50 @@ class PasswordManagerTest : public ChromeRenderViewHostTestHarness {
return form;
}
- PasswordManager* manager() {
- return PasswordManager::FromWebContents(web_contents());
+ bool FormsAreEqual(const content::PasswordForm& lhs,
+ const content::PasswordForm& rhs) {
+ if (lhs.origin != rhs.origin)
+ return false;
+ if (lhs.action != rhs.action)
+ return false;
+ if (lhs.username_element != rhs.username_element)
+ return false;
+ if (lhs.password_element != rhs.password_element)
+ return false;
+ if (lhs.username_value != rhs.username_value)
+ return false;
+ if (lhs.password_value != rhs.password_value)
+ return false;
+ if (lhs.password_autocomplete_set != rhs.password_autocomplete_set)
+ return false;
+ if (lhs.submit_element != rhs.submit_element)
+ return false;
+ if (lhs.signon_realm != rhs.signon_realm)
+ return false;
+ return true;
+ }
+
+ TestPasswordManager* manager() {
+ return manager_;
+ }
+
+ void OnPasswordFormSubmitted(const content::PasswordForm& form) {
+ manager()->OnPasswordFormSubmitted(form);
+ }
+
+ PasswordManager::PasswordSubmittedCallback SubmissionCallback() {
+ return base::Bind(&PasswordManagerTest::FormSubmitted,
+ base::Unretained(this));
+ }
+
+ void FormSubmitted(const content::PasswordForm& form) {
+ submitted_form_ = form;
}
scoped_refptr<MockPasswordStore> store_;
+ TestPasswordManager* manager_;
MockPasswordManagerDelegate delegate_; // Owned by manager_.
+ PasswordForm submitted_form_;
};
MATCHER_P(FormMatches, form, "") {
@@ -208,15 +273,8 @@ TEST_F(PasswordManagerTest, FormSeenThenLeftPage) {
manager()->OnPasswordFormsParsed(observed); // The initial load.
manager()->OnPasswordFormsRendered(observed); // The initial layout.
- PasswordForm empty_form(form);
- empty_form.username_value = string16();
- empty_form.password_value = string16();
- content::LoadCommittedDetails details;
- content::FrameNavigateParams params;
- params.password_form = empty_form;
- manager()->DidNavigateAnyFrame(details, params);
-
- // No expected calls.
+ // No message from the renderer that a password was submitted. No
+ // expected calls.
EXPECT_CALL(delegate_, AddSavePasswordInfoBarIfPermitted(_)).Times(0);
observed.clear();
manager()->OnPasswordFormsParsed(observed); // The post-navigation load.
@@ -238,14 +296,11 @@ TEST_F(PasswordManagerTest, FormSubmitAfterNavigateSubframe) {
// Simulate navigating a sub-frame.
content::LoadCommittedDetails details;
- details.is_main_frame = false;
content::FrameNavigateParams params;
manager()->DidNavigateAnyFrame(details, params);
- // Simulate navigating the real page.
- details.is_main_frame = true;
- params.password_form = form;
- manager()->DidNavigateAnyFrame(details, params);
+ // Simulate submitting the password.
+ OnPasswordFormSubmitted(form);
// Now the password manager waits for the navigation to complete.
scoped_ptr<PasswordFormManager> form_to_save;
@@ -289,7 +344,7 @@ TEST_F(PasswordManagerTest, FormSubmitWithFormOnPreviousPage) {
content::LoadCommittedDetails details;
details.is_main_frame = true;
content::FrameNavigateParams params;
- manager()->DidNavigateAnyFrame(details, params);
+ manager()->DidNavigateMainFrame(details, params);
// This page contains a form with the same markup, but on a different
// URL.
@@ -298,8 +353,7 @@ TEST_F(PasswordManagerTest, FormSubmitWithFormOnPreviousPage) {
manager()->OnPasswordFormsRendered(observed);
// Now submit this form
- params.password_form = second_form;
- manager()->DidNavigateAnyFrame(details, params);
+ OnPasswordFormSubmitted(second_form);
// Navigation after form submit.
scoped_ptr<PasswordFormManager> form_to_save;
@@ -475,3 +529,10 @@ TEST_F(PasswordManagerTest, GeneratedPasswordFormSavedAutocompleteOff) {
manager()->OnPasswordFormsParsed(observed); // The post-navigation load.
manager()->OnPasswordFormsRendered(observed); // The post-navigation layout.
}
+
+TEST_F(PasswordManagerTest, SubmissionCallbackTest) {
+ manager()->AddSubmissionCallback(SubmissionCallback());
+ PasswordForm form = MakeSimpleForm();
+ OnPasswordFormSubmitted(form);
+ EXPECT_TRUE(FormsAreEqual(form, submitted_form_));
+}
diff --git a/chrome/browser/prerender/prerender_tab_helper.cc b/chrome/browser/prerender/prerender_tab_helper.cc
index cd67ad2..17ff619 100644
--- a/chrome/browser/prerender/prerender_tab_helper.cc
+++ b/chrome/browser/prerender/prerender_tab_helper.cc
@@ -4,9 +4,11 @@
#include "chrome/browser/prerender/prerender_tab_helper.h"
+#include "base/bind.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
+#include "chrome/browser/password_manager/password_manager.h"
#include "chrome/browser/predictors/logged_in_predictor_table.h"
#include "chrome/browser/prerender/prerender_histograms.h"
#include "chrome/browser/prerender/prerender_local_predictor.h"
@@ -150,9 +152,24 @@ class PrerenderTabHelper::PixelStats {
PrerenderTabHelper* tab_helper_;
};
-PrerenderTabHelper::PrerenderTabHelper(content::WebContents* web_contents)
+// static
+void PrerenderTabHelper::CreateForWebContentsWithPasswordManager(
+ content::WebContents* web_contents,
+ PasswordManager* password_manager) {
+ if (!FromWebContents(web_contents)) {
+ web_contents->SetUserData(UserDataKey(),
+ new PrerenderTabHelper(web_contents,
+ password_manager));
+ }
+}
+
+PrerenderTabHelper::PrerenderTabHelper(content::WebContents* web_contents,
+ PasswordManager* password_manager)
: content::WebContentsObserver(web_contents),
weak_factory_(this) {
+ password_manager->AddSubmissionCallback(
+ base::Bind(&PrerenderTabHelper::PasswordSubmitted,
+ weak_factory_.GetWeakPtr()));
}
PrerenderTabHelper::~PrerenderTabHelper() {
@@ -243,22 +260,13 @@ void PrerenderTabHelper::DidStartProvisionalLoadForFrame(
}
}
-void PrerenderTabHelper::DidNavigateAnyFrame(
- const content::LoadCommittedDetails& details,
- const content::FrameNavigateParams& params) {
+void PrerenderTabHelper::PasswordSubmitted(const content::PasswordForm& form) {
PrerenderManager* prerender_manager = MaybeGetPrerenderManager();
- if (params.password_form.origin.is_valid() && prerender_manager) {
- prerender_manager->RecordLikelyLoginOnURL(params.url);
+ if (prerender_manager) {
+ prerender_manager->RecordLikelyLoginOnURL(form.origin);
RecordEvent(EVENT_LOGIN_ACTION_ADDED);
- if (details.is_main_frame) {
- RecordEvent(EVENT_LOGIN_ACTION_ADDED_MAINFRAME);
- if (params.password_form.password_value.empty())
- RecordEvent(EVENT_LOGIN_ACTION_ADDED_MAINFRAME_PW_EMPTY);
- } else {
- RecordEvent(EVENT_LOGIN_ACTION_ADDED_SUBFRAME);
- if (params.password_form.password_value.empty())
- RecordEvent(EVENT_LOGIN_ACTION_ADDED_SUBFRAME_PW_EMPTY);
- }
+ if (form.password_value.empty())
+ RecordEvent(EVENT_LOGIN_ACTION_ADDED_PW_EMPTY);
}
}
diff --git a/chrome/browser/prerender/prerender_tab_helper.h b/chrome/browser/prerender/prerender_tab_helper.h
index c48290e..4bfdd19 100644
--- a/chrome/browser/prerender/prerender_tab_helper.h
+++ b/chrome/browser/prerender/prerender_tab_helper.h
@@ -12,6 +12,12 @@
#include "content/public/browser/web_contents_user_data.h"
#include "url/gurl.h"
+class PasswordManager;
+
+namespace content {
+struct PasswordForm;
+}
+
namespace predictors {
class LoggedInPredictorTable;
}
@@ -34,13 +40,14 @@ class PrerenderTabHelper
EVENT_MAINFRAME_COMMIT = 4,
EVENT_MAINFRAME_COMMIT_DOMAIN_LOGGED_IN = 5,
EVENT_LOGIN_ACTION_ADDED = 6,
- EVENT_LOGIN_ACTION_ADDED_MAINFRAME = 7,
- EVENT_LOGIN_ACTION_ADDED_MAINFRAME_PW_EMPTY = 8,
- EVENT_LOGIN_ACTION_ADDED_SUBFRAME = 9,
- EVENT_LOGIN_ACTION_ADDED_SUBFRAME_PW_EMPTY = 10,
+ EVENT_LOGIN_ACTION_ADDED_PW_EMPTY = 7,
EVENT_MAX_VALUE
};
+ static void CreateForWebContentsWithPasswordManager(
+ content::WebContents* web_contents,
+ PasswordManager* password_manager);
+
virtual ~PrerenderTabHelper();
// content::WebContentsObserver implementation.
@@ -63,15 +70,16 @@ class PrerenderTabHelper
const GURL& validated_url,
content::PageTransition transition_type,
content::RenderViewHost* render_view_host) OVERRIDE;
- virtual void DidNavigateAnyFrame(
- const content::LoadCommittedDetails& details,
- const content::FrameNavigateParams& params) OVERRIDE;
+
+ // Called when a password form has been submitted.
+ void PasswordSubmitted(const content::PasswordForm& form);
// Called when this prerendered WebContents has just been swapped in.
void PrerenderSwappedIn();
private:
- explicit PrerenderTabHelper(content::WebContents* web_contents);
+ PrerenderTabHelper(content::WebContents* web_contents,
+ PasswordManager* password_manager);
friend class content::WebContentsUserData<PrerenderTabHelper>;
void RecordEvent(Event event) const;
diff --git a/chrome/browser/ui/browser_tab_contents.cc b/chrome/browser/ui/browser_tab_contents.cc
index 032f107..6680210 100644
--- a/chrome/browser/ui/browser_tab_contents.cc
+++ b/chrome/browser/ui/browser_tab_contents.cc
@@ -144,7 +144,8 @@ void BrowserTabContents::AttachTabHelpers(WebContents* web_contents) {
PopupBlockerTabHelper::CreateForWebContents(web_contents);
}
PrefsTabHelper::CreateForWebContents(web_contents);
- prerender::PrerenderTabHelper::CreateForWebContents(web_contents);
+ prerender::PrerenderTabHelper::CreateForWebContentsWithPasswordManager(
+ web_contents, PasswordManager::FromWebContents(web_contents));
SadTabHelper::CreateForWebContents(web_contents);
safe_browsing::SafeBrowsingTabObserver::CreateForWebContents(web_contents);
SearchEngineTabHelper::CreateForWebContents(web_contents);
@@ -183,7 +184,8 @@ void BrowserTabContents::AttachTabHelpers(WebContents* web_contents) {
OneClickSigninHelper::CAN_OFFER_FOR_ALL,
std::string(),
NULL)) {
- OneClickSigninHelper::CreateForWebContents(web_contents);
+ OneClickSigninHelper::CreateForWebContentsWithPasswordManager(
+ web_contents, PasswordManager::FromWebContents(web_contents));
}
#endif
diff --git a/chrome/browser/ui/sync/one_click_signin_helper.cc b/chrome/browser/ui/sync/one_click_signin_helper.cc
index 46f030d..adc3b7e 100644
--- a/chrome/browser/ui/sync/one_click_signin_helper.cc
+++ b/chrome/browser/ui/sync/one_click_signin_helper.cc
@@ -26,6 +26,7 @@
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/google/google_util.h"
+#include "chrome/browser/password_manager/password_manager.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_info_cache.h"
@@ -54,7 +55,6 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/net/url_util.h"
-#include "chrome/common/one_click_signin_messages.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/browser_thread.h"
@@ -560,7 +560,8 @@ DEFINE_WEB_CONTENTS_USER_DATA_KEY(OneClickSigninHelper);
// static
const int OneClickSigninHelper::kMaxNavigationsSince = 10;
-OneClickSigninHelper::OneClickSigninHelper(content::WebContents* web_contents)
+OneClickSigninHelper::OneClickSigninHelper(content::WebContents* web_contents,
+ PasswordManager* password_manager)
: content::WebContentsObserver(web_contents),
showing_signin_(false),
auto_accept_(AUTO_ACCEPT_NONE),
@@ -570,6 +571,12 @@ OneClickSigninHelper::OneClickSigninHelper(content::WebContents* web_contents)
untrusted_confirmation_required_(false),
do_not_clear_pending_email_(false),
weak_pointer_factory_(this) {
+ // May be NULL during testing.
+ if (password_manager) {
+ password_manager->AddSubmissionCallback(
+ base::Bind(&OneClickSigninHelper::PasswordSubmitted,
+ weak_pointer_factory_.GetWeakPtr()));
+ }
}
OneClickSigninHelper::~OneClickSigninHelper() {
@@ -585,6 +592,16 @@ OneClickSigninHelper::~OneClickSigninHelper() {
}
// static
+void OneClickSigninHelper::CreateForWebContentsWithPasswordManager(
+ content::WebContents* contents,
+ PasswordManager* password_manager) {
+ if (!FromWebContents(contents)) {
+ contents->SetUserData(UserDataKey(),
+ new OneClickSigninHelper(contents, password_manager));
+ }
+}
+
+// static
bool OneClickSigninHelper::CanOffer(content::WebContents* web_contents,
CanOfferFor can_offer_for,
const std::string& email,
@@ -999,29 +1016,13 @@ void OneClickSigninHelper::CleanTransientState() {
}
}
-bool OneClickSigninHelper::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(OneClickSigninHelper, message)
- IPC_MESSAGE_HANDLER(OneClickSigninHostMsg_FormSubmitted, OnFormSubmitted)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
-
- return handled;
-}
-
-bool OneClickSigninHelper::OnFormSubmitted(const content::PasswordForm& form) {
- // |password_| used to be set in DidNavigateAnyFrame, this is too late because
- // it is not executed until the end of redirect chains and password may
- // get lost if one of the redirects requires context swap.
-
+void OneClickSigninHelper::PasswordSubmitted(
+ const content::PasswordForm& form) {
// We only need to scrape the password for Gaia logins.
- if (form.origin.is_valid() &&
- gaia::IsGaiaSignonRealm(GURL(form.signon_realm))) {
+ if (gaia::IsGaiaSignonRealm(GURL(form.signon_realm))) {
VLOG(1) << "OneClickSigninHelper::DidNavigateAnyFrame: got password";
password_ = UTF16ToUTF8(form.password_value);
}
-
- return true;
}
void OneClickSigninHelper::SetDoNotClearPendingEmailForTesting() {
diff --git a/chrome/browser/ui/sync/one_click_signin_helper.h b/chrome/browser/ui/sync/one_click_signin_helper.h
index 46f7765..5ab7595 100644
--- a/chrome/browser/ui/sync/one_click_signin_helper.h
+++ b/chrome/browser/ui/sync/one_click_signin_helper.h
@@ -19,6 +19,7 @@
class Browser;
class GURL;
+class PasswordManager;
class ProfileIOData;
namespace content {
@@ -78,6 +79,10 @@ class OneClickSigninHelper
CAN_OFFER_FOR_INTERSTITAL_ONLY
};
+ static void CreateForWebContentsWithPasswordManager(
+ content::WebContents* contents,
+ PasswordManager* password_manager);
+
virtual ~OneClickSigninHelper();
// Returns true if the one-click signin feature can be offered at this time.
@@ -166,7 +171,8 @@ class OneClickSigninHelper
// SAML-based accounts, but causes bug crbug.com/181163.
static const int kMaxNavigationsSince;
- explicit OneClickSigninHelper(content::WebContents* web_contents);
+ OneClickSigninHelper(content::WebContents* web_contents,
+ PasswordManager* password_manager);
// Returns true if the one-click signin feature can be offered at this time.
// It can be offered if the io_data is not in an incognito window and if the
@@ -208,11 +214,10 @@ class OneClickSigninHelper
// TestingProfile provides.
void SetDoNotClearPendingEmailForTesting();
- // Grab Gaia password if available.
- bool OnFormSubmitted(const content::PasswordForm& form);
+ // Called when password has been submitted.
+ void PasswordSubmitted(const content::PasswordForm& form);
// content::WebContentsObserver overrides.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
virtual void NavigateToPendingEntry(
const GURL& url,
content::NavigationController::ReloadType reload_type) OVERRIDE;
diff --git a/chrome/browser/ui/sync/one_click_signin_helper_unittest.cc b/chrome/browser/ui/sync/one_click_signin_helper_unittest.cc
index 1406217..c61d806 100644
--- a/chrome/browser/ui/sync/one_click_signin_helper_unittest.cc
+++ b/chrome/browser/ui/sync/one_click_signin_helper_unittest.cc
@@ -325,7 +325,7 @@ void OneClickSigninHelperTest::SubmitGAIAPassword(
password_form.origin = GURL("https://accounts.google.com");
password_form.signon_realm = "https://accounts.google.com";
password_form.password_value = UTF8ToUTF16("password");
- helper->OnFormSubmitted(password_form);
+ helper->PasswordSubmitted(password_form);
}
class OneClickSigninHelperIOTest : public OneClickSigninHelperTest {
@@ -650,7 +650,7 @@ TEST_F(OneClickSigninHelperTest, SigninFromWebstoreWithConfigSyncfirst) {
content::WebContents* contents = web_contents();
- OneClickSigninHelper::CreateForWebContents(contents);
+ OneClickSigninHelper::CreateForWebContentsWithPasswordManager(contents, NULL);
OneClickSigninHelper* helper =
OneClickSigninHelper::FromWebContents(contents);
helper->SetDoNotClearPendingEmailForTesting();
@@ -678,7 +678,7 @@ TEST_F(OneClickSigninHelperTest, SigninFromWebstoreWithConfigSyncfirst) {
TEST_F(OneClickSigninHelperTest, CleanTransientStateOnNavigate) {
content::WebContents* contents = web_contents();
- OneClickSigninHelper::CreateForWebContents(contents);
+ OneClickSigninHelper::CreateForWebContentsWithPasswordManager(contents, NULL);
OneClickSigninHelper* helper =
OneClickSigninHelper::FromWebContents(contents);
helper->SetDoNotClearPendingEmailForTesting();
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index ed7b021..7457bcf 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -419,7 +419,6 @@
'common/omaha_query_params/omaha_query_params.cc',
'common/omaha_query_params/omaha_query_params.h',
'common/omnibox_focus_state.h',
- 'common/one_click_signin_messages.h',
'common/partial_circular_buffer.cc',
'common/partial_circular_buffer.h',
'common/pepper_flash.cc',
diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi
index 5b0d88c..3b72111 100644
--- a/chrome/chrome_renderer.gypi
+++ b/chrome/chrome_renderer.gypi
@@ -171,8 +171,6 @@
'renderer/net/renderer_net_predictor.h',
'renderer/net_benchmarking_extension.cc',
'renderer/net_benchmarking_extension.h',
- 'renderer/one_click_signin_agent.cc',
- 'renderer/one_click_signin_agent.h',
'renderer/playback_extension.cc',
'renderer/playback_extension.h',
'renderer/resource_bundle_source_map.cc',
diff --git a/chrome/common/common_message_generator.h b/chrome/common/common_message_generator.h
index b1819fc..d355031 100644
--- a/chrome/common/common_message_generator.h
+++ b/chrome/common/common_message_generator.h
@@ -8,7 +8,6 @@
#include "chrome/common/benchmarking_messages.h"
#include "chrome/common/chrome_utility_messages.h"
#include "chrome/common/extensions/extension_messages.h"
-#include "chrome/common/one_click_signin_messages.h"
#include "chrome/common/prerender_messages.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/safe_browsing/safebrowsing_messages.h"
diff --git a/chrome/common/one_click_signin_messages.h b/chrome/common/one_click_signin_messages.h
deleted file mode 100644
index fcbb75a..0000000
--- a/chrome/common/one_click_signin_messages.h
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Multiply-included message file, hence no include guard.
-
-#include "content/public/common/password_form.h"
-#include "ipc/ipc_message_macros.h"
-
-#define IPC_MESSAGE_START OneClickSigninMsgStart
-
-IPC_MESSAGE_ROUTED1(OneClickSigninHostMsg_FormSubmitted, content::PasswordForm)
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index 09ee4e3..e65f423 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -44,7 +44,6 @@
#include "chrome/renderer/net/prescient_networking_dispatcher.h"
#include "chrome/renderer/net/renderer_net_predictor.h"
#include "chrome/renderer/net_benchmarking_extension.h"
-#include "chrome/renderer/one_click_signin_agent.h"
#include "chrome/renderer/page_load_histograms.h"
#include "chrome/renderer/pepper/pepper_helper.h"
#include "chrome/renderer/pepper/ppb_nacl_private_impl.h"
@@ -389,10 +388,6 @@ void ChromeContentRendererClient::RenderViewCreated(
#endif
new NetErrorHelper(render_view);
-
-#if defined(ENABLE_ONE_CLICK_SIGNIN)
- new OneClickSigninAgent(render_view);
-#endif
}
void ChromeContentRendererClient::SetNumberOfViews(int number_of_views) {
diff --git a/chrome/renderer/one_click_signin_agent.cc b/chrome/renderer/one_click_signin_agent.cc
deleted file mode 100644
index b59c4aa..0000000
--- a/chrome/renderer/one_click_signin_agent.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/renderer/one_click_signin_agent.h"
-
-#include "chrome/common/one_click_signin_messages.h"
-#include "content/public/common/password_form.h"
-#include "content/public/renderer/document_state.h"
-#include "content/public/renderer/render_view.h"
-#include "third_party/WebKit/public/web/WebFormElement.h"
-#include "third_party/WebKit/public/web/WebFrame.h"
-
-OneClickSigninAgent::OneClickSigninAgent(
- content::RenderView* render_view)
- : content::RenderViewObserver(render_view) {
-}
-
-OneClickSigninAgent::~OneClickSigninAgent() {}
-
-void OneClickSigninAgent::WillSubmitForm(WebKit::WebFrame* frame,
- const WebKit::WebFormElement& form) {
- content::DocumentState* document_state =
- content::DocumentState::FromDataSource(frame->provisionalDataSource());
- if (document_state->password_form_data()) {
- Send(new OneClickSigninHostMsg_FormSubmitted(routing_id(),
- *(document_state->password_form_data())));
- }
-}
diff --git a/chrome/renderer/one_click_signin_agent.h b/chrome/renderer/one_click_signin_agent.h
deleted file mode 100644
index 17cd0b7..0000000
--- a/chrome/renderer/one_click_signin_agent.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_RENDERER_ONE_CLICK_SIGNIN_AGENT_H_
-#define CHROME_RENDERER_ONE_CLICK_SIGNIN_AGENT_H_
-
-#include "content/public/renderer/render_view_observer.h"
-
-// OneClickSigninAgent deals with oneclick signin related communications between
-// the renderer and the browser. There is one OneClickSigninAgent per
-// RenderView.
-class OneClickSigninAgent : public content::RenderViewObserver {
- public:
- explicit OneClickSigninAgent(content::RenderView* render_view);
- virtual ~OneClickSigninAgent();
-
- private:
- virtual void WillSubmitForm(WebKit::WebFrame* frame,
- const WebKit::WebFormElement& form) OVERRIDE;
-
- DISALLOW_COPY_AND_ASSIGN(OneClickSigninAgent);
-};
-
-#endif // CHROME_RENDERER_ONE_CLICK_SIGNIN_AGENT_H_
diff --git a/chrome/test/data/password/password_xhr_done.html b/chrome/test/data/password/done.html
index 99e103f..3aa6fb6 100644
--- a/chrome/test/data/password/password_xhr_done.html
+++ b/chrome/test/data/password/done.html
@@ -1,5 +1,5 @@
<html>
<body>
-XHR navigation complete.
+Navigation complete.
</body>
</html>
diff --git a/chrome/test/data/password/multi_frames.html b/chrome/test/data/password/multi_frames.html
new file mode 100644
index 0000000..1a569da
--- /dev/null
+++ b/chrome/test/data/password/multi_frames.html
@@ -0,0 +1,10 @@
+<html>
+<body>
+
+<iframe src="password_form.html" id="first_frame" name="first_frame">
+</iframe>
+<iframe src="password_form.html" id="second_frame" name="second_frame">
+</iframe>
+
+</body>
+</html>
diff --git a/chrome/test/data/password/password_form.html b/chrome/test/data/password/password_form.html
new file mode 100644
index 0000000..ac96b5b
--- /dev/null
+++ b/chrome/test/data/password/password_form.html
@@ -0,0 +1,15 @@
+<html>
+<body>
+<form action="done.html" onsubmit="return true;" id="testform">
+ <input type="text" id="username_field" name="username_field">
+ <input type="password" id="password_field" name="password_field">
+ <input type="submit" id="input_submit_button" name="input_submit_button">
+</form>
+
+<button id="submit_button" name="submit_button"
+ onclick="document.getElementById('testform').submit()">
+ Submit!
+</button>
+
+</body>
+</html>
diff --git a/chrome/test/data/password/password_xhr_submit.html b/chrome/test/data/password/password_xhr_submit.html
index 5a3d60f..57bbff1 100644
--- a/chrome/test/data/password/password_xhr_submit.html
+++ b/chrome/test/data/password/password_xhr_submit.html
@@ -4,7 +4,7 @@
function state_changed(xhr) {
if (xhr.readyState == 4)
- window.location.href = "password_xhr_done.html";
+ window.location.href = "done.html";
}
function send_xhr() {
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index b6294ab..c2f8267 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -24,6 +24,7 @@
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
+#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
#include "third_party/WebKit/public/web/WebView.h"
#include "ui/base/keycodes/keyboard_codes.h"
@@ -428,6 +429,65 @@ void PasswordAutofillAgent::FrameWillClose(WebKit::WebFrame* frame) {
FrameClosing(frame);
}
+void PasswordAutofillAgent::WillSendSubmitEvent(
+ WebKit::WebFrame* frame,
+ const WebKit::WebFormElement& form) {
+ // Some login forms have onSubmit handlers that put a hash of the password
+ // into a hidden field and then clear the password (http://crbug.com/28910).
+ // This method gets called before any of those handlers run, so save away
+ // a copy of the password in case it gets lost.
+ provisionally_saved_forms_[frame].reset(
+ content::CreatePasswordForm(form).release());
+}
+
+void PasswordAutofillAgent::WillSubmitForm(WebKit::WebFrame* frame,
+ const WebKit::WebFormElement& form) {
+ scoped_ptr<content::PasswordForm> submitted_form =
+ content::CreatePasswordForm(form);
+
+ // If there is a provisionally saved password, copy over the previous
+ // password value so we get the user's typed password, not the value that
+ // may have been transformed for submit.
+ // TODO(gcasto): Do we need to have this action equality check? Is it trying
+ // to prevent accidentally copying over passwords from a different form?
+ if (submitted_form) {
+ if (provisionally_saved_forms_[frame].get() &&
+ submitted_form->action == provisionally_saved_forms_[frame]->action) {
+ submitted_form->password_value =
+ provisionally_saved_forms_[frame]->password_value;
+ }
+
+ // Some observers depend on sending this information now instead of when
+ // the frame starts loading. If there are redirects that cause a new
+ // RenderView to be instantiated (such as redirects to the WebStore)
+ // we will never get to finish the load.
+ Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(),
+ *submitted_form));
+ // Remove reference since we have already submitted this form.
+ provisionally_saved_forms_.erase(frame);
+ }
+}
+
+void PasswordAutofillAgent::DidStartProvisionalLoad(WebKit::WebFrame* frame) {
+ if (!frame->parent()) {
+ // If the navigation is not triggered by a user gesture, e.g. by some ajax
+ // callback, then inherit the submitted password form from the previous
+ // state. This fixes the no password save issue for ajax login, tracked in
+ // [http://crbug/43219]. Note that there are still some sites that this
+ // fails for because they use some element other than a submit button to
+ // trigger submission (which means WillSendSubmitEvent will not be called).
+ if (!WebKit::WebUserGestureIndicator::isProcessingUserGesture() &&
+ provisionally_saved_forms_[frame].get()) {
+ Send(new AutofillHostMsg_PasswordFormSubmitted(
+ routing_id(),
+ *provisionally_saved_forms_[frame]));
+ provisionally_saved_forms_.erase(frame);
+ }
+ // Clear the whole map during main frame navigation.
+ provisionally_saved_forms_.clear();
+ }
+}
+
void PasswordAutofillAgent::OnFillPasswordForm(
const PasswordFormFillData& form_data) {
if (usernames_usage_ == NOTHING_TO_AUTOFILL) {
diff --git a/components/autofill/content/renderer/password_autofill_agent.h b/components/autofill/content/renderer/password_autofill_agent.h
index 30fef62..f151920 100644
--- a/components/autofill/content/renderer/password_autofill_agent.h
+++ b/components/autofill/content/renderer/password_autofill_agent.h
@@ -8,6 +8,7 @@
#include <map>
#include <vector>
+#include "base/memory/linked_ptr.h"
#include "base/memory/weak_ptr.h"
#include "components/autofill/core/common/password_form_fill_data.h"
#include "content/public/renderer/render_view_observer.h"
@@ -67,14 +68,21 @@ class PasswordAutofillAgent : public content::RenderViewObserver {
PasswordInfo() : backspace_pressed_last(false) {}
};
typedef std::map<WebKit::WebElement, PasswordInfo> LoginToPasswordInfoMap;
+ typedef std::map<WebKit::WebFrame*,
+ linked_ptr<content::PasswordForm> > FrameToPasswordFormMap;
// RenderViewObserver:
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ virtual void DidStartProvisionalLoad(WebKit::WebFrame* frame) OVERRIDE;
virtual void DidStartLoading() OVERRIDE;
virtual void DidFinishDocumentLoad(WebKit::WebFrame* frame) OVERRIDE;
virtual void DidFinishLoad(WebKit::WebFrame* frame) OVERRIDE;
virtual void FrameDetached(WebKit::WebFrame* frame) OVERRIDE;
virtual void FrameWillClose(WebKit::WebFrame* frame) OVERRIDE;
+ virtual void WillSendSubmitEvent(WebKit::WebFrame* frame,
+ const WebKit::WebFormElement& form) OVERRIDE;
+ virtual void WillSubmitForm(WebKit::WebFrame* frame,
+ const WebKit::WebFormElement& form) OVERRIDE;
// RenderView IPC handlers:
void OnFillPasswordForm(const PasswordFormFillData& form_data);
@@ -123,6 +131,10 @@ class PasswordAutofillAgent : public content::RenderViewObserver {
// Pointer to the WebView. Used to access page scale factor.
WebKit::WebView* web_view_;
+ // Set if the user might be submitting a password form on the current page,
+ // but the submit may still fail (i.e. doesn't pass JavaScript validation).
+ FrameToPasswordFormMap provisionally_saved_forms_;
+
base::WeakPtrFactory<PasswordAutofillAgent> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(PasswordAutofillAgent);
diff --git a/components/autofill/core/common/autofill_messages.h b/components/autofill/core/common/autofill_messages.h
index 13524df..b17ae64 100644
--- a/components/autofill/core/common/autofill_messages.h
+++ b/components/autofill/core/common/autofill_messages.h
@@ -212,6 +212,10 @@ IPC_MESSAGE_ROUTED1(AutofillHostMsg_PasswordFormsParsed,
IPC_MESSAGE_ROUTED1(AutofillHostMsg_PasswordFormsRendered,
std::vector<content::PasswordForm> /* forms */)
+// Notification that this password form was submitted by the user.
+IPC_MESSAGE_ROUTED1(AutofillHostMsg_PasswordFormSubmitted,
+ content::PasswordForm /* form */)
+
// Notification that a form has been submitted. The user hit the button.
IPC_MESSAGE_ROUTED2(AutofillHostMsg_FormSubmitted,
autofill::FormData /* form */,
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 56801c0..b1e5c12 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -1239,8 +1239,6 @@ void RenderViewHostImpl::OnNavigate(const IPC::Message& msg) {
FilterURL(policy, process, false, &(*it));
}
FilterURL(policy, process, true, &validated_params.searchable_form_url);
- FilterURL(policy, process, true, &validated_params.password_form.origin);
- FilterURL(policy, process, true, &validated_params.password_form.action);
// Without this check, the renderer can trick the browser into using
// filenames it can't access in a future session restore.
diff --git a/content/browser/renderer_host/test_render_view_host.cc b/content/browser/renderer_host/test_render_view_host.cc
index 129591c..d92aa07 100644
--- a/content/browser/renderer_host/test_render_view_host.cc
+++ b/content/browser/renderer_host/test_render_view_host.cc
@@ -15,7 +15,6 @@
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_client.h"
#include "content/public/common/page_state.h"
-#include "content/public/common/password_form.h"
#include "content/test/test_web_contents.h"
#include "media/base/video_frame.h"
#include "ui/gfx/rect.h"
@@ -42,7 +41,6 @@ void InitNavigateParams(ViewHostMsg_FrameNavigate_Params* params,
params->should_update_history = false;
params->searchable_form_url = GURL();
params->searchable_form_encoding = std::string();
- params->password_form = PasswordForm();
params->security_info = std::string();
params->gesture = NavigationGestureUser;
params->was_within_same_page = false;
@@ -333,7 +331,6 @@ void TestRenderViewHost::SendNavigateWithParameters(
params.should_update_history = true;
params.searchable_form_url = GURL();
params.searchable_form_encoding = std::string();
- params.password_form = PasswordForm();
params.security_info = std::string();
params.gesture = NavigationGestureUser;
params.contents_mime_type = contents_mime_type_;
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index 9ab0e99..d1b558bf 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -229,7 +229,6 @@ IPC_STRUCT_TRAITS_BEGIN(content::FrameNavigateParams)
IPC_STRUCT_TRAITS_MEMBER(should_update_history)
IPC_STRUCT_TRAITS_MEMBER(searchable_form_url)
IPC_STRUCT_TRAITS_MEMBER(searchable_form_encoding)
- IPC_STRUCT_TRAITS_MEMBER(password_form)
IPC_STRUCT_TRAITS_MEMBER(contents_mime_type)
IPC_STRUCT_TRAITS_MEMBER(socket_address)
IPC_STRUCT_TRAITS_END()
diff --git a/content/public/common/frame_navigate_params.h b/content/public/common/frame_navigate_params.h
index 0625175..2f9656a 100644
--- a/content/public/common/frame_navigate_params.h
+++ b/content/public/common/frame_navigate_params.h
@@ -10,7 +10,6 @@
#include "content/common/content_export.h"
#include "content/public/common/page_transition_types.h"
-#include "content/public/common/password_form.h"
#include "content/public/common/referrer.h"
#include "net/base/host_port_pair.h"
#include "url/gurl.h"
@@ -59,9 +58,6 @@ struct CONTENT_EXPORT FrameNavigateParams {
GURL searchable_form_url;
std::string searchable_form_encoding;
- // See password_form.h.
- content::PasswordForm password_form;
-
// Contents MIME type of main frame.
std::string contents_mime_type;
diff --git a/content/public/renderer/document_state.cc b/content/public/renderer/document_state.cc
index 235fc89..9add6b0 100644
--- a/content/public/renderer/document_state.cc
+++ b/content/public/renderer/document_state.cc
@@ -4,7 +4,6 @@
#include "content/public/renderer/document_state.h"
-#include "content/public/common/password_form.h"
#include "content/public/renderer/navigation_state.h"
namespace content {
@@ -26,11 +25,6 @@ DocumentState::DocumentState()
DocumentState::~DocumentState() {}
-void DocumentState::set_password_form_data(
- scoped_ptr<PasswordForm> data) {
- password_form_data_.reset(data.release());
-}
-
void DocumentState::set_navigation_state(NavigationState* navigation_state) {
navigation_state_.reset(navigation_state);
}
diff --git a/content/public/renderer/document_state.h b/content/public/renderer/document_state.h
index 40a5f42..cd9fd58 100644
--- a/content/public/renderer/document_state.h
+++ b/content/public/renderer/document_state.h
@@ -18,7 +18,6 @@
namespace content {
class NavigationState;
-struct PasswordForm;
// The RenderView stores an instance of this class in the "extra data" of each
// WebDataSource (see RenderView::DidCreateDataSource).
@@ -162,20 +161,6 @@ class CONTENT_EXPORT DocumentState
was_fetched_via_proxy_ = value;
}
- // If set, contains the PasswordForm that we believe triggered the current
- // navigation (there is some ambiguity in the case of javascript initiated
- // navigations). This information is used by the PasswordManager to determine
- // if the user should be prompted to save their password.
- //
- // Note that setting this field doesn't affect where the data is sent or what
- // origin we associate it with, only whether we prompt the user to save it.
- // That is, a false positive is a usability issue (e.g. may try to save a
- // mis-typed password) not a security issue.
- PasswordForm* password_form_data() const {
- return password_form_data_.get();
- }
- void set_password_form_data(scoped_ptr<PasswordForm> data);
-
void set_was_prefetcher(bool value) { was_prefetcher_ = value; }
bool was_prefetcher() const { return was_prefetcher_; }
@@ -220,8 +205,6 @@ class CONTENT_EXPORT DocumentState
net::HttpResponseInfo::ConnectionInfo connection_info_;
bool was_fetched_via_proxy_;
- scoped_ptr<PasswordForm> password_form_data_;
-
// A prefetcher is a page that contains link rel=prefetch elements.
bool was_prefetcher_;
bool was_referred_by_prefetcher_;
diff --git a/content/public/renderer/render_view_observer.h b/content/public/renderer/render_view_observer.h
index 4bb7dd8..9d57781 100644
--- a/content/public/renderer/render_view_observer.h
+++ b/content/public/renderer/render_view_observer.h
@@ -67,6 +67,8 @@ class CONTENT_EXPORT RenderViewObserver : public IPC::Listener,
WebKit::WebFrame* frame) {}
virtual void FrameDetached(WebKit::WebFrame* frame) {}
virtual void FrameWillClose(WebKit::WebFrame* frame) {}
+ virtual void WillSendSubmitEvent(WebKit::WebFrame* frame,
+ const WebKit::WebFormElement& form) {}
virtual void WillSubmitForm(WebKit::WebFrame* frame,
const WebKit::WebFormElement& form) {}
virtual void DidCreateDataSource(WebKit::WebFrame* frame,
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 92bfb3d..784e988 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -284,13 +284,9 @@ WebKit::WebNavigationPolicy RenderFrameImpl::decidePolicyForNavigation(
void RenderFrameImpl::willSendSubmitEvent(WebKit::WebFrame* frame,
const WebKit::WebFormElement& form) {
- // Some login forms have onSubmit handlers that put a hash of the password
- // into a hidden field and then clear the password. (Issue 28910.)
- // This method gets called before any of those handlers run, so save away
- // a copy of the password in case it gets lost.
- DocumentState* document_state =
- DocumentState::FromDataSource(frame->dataSource());
- document_state->set_password_form_data(CreatePasswordForm(form));
+ // Call back to RenderViewImpl for observers to be notified.
+ // TODO(nasko): Remove once we have RenderFrameObserver.
+ render_view_->willSendSubmitEvent(frame, form);
}
void RenderFrameImpl::willSubmitForm(WebKit::WebFrame* frame,
@@ -311,25 +307,6 @@ void RenderFrameImpl::willSubmitForm(WebKit::WebFrame* frame,
internal_data->set_searchable_form_url(web_searchable_form_data.url());
internal_data->set_searchable_form_encoding(
web_searchable_form_data.encoding().utf8());
- scoped_ptr<PasswordForm> password_form_data =
- CreatePasswordForm(form);
-
- // In order to save the password that the user actually typed and not one
- // that may have gotten transformed by the site prior to submit, recover it
- // from the form contents already stored by |willSendSubmitEvent| into the
- // dataSource's NavigationState (as opposed to the provisionalDataSource's,
- // which is what we're storing into now.)
- if (password_form_data) {
- DocumentState* old_document_state =
- DocumentState::FromDataSource(frame->dataSource());
- if (old_document_state) {
- PasswordForm* old_form_data = old_document_state->password_form_data();
- if (old_form_data && old_form_data->action == password_form_data->action)
- password_form_data->password_value = old_form_data->password_value;
- }
- }
-
- document_state->set_password_form_data(password_form_data.Pass());
// Call back to RenderViewImpl for observers to be notified.
// TODO(nasko): Remove once we have RenderFrameObserver.
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 2d0a115..7dbc675 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -67,7 +67,6 @@
#include "content/public/renderer/document_state.h"
#include "content/public/renderer/history_item_serialization.h"
#include "content/public/renderer/navigation_state.h"
-#include "content/public/renderer/password_form_conversion_utils.h"
#include "content/public/renderer/render_view_observer.h"
#include "content/public/renderer/render_view_visitor.h"
#include "content/renderer/accessibility/renderer_accessibility.h"
@@ -1991,10 +1990,6 @@ void RenderViewImpl::UpdateURL(WebFrame* frame) {
params.searchable_form_url = internal_data->searchable_form_url();
params.searchable_form_encoding = internal_data->searchable_form_encoding();
- const PasswordForm* password_form_data = document_state->password_form_data();
- if (password_form_data)
- params.password_form = *password_form_data;
-
params.gesture = navigation_gesture_;
navigation_gesture_ = NavigationGestureUnknown;
@@ -3385,7 +3380,8 @@ WebNavigationPolicy RenderViewImpl::decidePolicyForNavigation(
void RenderViewImpl::willSendSubmitEvent(WebKit::WebFrame* frame,
const WebKit::WebFormElement& form) {
- NOTREACHED();
+ FOR_EACH_OBSERVER(
+ RenderViewObserver, observers_, WillSendSubmitEvent(frame, form));
}
void RenderViewImpl::willSubmitForm(WebFrame* frame,
@@ -3599,23 +3595,6 @@ void RenderViewImpl::didStartProvisionalLoad(WebFrame* frame) {
if (is_top_most) {
navigation_gesture_ = WebUserGestureIndicator::isProcessingUserGesture() ?
NavigationGestureUser : NavigationGestureAuto;
-
- // If the navigation is not triggered by a user gesture, e.g. by some ajax
- // callback, then inherit the submitted password form from the previous
- // state. This fixes the no password save issue for ajax login, tracked in
- // [http://crbug/43219]. Note that there are still some sites that this
- // fails for because they use some element other than a submit button to
- // trigger submission.
- if (navigation_gesture_ == NavigationGestureAuto) {
- DocumentState* old_document_state = DocumentState::FromDataSource(
- frame->dataSource());
- const content::PasswordForm* old_password_form =
- old_document_state->password_form_data();
- if (old_password_form) {
- document_state->set_password_form_data(
- make_scoped_ptr(new content::PasswordForm(*old_password_form)));
- }
- }
} else if (frame->parent()->isLoading()) {
// Take note of AUTO_SUBFRAME loads here, so that we can know how to
// load an error page. See didFailProvisionalLoad.
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc
index d801f6b..ff77335 100644
--- a/content/test/test_web_contents.cc
+++ b/content/test/test_web_contents.cc
@@ -17,7 +17,6 @@
#include "content/public/browser/notification_types.h"
#include "content/public/common/page_state.h"
#include "content/public/common/page_transition_types.h"
-#include "content/public/common/password_form.h"
#include "content/public/test/mock_render_process_host.h"
namespace content {
@@ -78,7 +77,6 @@ void TestWebContents::TestDidNavigateWithReferrer(
params.should_update_history = false;
params.searchable_form_url = GURL();
params.searchable_form_encoding = std::string();
- params.password_form = PasswordForm();
params.security_info = std::string();
params.gesture = NavigationGestureUser;
params.was_within_same_page = false;