mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-02-25 08:27:41 +01:00
Add binary format support to CefMessageRouter (fixes #3502)
This commit is contained in:
parent
1b74ac5124
commit
44323082b1
@ -147,6 +147,8 @@
|
|||||||
'libcef_dll/wrapper/cef_byte_read_handler.cc',
|
'libcef_dll/wrapper/cef_byte_read_handler.cc',
|
||||||
'libcef_dll/wrapper/cef_closure_task.cc',
|
'libcef_dll/wrapper/cef_closure_task.cc',
|
||||||
'libcef_dll/wrapper/cef_message_router.cc',
|
'libcef_dll/wrapper/cef_message_router.cc',
|
||||||
|
'libcef_dll/wrapper/cef_message_router_utils.cc',
|
||||||
|
'libcef_dll/wrapper/cef_message_router_utils.h',
|
||||||
'libcef_dll/wrapper/cef_resource_manager.cc',
|
'libcef_dll/wrapper/cef_resource_manager.cc',
|
||||||
'libcef_dll/wrapper/cef_scoped_temp_dir.cc',
|
'libcef_dll/wrapper/cef_scoped_temp_dir.cc',
|
||||||
'libcef_dll/wrapper/cef_stream_resource_handler.cc',
|
'libcef_dll/wrapper/cef_stream_resource_handler.cc',
|
||||||
@ -218,6 +220,8 @@
|
|||||||
'tests/shared/browser/util_win.h',
|
'tests/shared/browser/util_win.h',
|
||||||
],
|
],
|
||||||
'cefclient_sources_browser': [
|
'cefclient_sources_browser': [
|
||||||
|
'tests/cefclient/browser/binary_transfer_test.cc',
|
||||||
|
'tests/cefclient/browser/binary_transfer_test.h',
|
||||||
'tests/cefclient/browser/binding_test.cc',
|
'tests/cefclient/browser/binding_test.cc',
|
||||||
'tests/cefclient/browser/binding_test.h',
|
'tests/cefclient/browser/binding_test.h',
|
||||||
'tests/cefclient/browser/browser_window.cc',
|
'tests/cefclient/browser/browser_window.cc',
|
||||||
@ -309,6 +313,7 @@
|
|||||||
'tests/cefclient/resources/dialogs.html',
|
'tests/cefclient/resources/dialogs.html',
|
||||||
'tests/cefclient/resources/draggable.html',
|
'tests/cefclient/resources/draggable.html',
|
||||||
'tests/cefclient/resources/ipc_performance.html',
|
'tests/cefclient/resources/ipc_performance.html',
|
||||||
|
'tests/cefclient/resources/binary_transfer.html',
|
||||||
'tests/cefclient/resources/localstorage.html',
|
'tests/cefclient/resources/localstorage.html',
|
||||||
'tests/cefclient/resources/logo.png',
|
'tests/cefclient/resources/logo.png',
|
||||||
'tests/cefclient/resources/media_router.html',
|
'tests/cefclient/resources/media_router.html',
|
||||||
@ -496,6 +501,7 @@
|
|||||||
'tests/ceftests/jsdialog_unittest.cc',
|
'tests/ceftests/jsdialog_unittest.cc',
|
||||||
'tests/ceftests/life_span_unittest.cc',
|
'tests/ceftests/life_span_unittest.cc',
|
||||||
'tests/ceftests/media_access_unittest.cc',
|
'tests/ceftests/media_access_unittest.cc',
|
||||||
|
'tests/ceftests/message_router_binary_unittest.cc',
|
||||||
'tests/ceftests/message_router_harness_unittest.cc',
|
'tests/ceftests/message_router_harness_unittest.cc',
|
||||||
'tests/ceftests/message_router_multi_query_unittest.cc',
|
'tests/ceftests/message_router_multi_query_unittest.cc',
|
||||||
'tests/ceftests/message_router_single_query_unittest.cc',
|
'tests/ceftests/message_router_single_query_unittest.cc',
|
||||||
@ -603,6 +609,7 @@
|
|||||||
'tests/ceftests/dom_unittest.cc',
|
'tests/ceftests/dom_unittest.cc',
|
||||||
'tests/ceftests/frame_unittest.cc',
|
'tests/ceftests/frame_unittest.cc',
|
||||||
'tests/ceftests/media_access_unittest.cc',
|
'tests/ceftests/media_access_unittest.cc',
|
||||||
|
'tests/ceftests/message_router_binary_unittest.cc',
|
||||||
'tests/ceftests/message_router_harness_unittest.cc',
|
'tests/ceftests/message_router_harness_unittest.cc',
|
||||||
'tests/ceftests/message_router_multi_query_unittest.cc',
|
'tests/ceftests/message_router_multi_query_unittest.cc',
|
||||||
'tests/ceftests/message_router_single_query_unittest.cc',
|
'tests/ceftests/message_router_single_query_unittest.cc',
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
// by hand. See the translator.README.txt file in the tools directory for
|
// by hand. See the translator.README.txt file in the tools directory for
|
||||||
// more information.
|
// more information.
|
||||||
//
|
//
|
||||||
// $hash=42de7c0e6f5ec529d9182fe4cbf2c1edfacd7392$
|
// $hash=865ca5bff4a0867d0c25cb41bd2aa808cf3fddbd$
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef CEF_INCLUDE_CAPI_CEF_V8_CAPI_H_
|
#ifndef CEF_INCLUDE_CAPI_CEF_V8_CAPI_H_
|
||||||
@ -679,6 +679,19 @@ typedef struct _cef_v8value_t {
|
|||||||
///
|
///
|
||||||
int(CEF_CALLBACK* neuter_array_buffer)(struct _cef_v8value_t* self);
|
int(CEF_CALLBACK* neuter_array_buffer)(struct _cef_v8value_t* self);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the length (in bytes) of the ArrayBuffer.
|
||||||
|
///
|
||||||
|
size_t(CEF_CALLBACK* get_array_buffer_byte_length)(
|
||||||
|
struct _cef_v8value_t* self);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a pointer to the beginning of the memory block for this
|
||||||
|
/// ArrayBuffer backing store. The returned pointer is valid as long as the
|
||||||
|
/// cef_v8value_t is alive.
|
||||||
|
///
|
||||||
|
void*(CEF_CALLBACK* get_array_buffer_data)(struct _cef_v8value_t* self);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Returns the function name.
|
/// Returns the function name.
|
||||||
///
|
///
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
// by hand. See the translator.README.txt file in the tools directory for
|
// by hand. See the translator.README.txt file in the tools directory for
|
||||||
// more information.
|
// more information.
|
||||||
//
|
//
|
||||||
// $hash=1b8f7f620685c30b91c8fa656e1a01d182684ae6$
|
// $hash=7b8fee9d4a0530782ed62f5741820708f110e24e$
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef CEF_INCLUDE_CAPI_CEF_VALUES_CAPI_H_
|
#ifndef CEF_INCLUDE_CAPI_CEF_VALUES_CAPI_H_
|
||||||
@ -265,6 +265,12 @@ typedef struct _cef_binary_value_t {
|
|||||||
struct _cef_binary_value_t*(CEF_CALLBACK* copy)(
|
struct _cef_binary_value_t*(CEF_CALLBACK* copy)(
|
||||||
struct _cef_binary_value_t* self);
|
struct _cef_binary_value_t* self);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a pointer to the beginning of the memory block. The returned
|
||||||
|
/// pointer is valid as long as the cef_binary_value_t is alive.
|
||||||
|
///
|
||||||
|
const void*(CEF_CALLBACK* get_raw_data)(struct _cef_binary_value_t* self);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Returns the data size.
|
/// Returns the data size.
|
||||||
///
|
///
|
||||||
|
@ -42,13 +42,13 @@
|
|||||||
// way that may cause binary incompatibility with other builds. The universal
|
// way that may cause binary incompatibility with other builds. The universal
|
||||||
// hash value will change if any platform is affected whereas the platform hash
|
// hash value will change if any platform is affected whereas the platform hash
|
||||||
// values will change only if that particular platform is affected.
|
// values will change only if that particular platform is affected.
|
||||||
#define CEF_API_HASH_UNIVERSAL "647a2df6b870951e70487997f30e75960d609632"
|
#define CEF_API_HASH_UNIVERSAL "1920c69ce75671bf41d947677d76cc92e9b0ca3b"
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
#define CEF_API_HASH_PLATFORM "4a22d727f3f1f625844191f0f5adf297a2f17fa7"
|
#define CEF_API_HASH_PLATFORM "c1c5f6ed3f032d525d36e737388b0b850f5e0c59"
|
||||||
#elif defined(OS_MAC)
|
#elif defined(OS_MAC)
|
||||||
#define CEF_API_HASH_PLATFORM "84a450a85c81d6cb16dda55d7f07047264d1e205"
|
#define CEF_API_HASH_PLATFORM "5a278846114ac057af673f522377552f41e09179"
|
||||||
#elif defined(OS_LINUX)
|
#elif defined(OS_LINUX)
|
||||||
#define CEF_API_HASH_PLATFORM "b7cbd7d044e02cb1854184cc1d5d621605b8476b"
|
#define CEF_API_HASH_PLATFORM "e94defd6a38fb3d2933f5f417ec0e727d6d35abf"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -520,7 +520,7 @@ class CefV8Value : public virtual CefBaseRefCounted {
|
|||||||
/// or CefV8Accessor callback, or in combination with calling Enter() and
|
/// or CefV8Accessor callback, or in combination with calling Enter() and
|
||||||
/// Exit() on a stored CefV8Context reference.
|
/// Exit() on a stored CefV8Context reference.
|
||||||
///
|
///
|
||||||
/*--cef()--*/
|
/*--cef(optional_param=buffer)--*/
|
||||||
static CefRefPtr<CefV8Value> CreateArrayBuffer(
|
static CefRefPtr<CefV8Value> CreateArrayBuffer(
|
||||||
void* buffer,
|
void* buffer,
|
||||||
size_t length,
|
size_t length,
|
||||||
@ -866,6 +866,20 @@ class CefV8Value : public virtual CefBaseRefCounted {
|
|||||||
/*--cef()--*/
|
/*--cef()--*/
|
||||||
virtual bool NeuterArrayBuffer() = 0;
|
virtual bool NeuterArrayBuffer() = 0;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the length (in bytes) of the ArrayBuffer.
|
||||||
|
///
|
||||||
|
/*--cef()--*/
|
||||||
|
virtual size_t GetArrayBufferByteLength() = 0;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a pointer to the beginning of the memory block for this
|
||||||
|
/// ArrayBuffer backing store. The returned pointer is valid as long as the
|
||||||
|
/// CefV8Value is alive.
|
||||||
|
///
|
||||||
|
/*--cef()--*/
|
||||||
|
virtual void* GetArrayBufferData() = 0;
|
||||||
|
|
||||||
// FUNCTION METHODS - These methods are only available on functions.
|
// FUNCTION METHODS - These methods are only available on functions.
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -278,6 +278,13 @@ class CefBinaryValue : public virtual CefBaseRefCounted {
|
|||||||
/*--cef()--*/
|
/*--cef()--*/
|
||||||
virtual CefRefPtr<CefBinaryValue> Copy() = 0;
|
virtual CefRefPtr<CefBinaryValue> Copy() = 0;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a pointer to the beginning of the memory block.
|
||||||
|
/// The returned pointer is valid as long as the CefBinaryValue is alive.
|
||||||
|
///
|
||||||
|
/*--cef()--*/
|
||||||
|
virtual const void* GetRawData() = 0;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Returns the data size.
|
/// Returns the data size.
|
||||||
///
|
///
|
||||||
|
@ -219,6 +219,38 @@ struct CefMessageRouterConfig {
|
|||||||
size_t message_size_threshold;
|
size_t message_size_threshold;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// This class acts as a container for managing binary data. It retains
|
||||||
|
/// references to the underlying backing store, ensuring it is valid as long as
|
||||||
|
/// the CefBinaryBuffer exists. This allows efficient, zero-copy access to data
|
||||||
|
/// received from another process.
|
||||||
|
///
|
||||||
|
/// This class is not designed to be thread-safe, and it is the user's
|
||||||
|
/// responsibility to synchronize access from multiple threads to ensure data
|
||||||
|
/// integrity.
|
||||||
|
///
|
||||||
|
class CefBinaryBuffer : public CefBaseRefCounted {
|
||||||
|
public:
|
||||||
|
///
|
||||||
|
/// Returns the read-only pointer to the memory. Returns nullptr if
|
||||||
|
/// |GetSize()| returns zero. The returned pointer is only valid for the life
|
||||||
|
/// span of this object.
|
||||||
|
///
|
||||||
|
virtual const void* GetData() const = 0;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the writable pointer to the memory. Returns nullptr if
|
||||||
|
/// |GetSize()| returns zero. The returned pointer is only valid for the life
|
||||||
|
/// span of this object.
|
||||||
|
///
|
||||||
|
virtual void* GetData() = 0;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the size of the data.
|
||||||
|
///
|
||||||
|
virtual size_t GetSize() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Implements the browser side of query routing. The methods of this class may
|
/// Implements the browser side of query routing. The methods of this class may
|
||||||
/// be called on any browser process thread unless otherwise indicated.
|
/// be called on any browser process thread unless otherwise indicated.
|
||||||
@ -238,10 +270,17 @@ class CefMessageRouterBrowserSide
|
|||||||
public:
|
public:
|
||||||
///
|
///
|
||||||
/// Notify the associated JavaScript onSuccess callback that the query has
|
/// Notify the associated JavaScript onSuccess callback that the query has
|
||||||
/// completed successfully with the specified |response|.
|
/// completed successfully with the specified string |response|.
|
||||||
///
|
///
|
||||||
virtual void Success(const CefString& response) = 0;
|
virtual void Success(const CefString& response) = 0;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Notify the associated JavaScript onSuccess callback that the query has
|
||||||
|
/// completed successfully with binary data. A |data| pointer to the binary
|
||||||
|
/// data can be nullptr only if the |size| is 0.
|
||||||
|
///
|
||||||
|
virtual void Success(const void* data, size_t size) = 0;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Notify the associated JavaScript onFailure callback that the query has
|
/// Notify the associated JavaScript onFailure callback that the query has
|
||||||
/// failed with the specified |error_code| and |error_message|.
|
/// failed with the specified |error_code| and |error_message|.
|
||||||
@ -276,6 +315,25 @@ class CefMessageRouterBrowserSide
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Executed when a new query is received. |query_id| uniquely identifies
|
||||||
|
/// the query for the life span of the router. Return true to handle the
|
||||||
|
/// query or false to propagate the query to other registered handlers, if
|
||||||
|
/// any. If no handlers return true from this method then the query will be
|
||||||
|
/// automatically canceled with an error code of -1 delivered to the
|
||||||
|
/// JavaScript onFailure callback. If this method returns true then a
|
||||||
|
/// Callback method must be executed either in this method or asynchronously
|
||||||
|
/// to complete the query.
|
||||||
|
///
|
||||||
|
virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||||
|
CefRefPtr<CefFrame> frame,
|
||||||
|
int64_t query_id,
|
||||||
|
CefRefPtr<const CefBinaryBuffer> request,
|
||||||
|
bool persistent,
|
||||||
|
CefRefPtr<Callback> callback) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Executed when a query has been canceled either explicitly using the
|
/// Executed when a query has been canceled either explicitly using the
|
||||||
/// JavaScript cancel function or implicitly due to browser destruction,
|
/// JavaScript cancel function or implicitly due to browser destruction,
|
||||||
|
@ -606,6 +606,11 @@ CefRefPtr<CefBinaryValue> CefBinaryValueImpl::Copy() {
|
|||||||
return new CefBinaryValueImpl(const_value().Clone());
|
return new CefBinaryValueImpl(const_value().Clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const void* CefBinaryValueImpl::GetRawData() {
|
||||||
|
CEF_VALUE_VERIFY_RETURN(false, nullptr);
|
||||||
|
return const_value().GetBlob().data();
|
||||||
|
}
|
||||||
|
|
||||||
size_t CefBinaryValueImpl::GetSize() {
|
size_t CefBinaryValueImpl::GetSize() {
|
||||||
CEF_VALUE_VERIFY_RETURN(false, 0);
|
CEF_VALUE_VERIFY_RETURN(false, 0);
|
||||||
return const_value().GetBlob().size();
|
return const_value().GetBlob().size();
|
||||||
|
@ -177,6 +177,7 @@ class CefBinaryValueImpl : public CefValueBase<CefBinaryValue, base::Value> {
|
|||||||
bool IsSame(CefRefPtr<CefBinaryValue> that) override;
|
bool IsSame(CefRefPtr<CefBinaryValue> that) override;
|
||||||
bool IsEqual(CefRefPtr<CefBinaryValue> that) override;
|
bool IsEqual(CefRefPtr<CefBinaryValue> that) override;
|
||||||
CefRefPtr<CefBinaryValue> Copy() override;
|
CefRefPtr<CefBinaryValue> Copy() override;
|
||||||
|
const void* GetRawData() override;
|
||||||
size_t GetSize() override;
|
size_t GetSize() override;
|
||||||
size_t GetData(void* buffer, size_t buffer_size, size_t data_offset) override;
|
size_t GetData(void* buffer, size_t buffer_size, size_t data_offset) override;
|
||||||
|
|
||||||
|
@ -2368,6 +2368,61 @@ bool CefV8ValueImpl::NeuterArrayBuffer() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t CefV8ValueImpl::GetArrayBufferByteLength() {
|
||||||
|
size_t rv = 0;
|
||||||
|
CEF_V8_REQUIRE_ISOLATE_RETURN(rv);
|
||||||
|
if (type_ != TYPE_OBJECT) {
|
||||||
|
DCHECK(false) << "V8 value is not an object";
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::Isolate* isolate = handle_->isolate();
|
||||||
|
v8::HandleScope handle_scope(isolate);
|
||||||
|
|
||||||
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||||
|
if (context.IsEmpty()) {
|
||||||
|
DCHECK(false) << "not currently in a V8 context";
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
||||||
|
if (!value->IsArrayBuffer()) {
|
||||||
|
DCHECK(false) << "V8 value is not an array buffer";
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
||||||
|
return v8::Local<v8::ArrayBuffer>::Cast(obj)->ByteLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
void* CefV8ValueImpl::GetArrayBufferData() {
|
||||||
|
void* rv = nullptr;
|
||||||
|
CEF_V8_REQUIRE_ISOLATE_RETURN(rv);
|
||||||
|
if (type_ != TYPE_OBJECT) {
|
||||||
|
DCHECK(false) << "V8 value is not an object";
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::Isolate* isolate = handle_->isolate();
|
||||||
|
v8::HandleScope handle_scope(isolate);
|
||||||
|
|
||||||
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||||
|
if (context.IsEmpty()) {
|
||||||
|
DCHECK(false) << "not currently in a V8 context";
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
||||||
|
if (!value->IsArrayBuffer()) {
|
||||||
|
DCHECK(false) << "V8 value is not an array buffer";
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
||||||
|
v8::Local<v8::ArrayBuffer> arr = v8::Local<v8::ArrayBuffer>::Cast(obj);
|
||||||
|
return arr->Data();
|
||||||
|
}
|
||||||
|
|
||||||
CefString CefV8ValueImpl::GetFunctionName() {
|
CefString CefV8ValueImpl::GetFunctionName() {
|
||||||
CefString rv;
|
CefString rv;
|
||||||
CEF_V8_REQUIRE_OBJECT_RETURN(rv);
|
CEF_V8_REQUIRE_OBJECT_RETURN(rv);
|
||||||
|
@ -274,6 +274,8 @@ class CefV8ValueImpl : public CefV8Value {
|
|||||||
CefRefPtr<CefV8ArrayBufferReleaseCallback> GetArrayBufferReleaseCallback()
|
CefRefPtr<CefV8ArrayBufferReleaseCallback> GetArrayBufferReleaseCallback()
|
||||||
override;
|
override;
|
||||||
bool NeuterArrayBuffer() override;
|
bool NeuterArrayBuffer() override;
|
||||||
|
size_t GetArrayBufferByteLength() override;
|
||||||
|
void* GetArrayBufferData() override;
|
||||||
CefString GetFunctionName() override;
|
CefString GetFunctionName() override;
|
||||||
CefRefPtr<CefV8Handler> GetFunctionHandler() override;
|
CefRefPtr<CefV8Handler> GetFunctionHandler() override;
|
||||||
CefRefPtr<CefV8Value> ExecuteFunction(
|
CefRefPtr<CefV8Value> ExecuteFunction(
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
// implementations. See the translator.README.txt file in the tools directory
|
// implementations. See the translator.README.txt file in the tools directory
|
||||||
// for more information.
|
// for more information.
|
||||||
//
|
//
|
||||||
// $hash=905b24443e08e2d3e2464d5f4138e97904be3e9e$
|
// $hash=8da36dc268f2f9beb26abc105656f3b04b1d46ed$
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "libcef_dll/cpptoc/binary_value_cpptoc.h"
|
#include "libcef_dll/cpptoc/binary_value_cpptoc.h"
|
||||||
@ -140,6 +140,25 @@ binary_value_copy(struct _cef_binary_value_t* self) {
|
|||||||
return CefBinaryValueCppToC::Wrap(_retval);
|
return CefBinaryValueCppToC::Wrap(_retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const void* CEF_CALLBACK
|
||||||
|
binary_value_get_raw_data(struct _cef_binary_value_t* self) {
|
||||||
|
shutdown_checker::AssertNotShutdown();
|
||||||
|
|
||||||
|
DCHECK(self);
|
||||||
|
if (!self) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This manual implementation can be removed once support for 'const void*'
|
||||||
|
// is integrated into the CEF translator tool (issue #3591).
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
const void* _retval = CefBinaryValueCppToC::Get(self)->GetRawData();
|
||||||
|
|
||||||
|
// Return type: simple_byaddr
|
||||||
|
return _retval;
|
||||||
|
}
|
||||||
|
|
||||||
size_t CEF_CALLBACK binary_value_get_size(struct _cef_binary_value_t* self) {
|
size_t CEF_CALLBACK binary_value_get_size(struct _cef_binary_value_t* self) {
|
||||||
shutdown_checker::AssertNotShutdown();
|
shutdown_checker::AssertNotShutdown();
|
||||||
|
|
||||||
@ -193,6 +212,7 @@ CefBinaryValueCppToC::CefBinaryValueCppToC() {
|
|||||||
GetStruct()->is_same = binary_value_is_same;
|
GetStruct()->is_same = binary_value_is_same;
|
||||||
GetStruct()->is_equal = binary_value_is_equal;
|
GetStruct()->is_equal = binary_value_is_equal;
|
||||||
GetStruct()->copy = binary_value_copy;
|
GetStruct()->copy = binary_value_copy;
|
||||||
|
GetStruct()->get_raw_data = binary_value_get_raw_data;
|
||||||
GetStruct()->get_size = binary_value_get_size;
|
GetStruct()->get_size = binary_value_get_size;
|
||||||
GetStruct()->get_data = binary_value_get_data;
|
GetStruct()->get_data = binary_value_get_data;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
// implementations. See the translator.README.txt file in the tools directory
|
// implementations. See the translator.README.txt file in the tools directory
|
||||||
// for more information.
|
// for more information.
|
||||||
//
|
//
|
||||||
// $hash=3bc6db85e54dc87c1e592291be01820547e0989f$
|
// $hash=4356ad718a385149741e4c8bbbe5d5290466ed40$
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "libcef_dll/cpptoc/shared_memory_region_cpptoc.h"
|
#include "libcef_dll/cpptoc/shared_memory_region_cpptoc.h"
|
||||||
@ -64,6 +64,9 @@ shared_memory_region_memory(struct _cef_shared_memory_region_t* self) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This manual implementation can be removed once support for 'void*'
|
||||||
|
// is integrated into the CEF translator tool (issue #3591).
|
||||||
|
|
||||||
// Execute
|
// Execute
|
||||||
void* _retval = CefSharedMemoryRegionCppToC::Get(self)->Memory();
|
void* _retval = CefSharedMemoryRegionCppToC::Get(self)->Memory();
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
// implementations. See the translator.README.txt file in the tools directory
|
// implementations. See the translator.README.txt file in the tools directory
|
||||||
// for more information.
|
// for more information.
|
||||||
//
|
//
|
||||||
// $hash=ecd6caa0c415b57e93bc66f3c7a4cfb547f022c1$
|
// $hash=21d8fb47eb282f40fb9d602f44b8c1fd4ff44dea$
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "libcef_dll/cpptoc/v8value_cpptoc.h"
|
#include "libcef_dll/cpptoc/v8value_cpptoc.h"
|
||||||
@ -138,16 +138,12 @@ CEF_EXPORT cef_v8value_t* cef_v8value_create_array_buffer(
|
|||||||
cef_v8array_buffer_release_callback_t* release_callback) {
|
cef_v8array_buffer_release_callback_t* release_callback) {
|
||||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||||
|
|
||||||
// Verify param: buffer; type: simple_byaddr
|
|
||||||
DCHECK(buffer);
|
|
||||||
if (!buffer) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
// Verify param: release_callback; type: refptr_diff
|
// Verify param: release_callback; type: refptr_diff
|
||||||
DCHECK(release_callback);
|
DCHECK(release_callback);
|
||||||
if (!release_callback) {
|
if (!release_callback) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
// Unverified params: buffer
|
||||||
|
|
||||||
// Execute
|
// Execute
|
||||||
CefRefPtr<CefV8Value> _retval = CefV8Value::CreateArrayBuffer(
|
CefRefPtr<CefV8Value> _retval = CefV8Value::CreateArrayBuffer(
|
||||||
@ -948,6 +944,38 @@ int CEF_CALLBACK v8value_neuter_array_buffer(struct _cef_v8value_t* self) {
|
|||||||
return _retval;
|
return _retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t CEF_CALLBACK
|
||||||
|
v8value_get_array_buffer_byte_length(struct _cef_v8value_t* self) {
|
||||||
|
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||||
|
|
||||||
|
DCHECK(self);
|
||||||
|
if (!self) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
size_t _retval = CefV8ValueCppToC::Get(self)->GetArrayBufferByteLength();
|
||||||
|
|
||||||
|
// Return type: simple
|
||||||
|
return _retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* CEF_CALLBACK v8value_get_array_buffer_data(struct _cef_v8value_t* self) {
|
||||||
|
DCHECK(self);
|
||||||
|
if (!self) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This manual implementation can be removed once support for 'void*'
|
||||||
|
// is integrated into the CEF translator tool (issue #3591).
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
void* _retval = CefV8ValueCppToC::Get(self)->GetArrayBufferData();
|
||||||
|
|
||||||
|
// Return type: simple_byaddr
|
||||||
|
return _retval;
|
||||||
|
}
|
||||||
|
|
||||||
cef_string_userfree_t CEF_CALLBACK
|
cef_string_userfree_t CEF_CALLBACK
|
||||||
v8value_get_function_name(struct _cef_v8value_t* self) {
|
v8value_get_function_name(struct _cef_v8value_t* self) {
|
||||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||||
@ -1153,6 +1181,9 @@ CefV8ValueCppToC::CefV8ValueCppToC() {
|
|||||||
GetStruct()->get_array_buffer_release_callback =
|
GetStruct()->get_array_buffer_release_callback =
|
||||||
v8value_get_array_buffer_release_callback;
|
v8value_get_array_buffer_release_callback;
|
||||||
GetStruct()->neuter_array_buffer = v8value_neuter_array_buffer;
|
GetStruct()->neuter_array_buffer = v8value_neuter_array_buffer;
|
||||||
|
GetStruct()->get_array_buffer_byte_length =
|
||||||
|
v8value_get_array_buffer_byte_length;
|
||||||
|
GetStruct()->get_array_buffer_data = v8value_get_array_buffer_data;
|
||||||
GetStruct()->get_function_name = v8value_get_function_name;
|
GetStruct()->get_function_name = v8value_get_function_name;
|
||||||
GetStruct()->get_function_handler = v8value_get_function_handler;
|
GetStruct()->get_function_handler = v8value_get_function_handler;
|
||||||
GetStruct()->execute_function = v8value_execute_function;
|
GetStruct()->execute_function = v8value_execute_function;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
// implementations. See the translator.README.txt file in the tools directory
|
// implementations. See the translator.README.txt file in the tools directory
|
||||||
// for more information.
|
// for more information.
|
||||||
//
|
//
|
||||||
// $hash=caaf5dfe8d56c784e213b1590c21194f08084b70$
|
// $hash=f42bab3d9e4ff45faf1fd8071646a8e5bed64177$
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "libcef_dll/ctocpp/binary_value_ctocpp.h"
|
#include "libcef_dll/ctocpp/binary_value_ctocpp.h"
|
||||||
@ -139,6 +139,24 @@ CefRefPtr<CefBinaryValue> CefBinaryValueCToCpp::Copy() {
|
|||||||
return CefBinaryValueCToCpp::Wrap(_retval);
|
return CefBinaryValueCToCpp::Wrap(_retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NO_SANITIZE("cfi-icall") const void* CefBinaryValueCToCpp::GetRawData() {
|
||||||
|
shutdown_checker::AssertNotShutdown();
|
||||||
|
|
||||||
|
cef_binary_value_t* _struct = GetStruct();
|
||||||
|
if (CEF_MEMBER_MISSING(_struct, get_raw_data)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This manual implementation can be removed once support for 'const void*'
|
||||||
|
// is integrated into the CEF translator tool (issue #3591).
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
const void* _retval = _struct->get_raw_data(_struct);
|
||||||
|
|
||||||
|
// Return type: simple_byaddr
|
||||||
|
return _retval;
|
||||||
|
}
|
||||||
|
|
||||||
NO_SANITIZE("cfi-icall") size_t CefBinaryValueCToCpp::GetSize() {
|
NO_SANITIZE("cfi-icall") size_t CefBinaryValueCToCpp::GetSize() {
|
||||||
shutdown_checker::AssertNotShutdown();
|
shutdown_checker::AssertNotShutdown();
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
// implementations. See the translator.README.txt file in the tools directory
|
// implementations. See the translator.README.txt file in the tools directory
|
||||||
// for more information.
|
// for more information.
|
||||||
//
|
//
|
||||||
// $hash=b6f011a6c26b4264084eb68dae0d63032c07013c$
|
// $hash=2e0ac9b73ba6bdb4b07ee0f8c445974359c5862f$
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef CEF_LIBCEF_DLL_CTOCPP_BINARY_VALUE_CTOCPP_H_
|
#ifndef CEF_LIBCEF_DLL_CTOCPP_BINARY_VALUE_CTOCPP_H_
|
||||||
@ -39,6 +39,7 @@ class CefBinaryValueCToCpp : public CefCToCppRefCounted<CefBinaryValueCToCpp,
|
|||||||
bool IsSame(CefRefPtr<CefBinaryValue> that) override;
|
bool IsSame(CefRefPtr<CefBinaryValue> that) override;
|
||||||
bool IsEqual(CefRefPtr<CefBinaryValue> that) override;
|
bool IsEqual(CefRefPtr<CefBinaryValue> that) override;
|
||||||
CefRefPtr<CefBinaryValue> Copy() override;
|
CefRefPtr<CefBinaryValue> Copy() override;
|
||||||
|
const void* GetRawData() override;
|
||||||
size_t GetSize() override;
|
size_t GetSize() override;
|
||||||
size_t GetData(void* buffer, size_t buffer_size, size_t data_offset) override;
|
size_t GetData(void* buffer, size_t buffer_size, size_t data_offset) override;
|
||||||
};
|
};
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
// implementations. See the translator.README.txt file in the tools directory
|
// implementations. See the translator.README.txt file in the tools directory
|
||||||
// for more information.
|
// for more information.
|
||||||
//
|
//
|
||||||
// $hash=31516110398f9fe682988645d74ac8789b712181$
|
// $hash=a396f422ed18fe4aae90d4fef3750b4726279c7e$
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "libcef_dll/ctocpp/shared_memory_region_ctocpp.h"
|
#include "libcef_dll/ctocpp/shared_memory_region_ctocpp.h"
|
||||||
@ -59,6 +59,9 @@ NO_SANITIZE("cfi-icall") void* CefSharedMemoryRegionCToCpp::Memory() {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This manual implementation can be removed once support for 'void*'
|
||||||
|
// is integrated into the CEF translator tool (issue #3591).
|
||||||
|
|
||||||
// Execute
|
// Execute
|
||||||
void* _retval = _struct->memory(_struct);
|
void* _retval = _struct->memory(_struct);
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
// implementations. See the translator.README.txt file in the tools directory
|
// implementations. See the translator.README.txt file in the tools directory
|
||||||
// for more information.
|
// for more information.
|
||||||
//
|
//
|
||||||
// $hash=459c331b0c02f55c4b700761ad2132d7320fd467$
|
// $hash=f67b0996d7e2133f3f28f2d8ba5446c5ff40aaba$
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "libcef_dll/ctocpp/v8value_ctocpp.h"
|
#include "libcef_dll/ctocpp/v8value_ctocpp.h"
|
||||||
@ -147,16 +147,12 @@ CefRefPtr<CefV8Value> CefV8Value::CreateArrayBuffer(
|
|||||||
CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback) {
|
CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback) {
|
||||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||||
|
|
||||||
// Verify param: buffer; type: simple_byaddr
|
|
||||||
DCHECK(buffer);
|
|
||||||
if (!buffer) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
// Verify param: release_callback; type: refptr_diff
|
// Verify param: release_callback; type: refptr_diff
|
||||||
DCHECK(release_callback.get());
|
DCHECK(release_callback.get());
|
||||||
if (!release_callback.get()) {
|
if (!release_callback.get()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
// Unverified params: buffer
|
||||||
|
|
||||||
// Execute
|
// Execute
|
||||||
cef_v8value_t* _retval = cef_v8value_create_array_buffer(
|
cef_v8value_t* _retval = cef_v8value_create_array_buffer(
|
||||||
@ -957,6 +953,37 @@ NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::NeuterArrayBuffer() {
|
|||||||
return _retval ? true : false;
|
return _retval ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NO_SANITIZE("cfi-icall") size_t CefV8ValueCToCpp::GetArrayBufferByteLength() {
|
||||||
|
cef_v8value_t* _struct = GetStruct();
|
||||||
|
if (CEF_MEMBER_MISSING(_struct, get_array_buffer_byte_length)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
size_t _retval = _struct->get_array_buffer_byte_length(_struct);
|
||||||
|
|
||||||
|
// Return type: simple
|
||||||
|
return _retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
NO_SANITIZE("cfi-icall") void* CefV8ValueCToCpp::GetArrayBufferData() {
|
||||||
|
cef_v8value_t* _struct = GetStruct();
|
||||||
|
if (CEF_MEMBER_MISSING(_struct, get_array_buffer_data)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This manual implementation can be removed once support for 'void*'
|
||||||
|
// is integrated into the CEF translator tool (issue #3591).
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
void* _retval = _struct->get_array_buffer_data(_struct);
|
||||||
|
|
||||||
|
// Return type: simple_byaddr
|
||||||
|
return _retval;
|
||||||
|
}
|
||||||
|
|
||||||
NO_SANITIZE("cfi-icall") CefString CefV8ValueCToCpp::GetFunctionName() {
|
NO_SANITIZE("cfi-icall") CefString CefV8ValueCToCpp::GetFunctionName() {
|
||||||
cef_v8value_t* _struct = GetStruct();
|
cef_v8value_t* _struct = GetStruct();
|
||||||
if (CEF_MEMBER_MISSING(_struct, get_function_name)) {
|
if (CEF_MEMBER_MISSING(_struct, get_function_name)) {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
// implementations. See the translator.README.txt file in the tools directory
|
// implementations. See the translator.README.txt file in the tools directory
|
||||||
// for more information.
|
// for more information.
|
||||||
//
|
//
|
||||||
// $hash=cab5b018f6706a3c8496865e0c9f30fcbc94cdd8$
|
// $hash=c81cc0910be6678c0512c5423b8fc5dc1df42743$
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef CEF_LIBCEF_DLL_CTOCPP_V8VALUE_CTOCPP_H_
|
#ifndef CEF_LIBCEF_DLL_CTOCPP_V8VALUE_CTOCPP_H_
|
||||||
@ -83,6 +83,8 @@ class CefV8ValueCToCpp
|
|||||||
CefRefPtr<CefV8ArrayBufferReleaseCallback> GetArrayBufferReleaseCallback()
|
CefRefPtr<CefV8ArrayBufferReleaseCallback> GetArrayBufferReleaseCallback()
|
||||||
override;
|
override;
|
||||||
bool NeuterArrayBuffer() override;
|
bool NeuterArrayBuffer() override;
|
||||||
|
size_t GetArrayBufferByteLength() override;
|
||||||
|
void* GetArrayBufferData() override;
|
||||||
CefString GetFunctionName() override;
|
CefString GetFunctionName() override;
|
||||||
CefRefPtr<CefV8Handler> GetFunctionHandler() override;
|
CefRefPtr<CefV8Handler> GetFunctionHandler() override;
|
||||||
CefRefPtr<CefV8Value> ExecuteFunction(
|
CefRefPtr<CefV8Value> ExecuteFunction(
|
||||||
|
@ -9,11 +9,11 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include "include/base/cef_callback.h"
|
#include "include/base/cef_callback.h"
|
||||||
#include "include/cef_shared_process_message_builder.h"
|
|
||||||
#include "include/cef_task.h"
|
#include "include/cef_task.h"
|
||||||
#include "include/wrapper/cef_closure_task.h"
|
#include "include/wrapper/cef_closure_task.h"
|
||||||
#include "include/wrapper/cef_helpers.h"
|
#include "include/wrapper/cef_helpers.h"
|
||||||
#include "libcef_dll/wrapper/cef_browser_info_map.h"
|
#include "libcef_dll/wrapper/cef_browser_info_map.h"
|
||||||
|
#include "libcef_dll/wrapper/cef_message_router_utils.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@ -47,126 +47,7 @@ bool ValidateConfig(CefMessageRouterConfig& config) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MessageHeader {
|
namespace cmru = cef_message_router_utils;
|
||||||
int context_id;
|
|
||||||
int request_id;
|
|
||||||
bool is_success;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ParsedMessage {
|
|
||||||
int context_id;
|
|
||||||
int request_id;
|
|
||||||
bool success;
|
|
||||||
int error_code;
|
|
||||||
CefString message;
|
|
||||||
};
|
|
||||||
|
|
||||||
size_t GetByteLength(const CefString& value) {
|
|
||||||
return value.size() * sizeof(CefString::char_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t GetMessageSize(const CefString& response) {
|
|
||||||
return sizeof(MessageHeader) + GetByteLength(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CopyResponseIntoMemory(void* memory, const CefString& response) {
|
|
||||||
const size_t bytes = response.size() * sizeof(CefString::char_type);
|
|
||||||
void* dest = static_cast<uint8_t*>(memory) + sizeof(MessageHeader);
|
|
||||||
memcpy(dest, response.c_str(), bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
CefString GetStringFromMemory(const void* memory, size_t size) {
|
|
||||||
const size_t bytes = size - sizeof(MessageHeader);
|
|
||||||
const size_t string_len = bytes / sizeof(CefString::char_type);
|
|
||||||
const CefString::char_type* src =
|
|
||||||
reinterpret_cast<const CefString::char_type*>(
|
|
||||||
static_cast<const uint8_t*>(memory) + sizeof(MessageHeader));
|
|
||||||
constexpr bool copy = true;
|
|
||||||
CefString result;
|
|
||||||
result.FromString(src, string_len, copy);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
CefRefPtr<CefProcessMessage> BuildListMessage(const std::string& message_name,
|
|
||||||
int context_id,
|
|
||||||
int request_id,
|
|
||||||
const CefString& response) {
|
|
||||||
auto message = CefProcessMessage::Create(message_name);
|
|
||||||
CefRefPtr<CefListValue> args = message->GetArgumentList();
|
|
||||||
args->SetInt(0, context_id);
|
|
||||||
args->SetInt(1, request_id);
|
|
||||||
args->SetBool(2, true); // Indicates a success result.
|
|
||||||
args->SetString(3, response);
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
CefRefPtr<CefProcessMessage> BuildBinaryMessage(const std::string& message_name,
|
|
||||||
int context_id,
|
|
||||||
int request_id,
|
|
||||||
const CefString& response) {
|
|
||||||
const size_t message_size = GetMessageSize(response);
|
|
||||||
auto builder =
|
|
||||||
CefSharedProcessMessageBuilder::Create(message_name, message_size);
|
|
||||||
if (!builder->IsValid()) {
|
|
||||||
LOG(ERROR) << "Failed to allocate shared memory region of size "
|
|
||||||
<< message_size;
|
|
||||||
// Use list message as a fallback
|
|
||||||
return BuildListMessage(message_name, context_id, request_id, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto header = static_cast<MessageHeader*>(builder->Memory());
|
|
||||||
header->context_id = context_id;
|
|
||||||
header->request_id = request_id;
|
|
||||||
header->is_success = true;
|
|
||||||
|
|
||||||
CopyResponseIntoMemory(builder->Memory(), response);
|
|
||||||
|
|
||||||
return builder->Build();
|
|
||||||
}
|
|
||||||
|
|
||||||
CefRefPtr<CefProcessMessage> BuildMessage(size_t threshold,
|
|
||||||
const std::string& message_name,
|
|
||||||
int context_id,
|
|
||||||
int request_id,
|
|
||||||
const CefString& response) {
|
|
||||||
if (GetByteLength(response) <= threshold) {
|
|
||||||
return BuildListMessage(message_name, context_id, request_id, response);
|
|
||||||
} else {
|
|
||||||
return BuildBinaryMessage(message_name, context_id, request_id, response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ParsedMessage ParseMessage(const CefRefPtr<CefProcessMessage>& message) {
|
|
||||||
if (auto args = message->GetArgumentList()) {
|
|
||||||
DCHECK_GT(args->GetSize(), 3U);
|
|
||||||
|
|
||||||
const int context_id = args->GetInt(0);
|
|
||||||
const int request_id = args->GetInt(1);
|
|
||||||
const bool is_success = args->GetBool(2);
|
|
||||||
|
|
||||||
if (is_success) {
|
|
||||||
return ParsedMessage{context_id, request_id, is_success, 0,
|
|
||||||
args->GetString(3)};
|
|
||||||
}
|
|
||||||
|
|
||||||
DCHECK_EQ(args->GetSize(), 5U);
|
|
||||||
return ParsedMessage{context_id, request_id, is_success, args->GetInt(3),
|
|
||||||
args->GetString(4)};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const auto region = message->GetSharedMemoryRegion()) {
|
|
||||||
if (region->IsValid()) {
|
|
||||||
DCHECK_GE(region->Size(), sizeof(MessageHeader));
|
|
||||||
auto header = static_cast<const MessageHeader*>(region->Memory());
|
|
||||||
DCHECK(header->is_success);
|
|
||||||
return ParsedMessage{
|
|
||||||
header->context_id, header->request_id, header->is_success, 0,
|
|
||||||
GetStringFromMemory(region->Memory(), region->Size())};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ParsedMessage{};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A helper template for generating ID values.
|
* @brief A helper template for generating ID values.
|
||||||
@ -204,11 +85,15 @@ class CefMessageRouterBrowserSideImpl : public CefMessageRouterBrowserSide {
|
|||||||
CallbackImpl(CefRefPtr<CefMessageRouterBrowserSideImpl> router,
|
CallbackImpl(CefRefPtr<CefMessageRouterBrowserSideImpl> router,
|
||||||
int browser_id,
|
int browser_id,
|
||||||
int64_t query_id,
|
int64_t query_id,
|
||||||
bool persistent)
|
bool persistent,
|
||||||
|
size_t message_size_threshold,
|
||||||
|
const std::string& query_message_name)
|
||||||
: router_(router),
|
: router_(router),
|
||||||
browser_id_(browser_id),
|
browser_id_(browser_id),
|
||||||
query_id_(query_id),
|
query_id_(query_id),
|
||||||
persistent_(persistent) {}
|
persistent_(persistent),
|
||||||
|
message_size_threshold_(message_size_threshold),
|
||||||
|
query_message_name_(query_message_name) {}
|
||||||
|
|
||||||
CallbackImpl(const CallbackImpl&) = delete;
|
CallbackImpl(const CallbackImpl&) = delete;
|
||||||
CallbackImpl& operator=(const CallbackImpl&) = delete;
|
CallbackImpl& operator=(const CallbackImpl&) = delete;
|
||||||
@ -221,44 +106,36 @@ class CefMessageRouterBrowserSideImpl : public CefMessageRouterBrowserSide {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Success(const CefString& response) override {
|
void Success(const CefString& response) override {
|
||||||
if (!CefCurrentlyOn(TID_UI)) {
|
auto builder = cmru::CreateBrowserResponseBuilder(
|
||||||
// Must execute on the UI thread to access member variables.
|
message_size_threshold_, query_message_name_, response);
|
||||||
|
|
||||||
|
// We need to post task here for two reasons:
|
||||||
|
// 1) To safely access member variables.
|
||||||
|
// 2) To let the router to persist the query information before
|
||||||
|
// the Success callback is executed.
|
||||||
CefPostTask(TID_UI,
|
CefPostTask(TID_UI,
|
||||||
base::BindOnce(&CallbackImpl::Success, this, response));
|
base::BindOnce(&CallbackImpl::SuccessImpl, this, builder));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (router_) {
|
void Success(const void* data, size_t size) override {
|
||||||
CefPostTask(
|
auto builder = cmru::CreateBrowserResponseBuilder(
|
||||||
TID_UI,
|
message_size_threshold_, query_message_name_, data, size);
|
||||||
base::BindOnce(&CefMessageRouterBrowserSideImpl::OnCallbackSuccess,
|
|
||||||
router_.get(), browser_id_, query_id_, response));
|
|
||||||
|
|
||||||
if (!persistent_) {
|
// We need to post task here for two reasons:
|
||||||
// Non-persistent callbacks are only good for a single use.
|
// 1) To safely access member variables.
|
||||||
router_ = nullptr;
|
// 2) To let the router to persist the query information before
|
||||||
}
|
// the Success callback is executed.
|
||||||
}
|
CefPostTask(TID_UI,
|
||||||
|
base::BindOnce(&CallbackImpl::SuccessImpl, this, builder));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Failure(int error_code, const CefString& error_message) override {
|
void Failure(int error_code, const CefString& error_message) override {
|
||||||
if (!CefCurrentlyOn(TID_UI)) {
|
// We need to post task here for two reasons:
|
||||||
// Must execute on the UI thread to access member variables.
|
// 1) To safely access member variables.
|
||||||
CefPostTask(TID_UI, base::BindOnce(&CallbackImpl::Failure, this,
|
// 2) To give previosly submitted tasks by the Success calls to execute
|
||||||
|
// before we invalidate the callback.
|
||||||
|
CefPostTask(TID_UI, base::BindOnce(&CallbackImpl::FailureImpl, this,
|
||||||
error_code, error_message));
|
error_code, error_message));
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (router_) {
|
|
||||||
CefPostTask(
|
|
||||||
TID_UI,
|
|
||||||
base::BindOnce(&CefMessageRouterBrowserSideImpl::OnCallbackFailure,
|
|
||||||
router_.get(), browser_id_, query_id_, error_code,
|
|
||||||
error_message));
|
|
||||||
|
|
||||||
// Failure always invalidates the callback.
|
|
||||||
router_ = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Detach() {
|
void Detach() {
|
||||||
@ -267,10 +144,37 @@ class CefMessageRouterBrowserSideImpl : public CefMessageRouterBrowserSide {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void SuccessImpl(const CefRefPtr<cmru::BrowserResponseBuilder>& builder) {
|
||||||
|
if (!router_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
router_->OnCallbackSuccess(browser_id_, query_id_, builder);
|
||||||
|
|
||||||
|
if (!persistent_) {
|
||||||
|
// Non-persistent callbacks are only good for a single use.
|
||||||
|
router_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FailureImpl(int error_code, const CefString& error_message) {
|
||||||
|
if (!router_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
router_->OnCallbackFailure(browser_id_, query_id_, error_code,
|
||||||
|
error_message);
|
||||||
|
|
||||||
|
// Failure always invalidates the callback.
|
||||||
|
router_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
CefRefPtr<CefMessageRouterBrowserSideImpl> router_;
|
CefRefPtr<CefMessageRouterBrowserSideImpl> router_;
|
||||||
const int browser_id_;
|
const int browser_id_;
|
||||||
const int64_t query_id_;
|
const int64_t query_id_;
|
||||||
const bool persistent_;
|
const bool persistent_;
|
||||||
|
const size_t message_size_threshold_;
|
||||||
|
const std::string query_message_name_;
|
||||||
|
|
||||||
IMPLEMENT_REFCOUNTING(CallbackImpl);
|
IMPLEMENT_REFCOUNTING(CallbackImpl);
|
||||||
};
|
};
|
||||||
@ -388,13 +292,10 @@ class CefMessageRouterBrowserSideImpl : public CefMessageRouterBrowserSide {
|
|||||||
|
|
||||||
const std::string& message_name = message->GetName();
|
const std::string& message_name = message->GetName();
|
||||||
if (message_name == query_message_name_) {
|
if (message_name == query_message_name_) {
|
||||||
CefRefPtr<CefListValue> args = message->GetArgumentList();
|
cmru::RendererMessage content = cmru::ParseRendererMessage(message);
|
||||||
DCHECK_EQ(args->GetSize(), 4U);
|
const int context_id = content.context_id;
|
||||||
|
const int request_id = content.request_id;
|
||||||
const int context_id = args->GetInt(0);
|
const bool persistent = content.is_persistent;
|
||||||
const int request_id = args->GetInt(1);
|
|
||||||
const CefString& request = args->GetString(2);
|
|
||||||
const bool persistent = args->GetBool(3);
|
|
||||||
|
|
||||||
if (handler_set_.empty()) {
|
if (handler_set_.empty()) {
|
||||||
// No handlers so cancel the query.
|
// No handlers so cancel the query.
|
||||||
@ -405,40 +306,38 @@ class CefMessageRouterBrowserSideImpl : public CefMessageRouterBrowserSide {
|
|||||||
const int browser_id = browser->GetIdentifier();
|
const int browser_id = browser->GetIdentifier();
|
||||||
const int64_t query_id = query_id_generator_.GetNextId();
|
const int64_t query_id = query_id_generator_.GetNextId();
|
||||||
|
|
||||||
CefRefPtr<CallbackImpl> callback(
|
CefRefPtr<CallbackImpl> callback =
|
||||||
new CallbackImpl(this, browser_id, query_id, persistent));
|
new CallbackImpl(this, browser_id, query_id, persistent,
|
||||||
|
config_.message_size_threshold, query_message_name_);
|
||||||
|
|
||||||
// Make a copy of the handler list in case the user adds or removes a
|
// Make a copy of the handler list in case the user adds or removes a
|
||||||
// handler while we're iterating.
|
// handler while we're iterating.
|
||||||
HandlerSet handler_set = handler_set_;
|
const HandlerSet handlers = handler_set_;
|
||||||
|
|
||||||
bool handled = false;
|
Handler* handler = std::visit(
|
||||||
HandlerSet::const_iterator it_handler = handler_set.begin();
|
[&](const auto& arg) -> CefMessageRouterBrowserSide::Handler* {
|
||||||
for (; it_handler != handler_set.end(); ++it_handler) {
|
for (auto handler : handlers) {
|
||||||
handled = (*it_handler)
|
bool handled = handler->OnQuery(browser, frame, query_id, arg,
|
||||||
->OnQuery(browser, frame, query_id, request, persistent,
|
persistent, callback.get());
|
||||||
callback.get());
|
|
||||||
if (handled) {
|
if (handled) {
|
||||||
break;
|
return handler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
|
},
|
||||||
|
content.payload);
|
||||||
|
|
||||||
// If the query isn't handled nothing should be keeping a reference to
|
// If the query isn't handled nothing should be keeping a reference to
|
||||||
// the callback.
|
// the callback.
|
||||||
DCHECK(handled || callback->HasOneRef());
|
DCHECK(handler != nullptr || callback->HasOneRef());
|
||||||
|
|
||||||
if (handled) {
|
if (handler) {
|
||||||
// Persist the query information until the callback executes.
|
// Persist the query information until the callback executes.
|
||||||
// It's safe to do this here because the callback will execute
|
// It's safe to do this here because the callback will execute
|
||||||
// asynchronously.
|
// asynchronously.
|
||||||
QueryInfo* info = new QueryInfo;
|
QueryInfo* info =
|
||||||
info->browser = browser;
|
new QueryInfo{browser, frame, context_id, request_id,
|
||||||
info->frame = frame;
|
persistent, callback, handler};
|
||||||
info->context_id = context_id;
|
|
||||||
info->request_id = request_id;
|
|
||||||
info->persistent = persistent;
|
|
||||||
info->callback = callback;
|
|
||||||
info->handler = *(it_handler);
|
|
||||||
browser_query_info_map_.Add(browser_id, query_id, info);
|
browser_query_info_map_.Add(browser_id, query_id, info);
|
||||||
} else {
|
} else {
|
||||||
// Invalidate the callback.
|
// Invalidate the callback.
|
||||||
@ -527,15 +426,17 @@ class CefMessageRouterBrowserSideImpl : public CefMessageRouterBrowserSide {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Called by CallbackImpl on success.
|
// Called by CallbackImpl on success.
|
||||||
void OnCallbackSuccess(int browser_id,
|
void OnCallbackSuccess(
|
||||||
|
int browser_id,
|
||||||
int64_t query_id,
|
int64_t query_id,
|
||||||
const CefString& response) {
|
const CefRefPtr<cmru::BrowserResponseBuilder>& builder) {
|
||||||
CEF_REQUIRE_UI_THREAD();
|
CEF_REQUIRE_UI_THREAD();
|
||||||
|
|
||||||
bool removed;
|
bool removed;
|
||||||
QueryInfo* info = GetQueryInfo(browser_id, query_id, false, &removed);
|
QueryInfo* info = GetQueryInfo(browser_id, query_id, false, &removed);
|
||||||
if (info) {
|
if (info) {
|
||||||
SendQuerySuccess(info, response);
|
SendQuerySuccess(info->browser, info->frame, info->context_id,
|
||||||
|
info->request_id, builder);
|
||||||
if (removed) {
|
if (removed) {
|
||||||
delete info;
|
delete info;
|
||||||
}
|
}
|
||||||
@ -558,19 +459,13 @@ class CefMessageRouterBrowserSideImpl : public CefMessageRouterBrowserSide {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendQuerySuccess(QueryInfo* info, const CefString& response) {
|
void SendQuerySuccess(
|
||||||
SendQuerySuccess(info->browser, info->frame, info->context_id,
|
CefRefPtr<CefBrowser> browser,
|
||||||
info->request_id, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SendQuerySuccess(CefRefPtr<CefBrowser> browser,
|
|
||||||
CefRefPtr<CefFrame> frame,
|
CefRefPtr<CefFrame> frame,
|
||||||
int context_id,
|
int context_id,
|
||||||
int request_id,
|
int request_id,
|
||||||
const CefString& response) {
|
const CefRefPtr<cmru::BrowserResponseBuilder>& builder) {
|
||||||
if (auto message =
|
if (auto message = builder->Build(context_id, request_id)) {
|
||||||
BuildMessage(config_.message_size_threshold, query_message_name_,
|
|
||||||
context_id, request_id, response)) {
|
|
||||||
frame->SendProcessMessage(PID_RENDERER, message);
|
frame->SendProcessMessage(PID_RENDERER, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -758,10 +653,16 @@ class CefMessageRouterRendererSideImpl : public CefMessageRouterRendererSide {
|
|||||||
CefRefPtr<CefV8Value> arg = arguments[0];
|
CefRefPtr<CefV8Value> arg = arguments[0];
|
||||||
|
|
||||||
CefRefPtr<CefV8Value> requestVal = arg->GetValue(kMemberRequest);
|
CefRefPtr<CefV8Value> requestVal = arg->GetValue(kMemberRequest);
|
||||||
if (!requestVal.get() || !requestVal->IsString()) {
|
if (!requestVal.get()) {
|
||||||
|
exception = "Invalid arguments; object member '" +
|
||||||
|
std::string(kMemberRequest) + "' is required";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!requestVal->IsString() && !requestVal->IsArrayBuffer()) {
|
||||||
exception = "Invalid arguments; object member '" +
|
exception = "Invalid arguments; object member '" +
|
||||||
std::string(kMemberRequest) +
|
std::string(kMemberRequest) +
|
||||||
"' is required and must have type string";
|
"' must have type string or ArrayBuffer";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -804,9 +705,11 @@ class CefMessageRouterRendererSideImpl : public CefMessageRouterRendererSide {
|
|||||||
(persistentVal.get() && persistentVal->GetBoolValue());
|
(persistentVal.get() && persistentVal->GetBoolValue());
|
||||||
|
|
||||||
const int request_id = router_->SendQuery(
|
const int request_id = router_->SendQuery(
|
||||||
context->GetBrowser(), context->GetFrame(), context_id,
|
context->GetBrowser(), context->GetFrame(), context_id, requestVal,
|
||||||
requestVal->GetStringValue(), persistent, successVal, failureVal);
|
persistent, successVal, failureVal);
|
||||||
|
|
||||||
retval = CefV8Value::CreateInt(request_id);
|
retval = CefV8Value::CreateInt(request_id);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else if (name == config_.js_cancel_function) {
|
} else if (name == config_.js_cancel_function) {
|
||||||
if (arguments.size() != 1 || !arguments[0]->IsInt()) {
|
if (arguments.size() != 1 || !arguments[0]->IsInt()) {
|
||||||
@ -958,31 +861,28 @@ class CefMessageRouterRendererSideImpl : public CefMessageRouterRendererSide {
|
|||||||
CefRefPtr<CefProcessMessage> message) override {
|
CefRefPtr<CefProcessMessage> message) override {
|
||||||
CEF_REQUIRE_RENDERER_THREAD();
|
CEF_REQUIRE_RENDERER_THREAD();
|
||||||
|
|
||||||
const std::string& message_name = message->GetName();
|
if (message->GetName() != query_message_name_) {
|
||||||
if (message_name == query_message_name_) {
|
return false;
|
||||||
auto content = ParseMessage(message);
|
}
|
||||||
if (content.success) {
|
|
||||||
CefPostTask(
|
cmru::BrowserMessage content = cmru::ParseBrowserMessage(message);
|
||||||
TID_RENDERER,
|
if (content.is_success) {
|
||||||
base::BindOnce(
|
std::visit(
|
||||||
&CefMessageRouterRendererSideImpl::ExecuteSuccessCallback, this,
|
[&](const auto& arg) {
|
||||||
browser->GetIdentifier(), content.context_id,
|
ExecuteSuccessCallback(browser->GetIdentifier(), content.context_id,
|
||||||
content.request_id, content.message));
|
content.request_id, arg);
|
||||||
|
},
|
||||||
|
content.payload);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
CefPostTask(
|
ExecuteFailureCallback(browser->GetIdentifier(), content.context_id,
|
||||||
TID_RENDERER,
|
content.request_id, content.error_code,
|
||||||
base::BindOnce(
|
std::get<CefString>(content.payload));
|
||||||
&CefMessageRouterRendererSideImpl::ExecuteFailureCallback, this,
|
|
||||||
browser->GetIdentifier(), content.context_id,
|
|
||||||
content.request_id, content.error_code, content.message));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Structure representing a pending request.
|
// Structure representing a pending request.
|
||||||
struct RequestInfo {
|
struct RequestInfo {
|
||||||
@ -1039,7 +939,7 @@ class CefMessageRouterRendererSideImpl : public CefMessageRouterRendererSide {
|
|||||||
int SendQuery(CefRefPtr<CefBrowser> browser,
|
int SendQuery(CefRefPtr<CefBrowser> browser,
|
||||||
CefRefPtr<CefFrame> frame,
|
CefRefPtr<CefFrame> frame,
|
||||||
int context_id,
|
int context_id,
|
||||||
const CefString& request,
|
CefRefPtr<CefV8Value> request,
|
||||||
bool persistent,
|
bool persistent,
|
||||||
CefRefPtr<CefV8Value> success_callback,
|
CefRefPtr<CefV8Value> success_callback,
|
||||||
CefRefPtr<CefV8Value> failure_callback) {
|
CefRefPtr<CefV8Value> failure_callback) {
|
||||||
@ -1053,14 +953,9 @@ class CefMessageRouterRendererSideImpl : public CefMessageRouterRendererSide {
|
|||||||
browser_request_info_map_.Add(browser->GetIdentifier(),
|
browser_request_info_map_.Add(browser->GetIdentifier(),
|
||||||
std::make_pair(context_id, request_id), info);
|
std::make_pair(context_id, request_id), info);
|
||||||
|
|
||||||
CefRefPtr<CefProcessMessage> message =
|
CefRefPtr<CefProcessMessage> message = cmru::BuildRendererMsg(
|
||||||
CefProcessMessage::Create(query_message_name_);
|
config_.message_size_threshold, query_message_name_, context_id,
|
||||||
|
request_id, request, persistent);
|
||||||
CefRefPtr<CefListValue> args = message->GetArgumentList();
|
|
||||||
args->SetInt(0, context_id);
|
|
||||||
args->SetInt(1, request_id);
|
|
||||||
args->SetString(2, request);
|
|
||||||
args->SetBool(3, persistent);
|
|
||||||
|
|
||||||
frame->SendProcessMessage(PID_BROWSER, message);
|
frame->SendProcessMessage(PID_BROWSER, message);
|
||||||
|
|
||||||
@ -1162,6 +1057,41 @@ class CefMessageRouterRendererSideImpl : public CefMessageRouterRendererSide {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Execute the onSuccess JavaScript callback.
|
||||||
|
void ExecuteSuccessCallback(int browser_id,
|
||||||
|
int context_id,
|
||||||
|
int request_id,
|
||||||
|
const CefRefPtr<CefBinaryBuffer>& response) {
|
||||||
|
CEF_REQUIRE_RENDERER_THREAD();
|
||||||
|
|
||||||
|
bool removed;
|
||||||
|
RequestInfo* info =
|
||||||
|
GetRequestInfo(browser_id, context_id, request_id, false, &removed);
|
||||||
|
if (!info) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CefRefPtr<CefV8Context> context = GetContextByID(context_id);
|
||||||
|
if (context && info->success_callback && context->Enter()) {
|
||||||
|
CefRefPtr<cmru::BinaryValueABRCallback> release_callback =
|
||||||
|
new cmru::BinaryValueABRCallback(response);
|
||||||
|
|
||||||
|
CefRefPtr<CefV8Value> value = CefV8Value::CreateArrayBuffer(
|
||||||
|
response->GetData(), response->GetSize(), release_callback);
|
||||||
|
|
||||||
|
context->Exit();
|
||||||
|
|
||||||
|
CefV8ValueList args;
|
||||||
|
args.push_back(value);
|
||||||
|
info->success_callback->ExecuteFunctionWithContext(context, nullptr,
|
||||||
|
args);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removed) {
|
||||||
|
delete info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Execute the onFailure JavaScript callback.
|
// Execute the onFailure JavaScript callback.
|
||||||
void ExecuteFailureCallback(int browser_id,
|
void ExecuteFailureCallback(int browser_id,
|
||||||
int context_id,
|
int context_id,
|
||||||
|
525
libcef_dll/wrapper/cef_message_router_utils.cc
Normal file
525
libcef_dll/wrapper/cef_message_router_utils.cc
Normal file
@ -0,0 +1,525 @@
|
|||||||
|
// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
|
||||||
|
// reserved. Use of this source code is governed by a BSD-style license that
|
||||||
|
// can be found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "libcef_dll/wrapper/cef_message_router_utils.h"
|
||||||
|
|
||||||
|
#include "include/cef_shared_process_message_builder.h"
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace cef_message_router_utils {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr int kNoError = 0;
|
||||||
|
|
||||||
|
constexpr size_t kContextId = 0;
|
||||||
|
constexpr size_t kRequestId = 1;
|
||||||
|
constexpr size_t kRendererPayload = 2;
|
||||||
|
constexpr size_t kIsSuccess = 2;
|
||||||
|
constexpr size_t kBrowserPayload = 3;
|
||||||
|
constexpr size_t kIsPersistent = 3;
|
||||||
|
|
||||||
|
struct BrowserMsgHeader {
|
||||||
|
int context_id;
|
||||||
|
int request_id;
|
||||||
|
bool is_binary;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
std::is_trivially_copyable_v<BrowserMsgHeader>,
|
||||||
|
"Copying non-trivially-copyable object across memory spaces is dangerous");
|
||||||
|
|
||||||
|
struct RendererMsgHeader {
|
||||||
|
int context_id;
|
||||||
|
int request_id;
|
||||||
|
bool is_persistent;
|
||||||
|
bool is_binary;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
std::is_trivially_copyable_v<RendererMsgHeader>,
|
||||||
|
"Copying non-trivially-copyable object across memory spaces is dangerous");
|
||||||
|
|
||||||
|
//
|
||||||
|
// This is a workaround for handling empty CefBinaryValues, as it's not possible
|
||||||
|
// to create an empty one directly. We use this empty struct as a tag to invoke
|
||||||
|
// the SetNull function within the BuildBrowserListMsg and BuildRendererListMsg
|
||||||
|
// functions.
|
||||||
|
//
|
||||||
|
struct Empty {};
|
||||||
|
|
||||||
|
size_t GetByteLength(const CefString& value) {
|
||||||
|
return value.size() * sizeof(CefString::char_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetByteLength(const CefRefPtr<CefV8Value>& value) {
|
||||||
|
return value->GetArrayBufferByteLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
const CefString& GetListRepresentation(const CefString& value) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
CefRefPtr<CefBinaryValue> GetListRepresentation(
|
||||||
|
const CefRefPtr<CefV8Value>& value) {
|
||||||
|
return CefBinaryValue::Create(value->GetArrayBufferData(),
|
||||||
|
value->GetArrayBufferByteLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Header, class T>
|
||||||
|
size_t GetMessageSize(const T& value) {
|
||||||
|
return sizeof(Header) + GetByteLength(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Header>
|
||||||
|
void CopyIntoMemory(void* memory, const void* data, size_t bytes) {
|
||||||
|
if (bytes > 0) {
|
||||||
|
void* dest = static_cast<uint8_t*>(memory) + sizeof(Header);
|
||||||
|
memcpy(dest, data, bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Header>
|
||||||
|
void CopyIntoMemory(void* memory, const CefRefPtr<CefV8Value>& value) {
|
||||||
|
CopyIntoMemory<Header>(memory, value->GetArrayBufferData(),
|
||||||
|
value->GetArrayBufferByteLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Header>
|
||||||
|
void CopyIntoMemory(void* memory, const CefString& value) {
|
||||||
|
const size_t bytes = GetByteLength(value);
|
||||||
|
CopyIntoMemory<Header>(memory, value.c_str(), bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Header>
|
||||||
|
CefString GetStringFromMemory(const void* memory, size_t size) {
|
||||||
|
const size_t bytes = size - sizeof(Header);
|
||||||
|
const size_t string_len = bytes / sizeof(CefString::char_type);
|
||||||
|
const void* string_data =
|
||||||
|
static_cast<const uint8_t*>(memory) + sizeof(Header);
|
||||||
|
const CefString::char_type* src =
|
||||||
|
static_cast<const CefString::char_type*>(string_data);
|
||||||
|
CefString result;
|
||||||
|
result.FromString(src, string_len, /*copy=*/true);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr bool IsCefString() {
|
||||||
|
return std::is_same_v<std::remove_cv_t<T>, CefString>;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr bool IsEmpty() {
|
||||||
|
return std::is_same_v<std::remove_cv_t<T>, Empty>;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ResponseType>
|
||||||
|
CefRefPtr<CefProcessMessage> BuildBrowserListMsg(const CefString& name,
|
||||||
|
int context_id,
|
||||||
|
int request_id,
|
||||||
|
const ResponseType& response) {
|
||||||
|
auto message = CefProcessMessage::Create(name);
|
||||||
|
CefRefPtr<CefListValue> args = message->GetArgumentList();
|
||||||
|
args->SetInt(kContextId, context_id);
|
||||||
|
args->SetInt(kRequestId, request_id);
|
||||||
|
args->SetBool(kIsSuccess, true);
|
||||||
|
|
||||||
|
if constexpr (IsCefString<ResponseType>()) {
|
||||||
|
args->SetString(kBrowserPayload, response);
|
||||||
|
} else if constexpr (IsEmpty<ResponseType>()) {
|
||||||
|
args->SetNull(kBrowserPayload);
|
||||||
|
} else {
|
||||||
|
args->SetBinary(kBrowserPayload, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
class EmptyResponseBuilder final : public BrowserResponseBuilder {
|
||||||
|
public:
|
||||||
|
explicit EmptyResponseBuilder(const std::string& name) : name_(name) {}
|
||||||
|
EmptyResponseBuilder(const EmptyResponseBuilder&) = delete;
|
||||||
|
EmptyResponseBuilder& operator=(const EmptyResponseBuilder&) = delete;
|
||||||
|
|
||||||
|
CefRefPtr<CefProcessMessage> Build(int context_id, int request_id) override {
|
||||||
|
return BuildBrowserListMsg(name_, context_id, request_id, Empty{});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const CefString name_;
|
||||||
|
|
||||||
|
IMPLEMENT_REFCOUNTING(EmptyResponseBuilder);
|
||||||
|
};
|
||||||
|
|
||||||
|
class BinaryResponseBuilder final : public BrowserResponseBuilder {
|
||||||
|
public:
|
||||||
|
BinaryResponseBuilder(const std::string& name, const void* data, size_t size)
|
||||||
|
: name_(name), value_(CefBinaryValue::Create(data, size)) {}
|
||||||
|
BinaryResponseBuilder(const BinaryResponseBuilder&) = delete;
|
||||||
|
BinaryResponseBuilder& operator=(const BinaryResponseBuilder&) = delete;
|
||||||
|
|
||||||
|
CefRefPtr<CefProcessMessage> Build(int context_id, int request_id) override {
|
||||||
|
return BuildBrowserListMsg(name_, context_id, request_id, value_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const CefString name_;
|
||||||
|
const CefRefPtr<CefBinaryValue> value_;
|
||||||
|
|
||||||
|
IMPLEMENT_REFCOUNTING(BinaryResponseBuilder);
|
||||||
|
};
|
||||||
|
|
||||||
|
class StringResponseBuilder final : public BrowserResponseBuilder {
|
||||||
|
public:
|
||||||
|
StringResponseBuilder(const std::string& name, const CefString& value)
|
||||||
|
: name_(name), value_(value) {}
|
||||||
|
StringResponseBuilder(const StringResponseBuilder&) = delete;
|
||||||
|
StringResponseBuilder& operator=(const StringResponseBuilder&) = delete;
|
||||||
|
|
||||||
|
CefRefPtr<CefProcessMessage> Build(int context_id, int request_id) override {
|
||||||
|
return BuildBrowserListMsg(name_, context_id, request_id, value_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const CefString name_;
|
||||||
|
const CefString value_;
|
||||||
|
|
||||||
|
IMPLEMENT_REFCOUNTING(StringResponseBuilder);
|
||||||
|
};
|
||||||
|
|
||||||
|
// SharedProcessMessageResponseBuilder
|
||||||
|
class SPMResponseBuilder final : public BrowserResponseBuilder {
|
||||||
|
public:
|
||||||
|
SPMResponseBuilder(const SPMResponseBuilder&) = delete;
|
||||||
|
SPMResponseBuilder& operator=(const SPMResponseBuilder&) = delete;
|
||||||
|
|
||||||
|
static CefRefPtr<BrowserResponseBuilder> Create(const std::string& name,
|
||||||
|
const void* data,
|
||||||
|
size_t size) {
|
||||||
|
const size_t message_size = sizeof(BrowserMsgHeader) + size;
|
||||||
|
auto builder = CefSharedProcessMessageBuilder::Create(name, message_size);
|
||||||
|
if (!builder->IsValid()) {
|
||||||
|
LOG(ERROR) << "Failed to allocate shared memory region of size "
|
||||||
|
<< message_size;
|
||||||
|
return new BinaryResponseBuilder(name, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
CopyIntoMemory<BrowserMsgHeader>(builder->Memory(), data, size);
|
||||||
|
return new SPMResponseBuilder(builder, /*is_binary=*/true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CefRefPtr<BrowserResponseBuilder> Create(const std::string& name,
|
||||||
|
const CefString& value) {
|
||||||
|
const size_t message_size = GetMessageSize<BrowserMsgHeader>(value);
|
||||||
|
auto builder = CefSharedProcessMessageBuilder::Create(name, message_size);
|
||||||
|
if (!builder->IsValid()) {
|
||||||
|
LOG(ERROR) << "Failed to allocate shared memory region of size "
|
||||||
|
<< message_size;
|
||||||
|
return new StringResponseBuilder(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
CopyIntoMemory<BrowserMsgHeader>(builder->Memory(), value);
|
||||||
|
return new SPMResponseBuilder(builder, /*is_binary=*/false);
|
||||||
|
}
|
||||||
|
|
||||||
|
CefRefPtr<CefProcessMessage> Build(int context_id, int request_id) override {
|
||||||
|
auto header = static_cast<BrowserMsgHeader*>(builder_->Memory());
|
||||||
|
header->context_id = context_id;
|
||||||
|
header->request_id = request_id;
|
||||||
|
header->is_binary = is_binary_;
|
||||||
|
return builder_->Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit SPMResponseBuilder(
|
||||||
|
const CefRefPtr<CefSharedProcessMessageBuilder>& builder,
|
||||||
|
bool is_binary)
|
||||||
|
: builder_(builder), is_binary_(is_binary) {}
|
||||||
|
|
||||||
|
CefRefPtr<CefSharedProcessMessageBuilder> builder_;
|
||||||
|
const bool is_binary_;
|
||||||
|
|
||||||
|
IMPLEMENT_REFCOUNTING(SPMResponseBuilder);
|
||||||
|
};
|
||||||
|
|
||||||
|
class EmptyBinaryBuffer final : public CefBinaryBuffer {
|
||||||
|
public:
|
||||||
|
EmptyBinaryBuffer() = default;
|
||||||
|
EmptyBinaryBuffer(const EmptyBinaryBuffer&) = delete;
|
||||||
|
EmptyBinaryBuffer& operator=(const EmptyBinaryBuffer&) = delete;
|
||||||
|
|
||||||
|
const void* GetData() const override { return nullptr; }
|
||||||
|
void* GetData() override { return nullptr; }
|
||||||
|
size_t GetSize() const override { return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
IMPLEMENT_REFCOUNTING(EmptyBinaryBuffer);
|
||||||
|
};
|
||||||
|
|
||||||
|
class BinaryValueBuffer final : public CefBinaryBuffer {
|
||||||
|
public:
|
||||||
|
BinaryValueBuffer(CefRefPtr<CefProcessMessage> message,
|
||||||
|
CefRefPtr<CefBinaryValue> value)
|
||||||
|
: message_(std::move(message)), value_(std::move(value)) {}
|
||||||
|
BinaryValueBuffer(const BinaryValueBuffer&) = delete;
|
||||||
|
BinaryValueBuffer& operator=(const BinaryValueBuffer&) = delete;
|
||||||
|
|
||||||
|
const void* GetData() const override { return value_->GetRawData(); }
|
||||||
|
void* GetData() override {
|
||||||
|
// This is not UB as long as underlying storage is vector<uint8_t>
|
||||||
|
return const_cast<void*>(value_->GetRawData());
|
||||||
|
}
|
||||||
|
size_t GetSize() const override { return value_->GetSize(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const CefRefPtr<CefProcessMessage> message_;
|
||||||
|
const CefRefPtr<CefBinaryValue> value_;
|
||||||
|
|
||||||
|
IMPLEMENT_REFCOUNTING(BinaryValueBuffer);
|
||||||
|
};
|
||||||
|
|
||||||
|
class SharedMemoryRegionBuffer final : public CefBinaryBuffer {
|
||||||
|
public:
|
||||||
|
SharedMemoryRegionBuffer(const CefRefPtr<CefSharedMemoryRegion>& region,
|
||||||
|
size_t offset)
|
||||||
|
: region_(region),
|
||||||
|
data_(static_cast<uint8_t*>(region->Memory()) + offset),
|
||||||
|
size_(region->Size() - offset) {}
|
||||||
|
SharedMemoryRegionBuffer(const SharedMemoryRegionBuffer&) = delete;
|
||||||
|
SharedMemoryRegionBuffer& operator=(const SharedMemoryRegionBuffer&) = delete;
|
||||||
|
|
||||||
|
const void* GetData() const override { return data_; }
|
||||||
|
void* GetData() override { return data_; }
|
||||||
|
size_t GetSize() const override { return size_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const CefRefPtr<CefSharedMemoryRegion> region_;
|
||||||
|
void* const data_;
|
||||||
|
const size_t size_;
|
||||||
|
|
||||||
|
IMPLEMENT_REFCOUNTING(SharedMemoryRegionBuffer);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class RequestType>
|
||||||
|
CefRefPtr<CefProcessMessage> BuildRendererListMsg(const std::string& name,
|
||||||
|
int context_id,
|
||||||
|
int request_id,
|
||||||
|
const RequestType& request,
|
||||||
|
bool persistent) {
|
||||||
|
auto message = CefProcessMessage::Create(name);
|
||||||
|
CefRefPtr<CefListValue> args = message->GetArgumentList();
|
||||||
|
args->SetInt(kContextId, context_id);
|
||||||
|
args->SetInt(kRequestId, request_id);
|
||||||
|
|
||||||
|
if constexpr (IsCefString<RequestType>()) {
|
||||||
|
args->SetString(kRendererPayload, request);
|
||||||
|
} else if constexpr (IsEmpty<RequestType>()) {
|
||||||
|
args->SetNull(kRendererPayload);
|
||||||
|
} else {
|
||||||
|
args->SetBinary(kRendererPayload, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
args->SetBool(kIsPersistent, persistent);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class RequestType>
|
||||||
|
CefRefPtr<CefProcessMessage> BuildRendererSharedMsg(const std::string& name,
|
||||||
|
int context_id,
|
||||||
|
int request_id,
|
||||||
|
const RequestType& request,
|
||||||
|
bool persistent) {
|
||||||
|
const size_t message_size = GetMessageSize<RendererMsgHeader>(request);
|
||||||
|
auto builder = CefSharedProcessMessageBuilder::Create(name, message_size);
|
||||||
|
if (!builder->IsValid()) {
|
||||||
|
LOG(ERROR) << "Failed to allocate shared memory region of size "
|
||||||
|
<< message_size;
|
||||||
|
return BuildRendererListMsg(name, context_id, request_id,
|
||||||
|
GetListRepresentation(request), persistent);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto header = static_cast<RendererMsgHeader*>(builder->Memory());
|
||||||
|
header->context_id = context_id;
|
||||||
|
header->request_id = request_id;
|
||||||
|
header->is_persistent = persistent;
|
||||||
|
header->is_binary = !IsCefString<RequestType>();
|
||||||
|
|
||||||
|
CopyIntoMemory<RendererMsgHeader>(builder->Memory(), request);
|
||||||
|
|
||||||
|
return builder->Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
CefRefPtr<CefProcessMessage> BuildRendererMsg(size_t threshold,
|
||||||
|
const std::string& name,
|
||||||
|
int context_id,
|
||||||
|
int request_id,
|
||||||
|
const CefString& request,
|
||||||
|
bool persistent) {
|
||||||
|
if (GetByteLength(request) < threshold) {
|
||||||
|
return BuildRendererListMsg(name, context_id, request_id, request,
|
||||||
|
persistent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BuildRendererSharedMsg(name, context_id, request_id, request,
|
||||||
|
persistent);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
CefRefPtr<BrowserResponseBuilder> CreateBrowserResponseBuilder(
|
||||||
|
size_t threshold,
|
||||||
|
const std::string& name,
|
||||||
|
const CefString& response) {
|
||||||
|
if (GetByteLength(response) < threshold) {
|
||||||
|
return new StringResponseBuilder(name, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SPMResponseBuilder::Create(name, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
CefRefPtr<BrowserResponseBuilder> CreateBrowserResponseBuilder(
|
||||||
|
size_t threshold,
|
||||||
|
const std::string& name,
|
||||||
|
const void* data,
|
||||||
|
size_t size) {
|
||||||
|
if (size == 0) {
|
||||||
|
return new EmptyResponseBuilder(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size < threshold) {
|
||||||
|
return new BinaryResponseBuilder(name, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SPMResponseBuilder::Create(name, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
CefRefPtr<CefProcessMessage> BuildRendererMsg(
|
||||||
|
size_t threshold,
|
||||||
|
const std::string& name,
|
||||||
|
int context_id,
|
||||||
|
int request_id,
|
||||||
|
const CefRefPtr<CefV8Value>& request,
|
||||||
|
bool persistent) {
|
||||||
|
if (request->IsString()) {
|
||||||
|
return BuildRendererMsg(threshold, name, context_id, request_id,
|
||||||
|
request->GetStringValue(), persistent);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto size = request->GetArrayBufferByteLength();
|
||||||
|
if (size == 0) {
|
||||||
|
return BuildRendererListMsg(name, context_id, request_id, Empty{},
|
||||||
|
persistent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size < threshold) {
|
||||||
|
return BuildRendererListMsg(name, context_id, request_id,
|
||||||
|
GetListRepresentation(request), persistent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BuildRendererSharedMsg(name, context_id, request_id, request,
|
||||||
|
persistent);
|
||||||
|
}
|
||||||
|
|
||||||
|
BrowserMessage ParseBrowserMessage(
|
||||||
|
const CefRefPtr<CefProcessMessage>& message) {
|
||||||
|
if (auto args = message->GetArgumentList()) {
|
||||||
|
DCHECK_GT(args->GetSize(), 3U);
|
||||||
|
|
||||||
|
const int context_id = args->GetInt(kContextId);
|
||||||
|
const int request_id = args->GetInt(kRequestId);
|
||||||
|
const bool is_success = args->GetBool(kIsSuccess);
|
||||||
|
|
||||||
|
if (is_success) {
|
||||||
|
DCHECK_EQ(args->GetSize(), 4U);
|
||||||
|
const auto payload_type = args->GetType(kBrowserPayload);
|
||||||
|
if (payload_type == CefValueType::VTYPE_STRING) {
|
||||||
|
return {context_id, request_id, is_success, kNoError,
|
||||||
|
args->GetString(kBrowserPayload)};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payload_type == CefValueType::VTYPE_BINARY) {
|
||||||
|
return {
|
||||||
|
context_id, request_id, is_success, kNoError,
|
||||||
|
new BinaryValueBuffer(message, args->GetBinary(kBrowserPayload))};
|
||||||
|
}
|
||||||
|
|
||||||
|
DCHECK(payload_type == CefValueType::VTYPE_NULL);
|
||||||
|
return {context_id, request_id, is_success, kNoError,
|
||||||
|
new EmptyBinaryBuffer()};
|
||||||
|
}
|
||||||
|
|
||||||
|
DCHECK_EQ(args->GetSize(), 5U);
|
||||||
|
return {context_id, request_id, is_success, args->GetInt(3),
|
||||||
|
args->GetString(4)};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto region = message->GetSharedMemoryRegion();
|
||||||
|
if (region && region->IsValid()) {
|
||||||
|
DCHECK_GE(region->Size(), sizeof(BrowserMsgHeader));
|
||||||
|
auto header = static_cast<const BrowserMsgHeader*>(region->Memory());
|
||||||
|
|
||||||
|
if (header->is_binary) {
|
||||||
|
return {header->context_id, header->request_id, true, kNoError,
|
||||||
|
new SharedMemoryRegionBuffer(region, sizeof(BrowserMsgHeader))};
|
||||||
|
}
|
||||||
|
return {header->context_id, header->request_id, true, kNoError,
|
||||||
|
GetStringFromMemory<BrowserMsgHeader>(region->Memory(),
|
||||||
|
region->Size())};
|
||||||
|
}
|
||||||
|
|
||||||
|
NOTREACHED();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
RendererMessage ParseRendererMessage(
|
||||||
|
const CefRefPtr<CefProcessMessage>& message) {
|
||||||
|
if (auto args = message->GetArgumentList()) {
|
||||||
|
DCHECK_EQ(args->GetSize(), 4U);
|
||||||
|
|
||||||
|
const int context_id = args->GetInt(kContextId);
|
||||||
|
const int request_id = args->GetInt(kRequestId);
|
||||||
|
const auto payload_type = args->GetType(kRendererPayload);
|
||||||
|
const bool persistent = args->GetBool(kIsPersistent);
|
||||||
|
|
||||||
|
if (payload_type == CefValueType::VTYPE_STRING) {
|
||||||
|
return {context_id, request_id, persistent,
|
||||||
|
args->GetString(kRendererPayload)};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payload_type == CefValueType::VTYPE_BINARY) {
|
||||||
|
return {
|
||||||
|
context_id, request_id, persistent,
|
||||||
|
new BinaryValueBuffer(message, args->GetBinary(kRendererPayload))};
|
||||||
|
}
|
||||||
|
|
||||||
|
DCHECK(payload_type == CefValueType::VTYPE_NULL);
|
||||||
|
return {context_id, request_id, persistent, new EmptyBinaryBuffer()};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto region = message->GetSharedMemoryRegion();
|
||||||
|
if (region && region->IsValid()) {
|
||||||
|
DCHECK_GE(region->Size(), sizeof(RendererMsgHeader));
|
||||||
|
auto header = static_cast<const RendererMsgHeader*>(region->Memory());
|
||||||
|
|
||||||
|
if (header->is_binary) {
|
||||||
|
return {header->context_id, header->request_id, header->is_persistent,
|
||||||
|
new SharedMemoryRegionBuffer(region, sizeof(RendererMsgHeader))};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
header->context_id,
|
||||||
|
header->request_id,
|
||||||
|
header->is_persistent,
|
||||||
|
GetStringFromMemory<RendererMsgHeader>(region->Memory(),
|
||||||
|
region->Size()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
NOTREACHED();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace cef_message_router_utils
|
92
libcef_dll/wrapper/cef_message_router_utils.h
Normal file
92
libcef_dll/wrapper/cef_message_router_utils.h
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
|
||||||
|
// reserved. Use of this source code is governed by a BSD-style license that
|
||||||
|
// can be found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef CEF_LIBCEF_DLL_WRAPPER_CEF_MESSAGE_ROUTER_UTILS_H_
|
||||||
|
#define CEF_LIBCEF_DLL_WRAPPER_CEF_MESSAGE_ROUTER_UTILS_H_
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
#include "include/wrapper/cef_message_router.h"
|
||||||
|
|
||||||
|
namespace cef_message_router_utils {
|
||||||
|
|
||||||
|
///
|
||||||
|
/// This class handles the task of copying user data, such as CefString or
|
||||||
|
/// binary values like (void*, size_t), directly to an appropriate buffer based
|
||||||
|
/// on the user data type and size.
|
||||||
|
///
|
||||||
|
/// There are four specializations of this abstract class. The appropriate
|
||||||
|
/// specialization is chosen by the `CreateBrowserResponseBuilder` function,
|
||||||
|
/// based on the provided data type and size. For instance, for a "short"
|
||||||
|
/// CefString, a StringResponseBuilder specialization is used, and for an empty
|
||||||
|
/// binary value - EmptyResponseBuilder.
|
||||||
|
///
|
||||||
|
class BrowserResponseBuilder : public CefBaseRefCounted {
|
||||||
|
public:
|
||||||
|
///
|
||||||
|
/// Creates a new CefProcessMessage from the data provided to the builder.
|
||||||
|
/// Returns nullptr for invalid instances. Invalidates this builder instance.
|
||||||
|
///
|
||||||
|
virtual CefRefPtr<CefProcessMessage> Build(int context_id,
|
||||||
|
int request_id) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BrowserMessage {
|
||||||
|
int context_id;
|
||||||
|
int request_id;
|
||||||
|
bool is_success;
|
||||||
|
int error_code;
|
||||||
|
std::variant<CefString, CefRefPtr<CefBinaryBuffer>> payload;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RendererMessage {
|
||||||
|
int context_id;
|
||||||
|
int request_id;
|
||||||
|
bool is_persistent;
|
||||||
|
std::variant<CefString, CefRefPtr<const CefBinaryBuffer>> payload;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BinaryValueABRCallback final : public CefV8ArrayBufferReleaseCallback {
|
||||||
|
public:
|
||||||
|
explicit BinaryValueABRCallback(CefRefPtr<CefBinaryBuffer> value)
|
||||||
|
: value_(std::move(value)) {}
|
||||||
|
BinaryValueABRCallback(const BinaryValueABRCallback&) = delete;
|
||||||
|
BinaryValueABRCallback& operator=(const BinaryValueABRCallback&) = delete;
|
||||||
|
|
||||||
|
void ReleaseBuffer(void* buffer) override {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const CefRefPtr<CefBinaryBuffer> value_;
|
||||||
|
|
||||||
|
IMPLEMENT_REFCOUNTING(BinaryValueABRCallback);
|
||||||
|
};
|
||||||
|
|
||||||
|
CefRefPtr<BrowserResponseBuilder> CreateBrowserResponseBuilder(
|
||||||
|
size_t threshold,
|
||||||
|
const std::string& name,
|
||||||
|
const CefString& response);
|
||||||
|
|
||||||
|
CefRefPtr<BrowserResponseBuilder> CreateBrowserResponseBuilder(
|
||||||
|
size_t threshold,
|
||||||
|
const std::string& name,
|
||||||
|
const void* data,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
|
CefRefPtr<CefProcessMessage> BuildRendererMsg(
|
||||||
|
size_t threshold,
|
||||||
|
const std::string& name,
|
||||||
|
int context_id,
|
||||||
|
int request_id,
|
||||||
|
const CefRefPtr<CefV8Value>& request,
|
||||||
|
bool persistent);
|
||||||
|
|
||||||
|
BrowserMessage ParseBrowserMessage(const CefRefPtr<CefProcessMessage>& message);
|
||||||
|
|
||||||
|
RendererMessage ParseRendererMessage(
|
||||||
|
const CefRefPtr<CefProcessMessage>& message);
|
||||||
|
|
||||||
|
} // namespace cef_message_router_utils
|
||||||
|
|
||||||
|
#endif // CEF_LIBCEF_DLL_WRAPPER_CEF_MESSAGE_ROUTER_UTILS_H_
|
60
tests/cefclient/browser/binary_transfer_test.cc
Normal file
60
tests/cefclient/browser/binary_transfer_test.cc
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
|
||||||
|
// reserved. Use of this source code is governed by a BSD-style license that
|
||||||
|
// can be found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "tests/cefclient/browser/binary_transfer_test.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const char kTestUrlPath[] = "/binary_transfer";
|
||||||
|
|
||||||
|
// Handle messages in the browser process.
|
||||||
|
class Handler final : public CefMessageRouterBrowserSide::Handler {
|
||||||
|
public:
|
||||||
|
// Called due to cefQuery execution in binary_transfer.html.
|
||||||
|
bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||||
|
CefRefPtr<CefFrame> frame,
|
||||||
|
int64_t query_id,
|
||||||
|
const CefString& request,
|
||||||
|
bool persistent,
|
||||||
|
CefRefPtr<Callback> callback) override {
|
||||||
|
// Only handle messages from the test URL.
|
||||||
|
const std::string& url = frame->GetURL();
|
||||||
|
if (!client::test_runner::IsTestURL(url, kTestUrlPath)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback->Success(request);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called due to cefQuery execution in binary_transfer.html.
|
||||||
|
bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||||
|
CefRefPtr<CefFrame> frame,
|
||||||
|
int64_t query_id,
|
||||||
|
CefRefPtr<const CefBinaryBuffer> request,
|
||||||
|
bool persistent,
|
||||||
|
CefRefPtr<Callback> callback) override {
|
||||||
|
// Only handle messages from the test URL.
|
||||||
|
const std::string& url = frame->GetURL();
|
||||||
|
if (!client::test_runner::IsTestURL(url, kTestUrlPath)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback->Success(request->GetData(), request->GetSize());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace client::binary_transfer_test {
|
||||||
|
|
||||||
|
void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers) {
|
||||||
|
handlers.insert(new Handler());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace client::binary_transfer_test
|
17
tests/cefclient/browser/binary_transfer_test.h
Normal file
17
tests/cefclient/browser/binary_transfer_test.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
|
||||||
|
// reserved. Use of this source code is governed by a BSD-style license that
|
||||||
|
// can be found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef CEF_TESTS_CEFCLIENT_BROWSER_BINARY_TRANSFER_TEST_H_
|
||||||
|
#define CEF_TESTS_CEFCLIENT_BROWSER_BINARY_TRANSFER_TEST_H_
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "tests/cefclient/browser/test_runner.h"
|
||||||
|
|
||||||
|
namespace client::binary_transfer_test {
|
||||||
|
|
||||||
|
void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers);
|
||||||
|
|
||||||
|
} // namespace client::binary_transfer_test
|
||||||
|
|
||||||
|
#endif // CEF_TESTS_CEFCLIENT_BROWSER_BINARY_TRANSFER_TEST_H_
|
@ -44,31 +44,32 @@
|
|||||||
#define ID_TESTS_UNMUTE_AUDIO 32717
|
#define ID_TESTS_UNMUTE_AUDIO 32717
|
||||||
#define ID_TESTS_LAST 32717
|
#define ID_TESTS_LAST 32717
|
||||||
#define IDC_STATIC -1
|
#define IDC_STATIC -1
|
||||||
#define IDS_BINDING_HTML 1000
|
#define IDS_BINARY_TRANSFER_HTML 1000
|
||||||
#define IDS_DIALOGS_HTML 1001
|
#define IDS_BINDING_HTML 1001
|
||||||
#define IDS_DRAGGABLE_HTML 1002
|
#define IDS_DIALOGS_HTML 1002
|
||||||
#define IDS_IPC_PERFORMANCE_HTML 1003
|
#define IDS_DRAGGABLE_HTML 1003
|
||||||
#define IDS_LOCALSTORAGE_HTML 1004
|
#define IDS_IPC_PERFORMANCE_HTML 1004
|
||||||
#define IDS_LOGO_PNG 1005
|
#define IDS_LOCALSTORAGE_HTML 1005
|
||||||
#define IDS_MEDIA_ROUTER_HTML 1006
|
#define IDS_LOGO_PNG 1006
|
||||||
#define IDS_MENU_ICON_1X_PNG 1007
|
#define IDS_MEDIA_ROUTER_HTML 1007
|
||||||
#define IDS_MENU_ICON_2X_PNG 1008
|
#define IDS_MENU_ICON_1X_PNG 1008
|
||||||
#define IDS_OSRTEST_HTML 1009
|
#define IDS_MENU_ICON_2X_PNG 1009
|
||||||
#define IDS_OTHER_TESTS_HTML 1010
|
#define IDS_OSRTEST_HTML 1010
|
||||||
#define IDS_PDF_HTML 1011
|
#define IDS_OTHER_TESTS_HTML 1011
|
||||||
#define IDS_PDF_PDF 1012
|
#define IDS_PDF_HTML 1012
|
||||||
#define IDS_PERFORMANCE_HTML 1013
|
#define IDS_PDF_PDF 1013
|
||||||
#define IDS_PERFORMANCE2_HTML 1014
|
#define IDS_PERFORMANCE_HTML 1014
|
||||||
#define IDS_PREFERENCES_HTML 1015
|
#define IDS_PERFORMANCE2_HTML 1015
|
||||||
#define IDS_RESPONSE_FILTER_HTML 1016
|
#define IDS_PREFERENCES_HTML 1016
|
||||||
#define IDS_SERVER_HTML 1017
|
#define IDS_RESPONSE_FILTER_HTML 1017
|
||||||
#define IDS_TRANSPARENCY_HTML 1018
|
#define IDS_SERVER_HTML 1018
|
||||||
#define IDS_URLREQUEST_HTML 1019
|
#define IDS_TRANSPARENCY_HTML 1019
|
||||||
#define IDS_WEBSOCKET_HTML 1020
|
#define IDS_URLREQUEST_HTML 1020
|
||||||
#define IDS_WINDOW_HTML 1021
|
#define IDS_WEBSOCKET_HTML 1021
|
||||||
#define IDS_WINDOW_ICON_1X_PNG 1022
|
#define IDS_WINDOW_HTML 1022
|
||||||
#define IDS_WINDOW_ICON_2X_PNG 1023
|
#define IDS_WINDOW_ICON_1X_PNG 1023
|
||||||
#define IDS_XMLHTTPREQUEST_HTML 1024
|
#define IDS_WINDOW_ICON_2X_PNG 1024
|
||||||
|
#define IDS_XMLHTTPREQUEST_HTML 1025
|
||||||
|
|
||||||
#define IDS_EXTENSIONS_SET_PAGE_COLOR_ICON_PNG 1030
|
#define IDS_EXTENSIONS_SET_PAGE_COLOR_ICON_PNG 1030
|
||||||
#define IDS_EXTENSIONS_SET_PAGE_COLOR_MANIFEST_JSON 1031
|
#define IDS_EXTENSIONS_SET_PAGE_COLOR_MANIFEST_JSON 1031
|
||||||
|
@ -13,7 +13,8 @@ int GetResourceId(const char* resource_name) {
|
|||||||
static struct _resource_map {
|
static struct _resource_map {
|
||||||
const char* name;
|
const char* name;
|
||||||
int id;
|
int id;
|
||||||
} resource_map[] = {{"binding.html", IDS_BINDING_HTML},
|
} resource_map[] = {{"binary_transfer.html", IDS_BINARY_TRANSFER_HTML},
|
||||||
|
{"binding.html", IDS_BINDING_HTML},
|
||||||
{"dialogs.html", IDS_DIALOGS_HTML},
|
{"dialogs.html", IDS_DIALOGS_HTML},
|
||||||
{"draggable.html", IDS_DRAGGABLE_HTML},
|
{"draggable.html", IDS_DRAGGABLE_HTML},
|
||||||
{"extensions/set_page_color/icon.png",
|
{"extensions/set_page_color/icon.png",
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "include/views/cef_browser_view.h"
|
#include "include/views/cef_browser_view.h"
|
||||||
#include "include/wrapper/cef_closure_task.h"
|
#include "include/wrapper/cef_closure_task.h"
|
||||||
#include "include/wrapper/cef_stream_resource_handler.h"
|
#include "include/wrapper/cef_stream_resource_handler.h"
|
||||||
|
#include "tests/cefclient/browser/binary_transfer_test.h"
|
||||||
#include "tests/cefclient/browser/binding_test.h"
|
#include "tests/cefclient/browser/binding_test.h"
|
||||||
#include "tests/cefclient/browser/client_handler.h"
|
#include "tests/cefclient/browser/client_handler.h"
|
||||||
#include "tests/cefclient/browser/dialog_test.h"
|
#include "tests/cefclient/browser/dialog_test.h"
|
||||||
@ -842,6 +843,9 @@ bool IsTestURL(const std::string& url, const std::string& path) {
|
|||||||
void CreateMessageHandlers(MessageHandlerSet& handlers) {
|
void CreateMessageHandlers(MessageHandlerSet& handlers) {
|
||||||
handlers.insert(new PromptHandler);
|
handlers.insert(new PromptHandler);
|
||||||
|
|
||||||
|
// Create the binary trasfer test handlers.
|
||||||
|
binary_transfer_test::CreateMessageHandlers(handlers);
|
||||||
|
|
||||||
// Create the binding test handlers.
|
// Create the binding test handlers.
|
||||||
binding_test::CreateMessageHandlers(handlers);
|
binding_test::CreateMessageHandlers(handlers);
|
||||||
|
|
||||||
|
498
tests/cefclient/resources/binary_transfer.html
Normal file
498
tests/cefclient/resources/binary_transfer.html
Normal file
@ -0,0 +1,498 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>Binary vs String Transfer Benchmark</title>
|
||||||
|
<script src="https://cdn.plot.ly/plotly-2.26.0.min.js"></script>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Tahoma, Serif;
|
||||||
|
font-size: 10pt;
|
||||||
|
}
|
||||||
|
.info {
|
||||||
|
font-size: 12pt;
|
||||||
|
}
|
||||||
|
.left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.positive {
|
||||||
|
color: green;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.negative {
|
||||||
|
color: red;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
table.resultTable {
|
||||||
|
border: 1px solid black;
|
||||||
|
border-collapse: collapse;
|
||||||
|
empty-cells: show;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
table.resultTable td {
|
||||||
|
padding: 2px 4px;
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
table.resultTable > thead > tr {
|
||||||
|
font-weight: bold;
|
||||||
|
background: lightblue;
|
||||||
|
}
|
||||||
|
table.resultTable > tbody > tr:nth-child(odd) {
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
table.resultTable > tbody > tr:nth-child(even) {
|
||||||
|
background: lightgray;
|
||||||
|
}
|
||||||
|
.hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body background-color="white">
|
||||||
|
<h1>Binary vs String Transfer Benchmark</h1>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<p class="info">
|
||||||
|
This benchmark evaluates the message transfer speed between the
|
||||||
|
renderer process and the browser process. <br />It compares the
|
||||||
|
performance of binary and string message transfer.
|
||||||
|
</p>
|
||||||
|
<p class="info">
|
||||||
|
<b>Note:</b> There is no progress indication of the tests because it
|
||||||
|
significantly influences measurements. <br />It usually takes 30
|
||||||
|
seconds (for 300 samples) to complete the tests.
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
Samples:
|
||||||
|
<input
|
||||||
|
id="sSamples"
|
||||||
|
type="text"
|
||||||
|
value="300"
|
||||||
|
required
|
||||||
|
pattern="[0-9]+"
|
||||||
|
/>
|
||||||
|
<button id="sRun" autofocus onclick="runTestSuite()">Run</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div style="padding-top: 10px; padding-bottom: 10px">
|
||||||
|
<table id="resultTable" class="resultTable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td class="center" style="width: 8%">Message Size</td>
|
||||||
|
<td class="center" style="width: 8%">
|
||||||
|
String Round Trip Avg, ms
|
||||||
|
</td>
|
||||||
|
<td class="center" style="width: 8%">
|
||||||
|
Binary Round Trip Avg, ms
|
||||||
|
</td>
|
||||||
|
<td class="center" style="width: 10%">Relative Trip Difference</td>
|
||||||
|
<td class="center" style="width: 8%">String Speed, MB/s</td>
|
||||||
|
<td class="center" style="width: 8%">Binary Speed, MB/s</td>
|
||||||
|
<td class="center" style="width: 10%">Relative Speed Difference</td>
|
||||||
|
<td class="center" style="width: 8%">String Standard Deviation</td>
|
||||||
|
<td class="center" style="width: 8%">Binary Standard Deviation</td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<!-- result rows here -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="round_trip_avg_chart">
|
||||||
|
<!-- Average round trip linear chart will be drawn inside this DIV -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="box_plot_chart">
|
||||||
|
<!-- Box plot of round trip time will be drawn inside this DIV -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
let tests = [];
|
||||||
|
let box_plot_test_data = [];
|
||||||
|
let round_trip_avg_plot_data = [];
|
||||||
|
|
||||||
|
function nextTestSuite(testIndex) {
|
||||||
|
const nextTestIndex = testIndex + 1;
|
||||||
|
setTimeout(execTestSuite, 0, nextTestIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateRandomString(size) {
|
||||||
|
// Symbols that will be encoded as two bytes in UTF-8
|
||||||
|
// so we compare transfer of the same amount of bytes
|
||||||
|
const characters =
|
||||||
|
"АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя";
|
||||||
|
let randomString = "";
|
||||||
|
for (let i = 0; i < size; i++) {
|
||||||
|
const randomIndex = Math.floor(Math.random() * characters.length);
|
||||||
|
randomString += characters.charAt(randomIndex);
|
||||||
|
}
|
||||||
|
return randomString;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateRandomArrayBuffer(size) {
|
||||||
|
const buffer = new ArrayBuffer(size);
|
||||||
|
const uint8Array = new Uint8Array(buffer);
|
||||||
|
for (let i = 0; i < uint8Array.length; i++) {
|
||||||
|
uint8Array[i] = Math.floor(Math.random() * 256);
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
function reportError(errorCode, errorMessage) {
|
||||||
|
console.error(`ErrorCode:${errorCode} Message:${errorMessage}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendString(size, testIndex) {
|
||||||
|
const request = generateRandomString(size);
|
||||||
|
const startTime = performance.now();
|
||||||
|
const onSuccess = (response) => {
|
||||||
|
const roundTrip = performance.now() - startTime;
|
||||||
|
const test = tests[testIndex];
|
||||||
|
test.totalRoundTrip += roundTrip;
|
||||||
|
test.sample++;
|
||||||
|
box_plot_test_data[testIndex].x.push(roundTrip);
|
||||||
|
setTimeout(execTest, 0, testIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.cefQuery({
|
||||||
|
request: request,
|
||||||
|
onSuccess: onSuccess,
|
||||||
|
onFailure: reportError,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendArrayBuffer(size, testIndex) {
|
||||||
|
const request = generateRandomArrayBuffer(size);
|
||||||
|
const startTime = performance.now();
|
||||||
|
const onSuccess = (response) => {
|
||||||
|
const roundTrip = performance.now() - startTime;
|
||||||
|
const test = tests[testIndex];
|
||||||
|
test.totalRoundTrip += roundTrip;
|
||||||
|
test.sample++;
|
||||||
|
box_plot_test_data[testIndex].x.push(roundTrip);
|
||||||
|
setTimeout(execTest, 0, testIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.cefQuery({
|
||||||
|
request: request,
|
||||||
|
onSuccess: onSuccess,
|
||||||
|
onFailure: reportError,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStandardDeviation(array, mean) {
|
||||||
|
const n = array.length;
|
||||||
|
if (n < 5) return null;
|
||||||
|
return Math.sqrt(
|
||||||
|
array.map((x) => Math.pow(x - mean, 2)).reduce((a, b) => a + b) /
|
||||||
|
(n - 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function execTest(testIndex) {
|
||||||
|
const test = tests[testIndex];
|
||||||
|
if (test.sample >= test.totalSamples) {
|
||||||
|
return nextTestSuite(testIndex);
|
||||||
|
}
|
||||||
|
test.func(test.length, test.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
function column(prepared, value) {
|
||||||
|
return (
|
||||||
|
"<td class='right'>" + (!prepared ? "-" : value.toFixed(3)) + "</td>"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function relativeDiffColumn(prepared, value, isBiggerBetter) {
|
||||||
|
if (!prepared) return "<td class='right'>-</td>";
|
||||||
|
|
||||||
|
const isPositive = value >= 0 == isBiggerBetter;
|
||||||
|
return [
|
||||||
|
"<td class='right ",
|
||||||
|
isPositive ? "positive" : "negative",
|
||||||
|
"'>",
|
||||||
|
value > 0 ? "+" : "",
|
||||||
|
value.toFixed(2),
|
||||||
|
"%</td>",
|
||||||
|
].join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayResult(test) {
|
||||||
|
const id = "testResultRow_" + test.index;
|
||||||
|
|
||||||
|
const markup = [
|
||||||
|
"<tr id='",
|
||||||
|
id,
|
||||||
|
"'>",
|
||||||
|
"<td class='left'>",
|
||||||
|
test.name,
|
||||||
|
"</td>",
|
||||||
|
column(test.prepared, test.avgRoundTrip),
|
||||||
|
column(test.prepared, test.avgRoundTripBin),
|
||||||
|
relativeDiffColumn(test.prepared, test.relativeTripDiff, false),
|
||||||
|
column(test.prepared, test.speed),
|
||||||
|
column(test.prepared, test.speedBinary),
|
||||||
|
relativeDiffColumn(test.prepared, test.relativeSpeedDiff, true),
|
||||||
|
"<td class='right'>",
|
||||||
|
!test.prepared || test.stdDeviation == null
|
||||||
|
? "-"
|
||||||
|
: test.stdDeviation.toFixed(3),
|
||||||
|
"</td>",
|
||||||
|
"<td class='right'>",
|
||||||
|
!test.prepared || test.stdDeviationBinary == null
|
||||||
|
? "-"
|
||||||
|
: test.stdDeviationBinary.toFixed(3),
|
||||||
|
"</td>",
|
||||||
|
"</tr>",
|
||||||
|
].join("");
|
||||||
|
|
||||||
|
const row = document.getElementById(id);
|
||||||
|
if (row) {
|
||||||
|
row.outerHTML = markup;
|
||||||
|
} else {
|
||||||
|
const tbody = document.getElementById("resultTable").tBodies[0];
|
||||||
|
tbody.insertAdjacentHTML("beforeEnd", markup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function relativeDiff(left, right) {
|
||||||
|
if (right != 0) {
|
||||||
|
return ((left - right) / right) * 100;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTestResults(tests) {
|
||||||
|
testResults = [];
|
||||||
|
|
||||||
|
let oldRoundTrip = {
|
||||||
|
x: [],
|
||||||
|
y: [],
|
||||||
|
type: "scatter",
|
||||||
|
name: "String",
|
||||||
|
};
|
||||||
|
|
||||||
|
let newRoundTrip = {
|
||||||
|
x: [],
|
||||||
|
y: [],
|
||||||
|
type: "scatter",
|
||||||
|
name: "Binary",
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let i = 0; i < tests.length / 2; i++) {
|
||||||
|
const index = testResults.length;
|
||||||
|
|
||||||
|
// Tests are in pairs - String and Binary
|
||||||
|
const test = tests[i * 2];
|
||||||
|
const testBin = tests[i * 2 + 1];
|
||||||
|
|
||||||
|
const avgRoundTrip = test.totalRoundTrip / test.totalSamples;
|
||||||
|
const avgRoundTripBin = testBin.totalRoundTrip / testBin.totalSamples;
|
||||||
|
const relativeTripDiff = relativeDiff(avgRoundTripBin, avgRoundTrip);
|
||||||
|
|
||||||
|
// In MB/s
|
||||||
|
const speed = test.byteSize / (avgRoundTrip * 1000);
|
||||||
|
const speedBinary = testBin.byteSize / (avgRoundTripBin * 1000);
|
||||||
|
const relativeSpeedDiff = relativeDiff(speedBinary, speed);
|
||||||
|
|
||||||
|
const stdDeviation = getStandardDeviation(
|
||||||
|
box_plot_test_data[test.index].x,
|
||||||
|
avgRoundTrip
|
||||||
|
);
|
||||||
|
const stdDeviationBinary = getStandardDeviation(
|
||||||
|
box_plot_test_data[testBin.index].x,
|
||||||
|
avgRoundTripBin
|
||||||
|
);
|
||||||
|
|
||||||
|
testResults.push({
|
||||||
|
name: humanFileSize(test.byteSize),
|
||||||
|
index: index,
|
||||||
|
prepared: true,
|
||||||
|
avgRoundTrip: avgRoundTrip,
|
||||||
|
avgRoundTripBin: avgRoundTripBin,
|
||||||
|
relativeTripDiff: relativeTripDiff,
|
||||||
|
speed: speed,
|
||||||
|
speedBinary: speedBinary,
|
||||||
|
relativeSpeedDiff: relativeSpeedDiff,
|
||||||
|
stdDeviation: stdDeviation,
|
||||||
|
stdDeviationBinary: stdDeviationBinary,
|
||||||
|
});
|
||||||
|
|
||||||
|
oldRoundTrip.x.push(test.byteSize);
|
||||||
|
newRoundTrip.x.push(test.byteSize);
|
||||||
|
oldRoundTrip.y.push(avgRoundTrip);
|
||||||
|
newRoundTrip.y.push(avgRoundTripBin);
|
||||||
|
}
|
||||||
|
|
||||||
|
round_trip_avg_plot_data = [oldRoundTrip, newRoundTrip];
|
||||||
|
return testResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildEmptyTestResults(tests) {
|
||||||
|
testResults = [];
|
||||||
|
for (let i = 0; i < tests.length / 2; i++) {
|
||||||
|
const index = testResults.length;
|
||||||
|
const test = tests[i * 2];
|
||||||
|
|
||||||
|
testResults.push({
|
||||||
|
name: humanFileSize(test.byteSize),
|
||||||
|
index: index,
|
||||||
|
prepared: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return testResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetTestsResults(totalSamples) {
|
||||||
|
if (totalSamples <= 0) totalSamples = 1;
|
||||||
|
|
||||||
|
// Reset tests results
|
||||||
|
tests.forEach((test) => {
|
||||||
|
test.sample = 0;
|
||||||
|
test.totalRoundTrip = 0;
|
||||||
|
test.totalSamples = totalSamples;
|
||||||
|
});
|
||||||
|
|
||||||
|
testResults = buildEmptyTestResults(tests);
|
||||||
|
testResults.forEach((result) => displayResult(result));
|
||||||
|
|
||||||
|
round_trip_avg_plot_data = [];
|
||||||
|
box_plot_test_data.forEach((data) => {
|
||||||
|
data.x = [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function queueTest(name, byteSize, length, testFunc) {
|
||||||
|
const testIndex = tests.length;
|
||||||
|
test = {
|
||||||
|
name: name,
|
||||||
|
byteSize: byteSize,
|
||||||
|
length: length,
|
||||||
|
index: testIndex,
|
||||||
|
sample: 0,
|
||||||
|
totalRoundTrip: 0,
|
||||||
|
func: testFunc,
|
||||||
|
};
|
||||||
|
tests.push(test);
|
||||||
|
|
||||||
|
box_plot_test_data.push({
|
||||||
|
x: [],
|
||||||
|
type: "box",
|
||||||
|
boxpoints: "all",
|
||||||
|
name: name,
|
||||||
|
jitter: 0.3,
|
||||||
|
pointpos: -1.8,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function execTestSuite(testIndex) {
|
||||||
|
if (testIndex < tests.length) {
|
||||||
|
execTest(testIndex);
|
||||||
|
} else {
|
||||||
|
testsRunFinished();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function startTests() {
|
||||||
|
// Let the updated table render before starting the tests
|
||||||
|
setTimeout(execTestSuite, 200, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function execQueuedTests(totalSamples) {
|
||||||
|
resetTestsResults(totalSamples);
|
||||||
|
startTests();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSettingsState(disabled) {
|
||||||
|
document.getElementById("sSamples").disabled = disabled;
|
||||||
|
document.getElementById("sRun").disabled = disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
function testsRunFinished() {
|
||||||
|
testResults = buildTestResults(tests);
|
||||||
|
testResults.forEach((result) => displayResult(result));
|
||||||
|
|
||||||
|
const round_trip_layout = {
|
||||||
|
title: "Average round trip, μs (Smaller Better)",
|
||||||
|
};
|
||||||
|
Plotly.newPlot(
|
||||||
|
"round_trip_avg_chart",
|
||||||
|
round_trip_avg_plot_data,
|
||||||
|
round_trip_layout
|
||||||
|
);
|
||||||
|
|
||||||
|
const box_plot_layout = {
|
||||||
|
title: "Round Trip Time, μs",
|
||||||
|
};
|
||||||
|
Plotly.newPlot("box_plot_chart", box_plot_test_data, box_plot_layout);
|
||||||
|
setSettingsState(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function humanFileSize(bytes) {
|
||||||
|
const step = 1024;
|
||||||
|
const originalBytes = bytes;
|
||||||
|
|
||||||
|
if (Math.abs(bytes) < step) {
|
||||||
|
return bytes + " B";
|
||||||
|
}
|
||||||
|
|
||||||
|
const units = [" KB", " MB", " GB"];
|
||||||
|
let u = -1;
|
||||||
|
let count = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
bytes /= step;
|
||||||
|
u += 1;
|
||||||
|
count += 1;
|
||||||
|
} while (Math.abs(bytes) >= step && u < units.length - 1);
|
||||||
|
|
||||||
|
return bytes.toString() + units[u];
|
||||||
|
}
|
||||||
|
|
||||||
|
window.runTestSuite = () => {
|
||||||
|
Plotly.purge("round_trip_avg_chart");
|
||||||
|
Plotly.purge("box_plot_chart");
|
||||||
|
setSettingsState(true);
|
||||||
|
const totalSamples = parseInt(
|
||||||
|
document.getElementById("sSamples").value
|
||||||
|
);
|
||||||
|
execQueuedTests(totalSamples);
|
||||||
|
};
|
||||||
|
|
||||||
|
const totalSamples = parseInt(document.getElementById("sSamples").value);
|
||||||
|
queueTest("Empty String", 0, 0, sendString);
|
||||||
|
queueTest("Empty Binary", 0, 0, sendArrayBuffer);
|
||||||
|
for (let byteSize = 8; byteSize <= 512 * 1024; byteSize *= 2) {
|
||||||
|
// Byte size of a string is twice its length because of UTF-16 encoding
|
||||||
|
const stringLen = byteSize / 2;
|
||||||
|
queueTest(
|
||||||
|
humanFileSize(byteSize) + " String",
|
||||||
|
byteSize,
|
||||||
|
stringLen,
|
||||||
|
sendString
|
||||||
|
);
|
||||||
|
queueTest(
|
||||||
|
humanFileSize(byteSize) + " Binary",
|
||||||
|
byteSize,
|
||||||
|
byteSize,
|
||||||
|
sendArrayBuffer
|
||||||
|
);
|
||||||
|
}
|
||||||
|
resetTestsResults(totalSamples);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -9,6 +9,7 @@
|
|||||||
<li><a href="http://webkit.org/blog-files/3d-transforms/poster-circle.html">Accelerated Layers</a></li>
|
<li><a href="http://webkit.org/blog-files/3d-transforms/poster-circle.html">Accelerated Layers</a></li>
|
||||||
<li><a href="https://jigsaw.w3.org/HTTP/Basic/">Authentication (Basic)</a> - credentials returned via GetAuthCredentials</li>
|
<li><a href="https://jigsaw.w3.org/HTTP/Basic/">Authentication (Basic)</a> - credentials returned via GetAuthCredentials</li>
|
||||||
<li><a href="https://jigsaw.w3.org/HTTP/Digest/">Authentication (Digest)</a> - credentials returned via GetAuthCredentials</li>
|
<li><a href="https://jigsaw.w3.org/HTTP/Digest/">Authentication (Digest)</a> - credentials returned via GetAuthCredentials</li>
|
||||||
|
<li><a href="binary_transfer">Binary vs String Transfer Benchmark</a></li>
|
||||||
<li><a href="http://html5advent2011.digitpaint.nl/3/index.html">Cursors</a></li>
|
<li><a href="http://html5advent2011.digitpaint.nl/3/index.html">Cursors</a></li>
|
||||||
<li><a href="dialogs">Dialogs</a></li>
|
<li><a href="dialogs">Dialogs</a></li>
|
||||||
<li><a href="http://html5demos.com/drag">Drag & Drop</a></li>
|
<li><a href="http://html5demos.com/drag">Drag & Drop</a></li>
|
||||||
|
@ -29,6 +29,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
|||||||
// Binary
|
// Binary
|
||||||
//
|
//
|
||||||
|
|
||||||
|
IDS_BINARY_TRANSFER_HTML BINARY "..\\binary_transfer.html"
|
||||||
IDS_BINDING_HTML BINARY "..\\binding.html"
|
IDS_BINDING_HTML BINARY "..\\binding.html"
|
||||||
IDS_DIALOGS_HTML BINARY "..\\dialogs.html"
|
IDS_DIALOGS_HTML BINARY "..\\dialogs.html"
|
||||||
IDS_DRAGGABLE_HTML BINARY "..\\draggable.html"
|
IDS_DRAGGABLE_HTML BINARY "..\\draggable.html"
|
||||||
@ -228,4 +229,3 @@ END
|
|||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
#endif // not APSTUDIO_INVOKED
|
#endif // not APSTUDIO_INVOKED
|
||||||
|
|
||||||
|
136
tests/ceftests/message_router_binary_unittest.cc
Normal file
136
tests/ceftests/message_router_binary_unittest.cc
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
|
||||||
|
// reserved. Use of this source code is governed by a BSD-style license that
|
||||||
|
// can be found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "tests/ceftests/message_router_unittest_utils.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr size_t kMsgSizeThresholdInBytes = 16000;
|
||||||
|
|
||||||
|
class BinaryTestHandler final : public SingleLoadTestHandler {
|
||||||
|
public:
|
||||||
|
explicit BinaryTestHandler(size_t message_size)
|
||||||
|
: message_size_(message_size) {}
|
||||||
|
|
||||||
|
std::string GetMainHTML() override {
|
||||||
|
return "<html><body><script>\n"
|
||||||
|
"function generateRandomArrayBuffer(size) {\n"
|
||||||
|
" const buffer = new ArrayBuffer(size);\n"
|
||||||
|
" const uint8Array = new Uint8Array(buffer);\n"
|
||||||
|
" for (let i = 0; i < uint8Array.length; i++) {\n"
|
||||||
|
" uint8Array[i] = Math.floor(Math.random() * 256);\n"
|
||||||
|
" }\n"
|
||||||
|
" return buffer;\n"
|
||||||
|
"}\n"
|
||||||
|
"function isEqualArrayBuffers(left, right) {\n"
|
||||||
|
" if (left.byteLength !== right.byteLength) { return false; }\n"
|
||||||
|
" const leftView = new DataView(left);\n"
|
||||||
|
" const rightView = new DataView(right);\n"
|
||||||
|
" for (let i = 0; i < left.byteLength; i++) {\n"
|
||||||
|
" if (leftView.getUint8(i) !== rightView.getUint8(i)) {\n"
|
||||||
|
" return false;\n"
|
||||||
|
" }\n"
|
||||||
|
" }\n"
|
||||||
|
" return true;\n"
|
||||||
|
"}\n"
|
||||||
|
"const request = generateRandomArrayBuffer(" +
|
||||||
|
std::to_string(message_size_) +
|
||||||
|
")\n"
|
||||||
|
"window." +
|
||||||
|
std::string(kJSQueryFunc) +
|
||||||
|
"({\n request: request,\n"
|
||||||
|
" persistent: false,\n"
|
||||||
|
" onSuccess: (response) => {\n"
|
||||||
|
" if (!isEqualArrayBuffers(request, response)) {\n"
|
||||||
|
" window.mrtNotify('error-ArrayBuffersDiffer');\n"
|
||||||
|
" } else {\n"
|
||||||
|
" window.mrtNotify('success');\n"
|
||||||
|
" }\n"
|
||||||
|
" },\n"
|
||||||
|
" onFailure: (errorCode, errorMessage) => {\n"
|
||||||
|
" window.mrtNotify('error-onFailureCalled');\n"
|
||||||
|
" }\n"
|
||||||
|
"});\n</script></body></html>";
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnNotify(CefRefPtr<CefBrowser> browser,
|
||||||
|
CefRefPtr<CefFrame> frame,
|
||||||
|
const std::string& message) override {
|
||||||
|
AssertMainBrowser(browser);
|
||||||
|
AssertMainFrame(frame);
|
||||||
|
|
||||||
|
// OnNotify only be called once.
|
||||||
|
EXPECT_FALSE(got_notify_);
|
||||||
|
got_notify_.yes();
|
||||||
|
|
||||||
|
EXPECT_EQ("success", message);
|
||||||
|
|
||||||
|
DestroyTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||||
|
CefRefPtr<CefFrame> frame,
|
||||||
|
int64_t query_id,
|
||||||
|
CefRefPtr<const CefBinaryBuffer> request,
|
||||||
|
bool persistent,
|
||||||
|
CefRefPtr<Callback> callback) override {
|
||||||
|
AssertMainBrowser(browser);
|
||||||
|
AssertMainFrame(frame);
|
||||||
|
EXPECT_NE(0, query_id);
|
||||||
|
EXPECT_FALSE(persistent);
|
||||||
|
EXPECT_EQ(message_size_, request->GetSize());
|
||||||
|
|
||||||
|
got_on_query_.yes();
|
||||||
|
|
||||||
|
callback->Success(request->GetData(), request->GetSize());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DestroyTest() override {
|
||||||
|
EXPECT_TRUE(got_notify_);
|
||||||
|
EXPECT_TRUE(got_on_query_);
|
||||||
|
|
||||||
|
TestHandler::DestroyTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const size_t message_size_;
|
||||||
|
TrackCallback got_on_query_;
|
||||||
|
TrackCallback got_notify_;
|
||||||
|
};
|
||||||
|
|
||||||
|
using TestHandlerPtr = CefRefPtr<BinaryTestHandler>;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST(MessageRouterTest, BinaryMessageEmpty) {
|
||||||
|
const auto message_size = 0;
|
||||||
|
TestHandlerPtr handler = new BinaryTestHandler(message_size);
|
||||||
|
handler->SetMessageSizeThreshold(kMsgSizeThresholdInBytes);
|
||||||
|
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
ReleaseAndWaitForDestructor(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MessageRouterTest, BinaryMessageUnderThresholdSize) {
|
||||||
|
const auto under_threshold = kMsgSizeThresholdInBytes - 1;
|
||||||
|
TestHandlerPtr handler = new BinaryTestHandler(under_threshold);
|
||||||
|
handler->SetMessageSizeThreshold(kMsgSizeThresholdInBytes);
|
||||||
|
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
ReleaseAndWaitForDestructor(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MessageRouterTest, BinaryMessageOverThresholdSize) {
|
||||||
|
const auto over_threshold = kMsgSizeThresholdInBytes + 1;
|
||||||
|
TestHandlerPtr handler = new BinaryTestHandler(over_threshold);
|
||||||
|
handler->SetMessageSizeThreshold(kMsgSizeThresholdInBytes);
|
||||||
|
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
ReleaseAndWaitForDestructor(handler);
|
||||||
|
}
|
@ -19,8 +19,18 @@ const char kMultiQueryError[] = "error";
|
|||||||
const char kMultiQueryErrorMessage[] = "errormsg";
|
const char kMultiQueryErrorMessage[] = "errormsg";
|
||||||
const int kMultiQueryPersistentResponseCount = 5;
|
const int kMultiQueryPersistentResponseCount = 5;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr bool IsCefString() {
|
||||||
|
return std::is_same_v<std::remove_cv_t<T>, CefString>;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class TransferType {
|
||||||
|
STRING,
|
||||||
|
BINARY,
|
||||||
|
};
|
||||||
|
|
||||||
// Generates HTML and verifies results for multiple simultanious queries.
|
// Generates HTML and verifies results for multiple simultanious queries.
|
||||||
class MultiQueryManager : public CefMessageRouterBrowserSide::Handler {
|
class MultiQueryManager {
|
||||||
public:
|
public:
|
||||||
enum TestType {
|
enum TestType {
|
||||||
// Initiates a non-persistent query with a successful response.
|
// Initiates a non-persistent query with a successful response.
|
||||||
@ -70,10 +80,12 @@ class MultiQueryManager : public CefMessageRouterBrowserSide::Handler {
|
|||||||
|
|
||||||
MultiQueryManager(const std::string& label,
|
MultiQueryManager(const std::string& label,
|
||||||
bool synchronous,
|
bool synchronous,
|
||||||
int id_offset = 0)
|
int id_offset = 0,
|
||||||
|
TransferType transfer_type = TransferType::STRING)
|
||||||
: label_(label),
|
: label_(label),
|
||||||
synchronous_(synchronous),
|
synchronous_(synchronous),
|
||||||
id_offset_(id_offset),
|
id_offset_(id_offset),
|
||||||
|
transfer_type_(transfer_type),
|
||||||
finalized_(false),
|
finalized_(false),
|
||||||
running_(false),
|
running_(false),
|
||||||
manual_total_(0),
|
manual_total_(0),
|
||||||
@ -83,8 +95,6 @@ class MultiQueryManager : public CefMessageRouterBrowserSide::Handler {
|
|||||||
will_cancel_by_removing_handler_(false),
|
will_cancel_by_removing_handler_(false),
|
||||||
weak_ptr_factory_(this) {}
|
weak_ptr_factory_(this) {}
|
||||||
|
|
||||||
virtual ~MultiQueryManager() {}
|
|
||||||
|
|
||||||
std::string label() const { return label_; }
|
std::string label() const { return label_; }
|
||||||
|
|
||||||
void AddObserver(Observer* observer) {
|
void AddObserver(Observer* observer) {
|
||||||
@ -282,12 +292,13 @@ class MultiQueryManager : public CefMessageRouterBrowserSide::Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OnQuery(CefRefPtr<CefBrowser> browser,
|
template <class RequestType>
|
||||||
|
bool OnQueryImpl(CefRefPtr<CefBrowser> browser,
|
||||||
CefRefPtr<CefFrame> frame,
|
CefRefPtr<CefFrame> frame,
|
||||||
int64_t query_id,
|
int64_t query_id,
|
||||||
const CefString& request,
|
const RequestType& request,
|
||||||
bool persistent,
|
bool persistent,
|
||||||
CefRefPtr<Callback> callback) override {
|
CefRefPtr<CefMessageRouterBrowserSide::Callback> callback) {
|
||||||
EXPECT_TRUE(finalized_);
|
EXPECT_TRUE(finalized_);
|
||||||
EXPECT_UI_THREAD();
|
EXPECT_UI_THREAD();
|
||||||
|
|
||||||
@ -328,13 +339,26 @@ class MultiQueryManager : public CefMessageRouterBrowserSide::Handler {
|
|||||||
|
|
||||||
if (query.type == SUCCESS) {
|
if (query.type == SUCCESS) {
|
||||||
// Send the single success response.
|
// Send the single success response.
|
||||||
callback->Success(GetIDString(kMultiQueryResponse, index));
|
if constexpr (IsCefString<RequestType>()) {
|
||||||
|
const auto response = GetIDString(kMultiQueryResponse, index);
|
||||||
|
callback->Success(response);
|
||||||
|
} else {
|
||||||
|
const auto response = GetIDBinary(kMultiQueryResponse, index);
|
||||||
|
callback->Success(response.data(), response.size());
|
||||||
|
}
|
||||||
} else if (IsPersistent(query.type)) {
|
} else if (IsPersistent(query.type)) {
|
||||||
// Send the required number of successful responses.
|
// Send the required number of successful responses.
|
||||||
const std::string& response = GetIDString(kMultiQueryResponse, index);
|
if constexpr (IsCefString<RequestType>()) {
|
||||||
|
const auto response = GetIDString(kMultiQueryResponse, index);
|
||||||
for (int i = 0; i < kMultiQueryPersistentResponseCount; ++i) {
|
for (int i = 0; i < kMultiQueryPersistentResponseCount; ++i) {
|
||||||
callback->Success(response);
|
callback->Success(response);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
const auto response = GetIDBinary(kMultiQueryResponse, index);
|
||||||
|
for (int i = 0; i < kMultiQueryPersistentResponseCount; ++i) {
|
||||||
|
callback->Success(response.data(), response.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WillFail(query.type)) {
|
if (WillFail(query.type)) {
|
||||||
@ -359,7 +383,7 @@ class MultiQueryManager : public CefMessageRouterBrowserSide::Handler {
|
|||||||
|
|
||||||
void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
|
void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
|
||||||
CefRefPtr<CefFrame> frame,
|
CefRefPtr<CefFrame> frame,
|
||||||
int64_t query_id) override {
|
int64_t query_id) {
|
||||||
EXPECT_TRUE(finalized_);
|
EXPECT_TRUE(finalized_);
|
||||||
EXPECT_UI_THREAD();
|
EXPECT_UI_THREAD();
|
||||||
|
|
||||||
@ -495,7 +519,7 @@ class MultiQueryManager : public CefMessageRouterBrowserSide::Handler {
|
|||||||
|
|
||||||
// Used when a query is canceled.
|
// Used when a query is canceled.
|
||||||
int64_t query_id;
|
int64_t query_id;
|
||||||
CefRefPtr<Callback> callback;
|
CefRefPtr<CefMessageRouterBrowserSide::Callback> callback;
|
||||||
|
|
||||||
TrackCallback got_query;
|
TrackCallback got_query;
|
||||||
TrackCallback got_query_canceled;
|
TrackCallback got_query_canceled;
|
||||||
@ -610,13 +634,24 @@ class MultiQueryManager : public CefMessageRouterBrowserSide::Handler {
|
|||||||
const std::string& request_id_var =
|
const std::string& request_id_var =
|
||||||
GetIDString(kMultiQueryRequestId, index);
|
GetIDString(kMultiQueryRequestId, index);
|
||||||
const std::string& repeat_ct_var = GetIDString(kMultiQueryRepeatCt, index);
|
const std::string& repeat_ct_var = GetIDString(kMultiQueryRepeatCt, index);
|
||||||
const std::string& request_val =
|
const std::string& request_str =
|
||||||
GetIDString(std::string(kMultiQueryRequest) + ":", index);
|
GetIDString(std::string(kMultiQueryRequest) + ":", index);
|
||||||
const std::string& success_val =
|
const std::string& success_val =
|
||||||
GetIDString(std::string(kMultiQuerySuccess) + ":", index);
|
GetIDString(std::string(kMultiQuerySuccess) + ":", index);
|
||||||
const std::string& error_val =
|
const std::string& error_val =
|
||||||
GetIDString(std::string(kMultiQueryError) + ":", index);
|
GetIDString(std::string(kMultiQueryError) + ":", index);
|
||||||
|
|
||||||
|
const std::string request_val =
|
||||||
|
transfer_type_ == TransferType::BINARY
|
||||||
|
? ("new TextEncoder().encode('" + request_str + "').buffer")
|
||||||
|
: "'" + request_str + "'";
|
||||||
|
|
||||||
|
const std::string response_conversion =
|
||||||
|
transfer_type_ == TransferType::BINARY
|
||||||
|
? " const decoder = new TextDecoder('utf-8');\n"
|
||||||
|
" const message = decoder.decode(response);\n"
|
||||||
|
: " const message = response;\n";
|
||||||
|
|
||||||
std::string html;
|
std::string html;
|
||||||
|
|
||||||
const bool persistent = IsPersistent(query.type);
|
const bool persistent = IsPersistent(query.type);
|
||||||
@ -627,19 +662,15 @@ class MultiQueryManager : public CefMessageRouterBrowserSide::Handler {
|
|||||||
|
|
||||||
html += "var " + request_id_var +
|
html += "var " + request_id_var +
|
||||||
" = window.mrtQuery({\n"
|
" = window.mrtQuery({\n"
|
||||||
" request: '" +
|
" request: " +
|
||||||
request_val +
|
request_val +
|
||||||
"',\n"
|
",\n persistent: " + (persistent ? "true" : "false") + ",\n";
|
||||||
" persistent: " +
|
|
||||||
(persistent ? "true" : "false") + ",\n";
|
|
||||||
|
|
||||||
if (query.type == SUCCESS) {
|
if (query.type == SUCCESS) {
|
||||||
const std::string& response_val = GetIDString(kMultiQueryResponse, index);
|
const std::string& response_val = GetIDString(kMultiQueryResponse, index);
|
||||||
|
|
||||||
html +=
|
html += " onSuccess: function(response) {\n" + response_conversion +
|
||||||
" onSuccess: function(response) {\n"
|
" if (message == '" + response_val +
|
||||||
" if (response == '" +
|
|
||||||
response_val +
|
|
||||||
"')\n"
|
"')\n"
|
||||||
" window.mrtNotify('" +
|
" window.mrtNotify('" +
|
||||||
success_val +
|
success_val +
|
||||||
@ -683,10 +714,8 @@ class MultiQueryManager : public CefMessageRouterBrowserSide::Handler {
|
|||||||
const std::string& repeat_ct =
|
const std::string& repeat_ct =
|
||||||
GetIntString(kMultiQueryPersistentResponseCount);
|
GetIntString(kMultiQueryPersistentResponseCount);
|
||||||
|
|
||||||
html +=
|
html += " onSuccess: function(response) {\n" + response_conversion +
|
||||||
" onSuccess: function(response) {\n"
|
" if (message == '" + response_val +
|
||||||
" if (response == '" +
|
|
||||||
response_val +
|
|
||||||
"') {\n"
|
"') {\n"
|
||||||
// Should get repeat_ct number of successful responses.
|
// Should get repeat_ct number of successful responses.
|
||||||
" if (++" +
|
" if (++" +
|
||||||
@ -773,9 +802,12 @@ class MultiQueryManager : public CefMessageRouterBrowserSide::Handler {
|
|||||||
|
|
||||||
std::string GetIDString(const std::string& prefix, int index) const {
|
std::string GetIDString(const std::string& prefix, int index) const {
|
||||||
EXPECT_TRUE(!prefix.empty());
|
EXPECT_TRUE(!prefix.empty());
|
||||||
std::stringstream ss;
|
return prefix + std::to_string(GetIDFromIndex(index));
|
||||||
ss << prefix << GetIDFromIndex(index);
|
}
|
||||||
return ss.str();
|
|
||||||
|
std::vector<uint8_t> GetIDBinary(const std::string& prefix, int index) const {
|
||||||
|
auto str = GetIDString(prefix, index);
|
||||||
|
return std::vector<uint8_t>(str.begin(), str.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SplitIDString(const std::string& str,
|
bool SplitIDString(const std::string& str,
|
||||||
@ -792,6 +824,19 @@ class MultiQueryManager : public CefMessageRouterBrowserSide::Handler {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SplitIDString(const CefRefPtr<const CefBinaryBuffer>& request,
|
||||||
|
std::string* value,
|
||||||
|
int* index) const {
|
||||||
|
const size_t string_len =
|
||||||
|
request->GetSize() / sizeof(std::string::value_type);
|
||||||
|
const auto* src =
|
||||||
|
static_cast<const std::string::value_type*>(request->GetData());
|
||||||
|
CefString result;
|
||||||
|
result.FromString(src, string_len);
|
||||||
|
|
||||||
|
return SplitIDString(result, value, index);
|
||||||
|
}
|
||||||
|
|
||||||
std::string GetIntString(int val) const {
|
std::string GetIntString(int val) const {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << val;
|
ss << val;
|
||||||
@ -804,6 +849,7 @@ class MultiQueryManager : public CefMessageRouterBrowserSide::Handler {
|
|||||||
const std::string label_;
|
const std::string label_;
|
||||||
const bool synchronous_;
|
const bool synchronous_;
|
||||||
const int id_offset_;
|
const int id_offset_;
|
||||||
|
const TransferType transfer_type_;
|
||||||
|
|
||||||
typedef std::vector<TestQuery> TestQueryVector;
|
typedef std::vector<TestQuery> TestQueryVector;
|
||||||
TestQueryVector test_query_vector_;
|
TestQueryVector test_query_vector_;
|
||||||
@ -904,8 +950,10 @@ class MultiQuerySingleFrameTestHandler : public SingleLoadTestHandler,
|
|||||||
|
|
||||||
MultiQuerySingleFrameTestHandler(
|
MultiQuerySingleFrameTestHandler(
|
||||||
bool synchronous,
|
bool synchronous,
|
||||||
|
TransferType transfer_type,
|
||||||
CancelType cancel_type = CANCEL_BY_NAVIGATION)
|
CancelType cancel_type = CANCEL_BY_NAVIGATION)
|
||||||
: manager_(std::string(), synchronous), cancel_type_(cancel_type) {
|
: manager_(std::string(), synchronous, 0, transfer_type),
|
||||||
|
cancel_type_(cancel_type) {
|
||||||
manager_.AddObserver(this);
|
manager_.AddObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -929,7 +977,20 @@ class MultiQuerySingleFrameTestHandler : public SingleLoadTestHandler,
|
|||||||
AssertMainBrowser(browser);
|
AssertMainBrowser(browser);
|
||||||
AssertMainFrame(frame);
|
AssertMainFrame(frame);
|
||||||
|
|
||||||
return manager_.OnQuery(browser, frame, query_id, request, persistent,
|
return manager_.OnQueryImpl(browser, frame, query_id, request, persistent,
|
||||||
|
callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||||
|
CefRefPtr<CefFrame> frame,
|
||||||
|
int64_t query_id,
|
||||||
|
CefRefPtr<const CefBinaryBuffer> request,
|
||||||
|
bool persistent,
|
||||||
|
CefRefPtr<Callback> callback) override {
|
||||||
|
AssertMainBrowser(browser);
|
||||||
|
AssertMainFrame(frame);
|
||||||
|
|
||||||
|
return manager_.OnQueryImpl(browser, frame, query_id, request, persistent,
|
||||||
callback);
|
callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -994,10 +1055,22 @@ class MultiQuerySingleFrameTestHandler : public SingleLoadTestHandler,
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
#define MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(name, type, synchronous) \
|
#define MQSF_TYPE_TEST(name, type, synchronous) \
|
||||||
TEST(MessageRouterTest, name) { \
|
TEST(MessageRouterTest, MultiQuerySingleFrame##name##String) { \
|
||||||
CefRefPtr<MultiQuerySingleFrameTestHandler> handler = \
|
CefRefPtr<MultiQuerySingleFrameTestHandler> handler = \
|
||||||
new MultiQuerySingleFrameTestHandler(synchronous); \
|
new MultiQuerySingleFrameTestHandler(synchronous, \
|
||||||
|
TransferType::STRING); \
|
||||||
|
MultiQueryManager* manager = handler->GetManager(); \
|
||||||
|
manager->AddTestQuery(MultiQueryManager::type); \
|
||||||
|
manager->Finalize(); \
|
||||||
|
handler->ExecuteTest(); \
|
||||||
|
ReleaseAndWaitForDestructor(handler); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
TEST(MessageRouterTest, MultiQuerySingleFrame##name##Binary) { \
|
||||||
|
CefRefPtr<MultiQuerySingleFrameTestHandler> handler = \
|
||||||
|
new MultiQuerySingleFrameTestHandler(synchronous, \
|
||||||
|
TransferType::BINARY); \
|
||||||
MultiQueryManager* manager = handler->GetManager(); \
|
MultiQueryManager* manager = handler->GetManager(); \
|
||||||
manager->AddTestQuery(MultiQueryManager::type); \
|
manager->AddTestQuery(MultiQueryManager::type); \
|
||||||
manager->Finalize(); \
|
manager->Finalize(); \
|
||||||
@ -1006,97 +1079,80 @@ class MultiQuerySingleFrameTestHandler : public SingleLoadTestHandler,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test the query types individually.
|
// Test the query types individually.
|
||||||
MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFrameSyncSuccess,
|
MQSF_TYPE_TEST(SyncSuccess, SUCCESS, true)
|
||||||
SUCCESS,
|
MQSF_TYPE_TEST(AsyncSuccess, SUCCESS, false)
|
||||||
true)
|
MQSF_TYPE_TEST(SyncFailure, FAILURE, true)
|
||||||
MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFrameAsyncSuccess,
|
MQSF_TYPE_TEST(AsyncFailure, FAILURE, false)
|
||||||
SUCCESS,
|
MQSF_TYPE_TEST(SyncPersistentSuccess, PERSISTENT_SUCCESS, true)
|
||||||
false)
|
MQSF_TYPE_TEST(AsyncPersistentSuccess, PERSISTENT_SUCCESS, false)
|
||||||
MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFrameSyncFailure,
|
MQSF_TYPE_TEST(SyncPersistentFailure, PERSISTENT_FAILURE, true)
|
||||||
FAILURE,
|
MQSF_TYPE_TEST(AsyncPersistentFailure, PERSISTENT_FAILURE, false)
|
||||||
true)
|
MQSF_TYPE_TEST(Cancel, CANCEL, true)
|
||||||
MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFrameAsyncFailure,
|
MQSF_TYPE_TEST(AutoCancel, AUTOCANCEL, true)
|
||||||
FAILURE,
|
MQSF_TYPE_TEST(PersistentAutoCancel, PERSISTENT_AUTOCANCEL, true)
|
||||||
false)
|
|
||||||
MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFrameSyncPersistentSuccess,
|
#define MQSF_QUERY_RANGE_TEST(name, some, synchronous) \
|
||||||
PERSISTENT_SUCCESS,
|
TEST(MessageRouterTest, MultiQuerySingleFrame##name##String) { \
|
||||||
true)
|
CefRefPtr<MultiQuerySingleFrameTestHandler> handler = \
|
||||||
MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFrameAsyncPersistentSuccess,
|
new MultiQuerySingleFrameTestHandler(synchronous, \
|
||||||
PERSISTENT_SUCCESS,
|
TransferType::STRING); \
|
||||||
false)
|
MakeTestQueries(handler->GetManager(), some); \
|
||||||
MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFrameSyncPersistentFailure,
|
handler->ExecuteTest(); \
|
||||||
PERSISTENT_FAILURE,
|
ReleaseAndWaitForDestructor(handler); \
|
||||||
true)
|
} \
|
||||||
MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFrameAsyncPersistentFailure,
|
\
|
||||||
PERSISTENT_FAILURE,
|
TEST(MessageRouterTest, MultiQuerySingleFrame##name##Binary) { \
|
||||||
false)
|
CefRefPtr<MultiQuerySingleFrameTestHandler> handler = \
|
||||||
MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFrameCancel, CANCEL, true)
|
new MultiQuerySingleFrameTestHandler(synchronous, \
|
||||||
MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFrameAutoCancel,
|
TransferType::BINARY); \
|
||||||
AUTOCANCEL,
|
MakeTestQueries(handler->GetManager(), some); \
|
||||||
true)
|
handler->ExecuteTest(); \
|
||||||
MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFramePersistentAutoCancel,
|
ReleaseAndWaitForDestructor(handler); \
|
||||||
PERSISTENT_AUTOCANCEL,
|
}
|
||||||
true)
|
|
||||||
|
|
||||||
// Test that one frame can run some queries successfully in a synchronous
|
// Test that one frame can run some queries successfully in a synchronous
|
||||||
// manner.
|
// manner
|
||||||
TEST(MessageRouterTest, MultiQuerySingleFrameSyncSome) {
|
MQSF_QUERY_RANGE_TEST(SyncSome, true, true)
|
||||||
CefRefPtr<MultiQuerySingleFrameTestHandler> handler =
|
|
||||||
new MultiQuerySingleFrameTestHandler(true);
|
|
||||||
MakeTestQueries(handler->GetManager(), true);
|
|
||||||
handler->ExecuteTest();
|
|
||||||
ReleaseAndWaitForDestructor(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that one frame can run some queries successfully in an asynchronous
|
// Test that one frame can run some queries successfully in an asynchronous
|
||||||
// manner.
|
// manner.
|
||||||
TEST(MessageRouterTest, MultiQuerySingleFrameAsyncSome) {
|
MQSF_QUERY_RANGE_TEST(AsyncSome, true, false)
|
||||||
CefRefPtr<MultiQuerySingleFrameTestHandler> handler =
|
|
||||||
new MultiQuerySingleFrameTestHandler(false);
|
|
||||||
MakeTestQueries(handler->GetManager(), true);
|
|
||||||
handler->ExecuteTest();
|
|
||||||
ReleaseAndWaitForDestructor(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that one frame can run many queries successfully in a synchronous
|
// Test that one frame can run many queries successfully in a synchronous
|
||||||
// manner.
|
// manner.
|
||||||
TEST(MessageRouterTest, MultiQuerySingleFrameSyncMany) {
|
MQSF_QUERY_RANGE_TEST(SyncMany, false, true)
|
||||||
CefRefPtr<MultiQuerySingleFrameTestHandler> handler =
|
|
||||||
new MultiQuerySingleFrameTestHandler(true);
|
|
||||||
MakeTestQueries(handler->GetManager(), false);
|
|
||||||
handler->ExecuteTest();
|
|
||||||
ReleaseAndWaitForDestructor(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that one frame can run many queries successfully in an asynchronous
|
// Test that one frame can run many queries successfully in an asynchronous
|
||||||
// manner.
|
// manner.
|
||||||
TEST(MessageRouterTest, MultiQuerySingleFrameAsyncMany) {
|
MQSF_QUERY_RANGE_TEST(AsyncMany, false, false)
|
||||||
CefRefPtr<MultiQuerySingleFrameTestHandler> handler =
|
|
||||||
new MultiQuerySingleFrameTestHandler(false);
|
#define MQSF_QUERY_RANGE_CANCEL_TEST(name, cancelType) \
|
||||||
MakeTestQueries(handler->GetManager(), false);
|
TEST(MessageRouterTest, MultiQuerySingleFrame##name##String) { \
|
||||||
handler->ExecuteTest();
|
CefRefPtr<MultiQuerySingleFrameTestHandler> handler = \
|
||||||
ReleaseAndWaitForDestructor(handler);
|
new MultiQuerySingleFrameTestHandler( \
|
||||||
|
false, TransferType::STRING, \
|
||||||
|
MultiQuerySingleFrameTestHandler::cancelType); \
|
||||||
|
MakeTestQueries(handler->GetManager(), false); \
|
||||||
|
handler->ExecuteTest(); \
|
||||||
|
ReleaseAndWaitForDestructor(handler); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
TEST(MessageRouterTest, MultiQuerySingleFrame##name##Binary) { \
|
||||||
|
CefRefPtr<MultiQuerySingleFrameTestHandler> handler = \
|
||||||
|
new MultiQuerySingleFrameTestHandler( \
|
||||||
|
false, TransferType::BINARY, \
|
||||||
|
MultiQuerySingleFrameTestHandler::cancelType); \
|
||||||
|
MakeTestQueries(handler->GetManager(), false); \
|
||||||
|
handler->ExecuteTest(); \
|
||||||
|
ReleaseAndWaitForDestructor(handler); \
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that pending queries can be canceled by removing the handler.
|
// Test that pending queries can be canceled by removing the handler.
|
||||||
TEST(MessageRouterTest, MultiQuerySingleFrameCancelByRemovingHandler) {
|
MQSF_QUERY_RANGE_CANCEL_TEST(CancelByRemovingHandler,
|
||||||
CefRefPtr<MultiQuerySingleFrameTestHandler> handler =
|
CANCEL_BY_REMOVING_HANDLER)
|
||||||
new MultiQuerySingleFrameTestHandler(
|
|
||||||
false, MultiQuerySingleFrameTestHandler::CANCEL_BY_REMOVING_HANDLER);
|
|
||||||
MakeTestQueries(handler->GetManager(), false);
|
|
||||||
handler->ExecuteTest();
|
|
||||||
ReleaseAndWaitForDestructor(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that pending queries can be canceled by closing the browser.
|
// Test that pending queries can be canceled by closing the browser.
|
||||||
TEST(MessageRouterTest, MultiQuerySingleFrameCancelByClosingBrowser) {
|
MQSF_QUERY_RANGE_CANCEL_TEST(CancelByClosingBrowser, CANCEL_BY_CLOSING_BROWSER)
|
||||||
CefRefPtr<MultiQuerySingleFrameTestHandler> handler =
|
|
||||||
new MultiQuerySingleFrameTestHandler(
|
|
||||||
false, MultiQuerySingleFrameTestHandler::CANCEL_BY_CLOSING_BROWSER);
|
|
||||||
MakeTestQueries(handler->GetManager(), false);
|
|
||||||
handler->ExecuteTest();
|
|
||||||
ReleaseAndWaitForDestructor(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@ -1211,7 +1267,20 @@ class MultiQueryMultiHandlerTestHandler : public SingleLoadTestHandler,
|
|||||||
AssertMainBrowser(browser);
|
AssertMainBrowser(browser);
|
||||||
AssertMainFrame(frame);
|
AssertMainFrame(frame);
|
||||||
|
|
||||||
return manager_.OnQuery(browser, frame, query_id, request, persistent,
|
return manager_.OnQueryImpl(browser, frame, query_id, request, persistent,
|
||||||
|
callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||||
|
CefRefPtr<CefFrame> frame,
|
||||||
|
int64_t query_id,
|
||||||
|
CefRefPtr<const CefBinaryBuffer> request,
|
||||||
|
bool persistent,
|
||||||
|
CefRefPtr<Callback> callback) override {
|
||||||
|
AssertMainBrowser(browser);
|
||||||
|
AssertMainFrame(frame);
|
||||||
|
|
||||||
|
return manager_.OnQueryImpl(browser, frame, query_id, request, persistent,
|
||||||
callback);
|
callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1334,8 +1403,7 @@ TEST(MessageRouterTest, MultiQueryMultiHandlerCancelByRemovingHandler) {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Map of managers on a per-URL basis.
|
// Map of managers on a per-URL basis.
|
||||||
class MultiQueryManagerMap : public CefMessageRouterBrowserSide::Handler,
|
class MultiQueryManagerMap : public MultiQueryManager::Observer {
|
||||||
public MultiQueryManager::Observer {
|
|
||||||
public:
|
public:
|
||||||
class Observer {
|
class Observer {
|
||||||
public:
|
public:
|
||||||
@ -1367,11 +1435,14 @@ class MultiQueryManagerMap : public CefMessageRouterBrowserSide::Handler,
|
|||||||
EXPECT_TRUE(observer_set_.erase(observer));
|
EXPECT_TRUE(observer_set_.erase(observer));
|
||||||
}
|
}
|
||||||
|
|
||||||
MultiQueryManager* CreateManager(const std::string& url, bool synchronous) {
|
MultiQueryManager* CreateManager(const std::string& url,
|
||||||
|
bool synchronous,
|
||||||
|
TransferType transfer_type) {
|
||||||
EXPECT_FALSE(finalized_);
|
EXPECT_FALSE(finalized_);
|
||||||
|
|
||||||
MultiQueryManager* manager = new MultiQueryManager(
|
MultiQueryManager* manager = new MultiQueryManager(
|
||||||
url, synchronous, static_cast<int>(manager_map_.size()) * 1000);
|
url, synchronous, static_cast<int>(manager_map_.size()) * 1000,
|
||||||
|
transfer_type);
|
||||||
manager->AddObserver(this);
|
manager->AddObserver(this);
|
||||||
all_managers_.push_back(manager);
|
all_managers_.push_back(manager);
|
||||||
pending_managers_.push_back(manager);
|
pending_managers_.push_back(manager);
|
||||||
@ -1412,25 +1483,26 @@ class MultiQueryManagerMap : public CefMessageRouterBrowserSide::Handler,
|
|||||||
manager->OnNotify(browser, frame, message);
|
manager->OnNotify(browser, frame, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OnQuery(CefRefPtr<CefBrowser> browser,
|
template <class RequestType>
|
||||||
|
bool OnQueryImpl(CefRefPtr<CefBrowser> browser,
|
||||||
CefRefPtr<CefFrame> frame,
|
CefRefPtr<CefFrame> frame,
|
||||||
int64_t query_id,
|
int64_t query_id,
|
||||||
const CefString& request,
|
const RequestType& request,
|
||||||
bool persistent,
|
bool persistent,
|
||||||
CefRefPtr<Callback> callback) override {
|
CefRefPtr<CefMessageRouterBrowserSide::Callback> callback) {
|
||||||
EXPECT_TRUE(finalized_);
|
EXPECT_TRUE(finalized_);
|
||||||
if (!running_) {
|
if (!running_) {
|
||||||
running_ = true;
|
running_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MultiQueryManager* manager = GetManager(browser, frame);
|
MultiQueryManager* manager = GetManager(browser, frame);
|
||||||
return manager->OnQuery(browser, frame, query_id, request, persistent,
|
return manager->OnQueryImpl(browser, frame, query_id, request, persistent,
|
||||||
callback);
|
callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
|
void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
|
||||||
CefRefPtr<CefFrame> frame,
|
CefRefPtr<CefFrame> frame,
|
||||||
int64_t query_id) override {
|
int64_t query_id) {
|
||||||
EXPECT_TRUE(finalized_);
|
EXPECT_TRUE(finalized_);
|
||||||
if (!running_) {
|
if (!running_) {
|
||||||
running_ = true;
|
running_ = true;
|
||||||
@ -1611,8 +1683,12 @@ class MultiQueryManagerMap : public CefMessageRouterBrowserSide::Handler,
|
|||||||
class MultiQueryMultiFrameTestHandler : public SingleLoadTestHandler,
|
class MultiQueryMultiFrameTestHandler : public SingleLoadTestHandler,
|
||||||
public MultiQueryManagerMap::Observer {
|
public MultiQueryManagerMap::Observer {
|
||||||
public:
|
public:
|
||||||
MultiQueryMultiFrameTestHandler(bool synchronous, bool cancel_with_subnav)
|
MultiQueryMultiFrameTestHandler(bool synchronous,
|
||||||
: synchronous_(synchronous), cancel_with_subnav_(cancel_with_subnav) {
|
bool cancel_with_subnav,
|
||||||
|
TransferType transfer_type)
|
||||||
|
: synchronous_(synchronous),
|
||||||
|
cancel_with_subnav_(cancel_with_subnav),
|
||||||
|
transfer_type_(transfer_type) {
|
||||||
manager_map_.AddObserver(this);
|
manager_map_.AddObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1657,8 +1733,21 @@ class MultiQueryMultiFrameTestHandler : public SingleLoadTestHandler,
|
|||||||
AssertMainBrowser(browser);
|
AssertMainBrowser(browser);
|
||||||
EXPECT_FALSE(frame->IsMain());
|
EXPECT_FALSE(frame->IsMain());
|
||||||
|
|
||||||
return manager_map_.OnQuery(browser, frame, query_id, request, persistent,
|
return manager_map_.OnQueryImpl(browser, frame, query_id, request,
|
||||||
callback);
|
persistent, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||||
|
CefRefPtr<CefFrame> frame,
|
||||||
|
int64_t query_id,
|
||||||
|
CefRefPtr<const CefBinaryBuffer> request,
|
||||||
|
bool persistent,
|
||||||
|
CefRefPtr<Callback> callback) override {
|
||||||
|
AssertMainBrowser(browser);
|
||||||
|
EXPECT_FALSE(frame->IsMain());
|
||||||
|
|
||||||
|
return manager_map_.OnQueryImpl(browser, frame, query_id, request,
|
||||||
|
persistent, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
|
void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
|
||||||
@ -1709,7 +1798,8 @@ class MultiQueryMultiFrameTestHandler : public SingleLoadTestHandler,
|
|||||||
void AddSubFrameResource(const std::string& name) {
|
void AddSubFrameResource(const std::string& name) {
|
||||||
const std::string& url = std::string(kTestDomain1) + name + ".html";
|
const std::string& url = std::string(kTestDomain1) + name + ".html";
|
||||||
|
|
||||||
MultiQueryManager* manager = manager_map_.CreateManager(url, synchronous_);
|
MultiQueryManager* manager =
|
||||||
|
manager_map_.CreateManager(url, synchronous_, transfer_type_);
|
||||||
MakeTestQueries(manager, false, 100);
|
MakeTestQueries(manager, false, 100);
|
||||||
|
|
||||||
const std::string& html = manager->GetHTML(false, false);
|
const std::string& html = manager->GetHTML(false, false);
|
||||||
@ -1718,6 +1808,7 @@ class MultiQueryMultiFrameTestHandler : public SingleLoadTestHandler,
|
|||||||
|
|
||||||
const bool synchronous_;
|
const bool synchronous_;
|
||||||
const bool cancel_with_subnav_;
|
const bool cancel_with_subnav_;
|
||||||
|
const TransferType transfer_type_;
|
||||||
|
|
||||||
MultiQueryManagerMap manager_map_;
|
MultiQueryManagerMap manager_map_;
|
||||||
|
|
||||||
@ -1726,41 +1817,38 @@ class MultiQueryMultiFrameTestHandler : public SingleLoadTestHandler,
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
#define MQMF_TEST(name, sync, cancel_with_subnav) \
|
||||||
|
TEST(MessageRouterTest, MultiQueryMultiFrame##name##String) { \
|
||||||
|
CefRefPtr<MultiQueryMultiFrameTestHandler> handler = \
|
||||||
|
new MultiQueryMultiFrameTestHandler(sync, cancel_with_subnav, \
|
||||||
|
TransferType::STRING); \
|
||||||
|
handler->ExecuteTest(); \
|
||||||
|
ReleaseAndWaitForDestructor(handler); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
TEST(MessageRouterTest, MultiQueryMultiFrame##name##Binary) { \
|
||||||
|
CefRefPtr<MultiQueryMultiFrameTestHandler> handler = \
|
||||||
|
new MultiQueryMultiFrameTestHandler(sync, cancel_with_subnav, \
|
||||||
|
TransferType::BINARY); \
|
||||||
|
handler->ExecuteTest(); \
|
||||||
|
ReleaseAndWaitForDestructor(handler); \
|
||||||
|
}
|
||||||
|
|
||||||
// Test that multiple frames can run many queries successfully in a synchronous
|
// Test that multiple frames can run many queries successfully in a synchronous
|
||||||
// manner.
|
// manner.
|
||||||
TEST(MessageRouterTest, MultiQueryMultiFrameSync) {
|
MQMF_TEST(Sync, true, false)
|
||||||
CefRefPtr<MultiQueryMultiFrameTestHandler> handler =
|
|
||||||
new MultiQueryMultiFrameTestHandler(true, false);
|
|
||||||
handler->ExecuteTest();
|
|
||||||
ReleaseAndWaitForDestructor(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that multiple frames can run many queries successfully in an
|
// Test that multiple frames can run many queries successfully in an
|
||||||
// asynchronous manner.
|
// asynchronous manner.
|
||||||
TEST(MessageRouterTest, MultiQueryMultiFrameAsync) {
|
MQMF_TEST(Async, false, false)
|
||||||
CefRefPtr<MultiQueryMultiFrameTestHandler> handler =
|
|
||||||
new MultiQueryMultiFrameTestHandler(false, false);
|
|
||||||
handler->ExecuteTest();
|
|
||||||
ReleaseAndWaitForDestructor(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that multiple frames can run many queries successfully in a synchronous
|
// Test that multiple frames can run many queries successfully in a synchronous
|
||||||
// manner. Cancel auto queries with sub-frame navigation.
|
// manner. Cancel auto queries with sub-frame navigation.
|
||||||
TEST(MessageRouterTest, MultiQueryMultiFrameSyncSubnavCancel) {
|
MQMF_TEST(SyncSubnavCancel, true, true)
|
||||||
CefRefPtr<MultiQueryMultiFrameTestHandler> handler =
|
|
||||||
new MultiQueryMultiFrameTestHandler(true, true);
|
|
||||||
handler->ExecuteTest();
|
|
||||||
ReleaseAndWaitForDestructor(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that multiple frames can run many queries successfully in an
|
// Test that multiple frames can run many queries successfully in an
|
||||||
// asynchronous manner. Cancel auto queries with sub-frame navigation.
|
// asynchronous manner. Cancel auto queries with sub-frame navigation.
|
||||||
TEST(MessageRouterTest, MultiQueryMultiFrameAsyncSubnavCancel) {
|
MQMF_TEST(AsyncSubnavCancel, false, true)
|
||||||
CefRefPtr<MultiQueryMultiFrameTestHandler> handler =
|
|
||||||
new MultiQueryMultiFrameTestHandler(false, true);
|
|
||||||
handler->ExecuteTest();
|
|
||||||
ReleaseAndWaitForDestructor(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@ -1772,8 +1860,10 @@ class MultiQueryMultiLoadTestHandler
|
|||||||
public MultiQueryManagerMap::Observer,
|
public MultiQueryManagerMap::Observer,
|
||||||
public MultiQueryManager::Observer {
|
public MultiQueryManager::Observer {
|
||||||
public:
|
public:
|
||||||
MultiQueryMultiLoadTestHandler(bool some, bool synchronous)
|
MultiQueryMultiLoadTestHandler(bool some,
|
||||||
: some_(some), synchronous_(synchronous) {
|
bool synchronous,
|
||||||
|
TransferType transfer_type)
|
||||||
|
: some_(some), synchronous_(synchronous), transfer_type_(transfer_type) {
|
||||||
manager_map_.AddObserver(this);
|
manager_map_.AddObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1795,8 +1885,18 @@ class MultiQueryMultiLoadTestHandler
|
|||||||
const CefString& request,
|
const CefString& request,
|
||||||
bool persistent,
|
bool persistent,
|
||||||
CefRefPtr<Callback> callback) override {
|
CefRefPtr<Callback> callback) override {
|
||||||
return manager_map_.OnQuery(browser, frame, query_id, request, persistent,
|
return manager_map_.OnQueryImpl(browser, frame, query_id, request,
|
||||||
callback);
|
persistent, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||||
|
CefRefPtr<CefFrame> frame,
|
||||||
|
int64_t query_id,
|
||||||
|
CefRefPtr<const CefBinaryBuffer> request,
|
||||||
|
bool persistent,
|
||||||
|
CefRefPtr<Callback> callback) override {
|
||||||
|
return manager_map_.OnQueryImpl(browser, frame, query_id, request,
|
||||||
|
persistent, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
|
void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
|
||||||
@ -1838,7 +1938,8 @@ class MultiQueryMultiLoadTestHandler
|
|||||||
void AddManagedResource(const std::string& url,
|
void AddManagedResource(const std::string& url,
|
||||||
bool assert_total,
|
bool assert_total,
|
||||||
bool assert_browser) {
|
bool assert_browser) {
|
||||||
MultiQueryManager* manager = manager_map_.CreateManager(url, synchronous_);
|
MultiQueryManager* manager =
|
||||||
|
manager_map_.CreateManager(url, synchronous_, transfer_type_);
|
||||||
manager->AddObserver(this);
|
manager->AddObserver(this);
|
||||||
MakeTestQueries(manager, some_, 75);
|
MakeTestQueries(manager, some_, 75);
|
||||||
|
|
||||||
@ -1860,6 +1961,7 @@ class MultiQueryMultiLoadTestHandler
|
|||||||
private:
|
private:
|
||||||
const bool some_;
|
const bool some_;
|
||||||
const bool synchronous_;
|
const bool synchronous_;
|
||||||
|
const TransferType transfer_type_;
|
||||||
|
|
||||||
std::string cancel_url_;
|
std::string cancel_url_;
|
||||||
};
|
};
|
||||||
@ -1868,8 +1970,10 @@ class MultiQueryMultiLoadTestHandler
|
|||||||
class MultiQueryMultiBrowserTestHandler
|
class MultiQueryMultiBrowserTestHandler
|
||||||
: public MultiQueryMultiLoadTestHandler {
|
: public MultiQueryMultiLoadTestHandler {
|
||||||
public:
|
public:
|
||||||
MultiQueryMultiBrowserTestHandler(bool synchronous, bool same_origin)
|
MultiQueryMultiBrowserTestHandler(bool synchronous,
|
||||||
: MultiQueryMultiLoadTestHandler(false, synchronous),
|
bool same_origin,
|
||||||
|
TransferType transfer_type)
|
||||||
|
: MultiQueryMultiLoadTestHandler(false, synchronous, transfer_type),
|
||||||
same_origin_(same_origin) {}
|
same_origin_(same_origin) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -1899,37 +2003,34 @@ class MultiQueryMultiBrowserTestHandler
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// Test that multiple browsers can query simultaniously from the same origin.
|
#define MQMB_TEST(name, sync, same_origin) \
|
||||||
TEST(MessageRouterTest, MultiQueryMultiBrowserSameOriginSync) {
|
TEST(MessageRouterTest, MultiQueryMultiBrowser##name##String) { \
|
||||||
CefRefPtr<MultiQueryMultiBrowserTestHandler> handler =
|
CefRefPtr<MultiQueryMultiBrowserTestHandler> handler = \
|
||||||
new MultiQueryMultiBrowserTestHandler(true, true);
|
new MultiQueryMultiBrowserTestHandler(sync, same_origin, \
|
||||||
handler->ExecuteTest();
|
TransferType::STRING); \
|
||||||
ReleaseAndWaitForDestructor(handler);
|
handler->ExecuteTest(); \
|
||||||
|
ReleaseAndWaitForDestructor(handler); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
TEST(MessageRouterTest, MultiQueryMultiBrowser##name##Binary) { \
|
||||||
|
CefRefPtr<MultiQueryMultiBrowserTestHandler> handler = \
|
||||||
|
new MultiQueryMultiBrowserTestHandler(sync, same_origin, \
|
||||||
|
TransferType::BINARY); \
|
||||||
|
handler->ExecuteTest(); \
|
||||||
|
ReleaseAndWaitForDestructor(handler); \
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that multiple browsers can query simultaniously from the same origin.
|
// Test that multiple browsers can query simultaniously from the same origin.
|
||||||
TEST(MessageRouterTest, MultiQueryMultiBrowserSameOriginAsync) {
|
MQMB_TEST(SameOriginSync, true, true)
|
||||||
CefRefPtr<MultiQueryMultiBrowserTestHandler> handler =
|
|
||||||
new MultiQueryMultiBrowserTestHandler(false, true);
|
// Test that multiple browsers can query simultaniously from the same origin.
|
||||||
handler->ExecuteTest();
|
MQMB_TEST(SameOriginAsync, false, true)
|
||||||
ReleaseAndWaitForDestructor(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that multiple browsers can query simultaniously from different origins.
|
// Test that multiple browsers can query simultaniously from different origins.
|
||||||
TEST(MessageRouterTest, MultiQueryMultiBrowserDifferentOriginSync) {
|
MQMB_TEST(DifferentOriginSync, true, false)
|
||||||
CefRefPtr<MultiQueryMultiBrowserTestHandler> handler =
|
|
||||||
new MultiQueryMultiBrowserTestHandler(true, false);
|
|
||||||
handler->ExecuteTest();
|
|
||||||
ReleaseAndWaitForDestructor(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that multiple browsers can query simultaniously from different origins.
|
// Test that multiple browsers can query simultaniously from different origins.
|
||||||
TEST(MessageRouterTest, MultiQueryMultiBrowserDifferentOriginAsync) {
|
MQMB_TEST(DifferentOriginAsync, false, false)
|
||||||
CefRefPtr<MultiQueryMultiBrowserTestHandler> handler =
|
|
||||||
new MultiQueryMultiBrowserTestHandler(false, false);
|
|
||||||
handler->ExecuteTest();
|
|
||||||
ReleaseAndWaitForDestructor(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@ -1937,8 +2038,10 @@ namespace {
|
|||||||
class MultiQueryMultiNavigateTestHandler
|
class MultiQueryMultiNavigateTestHandler
|
||||||
: public MultiQueryMultiLoadTestHandler {
|
: public MultiQueryMultiLoadTestHandler {
|
||||||
public:
|
public:
|
||||||
MultiQueryMultiNavigateTestHandler(bool synchronous, bool same_origin)
|
MultiQueryMultiNavigateTestHandler(bool synchronous,
|
||||||
: MultiQueryMultiLoadTestHandler(false, synchronous),
|
bool same_origin,
|
||||||
|
TransferType transfer_type)
|
||||||
|
: MultiQueryMultiLoadTestHandler(false, synchronous, transfer_type),
|
||||||
same_origin_(same_origin) {}
|
same_origin_(same_origin) {}
|
||||||
|
|
||||||
void OnManualQueriesCompleted(MultiQueryManager* manager) override {
|
void OnManualQueriesCompleted(MultiQueryManager* manager) override {
|
||||||
@ -1981,34 +2084,31 @@ class MultiQueryMultiNavigateTestHandler
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// Test that multiple navigations can query from the same origin.
|
#define MQMN_TEST(name, sync, same_origin) \
|
||||||
TEST(MessageRouterTest, MultiQueryMultiNavigateSameOriginSync) {
|
TEST(MessageRouterTest, MultiQueryMultiNavigate##name##String) { \
|
||||||
CefRefPtr<MultiQueryMultiNavigateTestHandler> handler =
|
CefRefPtr<MultiQueryMultiNavigateTestHandler> handler = \
|
||||||
new MultiQueryMultiNavigateTestHandler(true, true);
|
new MultiQueryMultiNavigateTestHandler(sync, same_origin, \
|
||||||
handler->ExecuteTest();
|
TransferType::STRING); \
|
||||||
ReleaseAndWaitForDestructor(handler);
|
handler->ExecuteTest(); \
|
||||||
|
ReleaseAndWaitForDestructor(handler); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
TEST(MessageRouterTest, MultiQueryMultiNavigate##name##Binary) { \
|
||||||
|
CefRefPtr<MultiQueryMultiNavigateTestHandler> handler = \
|
||||||
|
new MultiQueryMultiNavigateTestHandler(sync, same_origin, \
|
||||||
|
TransferType::BINARY); \
|
||||||
|
handler->ExecuteTest(); \
|
||||||
|
ReleaseAndWaitForDestructor(handler); \
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that multiple navigations can query from the same origin.
|
// Test that multiple navigations can query from the same origin.
|
||||||
TEST(MessageRouterTest, MultiQueryMultiNavigateSameOriginAsync) {
|
MQMN_TEST(SameOriginSync, true, true)
|
||||||
CefRefPtr<MultiQueryMultiNavigateTestHandler> handler =
|
|
||||||
new MultiQueryMultiNavigateTestHandler(false, true);
|
// Test that multiple navigations can query from the same origin.
|
||||||
handler->ExecuteTest();
|
MQMN_TEST(SameOriginAsync, false, true)
|
||||||
ReleaseAndWaitForDestructor(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that multiple navigations can query from different origins.
|
// Test that multiple navigations can query from different origins.
|
||||||
TEST(MessageRouterTest, MultiQueryMultiNavigateDifferentOriginSync) {
|
MQMN_TEST(DifferentOriginSync, true, false)
|
||||||
CefRefPtr<MultiQueryMultiNavigateTestHandler> handler =
|
|
||||||
new MultiQueryMultiNavigateTestHandler(true, false);
|
|
||||||
handler->ExecuteTest();
|
|
||||||
ReleaseAndWaitForDestructor(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that multiple navigations can query from different origins.
|
// Test that multiple navigations can query from different origins.
|
||||||
TEST(MessageRouterTest, MultiQueryMultiNavigateDifferentOriginAsync) {
|
MQMN_TEST(DifferentOriginAsync, false, false)
|
||||||
CefRefPtr<MultiQueryMultiNavigateTestHandler> handler =
|
|
||||||
new MultiQueryMultiNavigateTestHandler(false, false);
|
|
||||||
handler->ExecuteTest();
|
|
||||||
ReleaseAndWaitForDestructor(handler);
|
|
||||||
}
|
|
||||||
|
@ -59,6 +59,7 @@ enum V8TestMode {
|
|||||||
V8TEST_ARRAY_CREATE,
|
V8TEST_ARRAY_CREATE,
|
||||||
V8TEST_ARRAY_VALUE,
|
V8TEST_ARRAY_VALUE,
|
||||||
V8TEST_ARRAY_BUFFER,
|
V8TEST_ARRAY_BUFFER,
|
||||||
|
V8TEST_ARRAY_BUFFER_CREATE_EMPTY,
|
||||||
V8TEST_ARRAY_BUFFER_VALUE,
|
V8TEST_ARRAY_BUFFER_VALUE,
|
||||||
V8TEST_OBJECT_CREATE,
|
V8TEST_OBJECT_CREATE,
|
||||||
V8TEST_OBJECT_USERDATA,
|
V8TEST_OBJECT_USERDATA,
|
||||||
@ -145,6 +146,9 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
|||||||
case V8TEST_ARRAY_BUFFER:
|
case V8TEST_ARRAY_BUFFER:
|
||||||
RunArrayBufferTest();
|
RunArrayBufferTest();
|
||||||
break;
|
break;
|
||||||
|
case V8TEST_ARRAY_BUFFER_CREATE_EMPTY:
|
||||||
|
RunArrayBufferCreateEmptyTest();
|
||||||
|
break;
|
||||||
case V8TEST_ARRAY_BUFFER_VALUE:
|
case V8TEST_ARRAY_BUFFER_VALUE:
|
||||||
RunArrayBufferValueTest();
|
RunArrayBufferValueTest();
|
||||||
break;
|
break;
|
||||||
@ -593,6 +597,9 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
|||||||
EXPECT_TRUE(value.get());
|
EXPECT_TRUE(value.get());
|
||||||
EXPECT_TRUE(value->IsArrayBuffer());
|
EXPECT_TRUE(value->IsArrayBuffer());
|
||||||
EXPECT_TRUE(value->IsObject());
|
EXPECT_TRUE(value->IsObject());
|
||||||
|
EXPECT_EQ(value->GetArrayBufferByteLength(), sizeof(static_data));
|
||||||
|
void* data = value->GetArrayBufferData();
|
||||||
|
EXPECT_EQ(static_cast<int*>(data), static_data);
|
||||||
EXPECT_FALSE(value->HasValue(0));
|
EXPECT_FALSE(value->HasValue(0));
|
||||||
EXPECT_TRUE(value->GetArrayBufferReleaseCallback().get() != nullptr);
|
EXPECT_TRUE(value->GetArrayBufferReleaseCallback().get() != nullptr);
|
||||||
EXPECT_TRUE(((TestArrayBufferReleaseCallback*)value
|
EXPECT_TRUE(((TestArrayBufferReleaseCallback*)value
|
||||||
@ -636,6 +643,9 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
|||||||
static_data[0] = 3;
|
static_data[0] = 3;
|
||||||
value =
|
value =
|
||||||
CefV8Value::CreateArrayBuffer(static_data, sizeof(static_data), owner);
|
CefV8Value::CreateArrayBuffer(static_data, sizeof(static_data), owner);
|
||||||
|
EXPECT_EQ(value->GetArrayBufferByteLength(), sizeof(static_data));
|
||||||
|
void* data = value->GetArrayBufferData();
|
||||||
|
EXPECT_EQ(static_cast<int*>(data), static_data);
|
||||||
|
|
||||||
CefRefPtr<CefV8Value> object = context->GetGlobal();
|
CefRefPtr<CefV8Value> object = context->GetGlobal();
|
||||||
EXPECT_TRUE(object.get());
|
EXPECT_TRUE(object.get());
|
||||||
@ -649,8 +659,43 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
|||||||
ADD_FAILURE() << exception->GetMessage().c_str();
|
ADD_FAILURE() << exception->GetMessage().c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPECT_TRUE(static_data[0] == 19);
|
EXPECT_EQ(static_data[0], 19);
|
||||||
EXPECT_TRUE(value->GetArrayBufferReleaseCallback().get() != nullptr);
|
EXPECT_NE(value->GetArrayBufferReleaseCallback().get(), nullptr);
|
||||||
|
EXPECT_TRUE(value->NeuterArrayBuffer());
|
||||||
|
|
||||||
|
// Exit the V8 context.
|
||||||
|
EXPECT_TRUE(context->Exit());
|
||||||
|
DestroyTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunArrayBufferCreateEmptyTest() {
|
||||||
|
class TestArrayBufferReleaseCallback
|
||||||
|
: public CefV8ArrayBufferReleaseCallback {
|
||||||
|
public:
|
||||||
|
void ReleaseBuffer(void* buffer) override {}
|
||||||
|
|
||||||
|
IMPLEMENT_REFCOUNTING(TestArrayBufferReleaseCallback);
|
||||||
|
};
|
||||||
|
|
||||||
|
CefRefPtr<TestArrayBufferReleaseCallback> owner =
|
||||||
|
new TestArrayBufferReleaseCallback();
|
||||||
|
|
||||||
|
// Enter the V8 context
|
||||||
|
CefRefPtr<CefV8Context> context = GetContext();
|
||||||
|
EXPECT_TRUE(context->Enter());
|
||||||
|
|
||||||
|
const size_t zero_size = 0;
|
||||||
|
void* null_data = nullptr;
|
||||||
|
|
||||||
|
CefRefPtr<CefV8Value> value =
|
||||||
|
CefV8Value::CreateArrayBuffer(null_data, zero_size, owner);
|
||||||
|
EXPECT_EQ(value->GetArrayBufferByteLength(), zero_size);
|
||||||
|
EXPECT_EQ(value->GetArrayBufferData(), null_data);
|
||||||
|
|
||||||
|
CefRefPtr<CefV8Value> object = context->GetGlobal();
|
||||||
|
EXPECT_TRUE(object.get());
|
||||||
|
EXPECT_TRUE(object->SetValue("arr", value, V8_PROPERTY_ATTRIBUTE_NONE));
|
||||||
|
EXPECT_NE(value->GetArrayBufferReleaseCallback().get(), nullptr);
|
||||||
EXPECT_TRUE(value->NeuterArrayBuffer());
|
EXPECT_TRUE(value->NeuterArrayBuffer());
|
||||||
|
|
||||||
// Exit the V8 context.
|
// Exit the V8 context.
|
||||||
@ -3321,6 +3366,7 @@ V8_TEST(EmptyStringCreate, V8TEST_EMPTY_STRING_CREATE)
|
|||||||
V8_TEST(ArrayCreate, V8TEST_ARRAY_CREATE)
|
V8_TEST(ArrayCreate, V8TEST_ARRAY_CREATE)
|
||||||
V8_TEST(ArrayValue, V8TEST_ARRAY_VALUE)
|
V8_TEST(ArrayValue, V8TEST_ARRAY_VALUE)
|
||||||
V8_TEST(ArrayBuffer, V8TEST_ARRAY_BUFFER)
|
V8_TEST(ArrayBuffer, V8TEST_ARRAY_BUFFER)
|
||||||
|
V8_TEST(ArrayBufferCreateEmpty, V8TEST_ARRAY_BUFFER_CREATE_EMPTY)
|
||||||
V8_TEST(ArrayBufferValue, V8TEST_ARRAY_BUFFER_VALUE)
|
V8_TEST(ArrayBufferValue, V8TEST_ARRAY_BUFFER_VALUE)
|
||||||
V8_TEST(ObjectCreate, V8TEST_OBJECT_CREATE)
|
V8_TEST(ObjectCreate, V8TEST_OBJECT_CREATE)
|
||||||
V8_TEST(ObjectUserData, V8TEST_OBJECT_USERDATA)
|
V8_TEST(ObjectUserData, V8TEST_OBJECT_USERDATA)
|
||||||
|
@ -44,12 +44,12 @@ const char* kStringValue = "My string value";
|
|||||||
void TestBinary(CefRefPtr<CefBinaryValue> value, char* data, size_t data_size) {
|
void TestBinary(CefRefPtr<CefBinaryValue> value, char* data, size_t data_size) {
|
||||||
// Testing requires strings longer than 15 characters.
|
// Testing requires strings longer than 15 characters.
|
||||||
EXPECT_GT(data_size, 15U);
|
EXPECT_GT(data_size, 15U);
|
||||||
|
|
||||||
EXPECT_EQ(data_size, value->GetSize());
|
EXPECT_EQ(data_size, value->GetSize());
|
||||||
|
|
||||||
char* buff = new char[data_size + 1];
|
// Test direct access.
|
||||||
char old_char;
|
EXPECT_EQ(memcmp(value->GetRawData(), data, data_size), 0);
|
||||||
|
|
||||||
|
char* buff = new char[data_size + 1];
|
||||||
// Test full read.
|
// Test full read.
|
||||||
memset(buff, 0, data_size + 1);
|
memset(buff, 0, data_size + 1);
|
||||||
EXPECT_EQ(data_size, value->GetData(buff, data_size, 0));
|
EXPECT_EQ(data_size, value->GetData(buff, data_size, 0));
|
||||||
@ -57,7 +57,7 @@ void TestBinary(CefRefPtr<CefBinaryValue> value, char* data, size_t data_size) {
|
|||||||
|
|
||||||
// Test partial read with offset.
|
// Test partial read with offset.
|
||||||
memset(buff, 0, data_size + 1);
|
memset(buff, 0, data_size + 1);
|
||||||
old_char = data[15];
|
char old_char = data[15];
|
||||||
data[15] = 0;
|
data[15] = 0;
|
||||||
EXPECT_EQ(10U, value->GetData(buff, 10, 5));
|
EXPECT_EQ(10U, value->GetData(buff, 10, 5));
|
||||||
EXPECT_TRUE(!strcmp(buff, data + 5));
|
EXPECT_TRUE(!strcmp(buff, data + 5));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user