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

Side by Side 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 unified diff | 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/login_prompt.h"
6 #import "chrome/browser/login_prompt_mac.h"
7
8 #include "app/l10n_util.h"
9 #include "base/mac_util.h"
10 #include "base/message_loop.h"
11 #include "base/sys_string_conversions.h"
12 #include "chrome/browser/cocoa/constrained_window_mac.h"
13 #include "chrome/browser/password_manager/password_manager.h"
14 #include "chrome/browser/renderer_host/resource_dispatcher_host.h"
15 #include "chrome/browser/tab_contents/navigation_controller.h"
16 #include "chrome/browser/tab_contents/tab_contents.h"
17 #include "chrome/browser/tab_contents/tab_util.h"
18 #include "chrome/common/notification_service.h"
19 #include "grit/generated_resources.h"
20 #include "net/url_request/url_request.h"
21
22 using webkit_glue::PasswordForm;
23
24 // ----------------------------------------------------------------------------
25 // LoginHandlerMac
26
27 // This class simply forwards the authentication from the LoginView (on
28 // the UI thread) to the URLRequest (on the I/O thread).
29 // This class uses ref counting to ensure that it lives until all InvokeLaters
30 // have been called.
31 class LoginHandlerMac : public LoginHandler,
32 public base::RefCountedThreadSafe<LoginHandlerMac>,
33 public ConstrainedWindowMacDelegateCustomSheet {
34 public:
35 LoginHandlerMac(URLRequest* request, MessageLoop* ui_loop)
36 : handled_auth_(false),
37 dialog_(NULL),
38 ui_loop_(ui_loop),
39 request_(request),
40 request_loop_(MessageLoop::current()),
41 password_manager_(NULL) {
42 // This constructor is called on the I/O thread, so we cannot load the nib
43 // here. BuildViewForPasswordManager() will be invoked on the UI thread
44 // later, so wait with loading the nib until then.
45 DCHECK(request_) << "LoginHandlerMac constructed with NULL request";
46
47 AddRef(); // matched by ReleaseLater.
48 if (!ResourceDispatcherHost::RenderViewForRequest(request_,
49 &render_process_host_id_,
50 &tab_contents_id_)) {
51 NOTREACHED();
52 }
53 }
54
55 virtual ~LoginHandlerMac() {
56 }
57
58 // LoginHandler:
59 virtual void BuildViewForPasswordManager(PasswordManager* manager,
60 std::wstring explanation) {
61 DCHECK(MessageLoop::current() == ui_loop_);
62
63 // Load nib here instead of in constructor.
64 LoginHandlerSheet* sheetController = [[[LoginHandlerSheet alloc]
65 initWithLoginHandler:this] autorelease];
66 init([sheetController window], sheetController,
67 @selector(sheetDidEnd:returnCode:contextInfo:));
68
69 // Scary thread safety note: This can potentially be called *after* SetAuth
70 // or CancelAuth (say, if the request was cancelled before the UI thread got
71 // control). However, that's OK since any UI interaction in those functions
72 // will occur via an InvokeLater on the UI thread, which is guaranteed
73 // to happen after this is called (since this was InvokeLater'd first).
74 dialog_ = GetTabContentsForLogin()->CreateConstrainedDialog(this);
75
76 SendNotifications();
77 }
78
79 virtual void SetPasswordForm(const webkit_glue::PasswordForm& form) {
80 password_form_ = form;
81 }
82
83 virtual void SetPasswordManager(PasswordManager* password_manager) {
84 password_manager_ = password_manager;
85 }
86
87 virtual TabContents* GetTabContentsForLogin() {
88 DCHECK(MessageLoop::current() == ui_loop_);
89
90 return tab_util::GetTabContentsByID(render_process_host_id_,
91 tab_contents_id_);
92 }
93
94 virtual void SetAuth(const std::wstring& username,
95 const std::wstring& password) {
96 if (WasAuthHandled(true))
97 return;
98
99 // Tell the password manager the credentials were submitted / accepted.
100 if (password_manager_) {
101 password_form_.username_value = username;
102 password_form_.password_value = password;
103 password_manager_->ProvisionallySavePassword(password_form_);
104 }
105
106 ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(
107 this, &LoginHandlerMac::CloseContentsDeferred));
108 ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(
109 this, &LoginHandlerMac::SendNotifications));
110 request_loop_->PostTask(FROM_HERE, NewRunnableMethod(
111 this, &LoginHandlerMac::SetAuthDeferred, username, password));
112 }
113
114 virtual void CancelAuth() {
115 if (WasAuthHandled(true))
116 return;
117
118 ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(
119 this, &LoginHandlerMac::CloseContentsDeferred));
120 ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(
121 this, &LoginHandlerMac::SendNotifications));
122 request_loop_->PostTask(FROM_HERE, NewRunnableMethod(
123 this, &LoginHandlerMac::CancelAuthDeferred));
124 }
125
126 virtual void OnRequestCancelled() {
127 DCHECK(MessageLoop::current() == request_loop_) <<
128 "Why is OnRequestCancelled called from the UI thread?";
129
130 // Reference is no longer valid.
131 request_ = NULL;
132
133 // Give up on auth if the request was cancelled.
134 CancelAuth();
135 }
136
137 // Overridden from ConstrainedWindowMacDelegate:
138 virtual void DeleteDelegate() {
139 if (!WasAuthHandled(true)) {
140 request_loop_->PostTask(FROM_HERE, NewRunnableMethod(
141 this, &LoginHandlerMac::CancelAuthDeferred));
142 ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(
143 this, &LoginHandlerMac::SendNotifications));
144 }
145
146 // Delete this object once all InvokeLaters have been called.
147 request_loop_->ReleaseSoon(FROM_HERE, this);
148 }
149
150 void OnLoginPressed(const std::wstring& username,
151 const std::wstring& password) {
152 DCHECK(MessageLoop::current() == ui_loop_);
153 SetAuth(username, password);
154 }
155
156 void OnCancelPressed() {
157 DCHECK(MessageLoop::current() == ui_loop_);
158 CancelAuth();
159 }
160
161 private:
162 friend class LoginPrompt;
163
164 // Calls SetAuth from the request_loop.
165 void SetAuthDeferred(const std::wstring& username,
166 const std::wstring& password) {
167 DCHECK(MessageLoop::current() == request_loop_);
168
169 if (request_) {
170 request_->SetAuth(username, password);
171 ResetLoginHandlerForRequest(request_);
172 }
173 }
174
175 // Calls CancelAuth from the request_loop.
176 void CancelAuthDeferred() {
177 DCHECK(MessageLoop::current() == request_loop_);
178
179 if (request_) {
180 request_->CancelAuth();
181 // Verify that CancelAuth does destroy the request via our delegate.
182 DCHECK(request_ != NULL);
183 ResetLoginHandlerForRequest(request_);
184 }
185 }
186
187 // Closes the view_contents from the UI loop.
188 void CloseContentsDeferred() {
189 DCHECK(MessageLoop::current() == ui_loop_);
190
191 // Close sheet if it's still open, as required by
192 // ConstrainedWindowMacDelegate.
193 if (is_sheet_open())
194 [NSApp endSheet:sheet()];
195
196 // The hosting ConstrainedWindow may have been freed.
197 if (dialog_)
198 dialog_->CloseConstrainedWindow();
199 }
200
201 // Returns whether authentication had been handled (SetAuth or CancelAuth).
202 // If |set_handled| is true, it will mark authentication as handled.
203 bool WasAuthHandled(bool set_handled) {
204 AutoLock lock(handled_auth_lock_);
205 bool was_handled = handled_auth_;
206 if (set_handled)
207 handled_auth_ = true;
208 return was_handled;
209 }
210
211 // Notify observers that authentication is needed or received. The automation
212 // proxy uses this for testing.
213 void SendNotifications() {
214 DCHECK(MessageLoop::current() == ui_loop_);
215
216 NotificationService* service = NotificationService::current();
217 TabContents* requesting_contents = GetTabContentsForLogin();
218 if (!requesting_contents)
219 return;
220
221 NavigationController* controller = &requesting_contents->controller();
222
223 if (!WasAuthHandled(false)) {
224 LoginNotificationDetails details(this);
225 service->Notify(NotificationType::AUTH_NEEDED,
226 Source<NavigationController>(controller),
227 Details<LoginNotificationDetails>(&details));
228 } else {
229 service->Notify(NotificationType::AUTH_SUPPLIED,
230 Source<NavigationController>(controller),
231 NotificationService::NoDetails());
232 }
233 }
234
235 // True if we've handled auth (SetAuth or CancelAuth has been called).
236 bool handled_auth_;
237 Lock handled_auth_lock_;
238
239 // The ConstrainedWindow that is hosting our LoginView.
240 // This should only be accessed on the ui_loop_.
241 ConstrainedWindow* dialog_;
242
243 // The MessageLoop of the thread that the ChromeViewContents lives in.
244 MessageLoop* ui_loop_;
245
246 // The request that wants login data.
247 // This should only be accessed on the request_loop_.
248 URLRequest* request_;
249
250 // The MessageLoop of the thread that the URLRequest lives in.
251 MessageLoop* request_loop_;
252
253 // The PasswordForm sent to the PasswordManager. This is so we can refer to it
254 // when later notifying the password manager if the credentials were accepted
255 // or rejected.
256 // This should only be accessed on the ui_loop_.
257 PasswordForm password_form_;
258
259 // Points to the password manager owned by the TabContents requesting auth.
260 // Can be null if the TabContents is not a TabContents.
261 // This should only be accessed on the ui_loop_.
262 PasswordManager* password_manager_;
263
264 // Cached from the URLRequest, in case it goes NULL on us.
265 int render_process_host_id_;
266 int tab_contents_id_;
267
268 DISALLOW_COPY_AND_ASSIGN(LoginHandlerMac);
269 };
270
271 // static
272 LoginHandler* LoginHandler::Create(URLRequest* request, MessageLoop* ui_loop) {
273 return new LoginHandlerMac(request, ui_loop);
274 }
275
276 // ----------------------------------------------------------------------------
277 // LoginHandlerSheet
278
279 @implementation LoginHandlerSheet
280
281 - (id)initWithLoginHandler:(LoginHandlerMac*)handler {
282 if ((self = [super initWithWindowNibName:@"HttpAuthLoginSheet"
283 owner:self])) {
284 handler_ = handler;
285 }
286 return self;
287 }
288
289 - (IBAction)loginPressed:(id)sender {
290 using base::SysNSStringToWide;
291 [NSApp endSheet:[self window]];
292 handler_->OnLoginPressed(SysNSStringToWide([nameField_ stringValue]),
293 SysNSStringToWide([passwordField_ stringValue]));
294 }
295
296 - (IBAction)cancelPressed:(id)sender {
297 [NSApp endSheet:[self window]];
298 handler_->OnCancelPressed();
299 }
300
301 - (void)sheetDidEnd:(NSWindow*)sheet
302 returnCode:(int)returnCode
303 contextInfo:(void *)contextInfo {
304 [sheet orderOut:self];
305 // Also called when user navigates to another page while the sheet is open.
306 }
307
308 @end
OLDNEW
« 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