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

Side by Side Diff: chrome/browser/ui/login/login_prompt.cc

Issue 5814005: Minimize login prompts (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Fix race condition on Mac Created 9 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/login/login_prompt.h" 5 #include "chrome/browser/ui/login/login_prompt.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "app/l10n_util.h" 9 #include "app/l10n_util.h"
10 #include "base/command_line.h" 10 #include "base/command_line.h"
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 109
110 TabContents* LoginHandler::GetTabContentsForLogin() const { 110 TabContents* LoginHandler::GetTabContentsForLogin() const {
111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
112 112
113 return tab_util::GetTabContentsByID(render_process_host_id_, 113 return tab_util::GetTabContentsByID(render_process_host_id_,
114 tab_contents_id_); 114 tab_contents_id_);
115 } 115 }
116 116
117 void LoginHandler::SetAuth(const std::wstring& username, 117 void LoginHandler::SetAuth(const std::wstring& username,
118 const std::wstring& password) { 118 const std::wstring& password) {
119 if (WasAuthHandled(true)) 119 if (TestAndSetAuthHandled())
120 return; 120 return;
121 121
122 // Tell the password manager the credentials were submitted / accepted. 122 // Tell the password manager the credentials were submitted / accepted.
123 if (password_manager_) { 123 if (password_manager_) {
124 password_form_.username_value = WideToUTF16Hack(username); 124 password_form_.username_value = WideToUTF16Hack(username);
125 password_form_.password_value = WideToUTF16Hack(password); 125 password_form_.password_value = WideToUTF16Hack(password);
126 password_manager_->ProvisionallySavePassword(password_form_); 126 password_manager_->ProvisionallySavePassword(password_form_);
127 } 127 }
128 128
129 // If we are on the UI thread, then calling NotifyAuthSupplied()
130 // directly allows other LoginHandler instances to queue their
131 // CloseContentsDeferred() before ours. Closing dialogs in the
132 // opposite order as they were created avoids races where remaining
133 // dialogs may be briefly displayed to the user before they are
134 // removed.
135 if (BrowserThread::CurrentlyOn(BrowserThread::UI))
cbentzel 2011/01/04 16:09:54 I think this is always called from the UI thread.
asanka (google) 2011/01/04 22:34:49 Fixed. I didn't change the CancelAuth() case sinc
136 NotifyAuthSupplied(username, password);
137 else
138 BrowserThread::PostTask(
139 BrowserThread::UI, FROM_HERE,
140 NewRunnableMethod(
141 this, &LoginHandler::NotifyAuthSupplied, username, password));
142
129 BrowserThread::PostTask( 143 BrowserThread::PostTask(
130 BrowserThread::UI, FROM_HERE, 144 BrowserThread::UI, FROM_HERE,
131 NewRunnableMethod(this, &LoginHandler::CloseContentsDeferred)); 145 NewRunnableMethod(this, &LoginHandler::CloseContentsDeferred));
132 BrowserThread::PostTask( 146 BrowserThread::PostTask(
133 BrowserThread::UI, FROM_HERE,
134 NewRunnableMethod(
135 this, &LoginHandler::NotifyAuthSupplied, username, password));
136 BrowserThread::PostTask(
137 BrowserThread::IO, FROM_HERE, 147 BrowserThread::IO, FROM_HERE,
138 NewRunnableMethod( 148 NewRunnableMethod(
139 this, &LoginHandler::SetAuthDeferred, username, password)); 149 this, &LoginHandler::SetAuthDeferred, username, password));
140 } 150 }
141 151
142 void LoginHandler::CancelAuth() { 152 void LoginHandler::CancelAuth() {
143 if (WasAuthHandled(true)) 153 if (TestAndSetAuthHandled())
144 return; 154 return;
145 155
156 // Similar to how we deal with notifications above in SetAuth()
157 if (BrowserThread::CurrentlyOn(BrowserThread::UI))
158 NotifyAuthCancelled();
159 else
160 BrowserThread::PostTask(
161 BrowserThread::UI, FROM_HERE,
162 NewRunnableMethod(this, &LoginHandler::NotifyAuthCancelled));
163
146 BrowserThread::PostTask( 164 BrowserThread::PostTask(
147 BrowserThread::UI, FROM_HERE, 165 BrowserThread::UI, FROM_HERE,
148 NewRunnableMethod(this, &LoginHandler::CloseContentsDeferred)); 166 NewRunnableMethod(this, &LoginHandler::CloseContentsDeferred));
149 BrowserThread::PostTask( 167 BrowserThread::PostTask(
150 BrowserThread::UI, FROM_HERE,
151 NewRunnableMethod(this, &LoginHandler::NotifyAuthCancelled));
152 BrowserThread::PostTask(
153 BrowserThread::IO, FROM_HERE, 168 BrowserThread::IO, FROM_HERE,
154 NewRunnableMethod(this, &LoginHandler::CancelAuthDeferred)); 169 NewRunnableMethod(this, &LoginHandler::CancelAuthDeferred));
155 } 170 }
156 171
157 void LoginHandler::OnRequestCancelled() { 172 void LoginHandler::OnRequestCancelled() {
158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)) << 173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)) <<
159 "Why is OnRequestCancelled called from the UI thread?"; 174 "Why is OnRequestCancelled called from the UI thread?";
160 175
161 // Reference is no longer valid. 176 // Reference is no longer valid.
162 request_ = NULL; 177 request_ = NULL;
(...skipping 26 matching lines...) Expand all
189 const NotificationSource& source, 204 const NotificationSource& source,
190 const NotificationDetails& details) { 205 const NotificationDetails& details) {
191 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
192 DCHECK(type == NotificationType::AUTH_SUPPLIED || 207 DCHECK(type == NotificationType::AUTH_SUPPLIED ||
193 type == NotificationType::AUTH_CANCELLED); 208 type == NotificationType::AUTH_CANCELLED);
194 209
195 TabContents* requesting_contents = GetTabContentsForLogin(); 210 TabContents* requesting_contents = GetTabContentsForLogin();
196 if (!requesting_contents) 211 if (!requesting_contents)
197 return; 212 return;
198 213
199 NavigationController* this_controller = &requesting_contents->controller(); 214 // Break out early if we aren't interested in the notification.
200 NavigationController* that_controller = 215 if (WasAuthHandled())
201 Source<NavigationController>(source).ptr();
202
203 // Only handle notifications from other handlers.
204 if (this_controller == that_controller)
205 return; 216 return;
206 217
207 LoginNotificationDetails* login_details = 218 LoginNotificationDetails* login_details =
208 Details<LoginNotificationDetails>(details).ptr(); 219 Details<LoginNotificationDetails>(details).ptr();
209 220
221 // WasAuthHandled() should always test positive before we publish
222 // AUTH_SUPPLIED or AUTH_CANCELLED notifications.
223 DCHECK(login_details->handler() != this);
224
210 // Only handle notification for the identical auth info. 225 // Only handle notification for the identical auth info.
211 if (*login_details->handler()->auth_info() != *auth_info()) 226 if (*login_details->handler()->auth_info() != *auth_info())
212 return; 227 return;
213 228
214 // Set or cancel the auth in this handler. 229 // Set or cancel the auth in this handler.
215 if (type == NotificationType::AUTH_SUPPLIED) { 230 if (type == NotificationType::AUTH_SUPPLIED) {
216 AuthSuppliedLoginNotificationDetails* supplied_details = 231 AuthSuppliedLoginNotificationDetails* supplied_details =
217 Details<AuthSuppliedLoginNotificationDetails>(details).ptr(); 232 Details<AuthSuppliedLoginNotificationDetails>(details).ptr();
218 SetAuth(supplied_details->username(), supplied_details->password()); 233 SetAuth(supplied_details->username(), supplied_details->password());
219 } else { 234 } else {
220 DCHECK(type == NotificationType::AUTH_CANCELLED); 235 DCHECK(type == NotificationType::AUTH_CANCELLED);
221 CancelAuth(); 236 CancelAuth();
222 } 237 }
223 } 238 }
224 239
225 void LoginHandler::SetModel(LoginModel* model) { 240 void LoginHandler::SetModel(LoginModel* model) {
226 if (login_model_) 241 if (login_model_)
227 login_model_->SetObserver(NULL); 242 login_model_->SetObserver(NULL);
228 login_model_ = model; 243 login_model_ = model;
229 if (login_model_) 244 if (login_model_)
230 login_model_->SetObserver(this); 245 login_model_->SetObserver(this);
231 } 246 }
232 247
233 void LoginHandler::SetDialog(ConstrainedWindow* dialog) { 248 void LoginHandler::SetDialog(ConstrainedWindow* dialog) {
234 dialog_ = dialog; 249 dialog_ = dialog;
235 } 250 }
236 251
237 void LoginHandler::NotifyAuthNeeded() { 252 void LoginHandler::NotifyAuthNeeded() {
238 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 253 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
239 if (WasAuthHandled(false)) 254 if (WasAuthHandled())
240 return; 255 return;
241 256
242 TabContents* requesting_contents = GetTabContentsForLogin(); 257 TabContents* requesting_contents = GetTabContentsForLogin();
243 if (!requesting_contents) 258 if (!requesting_contents)
244 return; 259 return;
245 260
246 NotificationService* service = NotificationService::current(); 261 NotificationService* service = NotificationService::current();
247 NavigationController* controller = &requesting_contents->controller(); 262 NavigationController* controller = &requesting_contents->controller();
248 LoginNotificationDetails details(this); 263 LoginNotificationDetails details(this);
249 264
250 service->Notify(NotificationType::AUTH_NEEDED, 265 service->Notify(NotificationType::AUTH_NEEDED,
251 Source<NavigationController>(controller), 266 Source<NavigationController>(controller),
252 Details<LoginNotificationDetails>(&details)); 267 Details<LoginNotificationDetails>(&details));
253 } 268 }
254 269
255 void LoginHandler::NotifyAuthCancelled() { 270 void LoginHandler::NotifyAuthCancelled() {
256 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 271 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
257 DCHECK(WasAuthHandled(false)); 272 DCHECK(WasAuthHandled());
258 273
259 TabContents* requesting_contents = GetTabContentsForLogin(); 274 TabContents* requesting_contents = GetTabContentsForLogin();
260 if (!requesting_contents) 275 if (!requesting_contents)
261 return; 276 return;
262 277
263 NotificationService* service = NotificationService::current(); 278 NotificationService* service = NotificationService::current();
264 NavigationController* controller = &requesting_contents->controller(); 279 NavigationController* controller = &requesting_contents->controller();
265 LoginNotificationDetails details(this); 280 LoginNotificationDetails details(this);
266 281
267 service->Notify(NotificationType::AUTH_CANCELLED, 282 service->Notify(NotificationType::AUTH_CANCELLED,
268 Source<NavigationController>(controller), 283 Source<NavigationController>(controller),
269 Details<LoginNotificationDetails>(&details)); 284 Details<LoginNotificationDetails>(&details));
270 } 285 }
271 286
272 void LoginHandler::NotifyAuthSupplied(const std::wstring& username, 287 void LoginHandler::NotifyAuthSupplied(const std::wstring& username,
273 const std::wstring& password) { 288 const std::wstring& password) {
274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 289 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
275 DCHECK(WasAuthHandled(false)); 290 DCHECK(WasAuthHandled());
276 291
277 TabContents* requesting_contents = GetTabContentsForLogin(); 292 TabContents* requesting_contents = GetTabContentsForLogin();
278 if (!requesting_contents) 293 if (!requesting_contents)
279 return; 294 return;
280 295
281 NotificationService* service = NotificationService::current(); 296 NotificationService* service = NotificationService::current();
282 NavigationController* controller = &requesting_contents->controller(); 297 NavigationController* controller = &requesting_contents->controller();
283 AuthSuppliedLoginNotificationDetails details(this, username, password); 298 AuthSuppliedLoginNotificationDetails details(this, username, password);
284 299
285 service->Notify(NotificationType::AUTH_SUPPLIED, 300 service->Notify(NotificationType::AUTH_SUPPLIED,
286 Source<NavigationController>(controller), 301 Source<NavigationController>(controller),
287 Details<AuthSuppliedLoginNotificationDetails>(&details)); 302 Details<AuthSuppliedLoginNotificationDetails>(&details));
288 } 303 }
289 304
290 void LoginHandler::ReleaseSoon() { 305 void LoginHandler::ReleaseSoon() {
291 if (!WasAuthHandled(true)) { 306 if (!TestAndSetAuthHandled()) {
292 BrowserThread::PostTask( 307 BrowserThread::PostTask(
293 BrowserThread::IO, FROM_HERE, 308 BrowserThread::IO, FROM_HERE,
294 NewRunnableMethod(this, &LoginHandler::CancelAuthDeferred)); 309 NewRunnableMethod(this, &LoginHandler::CancelAuthDeferred));
295 BrowserThread::PostTask( 310 BrowserThread::PostTask(
296 BrowserThread::UI, FROM_HERE, 311 BrowserThread::UI, FROM_HERE,
297 NewRunnableMethod(this, &LoginHandler::NotifyAuthCancelled)); 312 NewRunnableMethod(this, &LoginHandler::NotifyAuthCancelled));
298 } 313 }
299 314
300 BrowserThread::PostTask( 315 BrowserThread::PostTask(
301 BrowserThread::UI, FROM_HERE, 316 BrowserThread::UI, FROM_HERE,
302 NewRunnableMethod(this, &LoginHandler::RemoveObservers)); 317 NewRunnableMethod(this, &LoginHandler::RemoveObservers));
303 318
304 // Delete this object once all InvokeLaters have been called. 319 // Delete this object once all InvokeLaters have been called.
305 BrowserThread::ReleaseSoon(BrowserThread::IO, FROM_HERE, this); 320 BrowserThread::ReleaseSoon(BrowserThread::IO, FROM_HERE, this);
306 } 321 }
307 322
308 // Returns whether authentication had been handled (SetAuth or CancelAuth). 323 // Returns whether authentication had been handled (SetAuth or CancelAuth).
309 // If |set_handled| is true, it will mark authentication as handled. 324 bool LoginHandler::WasAuthHandled() {
310 bool LoginHandler::WasAuthHandled(bool set_handled) {
311 AutoLock lock(handled_auth_lock_); 325 AutoLock lock(handled_auth_lock_);
312 bool was_handled = handled_auth_; 326 bool was_handled = handled_auth_;
313 if (set_handled)
314 handled_auth_ = true;
315 return was_handled; 327 return was_handled;
316 } 328 }
317 329
330 // Marks authentication as handled and returns the previous handled state.
331 bool LoginHandler::TestAndSetAuthHandled() {
332 AutoLock lock(handled_auth_lock_);
333 bool was_handled = handled_auth_;
334 handled_auth_ = true;
335 return was_handled;
336 }
337
318 // Calls SetAuth from the IO loop. 338 // Calls SetAuth from the IO loop.
319 void LoginHandler::SetAuthDeferred(const std::wstring& username, 339 void LoginHandler::SetAuthDeferred(const std::wstring& username,
320 const std::wstring& password) { 340 const std::wstring& password) {
321 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
322 342
323 if (request_) { 343 if (request_) {
324 request_->SetAuth(WideToUTF16Hack(username), WideToUTF16Hack(password)); 344 request_->SetAuth(WideToUTF16Hack(username), WideToUTF16Hack(password));
325 ResetLoginHandlerForRequest(request_); 345 ResetLoginHandlerForRequest(request_);
326 } 346 }
327 } 347 }
(...skipping 30 matching lines...) Expand all
358 LoginDialogTask(const GURL& request_url, 378 LoginDialogTask(const GURL& request_url,
359 net::AuthChallengeInfo* auth_info, 379 net::AuthChallengeInfo* auth_info,
360 LoginHandler* handler) 380 LoginHandler* handler)
361 : request_url_(request_url), auth_info_(auth_info), handler_(handler) { 381 : request_url_(request_url), auth_info_(auth_info), handler_(handler) {
362 } 382 }
363 virtual ~LoginDialogTask() { 383 virtual ~LoginDialogTask() {
364 } 384 }
365 385
366 void Run() { 386 void Run() {
367 TabContents* parent_contents = handler_->GetTabContentsForLogin(); 387 TabContents* parent_contents = handler_->GetTabContentsForLogin();
368 if (!parent_contents) { 388 if (!parent_contents || handler_->WasAuthHandled()) {
369 // The request may have been cancelled, or it may be for a renderer 389 // The request may have been cancelled, or it may be for a renderer
370 // not hosted by a tab (e.g. an extension). Cancel just in case 390 // not hosted by a tab (e.g. an extension). Cancel just in case
371 // (cancelling twice is a no-op). 391 // (cancelling twice is a no-op).
372 handler_->CancelAuth(); 392 handler_->CancelAuth();
373 return; 393 return;
374 } 394 }
375 395
376 // Tell the password manager to look for saved passwords. 396 // Tell the password manager to look for saved passwords.
377 TabContentsWrapper** wrapper = 397 TabContentsWrapper** wrapper =
378 TabContentsWrapper::property_accessor()->GetProperty( 398 TabContentsWrapper::property_accessor()->GetProperty(
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 // Public API 464 // Public API
445 465
446 LoginHandler* CreateLoginPrompt(net::AuthChallengeInfo* auth_info, 466 LoginHandler* CreateLoginPrompt(net::AuthChallengeInfo* auth_info,
447 net::URLRequest* request) { 467 net::URLRequest* request) {
448 LoginHandler* handler = LoginHandler::Create(auth_info, request); 468 LoginHandler* handler = LoginHandler::Create(auth_info, request);
449 BrowserThread::PostTask( 469 BrowserThread::PostTask(
450 BrowserThread::UI, FROM_HERE, new LoginDialogTask( 470 BrowserThread::UI, FROM_HERE, new LoginDialogTask(
451 request->url(), auth_info, handler)); 471 request->url(), auth_info, handler));
452 return handler; 472 return handler;
453 } 473 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/login/login_prompt.h ('k') | chrome/browser/ui/login/login_prompt_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698