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 |