diff options
author | gcasto@chromium.org <gcasto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-16 01:09:12 +0000 |
---|---|---|
committer | gcasto@chromium.org <gcasto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-16 01:09:12 +0000 |
commit | 0660a8c72b2841655ae2e0b852e7f8aca4b602b3 (patch) | |
tree | d56f2fa87ad6a35815e30f322f915b83757b0752 | |
parent | dcf99f46e7eeee2c2633d0eabb2f4dd21a5aaa79 (diff) | |
download | chromium_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
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; |