Index: chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm |
diff --git a/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm b/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm |
index a8d7912f5204808919e499b1910929f09ab09571..54ff89123d38624b0cf371dea480cbe7c67dc412 100644 |
--- a/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm |
+++ b/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm |
@@ -14,7 +14,9 @@ |
#include "chrome/browser/ssl/ssl_client_auth_observer.h" |
#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h" |
#include "chrome/grit/generated_resources.h" |
+#include "components/web_modal/popup_manager.h" |
#include "content/public/browser/browser_thread.h" |
+#include "content/public/browser/client_certificate_delegate.h" |
#include "content/public/browser/web_contents.h" |
#include "net/cert/x509_certificate.h" |
#include "net/cert/x509_util_mac.h" |
@@ -42,11 +44,12 @@ class SSLClientAuthObserverCocoaBridge : public SSLClientAuthObserver, |
SSLClientAuthObserverCocoaBridge( |
const content::BrowserContext* browser_context, |
net::SSLCertRequestInfo* cert_request_info, |
- const chrome::SelectCertificateCallback& callback, |
+ scoped_ptr<content::ClientCertificateDelegate> delegate, |
SSLClientCertificateSelectorCocoa* controller) |
- : SSLClientAuthObserver(browser_context, cert_request_info, callback), |
- controller_(controller) { |
- } |
+ : SSLClientAuthObserver(browser_context, |
+ cert_request_info, |
+ delegate.Pass()), |
+ controller_(controller) {} |
// SSLClientAuthObserver implementation: |
void OnCertSelectedByNotification() override { |
@@ -72,14 +75,22 @@ namespace chrome { |
void ShowSSLClientCertificateSelector( |
content::WebContents* contents, |
net::SSLCertRequestInfo* cert_request_info, |
- const SelectCertificateCallback& callback) { |
+ scoped_ptr<content::ClientCertificateDelegate> delegate) { |
DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ |
+ // Not all WebContentses can show modal dialogs. |
+ // |
+ // TODO(davidben): Move this hook to the WebContentsDelegate and only try to |
+ // show a dialog in Browser's implementation. https://crbug.com/456255 |
+ if (web_modal::PopupManager::FromWebContents(contents) == nullptr) |
+ return; |
+ |
// The dialog manages its own lifetime. |
SSLClientCertificateSelectorCocoa* selector = |
[[SSLClientCertificateSelectorCocoa alloc] |
initWithBrowserContext:contents->GetBrowserContext() |
certRequestInfo:cert_request_info |
- callback:callback]; |
+ delegate:delegate.Pass()]; |
[selector displayForWebContents:contents]; |
} |
@@ -88,13 +99,14 @@ void ShowSSLClientCertificateSelector( |
@implementation SSLClientCertificateSelectorCocoa |
- (id)initWithBrowserContext:(const content::BrowserContext*)browserContext |
- certRequestInfo:(net::SSLCertRequestInfo*)certRequestInfo |
- callback:(const chrome::SelectCertificateCallback&)callback { |
+ certRequestInfo:(net::SSLCertRequestInfo*)certRequestInfo |
+ delegate:(scoped_ptr<content::ClientCertificateDelegate>) |
+ delegate { |
DCHECK(browserContext); |
DCHECK(certRequestInfo); |
if ((self = [super init])) { |
observer_.reset(new SSLClientAuthObserverCocoaBridge( |
- browserContext, certRequestInfo, callback, self)); |
+ browserContext, certRequestInfo, delegate.Pass(), self)); |
} |
return self; |
} |
@@ -113,12 +125,16 @@ void ShowSSLClientCertificateSelector( |
NOTREACHED(); |
} |
- // Finally, tell the backend which identity (or none) the user selected. |
- observer_->StopObserving(); |
- observer_->CertificateSelected(cert); |
+ if (!closePending_) { |
+ // If |closePending_| is already set, |closeSheetWithAnimation:| was called |
+ // already to cancel the selection rather than continue with no |
+ // certificate. Otherwise, tell the backend which identity (or none) the |
+ // user selected. |
+ userResponded_ = YES; |
+ observer_->CertificateSelected(cert); |
- if (!closePending_) |
constrainedWindow_->CloseWebContentsModalDialog(); |
+ } |
} |
- (void)displayForWebContents:(content::WebContents*)webContents { |
@@ -184,6 +200,14 @@ void ShowSSLClientCertificateSelector( |
} |
- (void)closeSheetWithAnimation:(BOOL)withAnimation { |
+ if (!userResponded_) { |
+ // If the sheet is closed by closing the tab rather than the user explicitly |
+ // hitting Cancel, |closeSheetWithAnimation:| gets called before |
+ // |sheetDidEnd:|. In this case, the selection should be canceled rather |
+ // than continue with no certificate. The |returnCode| parameter to |
+ // |sheetDidEnd:| is the same in both cases. |
+ observer_->CancelCertificateSelection(); |
+ } |
closePending_ = YES; |
overlayWindow_.reset(); |
// Closing the sheet using -[NSApp endSheet:] doesn't work so use the private |