| OLD | NEW |
| 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/login_prompt.h" | 5 #include "chrome/browser/login_prompt.h" |
| 6 #import "chrome/browser/login_prompt_mac.h" | 6 #import "chrome/browser/login_prompt_mac.h" |
| 7 | 7 |
| 8 #include "app/l10n_util.h" | 8 #include "app/l10n_util.h" |
| 9 #include "base/mac_util.h" | 9 #include "base/mac_util.h" |
| 10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 using webkit_glue::PasswordForm; | 26 using webkit_glue::PasswordForm; |
| 27 | 27 |
| 28 // ---------------------------------------------------------------------------- | 28 // ---------------------------------------------------------------------------- |
| 29 // LoginHandlerMac | 29 // LoginHandlerMac |
| 30 | 30 |
| 31 // This class simply forwards the authentication from the LoginView (on | 31 // This class simply forwards the authentication from the LoginView (on |
| 32 // the UI thread) to the URLRequest (on the I/O thread). | 32 // the UI thread) to the URLRequest (on the I/O thread). |
| 33 // This class uses ref counting to ensure that it lives until all InvokeLaters | 33 // This class uses ref counting to ensure that it lives until all InvokeLaters |
| 34 // have been called. | 34 // have been called. |
| 35 class LoginHandlerMac : public LoginHandler, | 35 class LoginHandlerMac : public LoginHandler, |
| 36 public base::RefCountedThreadSafe<LoginHandlerMac>, | 36 public ConstrainedWindowMacDelegateCustomSheet { |
| 37 public ConstrainedWindowMacDelegateCustomSheet, | |
| 38 public LoginModelObserver { | |
| 39 public: | 37 public: |
| 40 LoginHandlerMac(URLRequest* request) | 38 explicit LoginHandlerMac(URLRequest* request) |
| 41 : handled_auth_(false), | 39 : LoginHandler(request), |
| 42 dialog_(NULL), | 40 sheet_controller_(nil) { |
| 43 request_(request), | |
| 44 password_manager_(NULL), | |
| 45 sheet_controller_(nil), | |
| 46 login_model_(NULL) { | |
| 47 // This constructor is called on the I/O thread, so we cannot load the nib | |
| 48 // here. BuildViewForPasswordManager() will be invoked on the UI thread | |
| 49 // later, so wait with loading the nib until then. | |
| 50 DCHECK(request_) << "LoginHandlerMac constructed with NULL request"; | |
| 51 | |
| 52 AddRef(); // matched by ReleaseLater. | |
| 53 if (!ResourceDispatcherHost::RenderViewForRequest(request_, | |
| 54 &render_process_host_id_, | |
| 55 &tab_contents_id_)) { | |
| 56 NOTREACHED(); | |
| 57 } | |
| 58 } | 41 } |
| 59 | 42 |
| 60 virtual ~LoginHandlerMac() { | 43 virtual ~LoginHandlerMac() { |
| 61 if (login_model_) | |
| 62 login_model_->SetObserver(NULL); | |
| 63 } | |
| 64 | |
| 65 void SetModel(LoginModel* model) { | |
| 66 if (login_model_) | |
| 67 login_model_->SetObserver(NULL); | |
| 68 login_model_ = model; | |
| 69 if (login_model_) | |
| 70 login_model_->SetObserver(this); | |
| 71 } | 44 } |
| 72 | 45 |
| 73 // LoginModelObserver implementation. | 46 // LoginModelObserver implementation. |
| 74 virtual void OnAutofillDataAvailable(const std::wstring& username, | 47 virtual void OnAutofillDataAvailable(const std::wstring& username, |
| 75 const std::wstring& password) { | 48 const std::wstring& password) { |
| 49 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 50 |
| 76 [sheet_controller_ autofillLogin:base::SysWideToNSString(username) | 51 [sheet_controller_ autofillLogin:base::SysWideToNSString(username) |
| 77 password:base::SysWideToNSString(password)]; | 52 password:base::SysWideToNSString(password)]; |
| 78 } | 53 } |
| 79 | 54 |
| 80 // LoginHandler: | 55 // LoginHandler: |
| 81 virtual void BuildViewForPasswordManager(PasswordManager* manager, | 56 virtual void BuildViewForPasswordManager(PasswordManager* manager, |
| 82 std::wstring explanation) { | 57 std::wstring explanation) { |
| 83 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 58 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 84 | 59 |
| 85 // Load nib here instead of in constructor. | 60 // Load nib here instead of in constructor. |
| 86 sheet_controller_ = [[[LoginHandlerSheet alloc] | 61 sheet_controller_ = [[[LoginHandlerSheet alloc] |
| 87 initWithLoginHandler:this] autorelease]; | 62 initWithLoginHandler:this] autorelease]; |
| 88 init([sheet_controller_ window], sheet_controller_, | 63 init([sheet_controller_ window], sheet_controller_, |
| 89 @selector(sheetDidEnd:returnCode:contextInfo:)); | 64 @selector(sheetDidEnd:returnCode:contextInfo:)); |
| 90 | 65 |
| 91 SetModel(manager); | 66 SetModel(manager); |
| 92 | 67 |
| 93 [sheet_controller_ setExplanation:base::SysWideToNSString(explanation)]; | 68 [sheet_controller_ setExplanation:base::SysWideToNSString(explanation)]; |
| 94 | 69 |
| 95 // Scary thread safety note: This can potentially be called *after* SetAuth | 70 // Scary thread safety note: This can potentially be called *after* SetAuth |
| 96 // or CancelAuth (say, if the request was cancelled before the UI thread got | 71 // or CancelAuth (say, if the request was cancelled before the UI thread got |
| 97 // control). However, that's OK since any UI interaction in those functions | 72 // control). However, that's OK since any UI interaction in those functions |
| 98 // will occur via an InvokeLater on the UI thread, which is guaranteed | 73 // will occur via an InvokeLater on the UI thread, which is guaranteed |
| 99 // to happen after this is called (since this was InvokeLater'd first). | 74 // to happen after this is called (since this was InvokeLater'd first). |
| 100 dialog_ = GetTabContentsForLogin()->CreateConstrainedDialog(this); | 75 SetDialog(GetTabContentsForLogin()->CreateConstrainedDialog(this)); |
| 101 | 76 |
| 102 SendNotifications(); | 77 SendNotifications(); |
| 103 } | 78 } |
| 104 | 79 |
| 105 virtual void SetPasswordForm(const webkit_glue::PasswordForm& form) { | 80 // Overridden from ConstrainedWindowMacDelegate: |
| 106 password_form_ = form; | 81 virtual void DeleteDelegate() { |
| 107 } | |
| 108 | |
| 109 virtual void SetPasswordManager(PasswordManager* password_manager) { | |
| 110 password_manager_ = password_manager; | |
| 111 } | |
| 112 | |
| 113 virtual TabContents* GetTabContentsForLogin() { | |
| 114 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 82 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 115 | 83 |
| 116 return tab_util::GetTabContentsByID(render_process_host_id_, | 84 // The constrained window is going to delete itself; clear our pointer. |
| 117 tab_contents_id_); | 85 SetDialog(NULL); |
| 118 } | 86 SetModel(NULL); |
| 119 | |
| 120 virtual void SetAuth(const std::wstring& username, | |
| 121 const std::wstring& password) { | |
| 122 if (WasAuthHandled(true)) | |
| 123 return; | |
| 124 | |
| 125 // Tell the password manager the credentials were submitted / accepted. | |
| 126 if (password_manager_) { | |
| 127 password_form_.username_value = WideToUTF16Hack(username); | |
| 128 password_form_.password_value = WideToUTF16Hack(password); | |
| 129 password_manager_->ProvisionallySavePassword(password_form_); | |
| 130 } | |
| 131 | |
| 132 ChromeThread::PostTask( | |
| 133 ChromeThread::UI, FROM_HERE, | |
| 134 NewRunnableMethod(this, &LoginHandlerMac::CloseContentsDeferred)); | |
| 135 ChromeThread::PostTask( | |
| 136 ChromeThread::UI, FROM_HERE, | |
| 137 NewRunnableMethod(this, &LoginHandlerMac::SendNotifications)); | |
| 138 ChromeThread::PostTask( | |
| 139 ChromeThread::IO, FROM_HERE, | |
| 140 NewRunnableMethod( | |
| 141 this, &LoginHandlerMac::SetAuthDeferred, username, password)); | |
| 142 } | |
| 143 | |
| 144 virtual void CancelAuth() { | |
| 145 if (WasAuthHandled(true)) | |
| 146 return; | |
| 147 | |
| 148 ChromeThread::PostTask( | |
| 149 ChromeThread::UI, FROM_HERE, | |
| 150 NewRunnableMethod(this, &LoginHandlerMac::CloseContentsDeferred)); | |
| 151 ChromeThread::PostTask( | |
| 152 ChromeThread::UI, FROM_HERE, | |
| 153 NewRunnableMethod(this, &LoginHandlerMac::SendNotifications)); | |
| 154 ChromeThread::PostTask( | |
| 155 ChromeThread::IO, FROM_HERE, | |
| 156 NewRunnableMethod(this, &LoginHandlerMac::CancelAuthDeferred)); | |
| 157 } | |
| 158 | |
| 159 virtual void OnRequestCancelled() { | |
| 160 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)) << | |
| 161 "Why is OnRequestCancelled called from the UI thread?"; | |
| 162 | |
| 163 // Reference is no longer valid. | |
| 164 request_ = NULL; | |
| 165 | |
| 166 // Give up on auth if the request was cancelled. | |
| 167 CancelAuth(); | |
| 168 } | |
| 169 | |
| 170 // Overridden from ConstrainedWindowMacDelegate: | |
| 171 virtual void DeleteDelegate() { | |
| 172 if (!WasAuthHandled(true)) { | |
| 173 ChromeThread::PostTask( | |
| 174 ChromeThread::IO, FROM_HERE, | |
| 175 NewRunnableMethod(this, &LoginHandlerMac::CancelAuthDeferred)); | |
| 176 ChromeThread::PostTask( | |
| 177 ChromeThread::UI, FROM_HERE, | |
| 178 NewRunnableMethod(this, &LoginHandlerMac::SendNotifications)); | |
| 179 } | |
| 180 | 87 |
| 181 // Close sheet if it's still open, as required by | 88 // Close sheet if it's still open, as required by |
| 182 // ConstrainedWindowMacDelegate. | 89 // ConstrainedWindowMacDelegate. |
| 183 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | |
| 184 if (is_sheet_open()) | 90 if (is_sheet_open()) |
| 185 [NSApp endSheet:sheet()]; | 91 [NSApp endSheet:sheet()]; |
| 186 | 92 |
| 187 SetModel(NULL); | 93 ReleaseSoon(); |
| 188 | |
| 189 // Delete this object once all InvokeLaters have been called. | |
| 190 ChromeThread::ReleaseSoon(ChromeThread::IO, FROM_HERE, this); | |
| 191 } | 94 } |
| 192 | 95 |
| 193 void OnLoginPressed(const std::wstring& username, | 96 void OnLoginPressed(const std::wstring& username, |
| 194 const std::wstring& password) { | 97 const std::wstring& password) { |
| 195 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 98 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 99 |
| 196 SetAuth(username, password); | 100 SetAuth(username, password); |
| 197 } | 101 } |
| 198 | 102 |
| 199 void OnCancelPressed() { | 103 void OnCancelPressed() { |
| 200 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 104 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 105 |
| 201 CancelAuth(); | 106 CancelAuth(); |
| 202 } | 107 } |
| 203 | 108 |
| 204 private: | 109 private: |
| 205 friend class LoginPrompt; | 110 friend class LoginPrompt; |
| 206 | 111 |
| 207 // Calls SetAuth from the IO loop. | |
| 208 void SetAuthDeferred(const std::wstring& username, | |
| 209 const std::wstring& password) { | |
| 210 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); | |
| 211 | |
| 212 if (request_) { | |
| 213 request_->SetAuth(username, password); | |
| 214 ResetLoginHandlerForRequest(request_); | |
| 215 } | |
| 216 } | |
| 217 | |
| 218 // Calls CancelAuth from the IO loop. | |
| 219 void CancelAuthDeferred() { | |
| 220 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); | |
| 221 | |
| 222 if (request_) { | |
| 223 request_->CancelAuth(); | |
| 224 // Verify that CancelAuth does destroy the request via our delegate. | |
| 225 DCHECK(request_ != NULL); | |
| 226 ResetLoginHandlerForRequest(request_); | |
| 227 } | |
| 228 } | |
| 229 | |
| 230 // Closes the view_contents from the UI loop. | |
| 231 void CloseContentsDeferred() { | |
| 232 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | |
| 233 | |
| 234 // The hosting ConstrainedWindow may have been freed. | |
| 235 if (dialog_) | |
| 236 dialog_->CloseConstrainedWindow(); | |
| 237 } | |
| 238 | |
| 239 // Returns whether authentication had been handled (SetAuth or CancelAuth). | |
| 240 // If |set_handled| is true, it will mark authentication as handled. | |
| 241 bool WasAuthHandled(bool set_handled) { | |
| 242 AutoLock lock(handled_auth_lock_); | |
| 243 bool was_handled = handled_auth_; | |
| 244 if (set_handled) | |
| 245 handled_auth_ = true; | |
| 246 return was_handled; | |
| 247 } | |
| 248 | |
| 249 // Notify observers that authentication is needed or received. The automation | |
| 250 // proxy uses this for testing. | |
| 251 void SendNotifications() { | |
| 252 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | |
| 253 | |
| 254 NotificationService* service = NotificationService::current(); | |
| 255 TabContents* requesting_contents = GetTabContentsForLogin(); | |
| 256 if (!requesting_contents) | |
| 257 return; | |
| 258 | |
| 259 NavigationController* controller = &requesting_contents->controller(); | |
| 260 | |
| 261 if (!WasAuthHandled(false)) { | |
| 262 LoginNotificationDetails details(this); | |
| 263 service->Notify(NotificationType::AUTH_NEEDED, | |
| 264 Source<NavigationController>(controller), | |
| 265 Details<LoginNotificationDetails>(&details)); | |
| 266 } else { | |
| 267 service->Notify(NotificationType::AUTH_SUPPLIED, | |
| 268 Source<NavigationController>(controller), | |
| 269 NotificationService::NoDetails()); | |
| 270 } | |
| 271 } | |
| 272 | |
| 273 // True if we've handled auth (SetAuth or CancelAuth has been called). | |
| 274 bool handled_auth_; | |
| 275 Lock handled_auth_lock_; | |
| 276 | |
| 277 // The ConstrainedWindow that is hosting our LoginView. | |
| 278 // This should only be accessed on the UI loop. | |
| 279 ConstrainedWindow* dialog_; | |
| 280 | |
| 281 // The request that wants login data. | |
| 282 // This should only be accessed on the IO loop. | |
| 283 URLRequest* request_; | |
| 284 | |
| 285 // The PasswordForm sent to the PasswordManager. This is so we can refer to it | |
| 286 // when later notifying the password manager if the credentials were accepted | |
| 287 // or rejected. | |
| 288 // This should only be accessed on the UI loop. | |
| 289 PasswordForm password_form_; | |
| 290 | |
| 291 // Points to the password manager owned by the TabContents requesting auth. | |
| 292 // Can be null if the TabContents is not a TabContents. | |
| 293 // This should only be accessed on the UI loop. | |
| 294 PasswordManager* password_manager_; | |
| 295 | |
| 296 // Cached from the URLRequest, in case it goes NULL on us. | |
| 297 int render_process_host_id_; | |
| 298 int tab_contents_id_; | |
| 299 | |
| 300 // The Cocoa controller of the GUI. | 112 // The Cocoa controller of the GUI. |
| 301 LoginHandlerSheet* sheet_controller_; | 113 LoginHandlerSheet* sheet_controller_; |
| 302 | 114 |
| 303 // If not null, points to a model we need to notify of our own destruction | |
| 304 // so it doesn't try and access this when its too late. | |
| 305 LoginModel* login_model_; | |
| 306 | |
| 307 DISALLOW_COPY_AND_ASSIGN(LoginHandlerMac); | 115 DISALLOW_COPY_AND_ASSIGN(LoginHandlerMac); |
| 308 }; | 116 }; |
| 309 | 117 |
| 310 // static | 118 // static |
| 311 LoginHandler* LoginHandler::Create(URLRequest* request) { | 119 LoginHandler* LoginHandler::Create(URLRequest* request) { |
| 312 return new LoginHandlerMac(request); | 120 return new LoginHandlerMac(request); |
| 313 } | 121 } |
| 314 | 122 |
| 315 // ---------------------------------------------------------------------------- | 123 // ---------------------------------------------------------------------------- |
| 316 // LoginHandlerSheet | 124 // LoginHandlerSheet |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 365 sizeToFitFixedWidthTextField:explanationField_]; | 173 sizeToFitFixedWidthTextField:explanationField_]; |
| 366 | 174 |
| 367 // Resize the window (no shifting needed due to window layout). | 175 // Resize the window (no shifting needed due to window layout). |
| 368 NSSize windowDelta = NSMakeSize(0, explanationShift); | 176 NSSize windowDelta = NSMakeSize(0, explanationShift); |
| 369 [GTMUILocalizerAndLayoutTweaker | 177 [GTMUILocalizerAndLayoutTweaker |
| 370 resizeWindowWithoutAutoResizingSubViews:[self window] | 178 resizeWindowWithoutAutoResizingSubViews:[self window] |
| 371 delta:windowDelta]; | 179 delta:windowDelta]; |
| 372 } | 180 } |
| 373 | 181 |
| 374 @end | 182 @end |
| OLD | NEW |