Skip to content

Commit f7a447f

Browse files
authored
Merge f1567eb into cde57b6
2 parents cde57b6 + f1567eb commit f7a447f

File tree

8 files changed

+251
-48
lines changed

8 files changed

+251
-48
lines changed

CefSharp.Core.Runtime/Internals/CefFrameWrapper.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,15 +237,15 @@ Task<JavascriptResponse^>^ CefFrameWrapper::EvaluateScriptAsync(String^ script,
237237
//If we're unable to get the underlying browser/browserhost then return null
238238
if (!browser.get() || !host.get())
239239
{
240-
return nullptr;
240+
return Task::FromException<JavascriptResponse^>(gcnew InvalidOperationException("Browser host not available"));
241241
}
242242

243243
auto client = static_cast<ClientAdapter*>(host->GetClient().get());
244244

245245
auto pendingTaskRepository = client->GetPendingTaskRepository();
246246

247247
//create a new taskcompletionsource
248-
auto idAndComplectionSource = pendingTaskRepository->CreatePendingTask(timeout);
248+
auto idAndComplectionSource = pendingTaskRepository->CreatePendingTask(Identifier, timeout);
249249

250250
if (useImmediatelyInvokedFuncExpression)
251251
{

CefSharp.Core.Runtime/Internals/ClientAdapter.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,8 @@ namespace CefSharp
701701

702702
void ClientAdapter::OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser, TerminationStatus status, int errorCode, const CefString& errorString)
703703
{
704+
_pendingTaskRepository->CancelPendingTasks();
705+
704706
auto handler = _browserControl->RequestHandler;
705707

706708
if (handler != nullptr)
@@ -1382,9 +1384,13 @@ namespace CefSharp
13821384
//we get here, only continue if we have a valid frame reference
13831385
if (frame.get() && frame->IsValid())
13841386
{
1387+
auto frameId = StringUtils::ToClr(frame->GetIdentifier());
1388+
1389+
_pendingTaskRepository->CancelPendingTasks(frameId);
1390+
13851391
if (frame->IsMain())
13861392
{
1387-
_browserControl->SetCanExecuteJavascriptOnMainFrame(StringUtils::ToClr(frame->GetIdentifier()), false);
1393+
_browserControl->SetCanExecuteJavascriptOnMainFrame(frameId, false);
13881394
}
13891395

13901396
auto handler = _browserControl->RenderProcessMessageHandler;
@@ -1475,14 +1481,16 @@ namespace CefSharp
14751481
return true;
14761482
}
14771483

1484+
auto frameId = StringUtils::ToClr(frame->GetIdentifier());
1485+
14781486
auto callbackFactory = browserAdapter->JavascriptCallbackFactory;
14791487

14801488
auto success = argList->GetBool(0);
14811489
auto callbackId = GetInt64(argList, 1);
14821490

14831491
auto pendingTask = name == kEvaluateJavascriptResponse ?
1484-
_pendingTaskRepository->RemovePendingTask(callbackId) :
1485-
_pendingTaskRepository->RemoveJavascriptCallbackPendingTask(callbackId);
1492+
_pendingTaskRepository->RemovePendingTask(frameId, callbackId) :
1493+
_pendingTaskRepository->RemoveJavascriptCallbackPendingTask(frameId, callbackId);
14861494

14871495
if (pendingTask != nullptr)
14881496
{

CefSharp.Core.Runtime/Internals/ClientAdapter.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ namespace CefSharp
7070

7171
CloseAllPopups(true);
7272

73-
//this will dispose the repository and cancel all pending tasks
74-
delete _pendingTaskRepository;
73+
_pendingTaskRepository->CancelPendingTasks();
7574

7675
_browser = nullptr;
7776
_browserControl = nullptr;
@@ -80,6 +79,7 @@ namespace CefSharp
8079
_tooltip = nullptr;
8180
_browserAdapter = nullptr;
8281
_popupBrowsers = nullptr;
82+
_pendingTaskRepository = nullptr;
8383
}
8484

8585
HWND GetBrowserHwnd() { return _browserHwnd; }

CefSharp.Core.Runtime/Internals/JavascriptCallbackProxy.cpp

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,30 +27,31 @@ namespace CefSharp
2727
auto browser = GetBrowser();
2828
if (browser == nullptr)
2929
{
30-
throw gcnew InvalidOperationException("Browser instance is null. Check CanExecute before calling this method.");
30+
return Task::FromException<JavascriptResponse^>(gcnew InvalidOperationException("Browser instance is null. Check CanExecute before calling this method."));
3131
}
3232

3333
auto browserWrapper = static_cast<CefBrowserWrapper^>(browser);
34-
auto javascriptNameConverter = GetJavascriptNameConverter();
35-
36-
auto doneCallback = _pendingTasks->CreateJavascriptCallbackPendingTask(_callback->Id, timeout);
37-
38-
auto callbackMessage = CefProcessMessage::Create(kJavascriptCallbackRequest);
39-
auto argList = callbackMessage->GetArgumentList();
40-
SetInt64(argList, 0, doneCallback.Key);
41-
SetInt64(argList, 1, _callback->Id);
42-
auto paramList = CefListValue::Create();
43-
for (int i = 0; i < parameters->Length; i++)
44-
{
45-
auto param = parameters[i];
46-
SerializeV8Object(paramList, i, param, javascriptNameConverter);
47-
}
48-
argList->SetList(2, paramList);
4934

5035
auto frame = browserWrapper->Browser->GetFrameByIdentifier(StringUtils::ToNative(_callback->FrameId));
5136

5237
if (frame.get() && frame->IsValid())
5338
{
39+
auto javascriptNameConverter = GetJavascriptNameConverter();
40+
41+
auto doneCallback = _pendingTasks->CreateJavascriptCallbackPendingTask(_callback->FrameId, _callback->Id, timeout);
42+
43+
auto callbackMessage = CefProcessMessage::Create(kJavascriptCallbackRequest);
44+
auto argList = callbackMessage->GetArgumentList();
45+
SetInt64(argList, 0, doneCallback.Key);
46+
SetInt64(argList, 1, _callback->Id);
47+
auto paramList = CefListValue::Create();
48+
for (int i = 0; i < parameters->Length; i++)
49+
{
50+
auto param = parameters[i];
51+
SerializeV8Object(paramList, i, param, javascriptNameConverter);
52+
}
53+
argList->SetList(2, paramList);
54+
5455
frame->SendProcessMessage(CefProcessId::PID_RENDERER, callbackMessage);
5556

5657
return doneCallback.Value->Task;

CefSharp.Test/Javascript/EvaluateScriptAsyncTests.cs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Text;
99
using System.Threading.Tasks;
1010
using Bogus;
11+
using CefSharp.Example;
1112
using Xunit;
1213
using Xunit.Abstractions;
1314
using Xunit.Repeat;
@@ -26,6 +27,52 @@ public EvaluateScriptAsyncTests(ITestOutputHelper output, CefSharpFixture collec
2627
this.collectionFixture = collectionFixture;
2728
}
2829

30+
[Fact]
31+
public async Task V8Context()
32+
{
33+
Task evaluateCancelAfterDisposeTask;
34+
using (var browser = new CefSharp.OffScreen.ChromiumWebBrowser(automaticallyCreateBrowser: false))
35+
{
36+
await browser.CreateBrowserAsync();
37+
38+
// no V8 context
39+
var withoutV8ContextException = await Assert.ThrowsAsync<Exception>(() => browser.EvaluateScriptAsync("1+1"));
40+
Assert.StartsWith("Unable to execute javascript at this time", withoutV8ContextException.Message);
41+
42+
Task<JavascriptResponse> evaluateWithoutV8ContextTask;
43+
using (var frame = browser.GetMainFrame())
44+
{
45+
evaluateWithoutV8ContextTask = frame.EvaluateScriptAsync("1+2");
46+
}
47+
48+
// V8 context
49+
await browser.LoadUrlAsync(CefExample.HelloWorldUrl);
50+
var evaluateWithoutV8ContextResponse = await evaluateWithoutV8ContextTask;
51+
Assert.True(evaluateWithoutV8ContextResponse.Success);
52+
Assert.Equal(3, evaluateWithoutV8ContextResponse.Result);
53+
54+
var evaluateCancelAfterV8ContextChangeTask = browser.EvaluateScriptAsync("new Promise(resolve => setTimeout(resolve, 1000))");
55+
56+
// change V8 context
57+
await browser.LoadUrlAsync(CefExample.HelloWorldUrl);
58+
59+
await Assert.ThrowsAsync<TaskCanceledException>(() => evaluateCancelAfterV8ContextChangeTask);
60+
61+
evaluateCancelAfterDisposeTask = browser.EvaluateScriptAsync("new Promise(resolve => setTimeout(resolve, 1000))");
62+
}
63+
await Assert.ThrowsAsync<TaskCanceledException>(() => evaluateCancelAfterDisposeTask);
64+
}
65+
66+
[Fact]
67+
public async Task CancelEvaluateOnCrash()
68+
{
69+
AssertInitialLoadComplete();
70+
71+
var task = Browser.EvaluateScriptAsync("new Promise(resolve => setTimeout(resolve, 1000))");
72+
await Browser.LoadUrlAsync("chrome://crash");
73+
await Assert.ThrowsAsync<TaskCanceledException>(() => task);
74+
}
75+
2976
[Theory]
3077
[InlineData(double.MaxValue, "Number.MAX_VALUE")]
3178
[InlineData(double.MaxValue / 2, "Number.MAX_VALUE / 2")]
@@ -264,7 +311,7 @@ public async Task CanEvaluateScriptAsyncReturnArrayBuffer(int iteration)
264311

265312
var randomizer = new Randomizer();
266313

267-
var expected = randomizer.Utf16String(minLength: iteration, maxLength:iteration);
314+
var expected = randomizer.Utf16String(minLength: iteration, maxLength: iteration);
268315
var expectedBytes = Encoding.UTF8.GetBytes(expected);
269316

270317
var javascriptResponse = await Browser.EvaluateScriptAsync($"new TextEncoder().encode('{expected}').buffer");

CefSharp.Test/Javascript/JavascriptCallbackTests.cs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Dynamic;
77
using System.Globalization;
88
using System.Threading.Tasks;
9+
using CefSharp.Example;
910
using Xunit;
1011
using Xunit.Abstractions;
1112

@@ -23,6 +24,68 @@ public JavascriptCallbackTests(ITestOutputHelper output, CefSharpFixture collect
2324
this.collectionFixture = collectionFixture;
2425
}
2526

27+
[Fact]
28+
public async Task V8Context()
29+
{
30+
Task callbackExecuteCancelAfterDisposeTask;
31+
using (var browser = new CefSharp.OffScreen.ChromiumWebBrowser(automaticallyCreateBrowser: false))
32+
{
33+
await browser.CreateBrowserAsync();
34+
35+
// no V8 context
36+
var withoutV8ContextException = await Assert.ThrowsAsync<Exception>(() => browser.EvaluateScriptAsync("(function() { return 1+1; })"));
37+
Assert.StartsWith("Unable to execute javascript at this time", withoutV8ContextException.Message);
38+
39+
Task<JavascriptResponse> callbackExecuteWithoutV8ContextTask;
40+
using (var frame = browser.GetMainFrame())
41+
{
42+
callbackExecuteWithoutV8ContextTask = frame.EvaluateScriptAsync("(function() { return 1+2; })");
43+
}
44+
45+
// V8 context
46+
await browser.LoadUrlAsync(CefExample.HelloWorldUrl);
47+
48+
var callbackExecuteWithoutV8ContextResponse = await callbackExecuteWithoutV8ContextTask;
49+
Assert.True(callbackExecuteWithoutV8ContextResponse.Success);
50+
var callbackExecuteWithoutV8ContextCallback = (IJavascriptCallback)callbackExecuteWithoutV8ContextResponse.Result;
51+
var callbackExecuteWithoutV8ContextExecuteResponse = await callbackExecuteWithoutV8ContextCallback.ExecuteAsync();
52+
Assert.True(callbackExecuteWithoutV8ContextExecuteResponse.Success);
53+
Assert.Equal(3, callbackExecuteWithoutV8ContextExecuteResponse.Result);
54+
55+
var callbackExecuteCancelAfterV8ContextResponse = await browser.EvaluateScriptAsync("(function() { return new Promise(resolve => setTimeout(resolve, 1000)); })");
56+
Assert.True(callbackExecuteCancelAfterV8ContextResponse.Success);
57+
var evaluateCancelAfterV8ContextCallback = (IJavascriptCallback)callbackExecuteCancelAfterV8ContextResponse.Result;
58+
var evaluateCancelAfterV8ContextTask = evaluateCancelAfterV8ContextCallback.ExecuteAsync();
59+
60+
// change V8 context
61+
await browser.LoadUrlAsync(CefExample.HelloWorldUrl);
62+
63+
await Assert.ThrowsAsync<TaskCanceledException>(() => evaluateCancelAfterV8ContextTask);
64+
65+
var callbackExecuteCancelAfterDisposeResponse = await browser.EvaluateScriptAsync("(function() { return new Promise(resolve => setTimeout(resolve, 1000)); })");
66+
Assert.True(callbackExecuteCancelAfterDisposeResponse.Success);
67+
var callbackExecuteCancelAfterDisposeCallback = (IJavascriptCallback)callbackExecuteCancelAfterDisposeResponse.Result;
68+
callbackExecuteCancelAfterDisposeTask = callbackExecuteCancelAfterDisposeCallback.ExecuteAsync();
69+
}
70+
await Assert.ThrowsAsync<TaskCanceledException>(() => callbackExecuteCancelAfterDisposeTask);
71+
}
72+
73+
[Fact]
74+
public async Task CancelCallbackOnCrash()
75+
{
76+
AssertInitialLoadComplete();
77+
78+
var javascriptResponse = await Browser.EvaluateScriptAsync("(function() { return new Promise(resolve => setTimeout(resolve, 1000)); })");
79+
Assert.True(javascriptResponse.Success);
80+
81+
var callback = (IJavascriptCallback)javascriptResponse.Result;
82+
83+
var task = callback.ExecuteAsync();
84+
85+
await Browser.LoadUrlAsync("chrome://crash");
86+
await Assert.ThrowsAsync<TaskCanceledException>(() => task);
87+
}
88+
2689
[Theory]
2790
[InlineData("(function() { return Promise.resolve(53)})", 53)]
2891
[InlineData("(function() { return Promise.resolve('53')})", "53")]

0 commit comments

Comments
 (0)