Skip to content

Commit 0386220

Browse files
authored
JavascriptBinding - Add JavascriptBindingSettings.JavascriptBindingApiEnabled property (#3571)
- The Javascript methods that CefSharp provides in relation to JavaScript Binding are created using a Global (window) Object. Settings this property allows you to disable the creation of this object. Features like EvaluateScriptAsPromiseAsync that rely on the creation of this object will no longer function.
1 parent a3f9140 commit 0386220

File tree

6 files changed

+122
-46
lines changed

6 files changed

+122
-46
lines changed

CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.cpp

Lines changed: 47 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ namespace CefSharp
9191
}
9292
}
9393
}
94+
95+
_jsBindingApiEnabled = extraInfo->GetBool("JavascriptBindingApiEnabled");
9496
}
9597

9698
if (extraInfo->HasKey("JsBindingPropertyName") || extraInfo->HasKey("JsBindingPropertyNameCamelCase"))
@@ -137,50 +139,53 @@ namespace CefSharp
137139
}
138140
}
139141

140-
//TODO: Look at adding some sort of javascript mapping layer to reduce the code duplication
141-
auto global = context->GetGlobal();
142-
auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier());
143-
auto processId = System::Diagnostics::Process::GetCurrentProcess()->Id;
144-
145-
//TODO: JSB: Split functions into their own classes
146-
//Browser wrapper is only used for BindObjectAsync
147-
auto bindObjAsyncFunction = CefV8Value::CreateFunction(kBindObjectAsync, new BindObjectAsyncHandler(_registerBoundObjectRegistry, _javascriptObjects, browserWrapper));
148-
auto unBindObjFunction = CefV8Value::CreateFunction(kDeleteBoundObject, new RegisterBoundObjectHandler(_javascriptObjects));
149-
auto removeObjectFromCacheFunction = CefV8Value::CreateFunction(kRemoveObjectFromCache, new RegisterBoundObjectHandler(_javascriptObjects));
150-
auto isObjectCachedFunction = CefV8Value::CreateFunction(kIsObjectCached, new RegisterBoundObjectHandler(_javascriptObjects));
151-
auto postMessageFunction = CefV8Value::CreateFunction(kPostMessage, new JavascriptPostMessageHandler(rootObject == nullptr ? nullptr : rootObject->CallbackRegistry));
152-
auto promiseHandlerFunction = CefV8Value::CreateFunction(kSendEvalScriptResponse, new JavascriptPromiseHandler());
153-
154-
//By default We'll support both CefSharp and cefSharp, for those who prefer the JS style
155-
auto createCefSharpObj = !_jsBindingPropertyName.empty();
156-
auto createCefSharpObjCamelCase = !_jsBindingPropertyNameCamelCase.empty();
157-
158-
if (createCefSharpObj)
142+
if (_jsBindingApiEnabled)
159143
{
160-
auto cefSharpObj = CefV8Value::CreateObject(NULL, NULL);
161-
cefSharpObj->SetValue(kBindObjectAsync, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
162-
cefSharpObj->SetValue(kDeleteBoundObject, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
163-
cefSharpObj->SetValue(kRemoveObjectFromCache, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
164-
cefSharpObj->SetValue(kIsObjectCached, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
165-
cefSharpObj->SetValue(kPostMessage, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
166-
cefSharpObj->SetValue(kSendEvalScriptResponse, promiseHandlerFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
167-
cefSharpObj->SetValue(kRenderProcessId, CefV8Value::CreateInt(processId), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
168-
169-
global->SetValue(_jsBindingPropertyName, cefSharpObj, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
170-
}
144+
//TODO: Look at adding some sort of javascript mapping layer to reduce the code duplication
145+
auto global = context->GetGlobal();
146+
auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier());
147+
auto processId = System::Diagnostics::Process::GetCurrentProcess()->Id;
148+
149+
//TODO: JSB: Split functions into their own classes
150+
//Browser wrapper is only used for BindObjectAsync
151+
auto bindObjAsyncFunction = CefV8Value::CreateFunction(kBindObjectAsync, new BindObjectAsyncHandler(_registerBoundObjectRegistry, _javascriptObjects, browserWrapper));
152+
auto unBindObjFunction = CefV8Value::CreateFunction(kDeleteBoundObject, new RegisterBoundObjectHandler(_javascriptObjects));
153+
auto removeObjectFromCacheFunction = CefV8Value::CreateFunction(kRemoveObjectFromCache, new RegisterBoundObjectHandler(_javascriptObjects));
154+
auto isObjectCachedFunction = CefV8Value::CreateFunction(kIsObjectCached, new RegisterBoundObjectHandler(_javascriptObjects));
155+
auto postMessageFunction = CefV8Value::CreateFunction(kPostMessage, new JavascriptPostMessageHandler(rootObject == nullptr ? nullptr : rootObject->CallbackRegistry));
156+
auto promiseHandlerFunction = CefV8Value::CreateFunction(kSendEvalScriptResponse, new JavascriptPromiseHandler());
157+
158+
//By default We'll support both CefSharp and cefSharp, for those who prefer the JS style
159+
auto createCefSharpObj = !_jsBindingPropertyName.empty();
160+
auto createCefSharpObjCamelCase = !_jsBindingPropertyNameCamelCase.empty();
161+
162+
if (createCefSharpObj)
163+
{
164+
auto cefSharpObj = CefV8Value::CreateObject(NULL, NULL);
165+
cefSharpObj->SetValue(kBindObjectAsync, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
166+
cefSharpObj->SetValue(kDeleteBoundObject, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
167+
cefSharpObj->SetValue(kRemoveObjectFromCache, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
168+
cefSharpObj->SetValue(kIsObjectCached, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
169+
cefSharpObj->SetValue(kPostMessage, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
170+
cefSharpObj->SetValue(kSendEvalScriptResponse, promiseHandlerFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
171+
cefSharpObj->SetValue(kRenderProcessId, CefV8Value::CreateInt(processId), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
172+
173+
global->SetValue(_jsBindingPropertyName, cefSharpObj, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
174+
}
171175

172-
if (createCefSharpObjCamelCase)
173-
{
174-
auto cefSharpObjCamelCase = CefV8Value::CreateObject(NULL, NULL);
175-
cefSharpObjCamelCase->SetValue(kBindObjectAsyncCamelCase, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
176-
cefSharpObjCamelCase->SetValue(kDeleteBoundObjectCamelCase, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
177-
cefSharpObjCamelCase->SetValue(kRemoveObjectFromCacheCamelCase, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
178-
cefSharpObjCamelCase->SetValue(kIsObjectCachedCamelCase, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
179-
cefSharpObjCamelCase->SetValue(kPostMessageCamelCase, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
180-
cefSharpObjCamelCase->SetValue(kSendEvalScriptResponseCamelCase, promiseHandlerFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
181-
cefSharpObjCamelCase->SetValue(kRenderProcessIdCamelCase, CefV8Value::CreateInt(processId), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
182-
183-
global->SetValue(_jsBindingPropertyNameCamelCase, cefSharpObjCamelCase, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
176+
if (createCefSharpObjCamelCase)
177+
{
178+
auto cefSharpObjCamelCase = CefV8Value::CreateObject(NULL, NULL);
179+
cefSharpObjCamelCase->SetValue(kBindObjectAsyncCamelCase, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
180+
cefSharpObjCamelCase->SetValue(kDeleteBoundObjectCamelCase, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
181+
cefSharpObjCamelCase->SetValue(kRemoveObjectFromCacheCamelCase, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
182+
cefSharpObjCamelCase->SetValue(kIsObjectCachedCamelCase, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
183+
cefSharpObjCamelCase->SetValue(kPostMessageCamelCase, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
184+
cefSharpObjCamelCase->SetValue(kSendEvalScriptResponseCamelCase, promiseHandlerFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
185+
cefSharpObjCamelCase->SetValue(kRenderProcessIdCamelCase, CefV8Value::CreateInt(processId), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
186+
187+
global->SetValue(_jsBindingPropertyNameCamelCase, cefSharpObjCamelCase, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
188+
}
184189
}
185190

186191
//Send a message to the browser processing signaling that OnContextCreated has been called

CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ namespace CefSharp
2828
gcroot<ConcurrentDictionary<int, CefBrowserWrapper^>^> _browserWrappers;
2929
bool _focusedNodeChangedEnabled;
3030
bool _legacyBindingEnabled;
31+
bool _jsBindingApiEnabled = true;
3132

3233
// The property names used to call bound objects
3334
CefString _jsBindingPropertyName;

CefSharp.Core.Runtime/ManagedCefBrowserAdapter.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,15 @@ namespace CefSharp
4141
}
4242

4343
auto objectRepository = _javaScriptObjectRepository;
44+
auto objectRepositorySettings = objectRepository->Settings;
4445

4546
//It's no longer possible to change these settings
46-
objectRepository->Settings->Freeze();
47+
objectRepositorySettings->Freeze();
4748

4849
CefRefPtr<CefDictionaryValue> extraInfo = CefDictionaryValue::Create();
4950
auto legacyBindingEnabled = false;
5051

51-
if (objectRepository->Settings->LegacyBindingEnabled)
52+
if (objectRepositorySettings->LegacyBindingEnabled)
5253
{
5354
auto legacyBoundObjects = objectRepository->GetLegacyBoundObjects();
5455

@@ -67,9 +68,9 @@ namespace CefSharp
6768

6869
extraInfo->SetBool("LegacyBindingEnabled", legacyBindingEnabled);
6970

70-
if (!String::IsNullOrEmpty(objectRepository->Settings->JavascriptBindingApiGlobalObjectName))
71+
if (!String::IsNullOrEmpty(objectRepositorySettings->JavascriptBindingApiGlobalObjectName))
7172
{
72-
auto globalObjName = objectRepository->Settings->JavascriptBindingApiGlobalObjectName;
73+
auto globalObjName = objectRepositorySettings->JavascriptBindingApiGlobalObjectName;
7374

7475
if (StringCheck::IsFirstCharacterLowercase(globalObjName))
7576
{
@@ -81,6 +82,8 @@ namespace CefSharp
8182
}
8283
}
8384

85+
extraInfo->SetBool("JavascriptBindingApiEnabled", objectRepositorySettings->JavascriptBindingApiEnabled);
86+
8487
CefRefPtr<CefRequestContext> requestCtx;
8588

8689
if (requestContext != nullptr)

CefSharp.Test/CefSharpFixture.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ private void CefInitialize()
5151
//HTML5 databases such as localStorage will only persist across sessions if a cache path is specified.
5252
settings.CachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CefSharp\\Tests\\Cache");
5353
settings.RootCachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CefSharp\\Tests");
54+
//settings.CefCommandLineArgs.Add("renderer-startup-dialog");
5455

5556
Cef.Initialize(settings, performDependencyCheck: false, browserProcessHandler: null);
5657
}

CefSharp.Test/JavascriptBinding/IntegrationTestFacts.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,54 @@ public async Task JsBindingGlobalObjectNameCustomValueExecuteIsObjectCachedSucce
140140
}
141141
}
142142

143+
[Fact]
144+
public async Task JsBindingGlobalApiDisabled()
145+
{
146+
using (var browser = new ChromiumWebBrowser(CefExample.BindingApiCustomObjectNameTestUrl, automaticallyCreateBrowser: false))
147+
{
148+
var settings = browser.JavascriptObjectRepository.Settings;
149+
settings.JavascriptBindingApiEnabled = false;
150+
151+
//To modify the settings we need to defer browser creation slightly
152+
browser.CreateBrowser();
153+
154+
await browser.LoadPageAsync();
155+
156+
var response1 = await browser.EvaluateScriptAsync("typeof window.cefSharp === 'undefined'");
157+
var response2 = await browser.EvaluateScriptAsync("typeof window.CefSharp === 'undefined'");
158+
159+
Assert.True(response1.Success);
160+
Assert.True((bool)response1.Result);
161+
162+
Assert.True(response2.Success);
163+
Assert.True((bool)response2.Result);
164+
}
165+
}
166+
167+
[Fact]
168+
public async Task JsBindingGlobalApiEnabled()
169+
{
170+
using (var browser = new ChromiumWebBrowser(CefExample.BindingApiCustomObjectNameTestUrl, automaticallyCreateBrowser: false))
171+
{
172+
var settings = browser.JavascriptObjectRepository.Settings;
173+
settings.JavascriptBindingApiEnabled = true;
174+
175+
//To modify the settings we need to defer browser creation slightly
176+
browser.CreateBrowser();
177+
178+
await browser.LoadPageAsync();
179+
180+
var response1 = await browser.EvaluateScriptAsync("typeof window.cefSharp === 'undefined'");
181+
var response2 = await browser.EvaluateScriptAsync("typeof window.CefSharp === 'undefined'");
182+
183+
Assert.True(response1.Success);
184+
Assert.False((bool)response1.Result);
185+
186+
Assert.True(response2.Success);
187+
Assert.False((bool)response2.Result);
188+
}
189+
}
190+
143191
[Theory]
144192
[InlineData("CefSharp.RenderProcessId")]
145193
[InlineData("cefSharp.renderProcessId")]

CefSharp/JavascriptBinding/JavascriptBindingSettings.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,24 @@ public class JavascriptBindingSettings : FreezableBase
1414
private bool alwaysInterceptAsynchronously;
1515
private bool legacyBindingEnabled;
1616
private string jsBindingGlobalObjectName;
17+
private bool jsBindingApiEnabled = true;
18+
19+
/// <summary>
20+
/// The Javascript methods that CefSharp provides in relation to JavaScript Binding are
21+
/// created using a Global (window) Object. Settings this property allows you to disable
22+
/// the creation of this object. Features like EvaluateScriptAsPromiseAsync that rely on
23+
/// the creation of this object will no longer function.
24+
/// </summary>
25+
public bool JavascriptBindingApiEnabled
26+
{
27+
get { return jsBindingApiEnabled; }
28+
set
29+
{
30+
ThrowIfFrozen();
31+
32+
jsBindingApiEnabled = value;
33+
}
34+
}
1735

1836
/// <summary>
1937
/// The Javascript methods that CefSharp provides in relation to JavaScript Binding are

0 commit comments

Comments
 (0)