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

Side by Side Diff: chrome/browser/login_prompt_gtk.cc

Issue 995004: Factoring duplicate code from platform-specific LoginHandlers into a base ... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 10 years, 9 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
« no previous file with comments | « chrome/browser/login_prompt.cc ('k') | chrome/browser/login_prompt_mac.mm » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/login_prompt.h" 5 #include "chrome/browser/login_prompt.h"
6 6
7 #include <gtk/gtk.h> 7 #include <gtk/gtk.h>
8 8
9 #include "app/l10n_util.h" 9 #include "app/l10n_util.h"
10 #include "base/utf_string_conversions.h" 10 #include "base/utf_string_conversions.h"
(...skipping 13 matching lines...) Expand all
24 using webkit_glue::PasswordForm; 24 using webkit_glue::PasswordForm;
25 25
26 // ---------------------------------------------------------------------------- 26 // ----------------------------------------------------------------------------
27 // LoginHandlerGtk 27 // LoginHandlerGtk
28 28
29 // This class simply forwards the authentication from the LoginView (on 29 // This class simply forwards the authentication from the LoginView (on
30 // the UI thread) to the URLRequest (on the I/O thread). 30 // the UI thread) to the URLRequest (on the I/O thread).
31 // This class uses ref counting to ensure that it lives until all InvokeLaters 31 // This class uses ref counting to ensure that it lives until all InvokeLaters
32 // have been called. 32 // have been called.
33 class LoginHandlerGtk : public LoginHandler, 33 class LoginHandlerGtk : public LoginHandler,
34 public base::RefCountedThreadSafe<LoginHandlerGtk>, 34 public ConstrainedWindowGtkDelegate {
35 public ConstrainedWindowGtkDelegate,
36 public LoginModelObserver {
37 public: 35 public:
38 explicit LoginHandlerGtk(URLRequest* request) 36 explicit LoginHandlerGtk(URLRequest* request) : LoginHandler(request) {
39 : handled_auth_(false),
40 dialog_(NULL),
41 request_(request),
42 password_manager_(NULL),
43 login_model_(NULL) {
44 DCHECK(request_) << "LoginHandlerGtk constructed with NULL request";
45
46 AddRef(); // matched by ReleaseLater.
47 if (!ResourceDispatcherHost::RenderViewForRequest(request_,
48 &render_process_host_id_,
49 &tab_contents_id_)) {
50 NOTREACHED();
51 }
52 } 37 }
53 38
54 virtual ~LoginHandlerGtk() { 39 virtual ~LoginHandlerGtk() {
55 if (login_model_)
56 login_model_->SetObserver(NULL);
57 root_.Destroy(); 40 root_.Destroy();
58 } 41 }
59 42
60 void SetModel(LoginModel* model) {
61 if (login_model_)
62 login_model_->SetObserver(NULL);
63 login_model_ = model;
64 if (login_model_)
65 login_model_->SetObserver(this);
66 }
67
68 // LoginModelObserver implementation. 43 // LoginModelObserver implementation.
69 virtual void OnAutofillDataAvailable(const std::wstring& username, 44 virtual void OnAutofillDataAvailable(const std::wstring& username,
70 const std::wstring& password) { 45 const std::wstring& password) {
46 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
47
71 // NOTE: Would be nice to use gtk_entry_get_text_length, but it is fairly 48 // NOTE: Would be nice to use gtk_entry_get_text_length, but it is fairly
72 // new and not always in our GTK version. 49 // new and not always in our GTK version.
73 if (strlen(gtk_entry_get_text(GTK_ENTRY(username_entry_))) == 0) { 50 if (strlen(gtk_entry_get_text(GTK_ENTRY(username_entry_))) == 0) {
74 gtk_entry_set_text(GTK_ENTRY(username_entry_), 51 gtk_entry_set_text(GTK_ENTRY(username_entry_),
75 WideToUTF8(username).c_str()); 52 WideToUTF8(username).c_str());
76 gtk_entry_set_text(GTK_ENTRY(password_entry_), 53 gtk_entry_set_text(GTK_ENTRY(password_entry_),
77 WideToUTF8(password).c_str()); 54 WideToUTF8(password).c_str());
78 gtk_editable_select_region(GTK_EDITABLE(username_entry_), 0, -1); 55 gtk_editable_select_region(GTK_EDITABLE(username_entry_), 0, -1);
79 } 56 }
80 } 57 }
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 g_signal_connect(root_.get(), "hierarchy-changed", 98 g_signal_connect(root_.get(), "hierarchy-changed",
122 G_CALLBACK(OnPromptShown), this); 99 G_CALLBACK(OnPromptShown), this);
123 100
124 SetModel(manager); 101 SetModel(manager);
125 102
126 // Scary thread safety note: This can potentially be called *after* SetAuth 103 // Scary thread safety note: This can potentially be called *after* SetAuth
127 // or CancelAuth (say, if the request was cancelled before the UI thread got 104 // or CancelAuth (say, if the request was cancelled before the UI thread got
128 // control). However, that's OK since any UI interaction in those functions 105 // control). However, that's OK since any UI interaction in those functions
129 // will occur via an InvokeLater on the UI thread, which is guaranteed 106 // will occur via an InvokeLater on the UI thread, which is guaranteed
130 // to happen after this is called (since this was InvokeLater'd first). 107 // to happen after this is called (since this was InvokeLater'd first).
131 dialog_ = GetTabContentsForLogin()->CreateConstrainedDialog(this); 108 SetDialog(GetTabContentsForLogin()->CreateConstrainedDialog(this));
132 109
133 SendNotifications(); 110 SendNotifications();
134 } 111 }
135 112
136 virtual void SetPasswordForm(const webkit_glue::PasswordForm& form) {
137 password_form_ = form;
138 }
139
140 virtual void SetPasswordManager(PasswordManager* password_manager) {
141 password_manager_ = password_manager;
142 }
143
144 virtual TabContents* GetTabContentsForLogin() {
145 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
146
147 return tab_util::GetTabContentsByID(render_process_host_id_,
148 tab_contents_id_);
149 }
150
151 virtual void SetAuth(const std::wstring& username,
152 const std::wstring& password) {
153 if (WasAuthHandled(true))
154 return;
155
156 // Tell the password manager the credentials were submitted / accepted.
157 if (password_manager_) {
158 password_form_.username_value = WideToUTF16Hack(username);
159 password_form_.password_value = WideToUTF16Hack(password);
160 password_manager_->ProvisionallySavePassword(password_form_);
161 }
162
163 ChromeThread::PostTask(
164 ChromeThread::UI, FROM_HERE,
165 NewRunnableMethod(this, &LoginHandlerGtk::CloseContentsDeferred));
166 ChromeThread::PostTask(
167 ChromeThread::UI, FROM_HERE,
168 NewRunnableMethod(this, &LoginHandlerGtk::SendNotifications));
169 ChromeThread::PostTask(
170 ChromeThread::IO, FROM_HERE,
171 NewRunnableMethod(this, &LoginHandlerGtk::SetAuthDeferred, username,
172 password));
173 }
174
175 virtual void CancelAuth() {
176 if (WasAuthHandled(true))
177 return;
178
179 ChromeThread::PostTask(
180 ChromeThread::UI, FROM_HERE,
181 NewRunnableMethod(this, &LoginHandlerGtk::CloseContentsDeferred));
182 ChromeThread::PostTask(
183 ChromeThread::UI, FROM_HERE,
184 NewRunnableMethod(this, &LoginHandlerGtk::SendNotifications));
185 ChromeThread::PostTask(
186 ChromeThread::IO, FROM_HERE,
187 NewRunnableMethod(this, &LoginHandlerGtk::CancelAuthDeferred));
188 }
189
190 virtual void OnRequestCancelled() {
191 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)) <<
192 "Why is OnRequestCancelled called from the UI thread?";
193
194 // Reference is no longer valid.
195 request_ = NULL;
196
197 // Give up on auth if the request was cancelled.
198 CancelAuth();
199 }
200
201 // Overridden from ConstrainedWindowGtkDelegate: 113 // Overridden from ConstrainedWindowGtkDelegate:
202 virtual GtkWidget* GetWidgetRoot() { 114 virtual GtkWidget* GetWidgetRoot() {
203 return root_.get(); 115 return root_.get();
204 } 116 }
205 117
206 virtual void DeleteDelegate() { 118 virtual void DeleteDelegate() {
207 if (!WasAuthHandled(true)) { 119 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
208 ChromeThread::PostTask(
209 ChromeThread::IO, FROM_HERE,
210 NewRunnableMethod(this, &LoginHandlerGtk::CancelAuthDeferred));
211 ChromeThread::PostTask(
212 ChromeThread::UI, FROM_HERE,
213 NewRunnableMethod(this, &LoginHandlerGtk::SendNotifications));
214 }
215 120
216 // The constrained window is going to delete itself; clear our pointer. 121 // The constrained window is going to delete itself; clear our pointer.
217 dialog_ = NULL; 122 SetDialog(NULL);
218 SetModel(NULL); 123 SetModel(NULL);
219 124
220 // Delete this object once all InvokeLaters have been called. 125 ReleaseSoon();
221 ChromeThread::ReleaseSoon(ChromeThread::IO, FROM_HERE, this);
222 } 126 }
223 127
224 private: 128 private:
225 friend class LoginPrompt; 129 friend class LoginPrompt;
226 130
227 // Calls SetAuth from the IO loop.
228 void SetAuthDeferred(const std::wstring& username,
229 const std::wstring& password) {
230 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
231
232 if (request_) {
233 request_->SetAuth(username, password);
234 ResetLoginHandlerForRequest(request_);
235 }
236 }
237
238 // Calls CancelAuth from the IO loop.
239 void CancelAuthDeferred() {
240 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
241
242 if (request_) {
243 request_->CancelAuth();
244 // Verify that CancelAuth does destroy the request via our delegate.
245 DCHECK(request_ != NULL);
246 ResetLoginHandlerForRequest(request_);
247 }
248 }
249
250 // Closes the view_contents from the UI loop.
251 void CloseContentsDeferred() {
252 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
253
254 // The hosting ConstrainedWindow may have been freed.
255 if (dialog_)
256 dialog_->CloseConstrainedWindow();
257 }
258
259 // Returns whether authentication had been handled (SetAuth or CancelAuth).
260 // If |set_handled| is true, it will mark authentication as handled.
261 bool WasAuthHandled(bool set_handled) {
262 AutoLock lock(handled_auth_lock_);
263 bool was_handled = handled_auth_;
264 if (set_handled)
265 handled_auth_ = true;
266 return was_handled;
267 }
268
269 // Notify observers that authentication is needed or received. The automation
270 // proxy uses this for testing.
271 void SendNotifications() {
272 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
273
274 NotificationService* service = NotificationService::current();
275 TabContents* requesting_contents = GetTabContentsForLogin();
276 if (!requesting_contents)
277 return;
278
279 NavigationController* controller = &requesting_contents->controller();
280
281 if (!WasAuthHandled(false)) {
282 LoginNotificationDetails details(this);
283 service->Notify(NotificationType::AUTH_NEEDED,
284 Source<NavigationController>(controller),
285 Details<LoginNotificationDetails>(&details));
286 } else {
287 service->Notify(NotificationType::AUTH_SUPPLIED,
288 Source<NavigationController>(controller),
289 NotificationService::NoDetails());
290 }
291 }
292
293 static void OnOKClicked(GtkButton *button, LoginHandlerGtk* handler) { 131 static void OnOKClicked(GtkButton *button, LoginHandlerGtk* handler) {
294 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); 132 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
295 133
296 handler->SetAuth( 134 handler->SetAuth(
297 UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(handler->username_entry_))), 135 UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(handler->username_entry_))),
298 UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(handler->password_entry_)))); 136 UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(handler->password_entry_))));
299 } 137 }
300 138
301 static void OnCancelClicked(GtkButton *button, LoginHandlerGtk* handler) { 139 static void OnCancelClicked(GtkButton *button, LoginHandlerGtk* handler) {
302 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); 140 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
141
303 handler->CancelAuth(); 142 handler->CancelAuth();
304 } 143 }
305 144
306 static void OnPromptShown(GtkButton* root, 145 static void OnPromptShown(GtkButton* root,
307 GtkWidget* previous_toplevel, 146 GtkWidget* previous_toplevel,
308 LoginHandlerGtk* handler) { 147 LoginHandlerGtk* handler) {
309 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); 148 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
149
310 if (!GTK_WIDGET_TOPLEVEL(gtk_widget_get_toplevel(handler->ok_))) 150 if (!GTK_WIDGET_TOPLEVEL(gtk_widget_get_toplevel(handler->ok_)))
311 return; 151 return;
312 152
313 // Now that we have attached ourself to the window, we can make our OK 153 // Now that we have attached ourself to the window, we can make our OK
314 // button the default action and mess with the focus. 154 // button the default action and mess with the focus.
315 GTK_WIDGET_SET_FLAGS(handler->ok_, GTK_CAN_DEFAULT); 155 GTK_WIDGET_SET_FLAGS(handler->ok_, GTK_CAN_DEFAULT);
316 gtk_widget_grab_default(handler->ok_); 156 gtk_widget_grab_default(handler->ok_);
317 gtk_widget_grab_focus(handler->username_entry_); 157 gtk_widget_grab_focus(handler->username_entry_);
318 } 158 }
319
320 // True if we've handled auth (SetAuth or CancelAuth has been called).
321 bool handled_auth_;
322 Lock handled_auth_lock_;
323
324 // The ConstrainedWindow that is hosting our LoginView.
325 // This should only be accessed on the UI loop.
326 ConstrainedWindow* dialog_;
327
328 // The request that wants login data.
329 // This should only be accessed on the IO loop.
330 URLRequest* request_;
331
332 // The PasswordForm sent to the PasswordManager. This is so we can refer to it
333 // when later notifying the password manager if the credentials were accepted
334 // or rejected.
335 // This should only be accessed on the UI loop.
336 PasswordForm password_form_;
337
338 // Points to the password manager owned by the TabContents requesting auth.
339 // Can be null if the TabContents is not a TabContents.
340 // This should only be accessed on the UI loop.
341 PasswordManager* password_manager_;
342
343 // Cached from the URLRequest, in case it goes NULL on us.
344 int render_process_host_id_;
345 int tab_contents_id_;
346 159
347 // The GtkWidgets that form our visual hierarchy: 160 // The GtkWidgets that form our visual hierarchy:
348 // The root container we pass to our parent. 161 // The root container we pass to our parent.
349 OwnedWidgetGtk root_; 162 OwnedWidgetGtk root_;
350 163
351 // GtkEntry widgets that the user types into. 164 // GtkEntry widgets that the user types into.
352 GtkWidget* username_entry_; 165 GtkWidget* username_entry_;
353 GtkWidget* password_entry_; 166 GtkWidget* password_entry_;
354 GtkWidget* ok_; 167 GtkWidget* ok_;
355 168
356 // If not null, points to a model we need to notify of our own destruction
357 // so it doesn't try and access this when its too late.
358 LoginModel* login_model_;
359
360 DISALLOW_COPY_AND_ASSIGN(LoginHandlerGtk); 169 DISALLOW_COPY_AND_ASSIGN(LoginHandlerGtk);
361 }; 170 };
362 171
363 // static 172 // static
364 LoginHandler* LoginHandler::Create(URLRequest* request) { 173 LoginHandler* LoginHandler::Create(URLRequest* request) {
365 return new LoginHandlerGtk(request); 174 return new LoginHandlerGtk(request);
366 } 175 }
OLDNEW
« no previous file with comments | « chrome/browser/login_prompt.cc ('k') | chrome/browser/login_prompt_mac.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698