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

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: LoginHandler::SetAuth() expects to be called on the UI thread Created 9 years, 11 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 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
120
121 if (TestAndSetAuthHandled())
120 return; 122 return;
121 123
122 // Tell the password manager the credentials were submitted / accepted. 124 // Tell the password manager the credentials were submitted / accepted.
123 if (password_manager_) { 125 if (password_manager_) {
124 password_form_.username_value = WideToUTF16Hack(username); 126 password_form_.username_value = WideToUTF16Hack(username);
125 password_form_.password_value = WideToUTF16Hack(password); 127 password_form_.password_value = WideToUTF16Hack(password);
126 password_manager_->ProvisionallySavePassword(password_form_); 128 password_manager_->ProvisionallySavePassword(password_form_);
127 } 129 }
128 130
131 // Calling NotifyAuthSupplied() directly instead of posting a task
132 // allows other LoginHandler instances to queue their
133 // CloseContentsDeferred() before ours. Closing dialogs in the
134 // opposite order as they were created avoids races where remaining
135 // dialogs in the same tab may be briefly displayed to the user
136 // before they are removed.
137 NotifyAuthSupplied(username, password);
138
129 BrowserThread::PostTask( 139 BrowserThread::PostTask(
130 BrowserThread::UI, FROM_HERE, 140 BrowserThread::UI, FROM_HERE,
131 NewRunnableMethod(this, &LoginHandler::CloseContentsDeferred)); 141 NewRunnableMethod(this, &LoginHandler::CloseContentsDeferred));
132 BrowserThread::PostTask( 142 BrowserThread::PostTask(
133 BrowserThread::UI, FROM_HERE,
134 NewRunnableMethod(
135 this, &LoginHandler::NotifyAuthSupplied, username, password));
136 BrowserThread::PostTask(
137 BrowserThread::IO, FROM_HERE, 143 BrowserThread::IO, FROM_HERE,
138 NewRunnableMethod( 144 NewRunnableMethod(
139 this, &LoginHandler::SetAuthDeferred, username, password)); 145 this, &LoginHandler::SetAuthDeferred, username, password));
140 } 146 }
141 147
142 void LoginHandler::CancelAuth() { 148 void LoginHandler::CancelAuth() {
143 if (WasAuthHandled(true)) 149 if (TestAndSetAuthHandled())
144 return; 150 return;
145 151
152 // Similar to how we deal with notifications above in SetAuth()
153 if (BrowserThread::CurrentlyOn(BrowserThread::UI))
154 NotifyAuthCancelled();
155 else
cbentzel 2011/01/05 13:13:52 Nit: use braces {} for multi-line else clauses [an
asanka (google) 2011/01/05 14:29:11 Done.
156 BrowserThread::PostTask(
157 BrowserThread::UI, FROM_HERE,
158 NewRunnableMethod(this, &LoginHandler::NotifyAuthCancelled));
159
146 BrowserThread::PostTask( 160 BrowserThread::PostTask(
147 BrowserThread::UI, FROM_HERE, 161 BrowserThread::UI, FROM_HERE,
148 NewRunnableMethod(this, &LoginHandler::CloseContentsDeferred)); 162 NewRunnableMethod(this, &LoginHandler::CloseContentsDeferred));
149 BrowserThread::PostTask( 163 BrowserThread::PostTask(
150 BrowserThread::UI, FROM_HERE,
151 NewRunnableMethod(this, &LoginHandler::NotifyAuthCancelled));
152 BrowserThread::PostTask(
153 BrowserThread::IO, FROM_HERE, 164 BrowserThread::IO, FROM_HERE,
154 NewRunnableMethod(this, &LoginHandler::CancelAuthDeferred)); 165 NewRunnableMethod(this, &LoginHandler::CancelAuthDeferred));
155 } 166 }
156 167
157 void LoginHandler::OnRequestCancelled() { 168 void LoginHandler::OnRequestCancelled() {
158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)) << 169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)) <<
159 "Why is OnRequestCancelled called from the UI thread?"; 170 "Why is OnRequestCancelled called from the UI thread?";
160 171
161 // Reference is no longer valid. 172 // Reference is no longer valid.
162 request_ = NULL; 173 request_ = NULL;
(...skipping 26 matching lines...) Expand all
189 const NotificationSource& source, 200 const NotificationSource& source,
190 const NotificationDetails& details) { 201 const NotificationDetails& details) {
191 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
192 DCHECK(type == NotificationType::AUTH_SUPPLIED || 203 DCHECK(type == NotificationType::AUTH_SUPPLIED ||
193 type == NotificationType::AUTH_CANCELLED); 204 type == NotificationType::AUTH_CANCELLED);
194 205
195 TabContents* requesting_contents = GetTabContentsForLogin(); 206 TabContents* requesting_contents = GetTabContentsForLogin();
196 if (!requesting_contents) 207 if (!requesting_contents)
197 return; 208 return;
198 209
199 NavigationController* this_controller = &requesting_contents->controller(); 210 // Break out early if we aren't interested in the notification.
200 NavigationController* that_controller = 211 if (WasAuthHandled())
201 Source<NavigationController>(source).ptr();
202
203 // Only handle notifications from other handlers.
204 if (this_controller == that_controller)
205 return; 212 return;
206 213
207 LoginNotificationDetails* login_details = 214 LoginNotificationDetails* login_details =
208 Details<LoginNotificationDetails>(details).ptr(); 215 Details<LoginNotificationDetails>(details).ptr();
209 216
217 // WasAuthHandled() should always test positive before we publish
218 // AUTH_SUPPLIED or AUTH_CANCELLED notifications.
219 DCHECK(login_details->handler() != this);
220
210 // Only handle notification for the identical auth info. 221 // Only handle notification for the identical auth info.
211 if (*login_details->handler()->auth_info() != *auth_info()) 222 if (*login_details->handler()->auth_info() != *auth_info())
212 return; 223 return;
213 224
214 // Set or cancel the auth in this handler. 225 // Set or cancel the auth in this handler.
215 if (type == NotificationType::AUTH_SUPPLIED) { 226 if (type == NotificationType::AUTH_SUPPLIED) {
216 AuthSuppliedLoginNotificationDetails* supplied_details = 227 AuthSuppliedLoginNotificationDetails* supplied_details =
217 Details<AuthSuppliedLoginNotificationDetails>(details).ptr(); 228 Details<AuthSuppliedLoginNotificationDetails>(details).ptr();
218 SetAuth(supplied_details->username(), supplied_details->password()); 229 SetAuth(supplied_details->username(), supplied_details->password());
219 } else { 230 } else {
220 DCHECK(type == NotificationType::AUTH_CANCELLED); 231 DCHECK(type == NotificationType::AUTH_CANCELLED);
221 CancelAuth(); 232 CancelAuth();
222 } 233 }
223 } 234 }
224 235
225 void LoginHandler::SetModel(LoginModel* model) { 236 void LoginHandler::SetModel(LoginModel* model) {
226 if (login_model_) 237 if (login_model_)
227 login_model_->SetObserver(NULL); 238 login_model_->SetObserver(NULL);
228 login_model_ = model; 239 login_model_ = model;
229 if (login_model_) 240 if (login_model_)
230 login_model_->SetObserver(this); 241 login_model_->SetObserver(this);
231 } 242 }
232 243
233 void LoginHandler::SetDialog(ConstrainedWindow* dialog) { 244 void LoginHandler::SetDialog(ConstrainedWindow* dialog) {
234 dialog_ = dialog; 245 dialog_ = dialog;
235 } 246 }
236 247
237 void LoginHandler::NotifyAuthNeeded() { 248 void LoginHandler::NotifyAuthNeeded() {
238 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
239 if (WasAuthHandled(false)) 250 if (WasAuthHandled())
240 return; 251 return;
241 252
242 TabContents* requesting_contents = GetTabContentsForLogin(); 253 TabContents* requesting_contents = GetTabContentsForLogin();
243 if (!requesting_contents) 254 if (!requesting_contents)
244 return; 255 return;
245 256
246 NotificationService* service = NotificationService::current(); 257 NotificationService* service = NotificationService::current();
247 NavigationController* controller = &requesting_contents->controller(); 258 NavigationController* controller = &requesting_contents->controller();
248 LoginNotificationDetails details(this); 259 LoginNotificationDetails details(this);
249 260
250 service->Notify(NotificationType::AUTH_NEEDED, 261 service->Notify(NotificationType::AUTH_NEEDED,
251 Source<NavigationController>(controller), 262 Source<NavigationController>(controller),
252 Details<LoginNotificationDetails>(&details)); 263 Details<LoginNotificationDetails>(&details));
253 } 264 }
254 265
255 void LoginHandler::NotifyAuthCancelled() { 266 void LoginHandler::NotifyAuthCancelled() {
256 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 267 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
257 DCHECK(WasAuthHandled(false)); 268 DCHECK(WasAuthHandled());
258 269
259 TabContents* requesting_contents = GetTabContentsForLogin(); 270 TabContents* requesting_contents = GetTabContentsForLogin();
260 if (!requesting_contents) 271 if (!requesting_contents)
261 return; 272 return;
262 273
263 NotificationService* service = NotificationService::current(); 274 NotificationService* service = NotificationService::current();
264 NavigationController* controller = &requesting_contents->controller(); 275 NavigationController* controller = &requesting_contents->controller();
265 LoginNotificationDetails details(this); 276 LoginNotificationDetails details(this);
266 277
267 service->Notify(NotificationType::AUTH_CANCELLED, 278 service->Notify(NotificationType::AUTH_CANCELLED,
268 Source<NavigationController>(controller), 279 Source<NavigationController>(controller),
269 Details<LoginNotificationDetails>(&details)); 280 Details<LoginNotificationDetails>(&details));
270 } 281 }
271 282
272 void LoginHandler::NotifyAuthSupplied(const std::wstring& username, 283 void LoginHandler::NotifyAuthSupplied(const std::wstring& username,
273 const std::wstring& password) { 284 const std::wstring& password) {
274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 285 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
275 DCHECK(WasAuthHandled(false)); 286 DCHECK(WasAuthHandled());
276 287
277 TabContents* requesting_contents = GetTabContentsForLogin(); 288 TabContents* requesting_contents = GetTabContentsForLogin();
278 if (!requesting_contents) 289 if (!requesting_contents)
279 return; 290 return;
280 291
281 NotificationService* service = NotificationService::current(); 292 NotificationService* service = NotificationService::current();
282 NavigationController* controller = &requesting_contents->controller(); 293 NavigationController* controller = &requesting_contents->controller();
283 AuthSuppliedLoginNotificationDetails details(this, username, password); 294 AuthSuppliedLoginNotificationDetails details(this, username, password);
284 295
285 service->Notify(NotificationType::AUTH_SUPPLIED, 296 service->Notify(NotificationType::AUTH_SUPPLIED,
286 Source<NavigationController>(controller), 297 Source<NavigationController>(controller),
287 Details<AuthSuppliedLoginNotificationDetails>(&details)); 298 Details<AuthSuppliedLoginNotificationDetails>(&details));
288 } 299 }
289 300
290 void LoginHandler::ReleaseSoon() { 301 void LoginHandler::ReleaseSoon() {
291 if (!WasAuthHandled(true)) { 302 if (!TestAndSetAuthHandled()) {
292 BrowserThread::PostTask( 303 BrowserThread::PostTask(
293 BrowserThread::IO, FROM_HERE, 304 BrowserThread::IO, FROM_HERE,
294 NewRunnableMethod(this, &LoginHandler::CancelAuthDeferred)); 305 NewRunnableMethod(this, &LoginHandler::CancelAuthDeferred));
295 BrowserThread::PostTask( 306 BrowserThread::PostTask(
296 BrowserThread::UI, FROM_HERE, 307 BrowserThread::UI, FROM_HERE,
297 NewRunnableMethod(this, &LoginHandler::NotifyAuthCancelled)); 308 NewRunnableMethod(this, &LoginHandler::NotifyAuthCancelled));
298 } 309 }
299 310
300 BrowserThread::PostTask( 311 BrowserThread::PostTask(
301 BrowserThread::UI, FROM_HERE, 312 BrowserThread::UI, FROM_HERE,
302 NewRunnableMethod(this, &LoginHandler::RemoveObservers)); 313 NewRunnableMethod(this, &LoginHandler::RemoveObservers));
303 314
304 // Delete this object once all InvokeLaters have been called. 315 // Delete this object once all InvokeLaters have been called.
305 BrowserThread::ReleaseSoon(BrowserThread::IO, FROM_HERE, this); 316 BrowserThread::ReleaseSoon(BrowserThread::IO, FROM_HERE, this);
306 } 317 }
307 318
308 // Returns whether authentication had been handled (SetAuth or CancelAuth). 319 // Returns whether authentication had been handled (SetAuth or CancelAuth).
309 // If |set_handled| is true, it will mark authentication as handled. 320 bool LoginHandler::WasAuthHandled() {
310 bool LoginHandler::WasAuthHandled(bool set_handled) {
311 AutoLock lock(handled_auth_lock_); 321 AutoLock lock(handled_auth_lock_);
312 bool was_handled = handled_auth_; 322 bool was_handled = handled_auth_;
313 if (set_handled)
314 handled_auth_ = true;
315 return was_handled; 323 return was_handled;
316 } 324 }
317 325
326 // Marks authentication as handled and returns the previous handled state.
327 bool LoginHandler::TestAndSetAuthHandled() {
328 AutoLock lock(handled_auth_lock_);
329 bool was_handled = handled_auth_;
330 handled_auth_ = true;
331 return was_handled;
332 }
333
318 // Calls SetAuth from the IO loop. 334 // Calls SetAuth from the IO loop.
319 void LoginHandler::SetAuthDeferred(const std::wstring& username, 335 void LoginHandler::SetAuthDeferred(const std::wstring& username,
320 const std::wstring& password) { 336 const std::wstring& password) {
321 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 337 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
322 338
323 if (request_) { 339 if (request_) {
324 request_->SetAuth(WideToUTF16Hack(username), WideToUTF16Hack(password)); 340 request_->SetAuth(WideToUTF16Hack(username), WideToUTF16Hack(password));
325 ResetLoginHandlerForRequest(request_); 341 ResetLoginHandlerForRequest(request_);
326 } 342 }
327 } 343 }
(...skipping 30 matching lines...) Expand all
358 LoginDialogTask(const GURL& request_url, 374 LoginDialogTask(const GURL& request_url,
359 net::AuthChallengeInfo* auth_info, 375 net::AuthChallengeInfo* auth_info,
360 LoginHandler* handler) 376 LoginHandler* handler)
361 : request_url_(request_url), auth_info_(auth_info), handler_(handler) { 377 : request_url_(request_url), auth_info_(auth_info), handler_(handler) {
362 } 378 }
363 virtual ~LoginDialogTask() { 379 virtual ~LoginDialogTask() {
364 } 380 }
365 381
366 void Run() { 382 void Run() {
367 TabContents* parent_contents = handler_->GetTabContentsForLogin(); 383 TabContents* parent_contents = handler_->GetTabContentsForLogin();
368 if (!parent_contents) { 384 if (!parent_contents || handler_->WasAuthHandled()) {
369 // The request may have been cancelled, or it may be for a renderer 385 // 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 386 // not hosted by a tab (e.g. an extension). Cancel just in case
371 // (cancelling twice is a no-op). 387 // (cancelling twice is a no-op).
372 handler_->CancelAuth(); 388 handler_->CancelAuth();
373 return; 389 return;
374 } 390 }
375 391
376 // Tell the password manager to look for saved passwords. 392 // Tell the password manager to look for saved passwords.
377 TabContentsWrapper** wrapper = 393 TabContentsWrapper** wrapper =
378 TabContentsWrapper::property_accessor()->GetProperty( 394 TabContentsWrapper::property_accessor()->GetProperty(
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
446 // Public API 462 // Public API
447 463
448 LoginHandler* CreateLoginPrompt(net::AuthChallengeInfo* auth_info, 464 LoginHandler* CreateLoginPrompt(net::AuthChallengeInfo* auth_info,
449 net::URLRequest* request) { 465 net::URLRequest* request) {
450 LoginHandler* handler = LoginHandler::Create(auth_info, request); 466 LoginHandler* handler = LoginHandler::Create(auth_info, request);
451 BrowserThread::PostTask( 467 BrowserThread::PostTask(
452 BrowserThread::UI, FROM_HERE, new LoginDialogTask( 468 BrowserThread::UI, FROM_HERE, new LoginDialogTask(
453 request->url(), auth_info, handler)); 469 request->url(), auth_info, handler));
454 return handler; 470 return handler;
455 } 471 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698