Make castv2 performance test work.
[chromium-blink-merge.git] / chrome / browser / password_manager / password_store_win.cc
blob08d6876b31fcdd5374a8ededf8da5e39d08c9169
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/password_manager/password_store_win.h"
7 #include <map>
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/profiler/scoped_tracker.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "components/os_crypt/ie7_password_win.h"
16 #include "components/password_manager/core/browser/password_manager.h"
17 #include "components/password_manager/core/browser/webdata/password_web_data_service_win.h"
18 #include "content/public/browser/browser_thread.h"
20 using autofill::PasswordForm;
21 using content::BrowserThread;
22 using password_manager::PasswordStoreDefault;
24 // Handles requests to PasswordWebDataService.
25 class PasswordStoreWin::DBHandler : public WebDataServiceConsumer {
26 public:
27 typedef base::Callback<void(ScopedVector<PasswordForm>)> ResultCallback;
29 DBHandler(const scoped_refptr<PasswordWebDataService>& web_data_service,
30 PasswordStoreWin* password_store)
31 : web_data_service_(web_data_service), password_store_(password_store) {}
33 ~DBHandler();
35 // Requests the IE7 login for |form|. This is async. |result_callback| will be
36 // run when complete.
37 void GetIE7Login(const PasswordForm& form,
38 const ResultCallback& result_callback);
40 private:
41 struct RequestInfo {
42 RequestInfo() {}
44 RequestInfo(PasswordForm* request_form,
45 const ResultCallback& result_callback)
46 : form(request_form), result_callback(result_callback) {}
48 PasswordForm* form;
49 ResultCallback result_callback;
52 // Holds info associated with in-flight GetIE7Login requests.
53 typedef std::map<PasswordWebDataService::Handle, RequestInfo>
54 PendingRequestMap;
56 // Gets logins from IE7 if no others are found. Also copies them into
57 // Chrome's WebDatabase so we don't need to look next time.
58 ScopedVector<autofill::PasswordForm> GetIE7Results(
59 const WDTypedResult* result,
60 const PasswordForm& form);
62 // WebDataServiceConsumer implementation.
63 virtual void OnWebDataServiceRequestDone(
64 PasswordWebDataService::Handle handle,
65 const WDTypedResult* result) override;
67 scoped_refptr<PasswordWebDataService> web_data_service_;
69 // This creates a cycle between us and PasswordStore. The cycle is broken
70 // from PasswordStoreWin::Shutdown, which deletes us.
71 scoped_refptr<PasswordStoreWin> password_store_;
73 PendingRequestMap pending_requests_;
75 DISALLOW_COPY_AND_ASSIGN(DBHandler);
78 PasswordStoreWin::DBHandler::~DBHandler() {
79 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
80 for (PendingRequestMap::const_iterator i = pending_requests_.begin();
81 i != pending_requests_.end();
82 ++i) {
83 web_data_service_->CancelRequest(i->first);
84 delete i->second.form;
88 void PasswordStoreWin::DBHandler::GetIE7Login(
89 const PasswordForm& form,
90 const ResultCallback& result_callback) {
91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
92 IE7PasswordInfo info;
93 info.url_hash =
94 ie7_password::GetUrlHash(base::UTF8ToWide(form.origin.spec()));
95 PasswordWebDataService::Handle handle =
96 web_data_service_->GetIE7Login(info, this);
97 pending_requests_[handle] =
98 RequestInfo(new PasswordForm(form), result_callback);
101 ScopedVector<autofill::PasswordForm> PasswordStoreWin::DBHandler::GetIE7Results(
102 const WDTypedResult* result,
103 const PasswordForm& form) {
104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
105 ScopedVector<autofill::PasswordForm> matched_forms;
106 const WDResult<IE7PasswordInfo>* r =
107 static_cast<const WDResult<IE7PasswordInfo>*>(result);
108 IE7PasswordInfo info = r->GetValue();
110 if (!info.encrypted_data.empty()) {
111 // We got a result.
112 // Delete the entry. If it's good we will add it to the real saved password
113 // table.
114 web_data_service_->RemoveIE7Login(info);
115 std::vector<ie7_password::DecryptedCredentials> credentials;
116 base::string16 url = base::ASCIIToUTF16(form.origin.spec());
117 if (ie7_password::DecryptPasswords(url,
118 info.encrypted_data,
119 &credentials)) {
120 for (size_t i = 0; i < credentials.size(); ++i) {
121 PasswordForm* autofill = new PasswordForm();
122 autofill->username_value = credentials[i].username;
123 autofill->password_value = credentials[i].password;
124 autofill->signon_realm = form.signon_realm;
125 autofill->origin = form.origin;
126 autofill->preferred = true;
127 autofill->ssl_valid = form.origin.SchemeIsSecure();
128 autofill->date_created = info.date_created;
130 matched_forms.push_back(autofill);
131 // Add this PasswordForm to the saved password table. We're on the DB
132 // thread already, so we use AddLoginImpl.
133 password_store_->AddLoginImpl(*autofill);
137 return matched_forms.Pass();
140 void PasswordStoreWin::DBHandler::OnWebDataServiceRequestDone(
141 PasswordWebDataService::Handle handle,
142 const WDTypedResult* result) {
143 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is
144 // fixed.
145 tracked_objects::ScopedTracker tracking_profile(
146 FROM_HERE_WITH_EXPLICIT_FUNCTION(
147 "422460 PasswordStoreWin::DBHandler::OnWebDataServiceRequestDone"));
149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
151 PendingRequestMap::iterator i = pending_requests_.find(handle);
152 DCHECK(i != pending_requests_.end());
154 scoped_ptr<PasswordForm> form(i->second.form);
155 ResultCallback result_callback(i->second.result_callback);
156 pending_requests_.erase(i);
158 if (!result) {
159 // The WDS returns NULL if it is shutting down. Run callback with empty
160 // result.
161 result_callback.Run(ScopedVector<autofill::PasswordForm>());
162 return;
165 DCHECK_EQ(PASSWORD_IE7_RESULT, result->GetType());
166 result_callback.Run(GetIE7Results(result, *form));
169 PasswordStoreWin::PasswordStoreWin(
170 scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
171 scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
172 scoped_ptr<password_manager::LoginDatabase> login_db,
173 const scoped_refptr<PasswordWebDataService>& web_data_service)
174 : PasswordStoreDefault(main_thread_runner,
175 db_thread_runner,
176 login_db.Pass()) {
177 db_handler_.reset(new DBHandler(web_data_service, this));
180 PasswordStoreWin::~PasswordStoreWin() {
183 void PasswordStoreWin::ShutdownOnDBThread() {
184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
185 db_handler_.reset();
188 void PasswordStoreWin::Shutdown() {
189 BrowserThread::PostTask(
190 BrowserThread::DB, FROM_HERE,
191 base::Bind(&PasswordStoreWin::ShutdownOnDBThread, this));
192 PasswordStoreDefault::Shutdown();
195 void PasswordStoreWin::GetLoginsImpl(const PasswordForm& form,
196 AuthorizationPromptPolicy prompt_policy,
197 scoped_ptr<GetLoginsRequest> request) {
198 // When importing from IE7, the credentials are first stored into a temporary
199 // Web SQL database. Then, after each GetLogins() request that does not yield
200 // any matches from the LoginDatabase, the matching credentials in the Web SQL
201 // database, if any, are returned as results instead, and simultaneously get
202 // moved to the LoginDatabase, so next time they will be found immediately.
203 // TODO(engedy): Make the IE7-specific code synchronous, so FillMatchingLogins
204 // can be overridden instead. See: https://crbug.com/78830.
205 // TODO(engedy): Credentials should be imported into the LoginDatabase in the
206 // first place. See: https://crbug.com/456119.
207 ScopedVector<autofill::PasswordForm> matched_forms(
208 FillMatchingLogins(form, prompt_policy));
209 if (matched_forms.empty() && db_handler_) {
210 db_handler_->GetIE7Login(
211 form, base::Bind(&GetLoginsRequest::NotifyConsumerWithResults,
212 base::Owned(request.release())));
213 } else {
214 request->NotifyConsumerWithResults(matched_forms.Pass());