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

Unified Diff: chrome/browser/login_prompt_mac.mm

Issue 164391: Implement http auth login dialog for OS X. (Closed)
Patch Set: re-disable nonfuntional test Created 11 years, 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/login_prompt_mac.h ('k') | chrome/browser/login_prompt_uitest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/login_prompt_mac.mm
diff --git a/chrome/browser/login_prompt_mac.mm b/chrome/browser/login_prompt_mac.mm
new file mode 100644
index 0000000000000000000000000000000000000000..a8da3804082670ac910e6402b113e4ea1b654a10
--- /dev/null
+++ b/chrome/browser/login_prompt_mac.mm
@@ -0,0 +1,308 @@
+// Copyright (c) 2009 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/browser/login_prompt.h"
+#import "chrome/browser/login_prompt_mac.h"
+
+#include "app/l10n_util.h"
+#include "base/mac_util.h"
+#include "base/message_loop.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/cocoa/constrained_window_mac.h"
+#include "chrome/browser/password_manager/password_manager.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/tab_contents/navigation_controller.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_util.h"
+#include "chrome/common/notification_service.h"
+#include "grit/generated_resources.h"
+#include "net/url_request/url_request.h"
+
+using webkit_glue::PasswordForm;
+
+// ----------------------------------------------------------------------------
+// LoginHandlerMac
+
+// This class simply forwards the authentication from the LoginView (on
+// the UI thread) to the URLRequest (on the I/O thread).
+// This class uses ref counting to ensure that it lives until all InvokeLaters
+// have been called.
+class LoginHandlerMac : public LoginHandler,
+ public base::RefCountedThreadSafe<LoginHandlerMac>,
+ public ConstrainedWindowMacDelegateCustomSheet {
+ public:
+ LoginHandlerMac(URLRequest* request, MessageLoop* ui_loop)
+ : handled_auth_(false),
+ dialog_(NULL),
+ ui_loop_(ui_loop),
+ request_(request),
+ request_loop_(MessageLoop::current()),
+ password_manager_(NULL) {
+ // This constructor is called on the I/O thread, so we cannot load the nib
+ // here. BuildViewForPasswordManager() will be invoked on the UI thread
+ // later, so wait with loading the nib until then.
+ DCHECK(request_) << "LoginHandlerMac constructed with NULL request";
+
+ AddRef(); // matched by ReleaseLater.
+ if (!ResourceDispatcherHost::RenderViewForRequest(request_,
+ &render_process_host_id_,
+ &tab_contents_id_)) {
+ NOTREACHED();
+ }
+ }
+
+ virtual ~LoginHandlerMac() {
+ }
+
+ // LoginHandler:
+ virtual void BuildViewForPasswordManager(PasswordManager* manager,
+ std::wstring explanation) {
+ DCHECK(MessageLoop::current() == ui_loop_);
+
+ // Load nib here instead of in constructor.
+ LoginHandlerSheet* sheetController = [[[LoginHandlerSheet alloc]
+ initWithLoginHandler:this] autorelease];
+ init([sheetController window], sheetController,
+ @selector(sheetDidEnd:returnCode:contextInfo:));
+
+ // Scary thread safety note: This can potentially be called *after* SetAuth
+ // or CancelAuth (say, if the request was cancelled before the UI thread got
+ // control). However, that's OK since any UI interaction in those functions
+ // will occur via an InvokeLater on the UI thread, which is guaranteed
+ // to happen after this is called (since this was InvokeLater'd first).
+ dialog_ = GetTabContentsForLogin()->CreateConstrainedDialog(this);
+
+ SendNotifications();
+ }
+
+ virtual void SetPasswordForm(const webkit_glue::PasswordForm& form) {
+ password_form_ = form;
+ }
+
+ virtual void SetPasswordManager(PasswordManager* password_manager) {
+ password_manager_ = password_manager;
+ }
+
+ virtual TabContents* GetTabContentsForLogin() {
+ DCHECK(MessageLoop::current() == ui_loop_);
+
+ return tab_util::GetTabContentsByID(render_process_host_id_,
+ tab_contents_id_);
+ }
+
+ virtual void SetAuth(const std::wstring& username,
+ const std::wstring& password) {
+ if (WasAuthHandled(true))
+ return;
+
+ // Tell the password manager the credentials were submitted / accepted.
+ if (password_manager_) {
+ password_form_.username_value = username;
+ password_form_.password_value = password;
+ password_manager_->ProvisionallySavePassword(password_form_);
+ }
+
+ ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &LoginHandlerMac::CloseContentsDeferred));
+ ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &LoginHandlerMac::SendNotifications));
+ request_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &LoginHandlerMac::SetAuthDeferred, username, password));
+ }
+
+ virtual void CancelAuth() {
+ if (WasAuthHandled(true))
+ return;
+
+ ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &LoginHandlerMac::CloseContentsDeferred));
+ ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &LoginHandlerMac::SendNotifications));
+ request_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &LoginHandlerMac::CancelAuthDeferred));
+ }
+
+ virtual void OnRequestCancelled() {
+ DCHECK(MessageLoop::current() == request_loop_) <<
+ "Why is OnRequestCancelled called from the UI thread?";
+
+ // Reference is no longer valid.
+ request_ = NULL;
+
+ // Give up on auth if the request was cancelled.
+ CancelAuth();
+ }
+
+ // Overridden from ConstrainedWindowMacDelegate:
+ virtual void DeleteDelegate() {
+ if (!WasAuthHandled(true)) {
+ request_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &LoginHandlerMac::CancelAuthDeferred));
+ ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &LoginHandlerMac::SendNotifications));
+ }
+
+ // Delete this object once all InvokeLaters have been called.
+ request_loop_->ReleaseSoon(FROM_HERE, this);
+ }
+
+ void OnLoginPressed(const std::wstring& username,
+ const std::wstring& password) {
+ DCHECK(MessageLoop::current() == ui_loop_);
+ SetAuth(username, password);
+ }
+
+ void OnCancelPressed() {
+ DCHECK(MessageLoop::current() == ui_loop_);
+ CancelAuth();
+ }
+
+ private:
+ friend class LoginPrompt;
+
+ // Calls SetAuth from the request_loop.
+ void SetAuthDeferred(const std::wstring& username,
+ const std::wstring& password) {
+ DCHECK(MessageLoop::current() == request_loop_);
+
+ if (request_) {
+ request_->SetAuth(username, password);
+ ResetLoginHandlerForRequest(request_);
+ }
+ }
+
+ // Calls CancelAuth from the request_loop.
+ void CancelAuthDeferred() {
+ DCHECK(MessageLoop::current() == request_loop_);
+
+ if (request_) {
+ request_->CancelAuth();
+ // Verify that CancelAuth does destroy the request via our delegate.
+ DCHECK(request_ != NULL);
+ ResetLoginHandlerForRequest(request_);
+ }
+ }
+
+ // Closes the view_contents from the UI loop.
+ void CloseContentsDeferred() {
+ DCHECK(MessageLoop::current() == ui_loop_);
+
+ // Close sheet if it's still open, as required by
+ // ConstrainedWindowMacDelegate.
+ if (is_sheet_open())
+ [NSApp endSheet:sheet()];
+
+ // The hosting ConstrainedWindow may have been freed.
+ if (dialog_)
+ dialog_->CloseConstrainedWindow();
+ }
+
+ // Returns whether authentication had been handled (SetAuth or CancelAuth).
+ // If |set_handled| is true, it will mark authentication as handled.
+ bool WasAuthHandled(bool set_handled) {
+ AutoLock lock(handled_auth_lock_);
+ bool was_handled = handled_auth_;
+ if (set_handled)
+ handled_auth_ = true;
+ return was_handled;
+ }
+
+ // Notify observers that authentication is needed or received. The automation
+ // proxy uses this for testing.
+ void SendNotifications() {
+ DCHECK(MessageLoop::current() == ui_loop_);
+
+ NotificationService* service = NotificationService::current();
+ TabContents* requesting_contents = GetTabContentsForLogin();
+ if (!requesting_contents)
+ return;
+
+ NavigationController* controller = &requesting_contents->controller();
+
+ if (!WasAuthHandled(false)) {
+ LoginNotificationDetails details(this);
+ service->Notify(NotificationType::AUTH_NEEDED,
+ Source<NavigationController>(controller),
+ Details<LoginNotificationDetails>(&details));
+ } else {
+ service->Notify(NotificationType::AUTH_SUPPLIED,
+ Source<NavigationController>(controller),
+ NotificationService::NoDetails());
+ }
+ }
+
+ // True if we've handled auth (SetAuth or CancelAuth has been called).
+ bool handled_auth_;
+ Lock handled_auth_lock_;
+
+ // The ConstrainedWindow that is hosting our LoginView.
+ // This should only be accessed on the ui_loop_.
+ ConstrainedWindow* dialog_;
+
+ // The MessageLoop of the thread that the ChromeViewContents lives in.
+ MessageLoop* ui_loop_;
+
+ // The request that wants login data.
+ // This should only be accessed on the request_loop_.
+ URLRequest* request_;
+
+ // The MessageLoop of the thread that the URLRequest lives in.
+ MessageLoop* request_loop_;
+
+ // The PasswordForm sent to the PasswordManager. This is so we can refer to it
+ // when later notifying the password manager if the credentials were accepted
+ // or rejected.
+ // This should only be accessed on the ui_loop_.
+ PasswordForm password_form_;
+
+ // Points to the password manager owned by the TabContents requesting auth.
+ // Can be null if the TabContents is not a TabContents.
+ // This should only be accessed on the ui_loop_.
+ PasswordManager* password_manager_;
+
+ // Cached from the URLRequest, in case it goes NULL on us.
+ int render_process_host_id_;
+ int tab_contents_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(LoginHandlerMac);
+};
+
+// static
+LoginHandler* LoginHandler::Create(URLRequest* request, MessageLoop* ui_loop) {
+ return new LoginHandlerMac(request, ui_loop);
+}
+
+// ----------------------------------------------------------------------------
+// LoginHandlerSheet
+
+@implementation LoginHandlerSheet
+
+- (id)initWithLoginHandler:(LoginHandlerMac*)handler {
+ if ((self = [super initWithWindowNibName:@"HttpAuthLoginSheet"
+ owner:self])) {
+ handler_ = handler;
+ }
+ return self;
+}
+
+- (IBAction)loginPressed:(id)sender {
+ using base::SysNSStringToWide;
+ [NSApp endSheet:[self window]];
+ handler_->OnLoginPressed(SysNSStringToWide([nameField_ stringValue]),
+ SysNSStringToWide([passwordField_ stringValue]));
+}
+
+- (IBAction)cancelPressed:(id)sender {
+ [NSApp endSheet:[self window]];
+ handler_->OnCancelPressed();
+}
+
+- (void)sheetDidEnd:(NSWindow*)sheet
+ returnCode:(int)returnCode
+ contextInfo:(void *)contextInfo {
+ [sheet orderOut:self];
+ // Also called when user navigates to another page while the sheet is open.
+}
+
+@end
« no previous file with comments | « chrome/browser/login_prompt_mac.h ('k') | chrome/browser/login_prompt_uitest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698