diff options
Diffstat (limited to 'android_webview')
6 files changed, 87 insertions, 64 deletions
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc index fb89fc6..a4db9971 100644 --- a/android_webview/browser/aw_content_browser_client.cc +++ b/android_webview/browser/aw_content_browser_client.cc @@ -28,6 +28,7 @@ #include "content/public/browser/browser_message_filter.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_security_policy.h" +#include "content/public/browser/client_certificate_delegate.h" #include "content/public/browser/permission_type.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" @@ -368,17 +369,13 @@ void AwContentBrowserClient::AllowCertificateError( } void AwContentBrowserClient::SelectClientCertificate( - int render_process_id, - int render_frame_id, - net::SSLCertRequestInfo* cert_request_info, - const base::Callback<void(net::X509Certificate*)>& callback) { + content::WebContents* web_contents, + net::SSLCertRequestInfo* cert_request_info, + scoped_ptr<content::ClientCertificateDelegate> delegate) { AwContentsClientBridgeBase* client = - AwContentsClientBridgeBase::FromID(render_process_id, render_frame_id); - if (client) { - client->SelectClientCertificate(cert_request_info, callback); - } else { - callback.Run(NULL); - } + AwContentsClientBridgeBase::FromWebContents(web_contents); + if (client) + client->SelectClientCertificate(cert_request_info, delegate.Pass()); } void AwContentBrowserClient::RequestPermission( diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h index cae1bf3..c61c2c4 100644 --- a/android_webview/browser/aw_content_browser_client.h +++ b/android_webview/browser/aw_content_browser_client.h @@ -102,10 +102,9 @@ class AwContentBrowserClient : public content::ContentBrowserClient { const base::Callback<void(bool)>& callback, content::CertificateRequestResultType* result) override; void SelectClientCertificate( - int render_process_id, - int render_frame_id, + content::WebContents* web_contents, net::SSLCertRequestInfo* cert_request_info, - const base::Callback<void(net::X509Certificate*)>& callback) override; + scoped_ptr<content::ClientCertificateDelegate> delegate) override; void RequestPermission( content::PermissionType permission, content::WebContents* web_contents, diff --git a/android_webview/browser/aw_contents_client_bridge_base.h b/android_webview/browser/aw_contents_client_bridge_base.h index a24aa4b..265004e 100644 --- a/android_webview/browser/aw_contents_client_bridge_base.h +++ b/android_webview/browser/aw_contents_client_bridge_base.h @@ -5,13 +5,14 @@ #ifndef ANDROID_WEBVIEW_BROWSER_AW_CONTENTS_CLIENT_BRIDGE_BASE_H_ #define ANDROID_WEBVIEW_BROWSER_AW_CONTENTS_CLIENT_BRIDGE_BASE_H_ -#include "base/callback_forward.h" +#include "base/memory/scoped_ptr.h" #include "base/supports_user_data.h" #include "content/public/browser/javascript_dialog_manager.h" class GURL; namespace content { +class ClientCertificateDelegate; class WebContents; } @@ -29,8 +30,6 @@ namespace android_webview { // native/ from browser/ layer. class AwContentsClientBridgeBase { public: - typedef base::Callback<void(net::X509Certificate*)> SelectCertificateCallback; - // Adds the handler to the UserData registry. static void Associate(content::WebContents* web_contents, AwContentsClientBridgeBase* handler); @@ -48,7 +47,7 @@ class AwContentsClientBridgeBase { bool* cancel_request) = 0; virtual void SelectClientCertificate( net::SSLCertRequestInfo* cert_request_info, - const SelectCertificateCallback& callback) = 0; + scoped_ptr<content::ClientCertificateDelegate> delegate) = 0; virtual void RunJavaScriptDialog( content::JavaScriptMessageType message_type, diff --git a/android_webview/native/aw_contents_client_bridge.cc b/android_webview/native/aw_contents_client_bridge.cc index 9d68603..c54b8a1 100644 --- a/android_webview/native/aw_contents_client_bridge.cc +++ b/android_webview/native/aw_contents_client_bridge.cc @@ -10,7 +10,9 @@ #include "base/android/jni_array.h" #include "base/android/jni_string.h" #include "base/callback_helpers.h" +#include "base/macros.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/client_certificate_delegate.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" @@ -58,11 +60,18 @@ AwContentsClientBridge::~AwContentsClientBridge() { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); - if (obj.is_null()) - return; - // Clear the weak reference from the java peer to the native object since - // it is possible that java object lifetime can exceed the AwContens. - Java_AwContentsClientBridge_setNativeContentsClientBridge(env, obj.obj(), 0); + if (!obj.is_null()) { + // Clear the weak reference from the java peer to the native object since + // it is possible that java object lifetime can exceed the AwContens. + Java_AwContentsClientBridge_setNativeContentsClientBridge(env, obj.obj(), + 0); + } + + for (IDMap<content::ClientCertificateDelegate>::iterator iter( + &pending_client_cert_request_delegates_); + !iter.IsAtEnd(); iter.Advance()) { + delete iter.GetCurrentValue(); + } } void AwContentsClientBridge::AllowCertificateError( @@ -114,13 +123,13 @@ void AwContentsClientBridge::ProceedSslError(JNIEnv* env, jobject obj, // This method is inspired by SelectClientCertificate() in // chrome/browser/ui/android/ssl_client_certificate_request.cc void AwContentsClientBridge::SelectClientCertificate( - net::SSLCertRequestInfo* cert_request_info, - const SelectCertificateCallback& callback) { + net::SSLCertRequestInfo* cert_request_info, + scoped_ptr<content::ClientCertificateDelegate> delegate) { DCHECK_CURRENTLY_ON(BrowserThread::UI); // Add the callback to id map. - int request_id = pending_client_cert_request_callbacks_.Add( - new SelectCertificateCallback(callback)); + int request_id = + pending_client_cert_request_delegates_.Add(delegate.release()); // Make sure callback is run on error. base::ScopedClosureRunner guard(base::Bind( &AwContentsClientBridge::HandleErrorInClientCertificateResponse, @@ -196,19 +205,24 @@ void AwContentsClientBridge::ProvideClientCertificateResponse( jobject private_key_ref) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - SelectCertificateCallback* callback = - pending_client_cert_request_callbacks_.Lookup(request_id); - DCHECK(callback); + content::ClientCertificateDelegate* delegate = + pending_client_cert_request_delegates_.Lookup(request_id); + DCHECK(delegate); + + if (encoded_chain_ref == NULL || private_key_ref == NULL) { + LOG(ERROR) << "No client certificate selected"; + pending_client_cert_request_delegates_.Remove(request_id); + delegate->ContinueWithCertificate(nullptr); + delete delegate; + return; + } // Make sure callback is run on error. base::ScopedClosureRunner guard(base::Bind( &AwContentsClientBridge::HandleErrorInClientCertificateResponse, base::Unretained(this), request_id)); - if (encoded_chain_ref == NULL || private_key_ref == NULL) { - LOG(ERROR) << "Client certificate request cancelled"; - return; - } + // Convert the encoded chain to a vector of strings. std::vector<std::string> encoded_chain_strings; if (encoded_chain_ref) { @@ -236,20 +250,20 @@ void AwContentsClientBridge::ProvideClientCertificateResponse( return; } + // Release the guard and |pending_client_cert_request_delegates_| references + // to |delegate|. + pending_client_cert_request_delegates_.Remove(request_id); + ignore_result(guard.Release()); + // RecordClientCertificateKey() must be called on the I/O thread, - // before the callback is called with the selected certificate on + // before the delegate is called with the selected certificate on // the UI thread. content::BrowserThread::PostTaskAndReply( - content::BrowserThread::IO, - FROM_HERE, - base::Bind(&RecordClientCertificateKey, - client_cert, + content::BrowserThread::IO, FROM_HERE, + base::Bind(&RecordClientCertificateKey, client_cert, base::Passed(&private_key)), - base::Bind(*callback, client_cert)); - pending_client_cert_request_callbacks_.Remove(request_id); - - // Release the guard. - ignore_result(guard.Release()); + base::Bind(&content::ClientCertificateDelegate::ContinueWithCertificate, + base::Owned(delegate), client_cert)); } void AwContentsClientBridge::RunJavaScriptDialog( @@ -377,10 +391,11 @@ void AwContentsClientBridge::CancelJsResult(JNIEnv*, jobject, int id) { // Use to cleanup if there is an error in client certificate response. void AwContentsClientBridge::HandleErrorInClientCertificateResponse( int request_id) { - SelectCertificateCallback* callback = - pending_client_cert_request_callbacks_.Lookup(request_id); - callback->Run(nullptr); - pending_client_cert_request_callbacks_.Remove(request_id); + content::ClientCertificateDelegate* delegate = + pending_client_cert_request_delegates_.Lookup(request_id); + pending_client_cert_request_delegates_.Remove(request_id); + + delete delegate; } bool RegisterAwContentsClientBridge(JNIEnv* env) { diff --git a/android_webview/native/aw_contents_client_bridge.h b/android_webview/native/aw_contents_client_bridge.h index 2a5caba..a2bde4b 100644 --- a/android_webview/native/aw_contents_client_bridge.h +++ b/android_webview/native/aw_contents_client_bridge.h @@ -40,7 +40,7 @@ class AwContentsClientBridge : public AwContentsClientBridgeBase { bool* cancel_request) override; void SelectClientCertificate( net::SSLCertRequestInfo* cert_request_info, - const SelectCertificateCallback& callback) override; + scoped_ptr<content::ClientCertificateDelegate> delegate) override; void RunJavaScriptDialog( content::JavaScriptMessageType message_type, @@ -73,8 +73,10 @@ class AwContentsClientBridge : public AwContentsClientBridgeBase { IDMap<CertErrorCallback, IDMapOwnPointer> pending_cert_error_callbacks_; IDMap<content::JavaScriptDialogManager::DialogClosedCallback, IDMapOwnPointer> pending_js_dialog_callbacks_; - IDMap<SelectCertificateCallback, IDMapOwnPointer> - pending_client_cert_request_callbacks_; + // |pending_client_cert_request_delegates_| owns its pointers, but IDMap + // doesn't provide Release, so ownership is managed manually. + IDMap<content::ClientCertificateDelegate> + pending_client_cert_request_delegates_; }; bool RegisterAwContentsClientBridge(JNIEnv* env); diff --git a/android_webview/native/aw_contents_client_bridge_unittest.cc b/android_webview/native/aw_contents_client_bridge_unittest.cc index b301f91..4b59144 100644 --- a/android_webview/native/aw_contents_client_bridge_unittest.cc +++ b/android_webview/native/aw_contents_client_bridge_unittest.cc @@ -8,8 +8,10 @@ #include "base/android/jni_array.h" #include "base/android/scoped_java_ref.h" #include "base/bind.h" +#include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/run_loop.h" +#include "content/public/browser/client_certificate_delegate.h" #include "content/public/test/test_browser_thread_bundle.h" #include "jni/MockAwContentsClientBridge_jni.h" #include "net/android/net_jni_registrar.h" @@ -33,9 +35,6 @@ namespace { // Tests the android_webview contents client bridge. class AwContentsClientBridgeTest : public Test { public: - typedef AwContentsClientBridge::SelectCertificateCallback - SelectCertificateCallback; - AwContentsClientBridgeTest() { } // Callback method called when a cert is selected. @@ -53,6 +52,24 @@ class AwContentsClientBridgeTest : public Test { JNIEnv* env_; }; +class TestClientCertificateDelegate + : public content::ClientCertificateDelegate { + public: + explicit TestClientCertificateDelegate(AwContentsClientBridgeTest* test) + : test_(test) {} + + // content::ClientCertificateDelegate. + void ContinueWithCertificate(net::X509Certificate* cert) override { + test_->CertSelected(cert); + test_ = nullptr; + } + + private: + AwContentsClientBridgeTest* test_; + + DISALLOW_COPY_AND_ASSIGN(TestClientCertificateDelegate); +}; + } // namespace void AwContentsClientBridgeTest::SetUp() { @@ -90,9 +107,7 @@ void AwContentsClientBridgeTest::TestCertType(SSLClientCertType type, cert_request_info_->cert_key_types.push_back(type); bridge_->SelectClientCertificate( cert_request_info_.get(), - base::Bind( - &AwContentsClientBridgeTest::CertSelected, - base::Unretained(static_cast<AwContentsClientBridgeTest*>(this)))); + make_scoped_ptr(new TestClientCertificateDelegate(this))); base::RunLoop().RunUntilIdle(); EXPECT_EQ(0, cert_selected_callbacks_); ScopedJavaLocalRef<jobjectArray> key_types = @@ -112,10 +127,8 @@ TEST_F(AwContentsClientBridgeTest, // Call SelectClientCertificate to create a callback id that mock java object // can call on. bridge_->SelectClientCertificate( - cert_request_info_.get(), - base::Bind( - &AwContentsClientBridgeTest::CertSelected, - base::Unretained(static_cast<AwContentsClientBridgeTest*>(this)))); + cert_request_info_.get(), + make_scoped_ptr(new TestClientCertificateDelegate(this))); bridge_->ProvideClientCertificateResponse(env_, jbridge_.obj(), Java_MockAwContentsClientBridge_getRequestId(env_, jbridge_.obj()), Java_MockAwContentsClientBridge_createTestCertChain( @@ -133,10 +146,8 @@ TEST_F(AwContentsClientBridgeTest, // Call SelectClientCertificate to create a callback id that mock java object // can call on. bridge_->SelectClientCertificate( - cert_request_info_.get(), - base::Bind( - &AwContentsClientBridgeTest::CertSelected, - base::Unretained(static_cast<AwContentsClientBridgeTest*>(this)))); + cert_request_info_.get(), + make_scoped_ptr(new TestClientCertificateDelegate(this))); int requestId = Java_MockAwContentsClientBridge_getRequestId(env_, jbridge_.obj()); bridge_->ProvideClientCertificateResponse(env_, jbridge_.obj(), |