Allow clients to clear certificate exceptions and close connections (issue #1793)

This commit is contained in:
Marshall Greenblatt 2016-02-23 14:29:18 -05:00
parent 912e94bf61
commit cd7e8a0558
8 changed files with 308 additions and 0 deletions

View File

@ -38,6 +38,7 @@
#define CEF_INCLUDE_CAPI_CEF_REQUEST_CONTEXT_CAPI_H_
#pragma once
#include "include/capi/cef_callback_capi.h"
#include "include/capi/cef_cookie_capi.h"
#include "include/capi/cef_request_context_handler_capi.h"
#include "include/capi/cef_values_capi.h"
@ -199,6 +200,28 @@ typedef struct _cef_request_context_t {
int (CEF_CALLBACK *set_preference)(struct _cef_request_context_t* self,
const cef_string_t* name, struct _cef_value_t* value,
cef_string_t* error);
///
// Clears all certificate exceptions that were added as part of handling
// cef_request_tHandler::on_certificate_error(). If you call this it is
// recommended that you also call close_all_connections() or you risk not
// being prompted again for server certificates if you reconnect quickly. If
// |callback| is non-NULL it will be executed on the UI thread after
// completion.
///
void (CEF_CALLBACK *clear_certificate_exceptions)(
struct _cef_request_context_t* self,
struct _cef_completion_callback_t* callback);
///
// Clears all active and idle connections that Chromium currently has. This is
// only recommended if you have released all other CEF objects but don't yet
// want to call cef_shutdown(). If |callback| is non-NULL it will be executed
// on the UI thread after completion.
///
void (CEF_CALLBACK *close_all_connections)(
struct _cef_request_context_t* self,
struct _cef_completion_callback_t* callback);
} cef_request_context_t;

View File

@ -38,6 +38,7 @@
#define CEF_INCLUDE_CEF_REQUEST_CONTEXT_H_
#pragma once
#include "include/cef_callback.h"
#include "include/cef_cookie.h"
#include "include/cef_request_context_handler.h"
#include "include/cef_values.h"
@ -217,6 +218,28 @@ class CefRequestContext : public virtual CefBase {
virtual bool SetPreference(const CefString& name,
CefRefPtr<CefValue> value,
CefString& error) =0;
///
// Clears all certificate exceptions that were added as part of handling
// CefRequestHandler::OnCertificateError(). If you call this it is
// recommended that you also call CloseAllConnections() or you risk not
// being prompted again for server certificates if you reconnect quickly.
// If |callback| is non-NULL it will be executed on the UI thread after
// completion.
///
/*--cef(optional_param=callback)--*/
virtual void ClearCertificateExceptions(
CefRefPtr<CefCompletionCallback> callback) =0;
///
// Clears all active and idle connections that Chromium currently has.
// This is only recommended if you have released all other CEF objects but
// don't yet want to call CefShutdown(). If |callback| is non-NULL it will be
// executed on the UI thread after completion.
///
/*--cef(optional_param=callback)--*/
virtual void CloseAllConnections(
CefRefPtr<CefCompletionCallback> callback) =0;
};
#endif // CEF_INCLUDE_CEF_REQUEST_CONTEXT_H_

View File

@ -16,6 +16,9 @@
#include "base/prefs/pref_service.h"
#include "base/strings/stringprintf.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/browser/ssl_host_state_delegate.h"
#include "net/http/http_cache.h"
#include "net/http/http_transaction_factory.h"
using content::BrowserThread;
@ -444,6 +447,22 @@ bool CefRequestContextImpl::SetPreference(const CefString& name,
return true;
}
void CefRequestContextImpl::ClearCertificateExceptions(
CefRefPtr<CefCompletionCallback> callback) {
GetBrowserContext(
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
base::Bind(&CefRequestContextImpl::ClearCertificateExceptionsInternal,
this, callback));
}
void CefRequestContextImpl::CloseAllConnections(
CefRefPtr<CefCompletionCallback> callback) {
GetRequestContextImpl(
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO),
base::Bind(&CefRequestContextImpl::CloseAllConnectionsInternal, this,
callback));
}
CefRequestContextImpl::CefRequestContextImpl(
scoped_refptr<CefBrowserContext> browser_context)
: browser_context_(browser_context),
@ -548,3 +567,41 @@ void CefRequestContextImpl::PurgePluginListCacheInternal(
content::PluginService::GetInstance()->PurgePluginListCache(
browser_context.get(), false);
}
void CefRequestContextImpl::ClearCertificateExceptionsInternal(
CefRefPtr<CefCompletionCallback> callback,
scoped_refptr<CefBrowserContext> browser_context) {
CEF_REQUIRE_UIT();
content::SSLHostStateDelegate* ssl_delegate =
browser_context->GetSSLHostStateDelegate();
if (ssl_delegate)
ssl_delegate->Clear();
if (callback) {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefCompletionCallback::OnComplete, callback.get()));
}
}
void CefRequestContextImpl::CloseAllConnectionsInternal(
CefRefPtr<CefCompletionCallback> callback,
scoped_refptr<CefURLRequestContextGetterImpl> request_context) {
CEF_REQUIRE_IOT();
net::URLRequestContext* url_context = request_context->GetURLRequestContext();
if (url_context) {
net::HttpTransactionFactory* http_factory =
url_context->http_transaction_factory();
if (http_factory) {
net::HttpCache* cache = http_factory->GetCache();
if (cache)
cache->CloseAllConnections();
}
}
if (callback) {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefCompletionCallback::OnComplete, callback.get()));
}
}

View File

@ -69,6 +69,9 @@ class CefRequestContextImpl : public CefRequestContext {
bool SetPreference(const CefString& name,
CefRefPtr<CefValue> value,
CefString& error) override;
void ClearCertificateExceptions(
CefRefPtr<CefCompletionCallback> callback) override;
void CloseAllConnections(CefRefPtr<CefCompletionCallback> callback) override;
const CefRequestContextSettings& settings() const { return settings_; }
@ -103,6 +106,12 @@ class CefRequestContextImpl : public CefRequestContext {
void PurgePluginListCacheInternal(
bool reload_pages,
scoped_refptr<CefBrowserContext> browser_context);
void ClearCertificateExceptionsInternal(
CefRefPtr<CefCompletionCallback> callback,
scoped_refptr<CefBrowserContext> browser_context);
void CloseAllConnectionsInternal(
CefRefPtr<CefCompletionCallback> callback,
scoped_refptr<CefURLRequestContextGetterImpl> request_context);
scoped_refptr<CefBrowserContext> browser_context_;
CefRequestContextSettings settings_;

View File

@ -350,6 +350,34 @@ int CEF_CALLBACK request_context_set_preference(
return _retval;
}
void CEF_CALLBACK request_context_clear_certificate_exceptions(
struct _cef_request_context_t* self, cef_completion_callback_t* callback) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Unverified params: callback
// Execute
CefRequestContextCppToC::Get(self)->ClearCertificateExceptions(
CefCompletionCallbackCToCpp::Wrap(callback));
}
void CEF_CALLBACK request_context_close_all_connections(
struct _cef_request_context_t* self, cef_completion_callback_t* callback) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Unverified params: callback
// Execute
CefRequestContextCppToC::Get(self)->CloseAllConnections(
CefCompletionCallbackCToCpp::Wrap(callback));
}
} // namespace
@ -374,6 +402,9 @@ CefRequestContextCppToC::CefRequestContextCppToC() {
GetStruct()->get_all_preferences = request_context_get_all_preferences;
GetStruct()->can_set_preference = request_context_can_set_preference;
GetStruct()->set_preference = request_context_set_preference;
GetStruct()->clear_certificate_exceptions =
request_context_clear_certificate_exceptions;
GetStruct()->close_all_connections = request_context_close_all_connections;
}
template<> CefRefPtr<CefRequestContext> CefCppToC<CefRequestContextCppToC,

View File

@ -325,6 +325,36 @@ bool CefRequestContextCToCpp::SetPreference(const CefString& name,
return _retval?true:false;
}
void CefRequestContextCToCpp::ClearCertificateExceptions(
CefRefPtr<CefCompletionCallback> callback) {
cef_request_context_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, clear_certificate_exceptions))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Unverified params: callback
// Execute
_struct->clear_certificate_exceptions(_struct,
CefCompletionCallbackCppToC::Wrap(callback));
}
void CefRequestContextCToCpp::CloseAllConnections(
CefRefPtr<CefCompletionCallback> callback) {
cef_request_context_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, close_all_connections))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Unverified params: callback
// Execute
_struct->close_all_connections(_struct,
CefCompletionCallbackCppToC::Wrap(callback));
}
// CONSTRUCTOR - Do not edit by hand.

View File

@ -52,6 +52,9 @@ class CefRequestContextCToCpp
bool CanSetPreference(const CefString& name) OVERRIDE;
bool SetPreference(const CefString& name, CefRefPtr<CefValue> value,
CefString& error) OVERRIDE;
void ClearCertificateExceptions(
CefRefPtr<CefCompletionCallback> callback) OVERRIDE;
void CloseAllConnections(CefRefPtr<CefCompletionCallback> callback) OVERRIDE;
};
#endif // USING_CEF_SHARED

View File

@ -650,3 +650,135 @@ TEST(RequestContextTest, NoReferrerLinkDifferentOrigin) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
namespace {
class MethodTestHandler : public TestHandler {
public:
enum Method {
METHOD_CLEAR_CERTIFICATE_EXCEPTIONS,
METHOD_CLOSE_ALL_CONNECTIONS,
};
class CompletionCallback : public CefCompletionCallback {
public:
explicit CompletionCallback(MethodTestHandler* test_handler)
: test_handler_(test_handler) {
}
~CompletionCallback() override {
EXPECT_UI_THREAD();
// OnComplete should be executed.
EXPECT_FALSE(test_handler_);
}
void OnComplete() override {
EXPECT_UI_THREAD();
// OnComplete should be executed only one time.
EXPECT_TRUE(test_handler_);
test_handler_->OnCompleteCallback();
test_handler_ = nullptr;
}
private:
MethodTestHandler* test_handler_;
IMPLEMENT_REFCOUNTING(CompletionCallback);
};
MethodTestHandler(bool global_context,
Method method)
: global_context_(global_context),
method_(method) {
}
void RunTest() override {
const char kUrl[] = "http://tests/method.html";
AddResource(kUrl, "<html><body>Method</body></html>", "text/html");
CefRefPtr<CefRequestContext> request_context;
if (!global_context_) {
CefRequestContextSettings settings;
request_context = CefRequestContext::CreateContext(settings, nullptr);
}
CreateBrowser(kUrl, request_context);
// Time out the test after a reasonable period of time.
SetTestTimeout();
}
void OnLoadEnd(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int httpStatusCode) override {
CefRefPtr<CefRequestContext> context =
browser->GetHost()->GetRequestContext();
CefRefPtr<CefCompletionCallback> callback = new CompletionCallback(this);
if (method_ == METHOD_CLEAR_CERTIFICATE_EXCEPTIONS)
context->ClearCertificateExceptions(callback);
else if (method_ == METHOD_CLOSE_ALL_CONNECTIONS)
context->CloseAllConnections(callback);
}
void OnCompleteCallback() {
EXPECT_UI_THREAD();
EXPECT_FALSE(got_completion_callback_);
got_completion_callback_.yes();
DestroyTest();
}
private:
void DestroyTest() override {
EXPECT_TRUE(got_completion_callback_);
TestHandler::DestroyTest();
}
const bool global_context_;
const Method method_;
TrackCallback got_completion_callback_;
IMPLEMENT_REFCOUNTING(MethodTestHandler);
};
} // namespace
// Test CefRequestContext::ClearCertificateExceptions with the global context.
TEST(RequestContextTest, ClearCertificateExceptionsGlobal) {
CefRefPtr<MethodTestHandler> handler =
new MethodTestHandler(true,
MethodTestHandler::METHOD_CLEAR_CERTIFICATE_EXCEPTIONS);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Test CefRequestContext::ClearCertificateExceptions with a custom context.
TEST(RequestContextTest, ClearCertificateExceptionsCustom) {
CefRefPtr<MethodTestHandler> handler =
new MethodTestHandler(false,
MethodTestHandler::METHOD_CLEAR_CERTIFICATE_EXCEPTIONS);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Test CefRequestContext::CloseAllConnections with the global context.
TEST(RequestContextTest, CloseAllConnectionsGlobal) {
CefRefPtr<MethodTestHandler> handler =
new MethodTestHandler(true,
MethodTestHandler::METHOD_CLOSE_ALL_CONNECTIONS);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Test CefRequestContext::CloseAllConnections with a custom context.
TEST(RequestContextTest, CloseAllConnectionsCustom) {
CefRefPtr<MethodTestHandler> handler =
new MethodTestHandler(false,
MethodTestHandler::METHOD_CLOSE_ALL_CONNECTIONS);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}