EDIT: What follows has been tried only on Windows. You might want to check/change certain includes (and maybe add some specific code, I didn't tried) if you plan to support this also for Mac and Linux.
One way would be to fork CEF and implement a CefProxyHandler new class.
What I did in my projects is this:
- declare proxy type structs and classes
include/internal/cef_types.h
- Code: Select all
...
enum cef_proxy_type_t {
CEF_PROXY_TYPE_DIRECT = 0,
CEF_PROXY_TYPE_NAMED,
CEF_PROXY_TYPE_PAC_STRING,
};
typedef struct _cef_proxy_info_t {
enum cef_proxy_type_t proxyType;
cef_string_t proxyList;
} cef_proxy_info_t;
...
include/internal/cef_types_wrappers.h
- Code: Select all
struct CefProxyInfoTraits {
typedef cef_proxy_info_t struct_type;
static inline void init(struct_type* s) {}
static inline void clear(struct_type* s) {
cef_string_clear(&s->proxyList);
}
static inline void set(const struct_type* src, struct_type* target,
bool copy) {
target->proxyType = src->proxyType;
cef_string_set(src->proxyList.str, src->proxyList.length,
&target->proxyList, copy);
}
};
class CefProxyInfo : public CefStructBase<CefProxyInfoTraits> {
public:
void UseDirect() {
proxyType = CEF_PROXY_TYPE_DIRECT;
}
void UseNamedProxy(const CefString& proxy_uri_list) {
proxyType = CEF_PROXY_TYPE_NAMED;
(CefString(&proxyList)) = proxy_uri_list;
}
void UsePacString(const CefString& pac_string) {
proxyType = CEF_PROXY_TYPE_PAC_STRING;
(CefString(&proxyList)) = pac_string;
}
bool IsDirect() const { return proxyType == CEF_PROXY_TYPE_DIRECT; }
bool IsNamedProxy() const { return proxyType == CEF_PROXY_TYPE_NAMED; }
bool IsPacString() const { return proxyType == CEF_PROXY_TYPE_PAC_STRING; }
CefString ProxyList() const { return CefString(&proxyList); }
};
- add include/cef_proxy_handler.h
- Code: Select all
class CefProxyHandler : public virtual CefBaseRefCounted {
public:
///
// Called to retrieve proxy information for the specified |url|.
///
/*--cef()--*/
virtual void GetProxyForUrl(const CefString& url,
CefProxyInfo& proxy_info) {}
};
- declare WT_ for the new object in libcef/libcef_dll/wrapper_types.h
- Code: Select all
enum CefWrapperType {
WT_BASE_REF_COUNTED = 1,
WT_BASE_SCOPED,
...
WT_PRINT_HANDLER,
WT_PROXY_HANDLER,
WT_PRINT_JOB_CALLBACK,
...
WT_LAST
};
- generate/add manually cpptoc and ctocpp files
libcef_dll/cpptoc/proxy_handler_cpptoc.cc
- Code: Select all
...
#include "libcef_dll/cpptoc/proxy_handler_cpptoc.h"
// MEMBER FUNCTIONS - Body may be edited by hand.
void CEF_CALLBACK proxy_handler_get_proxy_for_url(
struct _cef_proxy_handler_t* self, const cef_string_t* url,
struct _cef_proxy_info_t* proxy_info) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Verify param: url; type: string_byref_const
DCHECK(url);
if (!url)
return;
// Verify param: proxy_info; type: struct_byref
DCHECK(proxy_info);
if (!proxy_info)
return;
// Translate param: proxy_info; type: struct_byref
CefProxyInfo proxy_infoObj;
if (proxy_info)
proxy_infoObj.AttachTo(*proxy_info);
// Execute
CefProxyHandlerCppToC::Get(self)->GetProxyForUrl(
CefString(url),
proxy_infoObj);
// Restore param: proxy_info; type: struct_byref
if (proxy_info)
proxy_infoObj.DetachTo(*proxy_info);
}
// CONSTRUCTOR - Do not edit by hand.
CefProxyHandlerCppToC::CefProxyHandlerCppToC() {
GetStruct()->get_proxy_for_url = proxy_handler_get_proxy_for_url;
}
template<>
CefRefPtr<CefProxyHandler> CefCppToCRefCounted<
CefProxyHandlerCppToC,
CefProxyHandler,
cef_proxy_handler_t>::UnwrapDerived(CefWrapperType type,
cef_proxy_handler_t* s) {
NOTREACHED() << "Unexpected class type: " << type;
return NULL;
}
#ifndef NDEBUG
template<>
base::AtomicRefCount CefCppToCRefCounted<CefProxyHandlerCppToC,
CefProxyHandler,
cef_proxy_handler_t>::DebugObjCt = 0;
#endif
template<>
CefWrapperType CefCppToCRefCounted<CefProxyHandlerCppToC,
CefProxyHandler,
cef_proxy_handler_t>::kWrapperType =
WT_PROXY_HANDLER;
libcef_dll/ctocpp/proxy_handler_cpptoc.h
- Code: Select all
#ifndef CEF_LIBCEF_DLL_CPPTOC_PROXY_HANDLER_CPPTOC_H_
#define CEF_LIBCEF_DLL_CPPTOC_PROXY_HANDLER_CPPTOC_H_
#pragma once
#if !defined(WRAPPING_CEF_SHARED)
#error This file can be included wrapper-side only
#endif
#include "include/cef_proxy_handler.h"
#include "include/capi/cef_proxy_handler_capi.h"
#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
// Wrap a C++ class with a C structure.
// This class may be instantiated and accessed wrapper-side only.
class CefProxyHandlerCppToC : public CefCppToCRefCounted<CefProxyHandlerCppToC,
CefProxyHandler,
cef_proxy_handler_t> {
public:
CefProxyHandlerCppToC();
};
#endif // CEF_LIBCEF_DLL_CPPTOC_PROXY_HANDLER_CPPTOC_H_
libcef_dll/ctocpp/proxy_handler_ctocpp.cc
- Code: Select all
#include "libcef_dll/ctocpp/proxy_handler_ctocpp.h"
// VIRTUAL METHODS - Body may be edited by hand.
void CefProxyHandlerCToCpp::GetProxyForUrl(const CefString& url,
CefProxyInfo& proxy_info) {
cef_proxy_handler_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, get_proxy_for_url))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: url; type: string_byref_const
DCHECK(!url.empty());
if (url.empty())
return;
// Execute
_struct->get_proxy_for_url(_struct,
url.GetStruct(),
&proxy_info);
}
// CONSTRUCTOR - Do not edit by hand.
CefProxyHandlerCToCpp::CefProxyHandlerCToCpp() {
}
template<>
cef_proxy_handler_t*
CefCToCppRefCounted<CefProxyHandlerCToCpp, CefProxyHandler, cef_proxy_handler_t>::
UnwrapDerived(CefWrapperType type, CefProxyHandler* c) {
NOTREACHED() << "Unexpected class type: " << type;
return NULL;
}
#if DCHECK_IS_ON()
template<>
base::AtomicRefCount CefCToCppRefCounted<CefProxyHandlerCToCpp,
CefProxyHandler,
cef_proxy_handler_t>::DebugObjCt
ATOMIC_DECLARATION;
#endif
template<>
CefWrapperType CefCToCppRefCounted<CefProxyHandlerCToCpp,
CefProxyHandler,
cef_proxy_handler_t>::kWrapperType =
WT_PROXY_HANDLER;
libcef_dll/ctocpp/proxy_handler_ctocpp.h
- Code: Select all
class CefProxyHandlerCToCpp : public CefCToCppRefCounted<CefProxyHandlerCToCpp,
CefProxyHandler,
cef_proxy_handler_t> {
public:
CefProxyHandlerCToCpp();
// CefProxyHandler methods
virtual void GetProxyForUrl(const CefString& url,
CefProxyInfo& proxy_info) override;
};
- modify accordingly app files
libcef_dll/cpptoc/app_ctocpp.cc
- Code: Select all
NO_SANITIZE("cfi-icall")
CefRefPtr<CefProxyHandler> CefAppCToCpp::GetProxyHandler() {
cef_app_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, get_proxy_handler))
return NULL;
// Execute
cef_proxy_handler_t* _retval = _struct->get_proxy_handler(_struct);
// Return type: refptr_same
return CefProxyHandlerCToCpp::Wrap(_retval);
}
libcef_dll/ctocpp/app_cpptoc.cc
- Code: Select all
struct _cef_proxy_handler_t* CEF_CALLBACK app_get_proxy_handler(
struct _cef_app_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return NULL;
// Execute
CefRefPtr<CefProxyHandler> _retval = CefAppCppToC::Get(self)->GetProxyHandler(
);
// Return type: refptr_same
return CefProxyHandlerCppToC::Wrap(_retval);
}
...
CefAppCppToC::CefAppCppToC() {
...
GetStruct()->get_proxy_handler = app_get_proxy_handler;
...
}
- modify cef_app.h and add handler
- Code: Select all
virtual CefRefPtr<CefProxyHandler> GetProxyHandler() {
return NULL;
}
- modify libcef/browser/net/url_request_context_getter_impl.cc to use proxy:
- Code: Select all
...
#include "net/proxy_resolution/proxy_config_service.h"
#include "net/proxy_resolution/proxy_resolver_factory.h"
#include "net/proxy_resolution/proxy_resolver.h"
...
namespace {
class ProxyConfigServiceNull : public net::ProxyConfigService {
public:
ProxyConfigServiceNull() {}
virtual void AddObserver(Observer* observer) override {}
virtual void RemoveObserver(Observer* observer) override {}
virtual ProxyConfigService::ConfigAvailability
GetLatestProxyConfig(net::ProxyConfigWithAnnotation* config) override
{ return ProxyConfigService::CONFIG_VALID; }
virtual void OnLazyPoll() override {}
};
// An implementation of |HttpUserAgentSettings| that provides a static
class CefProxyResolver
: public net::ProxyResolver {
public:
explicit CefProxyResolver(CefRefPtr<CefProxyHandler> handler)
: handler_(handler) {}
virtual ~CefProxyResolver() {}
// HTTP Accept-Language header value and uses |content::GetUserAgent|
virtual int GetProxyForURL(const GURL& url,
net::ProxyInfo* results,
const net::CompletionCallback& callback,
std::unique_ptr<Request>* request,
const net::NetLogWithSource& net_log) override {
CefProxyInfo proxy_info;
handler_->GetProxyForUrl(url.spec(), proxy_info);
if (proxy_info.IsDirect())
results->UseDirect();
else if (proxy_info.IsNamedProxy())
results->UseNamedProxy(proxy_info.ProxyList());
else if (proxy_info.IsPacString())
results->UsePacString(proxy_info.ProxyList());
// to provide the HTTP User-Agent header value.
return net::OK;
}
protected:
CefRefPtr<CefProxyHandler> handler_;
};
class CefProxyResolverFactory
: public net::ProxyResolverFactory {
public:
explicit CefProxyResolverFactory(CefRefPtr<CefProxyHandler> handler)
: net::ProxyResolverFactory(false)
, handler_(handler) {
}
virtual ~CefProxyResolverFactory() {
}
// Creates a new ProxyResolver. The caller is responsible for freeing this
// object.
virtual int CreateProxyResolver(
const scoped_refptr<net::PacFileData>& pac_script,
std::unique_ptr<net::ProxyResolver>* resolver,
const net::CompletionCallback& callback,
std::unique_ptr<Request>* request) override {
resolver->reset(new CefProxyResolver(handler_));
return net::OK;
}
private:
CefRefPtr<CefProxyHandler> handler_;
DISALLOW_COPY_AND_ASSIGN(CefProxyResolverFactory);
};
}; // namespace
...
net::URLRequestContext* CefURLRequestContextGetterImpl::GetURLRequestContext() {
CEF_REQUIRE_IOT();
...
io_state_->storage_->set_ct_policy_enforcer(std::move(ct_policy_enforcer));
// START HERE ==>
bool fCustomProxyHandler = false;
if(app.get()) {
CefRefPtr<CefProxyHandler> handler = app->GetProxyHandler();
if(handler.get()) {
// Force auto-detect so the client resolver will be called.
net::ProxyConfigServiceWin::set_force_auto_detect(true);
// The client will provide proxy resolution.
std::unique_ptr<net::ProxyResolutionService> custom_proxy_service(
new net::ProxyResolutionService(
net::ProxyResolutionService::CreateSystemProxyConfigService(
io_state_->io_task_runner_),
base::WrapUnique(
new CefProxyResolverFactory(handler)),
nullptr));
io_state_->storage_->set_proxy_resolution_service(
std::move(custom_proxy_service));
fCustomProxyHandler = true;
}
}
if(!fCustomProxyHandler) {
// custom proxy resolution not provided
std::unique_ptr<net::ProxyResolutionService> system_proxy_service =
CreateProxyResolutionService(
io_state_->net_log_,
io_state_->url_request_context_.get(),
io_state_->url_request_context_->network_delegate(),
std::move(io_state_->proxy_resolver_factory_),
std::move(io_state_->proxy_config_service_), *command_line,
quick_check_enabled_.GetValue(),
pac_https_url_stripping_enabled_.GetValue());
io_state_->storage_->set_proxy_resolution_service(
std::move(system_proxy_service));
}
// <== END HERE
io_state_->storage_->set_ssl_config_service(
std::make_unique<net::SSLConfigServiceDefaults>());
...
}
...
- modify cef_paths.gypi to add the new files
Should be enough to add in
- Code: Select all
...
'autogen_client_side': [
...
'libcef_dll/cpptoc/proxy_handler_cpptoc.cc',
'libcef_dll/cpptoc/proxy_handler_cpptoc.h',
...
],
...
- add it to the objects known to libcef dll:
libcef_dll/libcef_dll.cc
- Code: Select all
...
#include "libcef_dll/ctocpp/proxy_handler_ctocpp.h"
...
CEF_EXPORT void cef_shutdown() {
...
DCHECK(base::AtomicRefCountIsZero(&CefProxyHandlerCToCpp::DebugObjCt));
...
}
- finally, in cefclient the usage should be straightforward
tests/shared/common/client_app.h
- Code: Select all
class ClientApp : public CefApp, public CefProxyHandler {
...
CefRefPtr<CefProxyHandler> GetProxyHandler() override;
void GetProxyForUrl(const CefString& url, CefProxyInfo& proxy_info) override;
...
};
tests/shared/common/client_app.cc
- Code: Select all
...
CefRefPtr<CefProxyHandler> ClientApp::GetProxyHandler()
{
return this;
}
void ClientApp::GetProxyForUrl(const CefString& url,
CefProxyInfo& proxy_info)
{
// dummy values
proxy_info.proxyType = CEF_PROXY_TYPE_NAMED;
CefString(&proxy_info.proxyList) = "http://my-proxy-server:12345";
}
...
I might have forgotten/skipped something, but that's what I used.
Basically is what CEF1 had once updated for CEF3.