Revamp exception handling in script evaluation on workers
#1. Remove importScripts() special handling
WorkerOrWorkletScriptController has a special logic for
exceptions in importScripts(), which plumbs ErrorEvent
outside V8 (i.e. via error_event_from_imported_script_)
while rethrowing exceptions in V8, in order to transmit
the original exception location information, eventually
to WorkerGlobalScope's error event.
In order to merge WorkerOrWorkletScriptController logic
with its counterpart in ScriptController, this CL removes
this importScripts() special logic and makes the logic
look more spec conformant. This CL:
- Uses v8::TryCatch::ReThrow() instead of
ExceptionState::RethrowV8Exception(), because
ReThrow() seems to preserve the original exception location
while RethrowV8Exception() doesn't seem so.
- Uses `v8::TryCatch::SetVerbose(true)` to #report-the-error,
instead of `DispatchErrorEvent()`. After this CL,
WorkerGlobalScope's error event is triggered from inside V8,
and the original exception location is plumbed through V8.
By doing so, the original exception location is passed using
V8's error rethrowing mechanism, and thus the followings are removed:
- ExecutionState
- RethrowExceptionFromImportedScript
This CL makes exceptions around cross-origin importScripts()
spec conformant:
- Previously cross-origin importScripts() throws `null` when
there are parse errors or evaluation errors, and
muted errors ("Script error.") is reported to
WorkerGlobalScope error event handler.
After this CL, it throws and reports to error event handler
NetworkError DOMException as spec'ed. (crbug.com/1111750)
- This CL also fixes exceptions around same- and cross-origin
importScripts() from setTimeout().
As a result of switching to `v8::TryCatch::SetVerbose(true)`,
the following things are achieved:
#2. Fire WorkerGlobalScope error events before a microtask checkpoint
Before this CL:
1. Script evaluation (top-level worker script or setTimeout(string))
2. Microtasks checkpoint in V8ScriptRunner::RunCompiledScript()
3. WorkerGlobalScope error events in EvaluateAndReturnValue()
After this CL:
1. Script evaluation (top-level worker script or setTimeout(string))
3. WorkerGlobalScope error events in v8::Script::Run()
2. Microtasks checkpoint in V8ScriptRunner::RunCompiledScript()
observable changes are: crbug/1114028 and crbug/1120293 are fixed.
#3. Fix error's `message` value.
This CL fixes the `message` field values of `Error` objects
reported to WorkerGlobalScope error events,
because the code path for `v8::TryCatch::SetVerbose(true)` handles
such cases appropriately while `DispatchErrorEvent()` doesn't.
For background and previous attempts, see crbug/590219 and
https://codereview.chromium.org/2090953006/#msg42.
#4. Use `v8::TryCatch::SetVerbose(true)` for all classic script evaluation
This makes easier to unify script evaluation code paths
(crbug.com/1111134).
An alternative considered was to switch all classic script evaluation
to `V8ScriptRunner::ReportException()`, but it would be much harder:
- We'll need to fix `V8ScriptRunner::ReportException()` and its
underlying V8 code to handle cases like #3 appropriately.
_ We'll need more subtle behavior/ordering changes, affecting
broader range of script evaluation (i.e. not limited to workers).
Bug: 1111134, 1111750
, 1114028, 1120293, 590219
Change-Id: I9395088a73ed76e241e89ce7d15e95417ca829d9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2328394
Commit-Queue: Hiroshige Hayashizaki <hiroshige@chromium.org>
Reviewed-by: Dominic Farolino <dom@chromium.org>
Reviewed-by: Kenichi Ishibashi <bashi@chromium.org>
Reviewed-by: Mike West <mkwst@chromium.org>
Reviewed-by: Yuki Shiino <yukishiino@chromium.org>
Reviewed-by: Hiroki Nakagawa <nhiroki@chromium.org>
Cr-Commit-Position: refs/heads/master@{#807341}
This commit is contained in:

committed by
Commit Bot

parent
c73af3a906
commit
6ae6a462af
third_party/blink
renderer
web_tests
external
wpt
html
semantics
scripting-1
wasm
webtransport
workers
interfaces
WorkerGlobalScope
WorkerUtils
importScripts
catch.sub.any.serviceworker-expected.txtcatch.sub.any.sharedworker-expected.txtcatch.sub.any.worker-expected.txtreport-error-cross-origin.sub.any.sharedworker-expected.txtreport-error-cross-origin.sub.any.worker-expected.txtreport-error-redirect-to-cross-origin.sub.any.sharedworker-expected.txtreport-error-redirect-to-cross-origin.sub.any.worker-expected.txtreport-error-setTimeout-cross-origin.sub.any.sharedworker-expected.txtreport-error-setTimeout-cross-origin.sub.any.worker-expected.txtreport-error-setTimeout-redirect-to-cross-origin.sub.any.sharedworker-expected.txtreport-error-setTimeout-redirect-to-cross-origin.sub.any.worker-expected.txtreport-error-setTimeout-same-origin.sub.any.sharedworker-expected.txtreport-error-setTimeout-same-origin.sub.any.worker-expected.txt
@ -17,6 +17,7 @@ bindings_core_v8_files =
|
||||
"core/v8/binding_security.h",
|
||||
"core/v8/boxed_v8_module.h",
|
||||
"core/v8/callback_promise_adapter.h",
|
||||
"core/v8/classic_evaluation_result.h",
|
||||
"core/v8/custom/v8_custom_xpath_ns_resolver.cc",
|
||||
"core/v8/custom/v8_custom_xpath_ns_resolver.h",
|
||||
"core/v8/custom/v8_dev_tools_host_custom.cc",
|
||||
|
61
third_party/blink/renderer/bindings/core/v8/classic_evaluation_result.h
vendored
Normal file
61
third_party/blink/renderer/bindings/core/v8/classic_evaluation_result.h
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_CLASSIC_EVALUATION_RESULT_H_
|
||||
#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_CLASSIC_EVALUATION_RESULT_H_
|
||||
|
||||
#include "third_party/blink/renderer/bindings/core/v8/script_source_location_type.h"
|
||||
#include "third_party/blink/renderer/bindings/core/v8/v8_code_cache.h"
|
||||
#include "third_party/blink/renderer/core/core_export.h"
|
||||
#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
|
||||
#include "third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler.h"
|
||||
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
|
||||
#include "third_party/blink/renderer/platform/wtf/text/text_position.h"
|
||||
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
|
||||
#include "third_party/blink/renderer/platform/wtf/vector.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace blink {
|
||||
|
||||
// ClassicEvaluationResult encapsulates the result of a classic script
|
||||
// evaluation.
|
||||
// - If IsEmpty() is false:
|
||||
// A script is evaluated successfully.
|
||||
// No exceptions are thrown.
|
||||
// GetValue() returns a non-Empty value.
|
||||
// - If IsEmpty() is true:
|
||||
// Script evaluation failed (compile error, evaluation error, or so).
|
||||
// An exception might or might not be thrown in V8.
|
||||
// Unlike v8::MaybeLocal<>, there are cases where no exceptions are thrown
|
||||
// to V8 while returning an Empty ClassicEvaluationResult, like when:
|
||||
// - An exception is thrown during script evaluation but caught and passed
|
||||
// to https://html.spec.whatwg.org/C/#report-the-error, instead of
|
||||
// being rethrown, or
|
||||
// - Script evaluation is skipped due to checks within Blink.
|
||||
//
|
||||
// TODO(crbug/1111134): Consider merging with ModuleEvaluationResult later.
|
||||
// Right now classic and module evaluation paths are not yet merged, and
|
||||
// top-level await (crbug/1022182) will modify ModuleEvaluationResult.
|
||||
class CORE_EXPORT ClassicEvaluationResult final {
|
||||
STACK_ALLOCATED();
|
||||
|
||||
public:
|
||||
ClassicEvaluationResult() = default;
|
||||
explicit ClassicEvaluationResult(v8::Local<v8::Value> value) : value_(value) {
|
||||
DCHECK(!IsEmpty());
|
||||
}
|
||||
|
||||
bool IsEmpty() const { return value_.IsEmpty(); }
|
||||
v8::Local<v8::Value> GetValue() const {
|
||||
DCHECK(!IsEmpty());
|
||||
return value_;
|
||||
}
|
||||
|
||||
private:
|
||||
v8::Local<v8::Value> value_;
|
||||
};
|
||||
|
||||
} // namespace blink
|
||||
|
||||
#endif // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_CLASSIC_EVALUATION_RESULT_H_
|
@ -41,6 +41,7 @@
|
||||
#include "third_party/blink/renderer/bindings/core/v8/v8_code_cache.h"
|
||||
#include "third_party/blink/renderer/bindings/core/v8/v8_initializer.h"
|
||||
#include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
|
||||
#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
|
||||
#include "third_party/blink/renderer/core/events/error_event.h"
|
||||
#include "third_party/blink/renderer/core/execution_context/agent.h"
|
||||
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
|
||||
@ -54,6 +55,7 @@
|
||||
#include "third_party/blink/renderer/platform/bindings/origin_trial_features.h"
|
||||
#include "third_party/blink/renderer/platform/bindings/v8_dom_wrapper.h"
|
||||
#include "third_party/blink/renderer/platform/bindings/v8_object_constructor.h"
|
||||
#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
|
||||
#include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
|
||||
#include "third_party/blink/renderer/platform/heap/heap.h"
|
||||
#include "third_party/blink/renderer/platform/heap/thread_state.h"
|
||||
@ -62,48 +64,12 @@
|
||||
|
||||
namespace blink {
|
||||
|
||||
class WorkerOrWorkletScriptController::ExecutionState final {
|
||||
STACK_ALLOCATED();
|
||||
|
||||
public:
|
||||
explicit ExecutionState(WorkerOrWorkletScriptController* controller)
|
||||
: had_exception(false),
|
||||
error_event_from_imported_script_(nullptr),
|
||||
controller_(controller),
|
||||
outer_state_(controller->execution_state_) {
|
||||
controller_->execution_state_ = this;
|
||||
}
|
||||
|
||||
~ExecutionState() { controller_->execution_state_ = outer_state_; }
|
||||
|
||||
bool had_exception;
|
||||
String error_message;
|
||||
std::unique_ptr<SourceLocation> location_;
|
||||
ScriptValue exception;
|
||||
ErrorEvent* error_event_from_imported_script_;
|
||||
|
||||
// A ExecutionState context is stack allocated by
|
||||
// WorkerOrWorkletScriptController::evaluate(), with the contoller using it
|
||||
// during script evaluation. To handle nested evaluate() uses,
|
||||
// ExecutionStates are chained together;
|
||||
// |outer_state_| keeps a pointer to the context object one level out
|
||||
// (or 0, if outermost.) Upon return from evaluate(), the
|
||||
// WorkerOrWorkletScriptController's ExecutionState is popped and the
|
||||
// previous one restored (see above dtor.)
|
||||
//
|
||||
// With Oilpan, |outer_state_| isn't traced. It'll be "up the stack"
|
||||
// and its fields will be traced when scanning the stack.
|
||||
WorkerOrWorkletScriptController* controller_;
|
||||
ExecutionState* outer_state_;
|
||||
};
|
||||
|
||||
WorkerOrWorkletScriptController::WorkerOrWorkletScriptController(
|
||||
WorkerOrWorkletGlobalScope* global_scope,
|
||||
v8::Isolate* isolate)
|
||||
: global_scope_(global_scope),
|
||||
isolate_(isolate),
|
||||
rejected_promises_(RejectedPromises::Create()),
|
||||
execution_state_(nullptr) {
|
||||
rejected_promises_(RejectedPromises::Create()) {
|
||||
DCHECK(isolate);
|
||||
world_ =
|
||||
DOMWrapperWorld::Create(isolate, DOMWrapperWorld::WorldType::kWorker);
|
||||
@ -345,109 +311,120 @@ void WorkerOrWorkletScriptController::DisableEvalInternal(
|
||||
V8String(isolate_, error_message));
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> WorkerOrWorkletScriptController::EvaluateInternal(
|
||||
// https://html.spec.whatwg.org/C/#run-a-classic-script
|
||||
ClassicEvaluationResult WorkerOrWorkletScriptController::EvaluateAndReturnValue(
|
||||
const ScriptSourceCode& source_code,
|
||||
SanitizeScriptErrors sanitize_script_errors,
|
||||
V8CacheOptions v8_cache_options) {
|
||||
DCHECK(IsContextInitialized());
|
||||
DCHECK(is_ready_to_evaluate_);
|
||||
|
||||
TRACE_EVENT1("devtools.timeline", "EvaluateScript", "data",
|
||||
inspector_evaluate_script_event::Data(
|
||||
nullptr, source_code.Url(), source_code.StartPosition()));
|
||||
|
||||
v8::TryCatch block(isolate_);
|
||||
|
||||
// TODO(crbug/1114994): Plumb this from ClassicScript.
|
||||
const KURL base_url = source_code.Url();
|
||||
|
||||
// Use default ReferrerScriptInfo here, as
|
||||
// - A work{er,let} script doesn't have a nonce, and
|
||||
// - a work{er,let} script is always "not parser inserted".
|
||||
// TODO(crbug/1114988): After crbug/1114988 is fixed, this can be the
|
||||
// default ScriptFetchOptions(). Currently the default ScriptFetchOptions()
|
||||
// is not used because it has CredentialsMode::kOmit.
|
||||
// TODO(crbug/1114989): Plumb this from ClassicScript.
|
||||
ScriptFetchOptions script_fetch_options(
|
||||
String(), IntegrityMetadataSet(), String(),
|
||||
ParserDisposition::kNotParserInserted,
|
||||
network::mojom::CredentialsMode::kSameOrigin,
|
||||
network::mojom::ReferrerPolicy::kDefault,
|
||||
mojom::blink::FetchImportanceMode::kImportanceAuto);
|
||||
|
||||
v8::MaybeLocal<v8::Value> maybe_result = V8ScriptRunner::CompileAndRunScript(
|
||||
isolate_, script_state_, global_scope_, source_code, base_url,
|
||||
sanitize_script_errors, script_fetch_options, v8_cache_options);
|
||||
|
||||
if (!block.CanContinue()) {
|
||||
ForbidExecution();
|
||||
return v8::Local<v8::Value>();
|
||||
}
|
||||
|
||||
if (block.HasCaught()) {
|
||||
v8::Local<v8::Message> message = block.Message();
|
||||
execution_state_->had_exception = true;
|
||||
execution_state_->error_message = ToCoreString(message->Get());
|
||||
execution_state_->location_ = SourceLocation::FromMessage(
|
||||
isolate_, message, ExecutionContext::From(script_state_));
|
||||
execution_state_->exception =
|
||||
ScriptValue(script_state_->GetIsolate(), block.Exception());
|
||||
block.Reset();
|
||||
} else {
|
||||
execution_state_->had_exception = false;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> result;
|
||||
if (!maybe_result.ToLocal(&result))
|
||||
return v8::Local<v8::Value>();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> WorkerOrWorkletScriptController::EvaluateAndReturnValue(
|
||||
const ScriptSourceCode& source_code,
|
||||
SanitizeScriptErrors sanitize_script_errors,
|
||||
ErrorEvent** error_event,
|
||||
V8CacheOptions v8_cache_options) {
|
||||
V8CacheOptions v8_cache_options,
|
||||
RethrowErrorsOption rethrow_errors) {
|
||||
if (IsExecutionForbidden())
|
||||
return v8::Local<v8::Value>();
|
||||
return ClassicEvaluationResult();
|
||||
|
||||
ExecutionState state(this);
|
||||
v8::Local<v8::Value> result =
|
||||
EvaluateInternal(source_code, sanitize_script_errors, v8_cache_options);
|
||||
if (IsExecutionForbidden())
|
||||
return v8::Local<v8::Value>();
|
||||
// Scope for |TRACE_EVENT1| and |v8::TryCatch| below.
|
||||
{
|
||||
DCHECK(IsContextInitialized());
|
||||
DCHECK(is_ready_to_evaluate_);
|
||||
|
||||
if (state.had_exception) {
|
||||
if (error_event) {
|
||||
if (state.error_event_from_imported_script_) {
|
||||
// Propagate inner error event outwards.
|
||||
*error_event = state.error_event_from_imported_script_;
|
||||
state.error_event_from_imported_script_ = nullptr;
|
||||
return v8::Local<v8::Value>();
|
||||
}
|
||||
if (sanitize_script_errors == SanitizeScriptErrors::kSanitize) {
|
||||
*error_event = ErrorEvent::CreateSanitizedError(script_state_);
|
||||
} else {
|
||||
*error_event =
|
||||
ErrorEvent::Create(state.error_message, state.location_->Clone(),
|
||||
state.exception, world_.get());
|
||||
}
|
||||
} else {
|
||||
ErrorEvent* event = nullptr;
|
||||
if (state.error_event_from_imported_script_) {
|
||||
event = state.error_event_from_imported_script_;
|
||||
state.error_event_from_imported_script_ = nullptr;
|
||||
} else {
|
||||
event =
|
||||
ErrorEvent::Create(state.error_message, state.location_->Clone(),
|
||||
state.exception, world_.get());
|
||||
}
|
||||
global_scope_->DispatchErrorEvent(event, sanitize_script_errors);
|
||||
TRACE_EVENT1("devtools.timeline", "EvaluateScript", "data",
|
||||
inspector_evaluate_script_event::Data(
|
||||
nullptr, source_code.Url(), source_code.StartPosition()));
|
||||
|
||||
v8::TryCatch block(isolate_);
|
||||
|
||||
// Step 8.3. Otherwise, rethrow errors is false. Perform the following
|
||||
// steps: [spec text]
|
||||
// Step 8.3.1. Report the exception given by evaluationStatus.[[Value]]
|
||||
// for script. [spec text]
|
||||
//
|
||||
// This will be done inside V8 (inside V8ScriptRunner::CompileAndRunScript()
|
||||
// below) by setting TryCatch::SetVerbose(true) here.
|
||||
if (!rethrow_errors.ShouldRethrow()) {
|
||||
block.SetVerbose(true);
|
||||
}
|
||||
|
||||
// TODO(crbug/1114994): Plumb this from ClassicScript.
|
||||
const KURL base_url = source_code.Url();
|
||||
|
||||
// Use default ReferrerScriptInfo here, as
|
||||
// - A work{er,let} script doesn't have a nonce, and
|
||||
// - a work{er,let} script is always "not parser inserted".
|
||||
// TODO(crbug/1114988): After crbug/1114988 is fixed, this can be the
|
||||
// default ScriptFetchOptions(). Currently the default ScriptFetchOptions()
|
||||
// is not used because it has CredentialsMode::kOmit.
|
||||
// TODO(crbug/1114989): Plumb this from ClassicScript.
|
||||
ScriptFetchOptions script_fetch_options(
|
||||
String(), IntegrityMetadataSet(), String(),
|
||||
ParserDisposition::kNotParserInserted,
|
||||
network::mojom::CredentialsMode::kSameOrigin,
|
||||
network::mojom::ReferrerPolicy::kDefault,
|
||||
mojom::blink::FetchImportanceMode::kImportanceAuto);
|
||||
|
||||
v8::MaybeLocal<v8::Value> maybe_result =
|
||||
V8ScriptRunner::CompileAndRunScript(
|
||||
isolate_, script_state_, global_scope_, source_code, base_url,
|
||||
sanitize_script_errors, script_fetch_options, v8_cache_options);
|
||||
|
||||
// TODO(crbug/1114601): Investigate whether to check CanContinue() in other
|
||||
// script evaluation code paths.
|
||||
if (!block.CanContinue()) {
|
||||
ForbidExecution();
|
||||
}
|
||||
|
||||
if (IsExecutionForbidden()) {
|
||||
return ClassicEvaluationResult();
|
||||
}
|
||||
|
||||
if (!block.HasCaught()) {
|
||||
// Step 10. If evaluationStatus is a normal completion, then return
|
||||
// evaluationStatus. [spec text]
|
||||
v8::Local<v8::Value> result;
|
||||
if (!maybe_result.ToLocal(&result))
|
||||
return ClassicEvaluationResult();
|
||||
|
||||
return ClassicEvaluationResult(result);
|
||||
}
|
||||
|
||||
DCHECK(maybe_result.IsEmpty());
|
||||
|
||||
if (rethrow_errors.ShouldRethrow() &&
|
||||
sanitize_script_errors == SanitizeScriptErrors::kDoNotSanitize) {
|
||||
// Step 8.1. If rethrow errors is true and script's muted errors is
|
||||
// false, then: [spec text]
|
||||
//
|
||||
// Step 8.1.2. Rethrow evaluationStatus.[[Value]]. [spec text]
|
||||
//
|
||||
// We rethrow exceptions reported from importScripts() here. The
|
||||
// original filename/lineno/colno information (which points inside of
|
||||
// imported scripts) is kept through ReThrow(), and will be eventually
|
||||
// reported to WorkerGlobalScope.onerror via `TryCatch::SetVerbose(true)`
|
||||
// called at top-level worker script evaluation.
|
||||
block.ReThrow();
|
||||
return ClassicEvaluationResult();
|
||||
}
|
||||
return v8::Local<v8::Value>();
|
||||
}
|
||||
return result;
|
||||
// |v8::TryCatch| is (and should be) exited, before ThrowException() below.
|
||||
|
||||
if (rethrow_errors.ShouldRethrow()) {
|
||||
// kDoNotSanitize case is processed and early-exited above.
|
||||
DCHECK_EQ(sanitize_script_errors, SanitizeScriptErrors::kSanitize);
|
||||
|
||||
// Step 8.2. If rethrow errors is true and script's muted errors is
|
||||
// true, then: [spec text]
|
||||
//
|
||||
// Step 8.2.2. Throw a "NetworkError" DOMException. [spec text]
|
||||
//
|
||||
// We don't supply any message here to avoid leaking details of muted
|
||||
// errors.
|
||||
V8ThrowException::ThrowException(
|
||||
isolate_, V8ThrowDOMException::CreateOrEmpty(
|
||||
isolate_, DOMExceptionCode::kNetworkError,
|
||||
rethrow_errors.Message()));
|
||||
return ClassicEvaluationResult();
|
||||
}
|
||||
|
||||
// #report-the-error for rethrow errors == true is already handled via
|
||||
// |TryCatch::SetVerbose(true)| above.
|
||||
return ClassicEvaluationResult();
|
||||
}
|
||||
|
||||
void WorkerOrWorkletScriptController::ForbidExecution() {
|
||||
@ -481,15 +458,6 @@ void WorkerOrWorkletScriptController::DisableEval(const String& error_message) {
|
||||
disable_eval_pending_ = error_message;
|
||||
}
|
||||
|
||||
void WorkerOrWorkletScriptController::RethrowExceptionFromImportedScript(
|
||||
ErrorEvent* error_event,
|
||||
ExceptionState& exception_state) {
|
||||
if (execution_state_)
|
||||
execution_state_->error_event_from_imported_script_ = error_event;
|
||||
exception_state.RethrowV8Exception(
|
||||
error_event->error(script_state_).V8ValueFor(script_state_));
|
||||
}
|
||||
|
||||
void WorkerOrWorkletScriptController::Trace(Visitor* visitor) const {
|
||||
visitor->Trace(global_scope_);
|
||||
visitor->Trace(script_state_);
|
||||
|
@ -32,6 +32,7 @@
|
||||
#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_WORKER_OR_WORKLET_SCRIPT_CONTROLLER_H_
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "third_party/blink/renderer/bindings/core/v8/classic_evaluation_result.h"
|
||||
#include "third_party/blink/renderer/bindings/core/v8/rejected_promises.h"
|
||||
#include "third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h"
|
||||
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
|
||||
@ -44,8 +45,6 @@
|
||||
|
||||
namespace blink {
|
||||
|
||||
class ErrorEvent;
|
||||
class ExceptionState;
|
||||
class ScriptSourceCode;
|
||||
class WorkerOrWorkletGlobalScope;
|
||||
|
||||
@ -58,13 +57,50 @@ class CORE_EXPORT WorkerOrWorkletScriptController final
|
||||
|
||||
bool IsExecutionForbidden() const;
|
||||
|
||||
// Returns a non-Empty value if the evaluation completed with no uncaught
|
||||
// exception. Callers should enter ScriptState::Scope before calling this.
|
||||
v8::Local<v8::Value> EvaluateAndReturnValue(
|
||||
// Rethrow errors flag in
|
||||
// https://html.spec.whatwg.org/C/#run-a-classic-script
|
||||
class RethrowErrorsOption final {
|
||||
STACK_ALLOCATED();
|
||||
|
||||
public:
|
||||
RethrowErrorsOption(RethrowErrorsOption&&) = default;
|
||||
RethrowErrorsOption& operator=(RethrowErrorsOption&&) = default;
|
||||
|
||||
RethrowErrorsOption(const RethrowErrorsOption&) = delete;
|
||||
RethrowErrorsOption& operator=(const RethrowErrorsOption&) = delete;
|
||||
|
||||
// Rethrow errors flag is false.
|
||||
static RethrowErrorsOption DoNotRethrow() {
|
||||
return RethrowErrorsOption(base::nullopt);
|
||||
}
|
||||
|
||||
// Rethrow errors flag is true. When rethrowing, a NetworkError with
|
||||
// `message` is thrown. This is used only for importScripts(), and
|
||||
// `message` is used to throw NetworkErrors with the same message text,
|
||||
// no matter whether the NetworkError is thrown inside or outside
|
||||
// EvaluateAndReturnValue().
|
||||
static RethrowErrorsOption Rethrow(const String& message) {
|
||||
return RethrowErrorsOption(message);
|
||||
}
|
||||
|
||||
bool ShouldRethrow() const { return static_cast<bool>(message_); }
|
||||
String Message() const { return *message_; }
|
||||
|
||||
private:
|
||||
explicit RethrowErrorsOption(base::Optional<String> message)
|
||||
: message_(std::move(message)) {}
|
||||
|
||||
// `nullopt` <=> rethrow errors is false.
|
||||
base::Optional<String> message_;
|
||||
};
|
||||
|
||||
// https://html.spec.whatwg.org/C/#run-a-classic-script
|
||||
// Callers should enter ScriptState::Scope before calling this.
|
||||
ClassicEvaluationResult EvaluateAndReturnValue(
|
||||
const ScriptSourceCode&,
|
||||
SanitizeScriptErrors sanitize_script_errors,
|
||||
ErrorEvent** = nullptr,
|
||||
V8CacheOptions = kV8CacheOptionsDefault);
|
||||
V8CacheOptions = kV8CacheOptionsDefault,
|
||||
RethrowErrorsOption = RethrowErrorsOption::DoNotRethrow());
|
||||
|
||||
// Prevents future JavaScript execution.
|
||||
void ForbidExecution();
|
||||
@ -81,8 +117,6 @@ class CORE_EXPORT WorkerOrWorkletScriptController final
|
||||
// before Evaluate().
|
||||
void PrepareForEvaluation();
|
||||
|
||||
// Used by WorkerGlobalScope:
|
||||
void RethrowExceptionFromImportedScript(ErrorEvent*, ExceptionState&);
|
||||
// Disables `eval()` on JavaScript. This must be called before Evaluate().
|
||||
void DisableEval(const String&);
|
||||
|
||||
@ -106,14 +140,8 @@ class CORE_EXPORT WorkerOrWorkletScriptController final
|
||||
}
|
||||
|
||||
private:
|
||||
class ExecutionState;
|
||||
|
||||
void DisableEvalInternal(const String& error_message);
|
||||
|
||||
// Evaluate a script file in the current execution environment.
|
||||
v8::Local<v8::Value> EvaluateInternal(const ScriptSourceCode&,
|
||||
SanitizeScriptErrors,
|
||||
V8CacheOptions);
|
||||
void DisposeContextIfNeeded();
|
||||
|
||||
Member<WorkerOrWorkletGlobalScope> global_scope_;
|
||||
@ -134,14 +162,6 @@ class CORE_EXPORT WorkerOrWorkletScriptController final
|
||||
|
||||
scoped_refptr<RejectedPromises> rejected_promises_;
|
||||
|
||||
// |execution_state_| refers to a stack object that evaluate() allocates;
|
||||
// evaluate() ensuring that the pointer reference to it is removed upon
|
||||
// returning. Hence kept as a bare pointer here, and not a Persistent with
|
||||
// Oilpan enabled; stack scanning will visit the object and
|
||||
// trace its on-heap fields.
|
||||
GC_PLUGIN_IGNORE("394615")
|
||||
ExecutionState* execution_state_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WorkerOrWorkletScriptController);
|
||||
};
|
||||
|
||||
|
@ -57,10 +57,10 @@ bool ClassicScript::RunScriptOnWorkerOrWorklet(
|
||||
DCHECK(global_scope.IsContextThread());
|
||||
|
||||
ScriptState::Scope scope(global_scope.ScriptController()->GetScriptState());
|
||||
v8::Local<v8::Value> result =
|
||||
ClassicEvaluationResult result =
|
||||
global_scope.ScriptController()->EvaluateAndReturnValue(
|
||||
GetScriptSourceCode(), sanitize_script_errors_,
|
||||
nullptr /* error_event */, global_scope.GetV8CacheOptions());
|
||||
global_scope.GetV8CacheOptions());
|
||||
return !result.IsEmpty();
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "third_party/blink/public/platform/web_url_request.h"
|
||||
#include "third_party/blink/renderer/bindings/core/v8/script_source_code.h"
|
||||
#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
|
||||
#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
|
||||
#include "third_party/blink/renderer/bindings/core/v8/v8_void_function.h"
|
||||
#include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h"
|
||||
#include "third_party/blink/renderer/core/css/font_face_set_worker.h"
|
||||
@ -216,23 +217,42 @@ String WorkerGlobalScope::origin() const {
|
||||
return GetSecurityOrigin()->ToString();
|
||||
}
|
||||
|
||||
void WorkerGlobalScope::importScripts(const Vector<String>& urls,
|
||||
ExceptionState& exception_state) {
|
||||
ImportScriptsInternal(urls, exception_state);
|
||||
void WorkerGlobalScope::importScripts(const Vector<String>& urls) {
|
||||
ImportScriptsInternal(urls);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
String NetworkErrorMessageAtImportScript(const char* const property_name,
|
||||
const char* const interface_name,
|
||||
const KURL& url) {
|
||||
return ExceptionMessages::FailedToExecute(
|
||||
property_name, interface_name,
|
||||
"The script at '" + url.ElidedString() + "' failed to load.");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Implementation of the "import scripts into worker global scope" algorithm:
|
||||
// https://html.spec.whatwg.org/C/#import-scripts-into-worker-global-scope
|
||||
void WorkerGlobalScope::ImportScriptsInternal(const Vector<String>& urls,
|
||||
ExceptionState& exception_state) {
|
||||
void WorkerGlobalScope::ImportScriptsInternal(const Vector<String>& urls) {
|
||||
DCHECK(GetContentSecurityPolicy());
|
||||
DCHECK(GetExecutionContext());
|
||||
v8::Isolate* isolate = GetThread()->GetIsolate();
|
||||
|
||||
// Previously, exceptions here were thrown via ExceptionState but now are
|
||||
// thrown via V8ThrowException. To keep the existing error messages,
|
||||
// ExceptionMessages::FailedToExecute() is called directly (crbug/1114610).
|
||||
const char* const property_name = "importScripts";
|
||||
const char* const interface_name = "WorkerGlobalScope";
|
||||
|
||||
// Step 1: "If worker global scope's type is "module", throw a TypeError
|
||||
// exception."
|
||||
if (script_type_ == mojom::ScriptType::kModule) {
|
||||
exception_state.ThrowTypeError(
|
||||
"Module scripts don't support importScripts().");
|
||||
V8ThrowException::ThrowTypeError(
|
||||
isolate, ExceptionMessages::FailedToExecute(
|
||||
property_name, interface_name,
|
||||
"Module scripts don't support importScripts()."));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -249,17 +269,22 @@ void WorkerGlobalScope::ImportScriptsInternal(const Vector<String>& urls,
|
||||
for (const String& url_string : urls) {
|
||||
const KURL& url = CompleteURL(url_string);
|
||||
if (!url.IsValid()) {
|
||||
exception_state.ThrowDOMException(
|
||||
DOMExceptionCode::kSyntaxError,
|
||||
"The URL '" + url_string + "' is invalid.");
|
||||
V8ThrowException::ThrowException(
|
||||
isolate, V8ThrowDOMException::CreateOrEmpty(
|
||||
isolate, DOMExceptionCode::kSyntaxError,
|
||||
ExceptionMessages::FailedToExecute(
|
||||
property_name, interface_name,
|
||||
"The URL '" + url_string + "' is invalid.")));
|
||||
return;
|
||||
}
|
||||
if (!GetContentSecurityPolicy()->AllowScriptFromSource(
|
||||
url, AtomicString(), IntegrityMetadataSet(), kNotParserInserted,
|
||||
url, RedirectStatus::kNoRedirect)) {
|
||||
exception_state.ThrowDOMException(
|
||||
DOMExceptionCode::kNetworkError,
|
||||
"The script at '" + url.ElidedString() + "' failed to load.");
|
||||
V8ThrowException::ThrowException(
|
||||
isolate, V8ThrowDOMException::CreateOrEmpty(
|
||||
isolate, DOMExceptionCode::kNetworkError,
|
||||
NetworkErrorMessageAtImportScript(property_name,
|
||||
interface_name, url)));
|
||||
return;
|
||||
}
|
||||
completed_urls.push_back(url);
|
||||
@ -270,6 +295,8 @@ void WorkerGlobalScope::ImportScriptsInternal(const Vector<String>& urls,
|
||||
KURL response_url;
|
||||
String source_code;
|
||||
std::unique_ptr<Vector<uint8_t>> cached_meta_data;
|
||||
const String error_message = NetworkErrorMessageAtImportScript(
|
||||
property_name, interface_name, complete_url);
|
||||
|
||||
// Step 5.1: "Fetch a classic worker-imported script given url and settings
|
||||
// object, passing along any custom perform the fetch steps provided. If
|
||||
@ -280,10 +307,10 @@ void WorkerGlobalScope::ImportScriptsInternal(const Vector<String>& urls,
|
||||
// TODO(vogelheim): In case of certain types of failure - e.g. 'nosniff'
|
||||
// block - this ought to be a DOMExceptionCode::kSecurityError, but that
|
||||
// information presently gets lost on the way.
|
||||
exception_state.ThrowDOMException(DOMExceptionCode::kNetworkError,
|
||||
"The script at '" +
|
||||
complete_url.ElidedString() +
|
||||
"' failed to load.");
|
||||
V8ThrowException::ThrowException(
|
||||
isolate,
|
||||
V8ThrowDOMException::CreateOrEmpty(
|
||||
isolate, DOMExceptionCode::kNetworkError, error_message));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -297,24 +324,26 @@ void WorkerGlobalScope::ImportScriptsInternal(const Vector<String>& urls,
|
||||
|
||||
// Step 5.2: "Run the classic script script, with the rethrow errors
|
||||
// argument set to true."
|
||||
ErrorEvent* error_event = nullptr;
|
||||
SingleCachedMetadataHandler* handler(
|
||||
CreateWorkerScriptCachedMetadataHandler(complete_url,
|
||||
std::move(cached_meta_data)));
|
||||
ReportingProxy().WillEvaluateImportedClassicScript(
|
||||
source_code.length(), handler ? handler->GetCodeCacheSize() : 0);
|
||||
ScriptState::Scope scope(ScriptController()->GetScriptState());
|
||||
ScriptController()->EvaluateAndReturnValue(
|
||||
ClassicEvaluationResult result = ScriptController()->EvaluateAndReturnValue(
|
||||
ScriptSourceCode(source_code, ScriptSourceLocationType::kUnknown,
|
||||
handler,
|
||||
ScriptSourceCode::UsePostRedirectURL() ? response_url
|
||||
: complete_url),
|
||||
sanitize_script_errors, &error_event, GetV8CacheOptions());
|
||||
if (error_event) {
|
||||
ScriptController()->RethrowExceptionFromImportedScript(error_event,
|
||||
exception_state);
|
||||
sanitize_script_errors, GetV8CacheOptions(),
|
||||
WorkerOrWorkletScriptController::RethrowErrorsOption::Rethrow(
|
||||
error_message));
|
||||
|
||||
// Step 5.2: "If an exception was thrown or if the script was prematurely
|
||||
// aborted, then abort all these steps, letting the exception or aborting
|
||||
// continue to be processed by the calling script."
|
||||
if (result.IsEmpty())
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,6 @@ namespace blink {
|
||||
|
||||
struct BlinkTransferableMessage;
|
||||
class ConsoleMessage;
|
||||
class ExceptionState;
|
||||
class FetchClientSettingsObjectSnapshot;
|
||||
class FontFaceSet;
|
||||
class InstalledScriptsManager;
|
||||
@ -105,8 +104,9 @@ class CORE_EXPORT WorkerGlobalScope
|
||||
DEFINE_ATTRIBUTE_EVENT_LISTENER(timezonechange, kTimezonechange)
|
||||
DEFINE_ATTRIBUTE_EVENT_LISTENER(unhandledrejection, kUnhandledrejection)
|
||||
|
||||
// WorkerUtils
|
||||
virtual void importScripts(const Vector<String>& urls, ExceptionState&);
|
||||
// This doesn't take an ExceptionState argument, but actually can throw
|
||||
// exceptions directly to V8 (crbug/1114610).
|
||||
virtual void importScripts(const Vector<String>& urls);
|
||||
|
||||
// ExecutionContext
|
||||
const KURL& Url() const final;
|
||||
@ -255,7 +255,7 @@ class CORE_EXPORT WorkerGlobalScope
|
||||
void RunWorkerScript();
|
||||
|
||||
// Used for importScripts().
|
||||
void ImportScriptsInternal(const Vector<String>& urls, ExceptionState&);
|
||||
void ImportScriptsInternal(const Vector<String>& urls);
|
||||
// ExecutionContext
|
||||
void AddInspectorIssue(mojom::blink::InspectorIssueInfoPtr) final;
|
||||
EventTarget* ErrorEventTarget() final { return this; }
|
||||
|
@ -41,7 +41,9 @@
|
||||
// attribute EventHandler ononline;
|
||||
|
||||
// https://html.spec.whatwg.org/C/#apis-available-to-workers
|
||||
[RaisesException] void importScripts(ScriptURLString... urls);
|
||||
// Although RaisesException is not specified, importScripts() can actually
|
||||
// throw exceptions directly to V8.
|
||||
void importScripts(ScriptURLString... urls);
|
||||
readonly attribute WorkerNavigator navigator;
|
||||
|
||||
|
||||
|
51
third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc
vendored
51
third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc
vendored
@ -148,18 +148,27 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase {
|
||||
waitable_event->Signal();
|
||||
}
|
||||
|
||||
static bool RunScriptAndGetBoolean(AnimationWorkletGlobalScope* global_scope,
|
||||
const String& script) {
|
||||
ScriptState* script_state =
|
||||
global_scope->ScriptController()->GetScriptState();
|
||||
DCHECK(script_state);
|
||||
v8::Isolate* isolate = script_state->GetIsolate();
|
||||
DCHECK(isolate);
|
||||
ScriptState::Scope scope(script_state);
|
||||
|
||||
ClassicEvaluationResult result =
|
||||
global_scope->ScriptController()->EvaluateAndReturnValue(
|
||||
ScriptSourceCode(script), SanitizeScriptErrors::kSanitize);
|
||||
DCHECK(!result.IsEmpty());
|
||||
return ToBoolean(isolate, result.GetValue(), ASSERT_NO_EXCEPTION);
|
||||
}
|
||||
|
||||
void RunConstructAndAnimateTestOnWorklet(
|
||||
WorkerThread* thread,
|
||||
base::WaitableEvent* waitable_event) {
|
||||
ASSERT_TRUE(thread->IsCurrentThread());
|
||||
auto* global_scope = To<AnimationWorkletGlobalScope>(thread->GlobalScope());
|
||||
ScriptState* script_state =
|
||||
global_scope->ScriptController()->GetScriptState();
|
||||
ASSERT_TRUE(script_state);
|
||||
v8::Isolate* isolate = script_state->GetIsolate();
|
||||
ASSERT_TRUE(isolate);
|
||||
|
||||
ScriptState::Scope scope(script_state);
|
||||
|
||||
String source_code =
|
||||
R"JS(
|
||||
@ -182,18 +191,12 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase {
|
||||
ClassicScript::CreateUnspecifiedScript(ScriptSourceCode(source_code))
|
||||
->RunScriptOnWorkerOrWorklet(*global_scope));
|
||||
|
||||
v8::Local<v8::Value> constructed_before =
|
||||
global_scope->ScriptController()->EvaluateAndReturnValue(
|
||||
ScriptSourceCode("Function('return this')().constructed"),
|
||||
SanitizeScriptErrors::kSanitize);
|
||||
EXPECT_FALSE(ToBoolean(isolate, constructed_before, ASSERT_NO_EXCEPTION))
|
||||
EXPECT_FALSE(RunScriptAndGetBoolean(
|
||||
global_scope, "Function('return this')().constructed"))
|
||||
<< "constructor is not invoked";
|
||||
|
||||
v8::Local<v8::Value> animated_before =
|
||||
global_scope->ScriptController()->EvaluateAndReturnValue(
|
||||
ScriptSourceCode("Function('return this')().animated"),
|
||||
SanitizeScriptErrors::kSanitize);
|
||||
EXPECT_FALSE(ToBoolean(isolate, animated_before, ASSERT_NO_EXCEPTION))
|
||||
EXPECT_FALSE(RunScriptAndGetBoolean(global_scope,
|
||||
"Function('return this')().animated"))
|
||||
<< "animate function is invoked early";
|
||||
|
||||
// Passing a new input state with a new animation id should cause the
|
||||
@ -209,18 +212,12 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase {
|
||||
ProxyClientMutate(state, global_scope);
|
||||
EXPECT_EQ(output->animations.size(), 1ul);
|
||||
|
||||
v8::Local<v8::Value> constructed_after =
|
||||
global_scope->ScriptController()->EvaluateAndReturnValue(
|
||||
ScriptSourceCode("Function('return this')().constructed"),
|
||||
SanitizeScriptErrors::kSanitize);
|
||||
EXPECT_TRUE(ToBoolean(isolate, constructed_after, ASSERT_NO_EXCEPTION))
|
||||
EXPECT_TRUE(RunScriptAndGetBoolean(global_scope,
|
||||
"Function('return this')().constructed"))
|
||||
<< "constructor is not invoked";
|
||||
|
||||
v8::Local<v8::Value> animated_after =
|
||||
global_scope->ScriptController()->EvaluateAndReturnValue(
|
||||
ScriptSourceCode("Function('return this')().animated"),
|
||||
SanitizeScriptErrors::kSanitize);
|
||||
EXPECT_TRUE(ToBoolean(isolate, animated_after, ASSERT_NO_EXCEPTION))
|
||||
EXPECT_TRUE(RunScriptAndGetBoolean(global_scope,
|
||||
"Function('return this')().animated"))
|
||||
<< "animate function is not invoked";
|
||||
|
||||
waitable_event->Signal();
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
|
||||
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
|
||||
#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
|
||||
#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
|
||||
#include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h"
|
||||
#include "third_party/blink/renderer/bindings/modules/v8/v8_background_fetch_event_init.h"
|
||||
#include "third_party/blink/renderer/bindings/modules/v8/v8_content_index_event_init.h"
|
||||
@ -825,22 +826,24 @@ int ServiceWorkerGlobalScope::GetOutstandingThrottledLimit() const {
|
||||
return features::kInstallingServiceWorkerOutstandingThrottledLimit.Get();
|
||||
}
|
||||
|
||||
void ServiceWorkerGlobalScope::importScripts(const Vector<String>& urls,
|
||||
ExceptionState& exception_state) {
|
||||
void ServiceWorkerGlobalScope::importScripts(const Vector<String>& urls) {
|
||||
for (const String& string_url : urls) {
|
||||
KURL completed_url = CompleteURL(string_url);
|
||||
if (installed_scripts_manager_ &&
|
||||
!installed_scripts_manager_->IsScriptInstalled(completed_url)) {
|
||||
DCHECK(installed_scripts_manager_->IsScriptInstalled(Url()));
|
||||
exception_state.ThrowDOMException(
|
||||
DOMExceptionCode::kNetworkError,
|
||||
"Failed to import '" + completed_url.ElidedString() +
|
||||
"'. importScripts() of new scripts after service worker "
|
||||
"installation is not allowed.");
|
||||
v8::Isolate* isolate = GetThread()->GetIsolate();
|
||||
V8ThrowException::ThrowException(
|
||||
isolate,
|
||||
V8ThrowDOMException::CreateOrEmpty(
|
||||
isolate, DOMExceptionCode::kNetworkError,
|
||||
"Failed to import '" + completed_url.ElidedString() +
|
||||
"'. importScripts() of new scripts after service worker "
|
||||
"installation is not allowed."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
WorkerGlobalScope::importScripts(urls, exception_state);
|
||||
WorkerGlobalScope::importScripts(urls);
|
||||
}
|
||||
|
||||
SingleCachedMetadataHandler*
|
||||
|
@ -339,7 +339,7 @@ class MODULES_EXPORT ServiceWorkerGlobalScope final
|
||||
const override;
|
||||
|
||||
private:
|
||||
void importScripts(const Vector<String>& urls, ExceptionState&) override;
|
||||
void importScripts(const Vector<String>& urls) override;
|
||||
SingleCachedMetadataHandler* CreateWorkerScriptCachedMetadataHandler(
|
||||
const KURL& script_url,
|
||||
std::unique_ptr<Vector<uint8_t>> meta_data) override;
|
||||
|
@ -1,4 +0,0 @@
|
||||
This is a testharness.js-based test.
|
||||
FAIL Test evaluation order of modules assert_array_equals: expected property 2 to be "global-error" but got "microtask" (expected array ["step-1-1", "step-1-2", "global-error", "error", "microtask"] got ["step-1-1", "step-1-2", "microtask", "global-error", "error"])
|
||||
Harness: the test ran to completion.
|
||||
|
@ -1,4 +0,0 @@
|
||||
This is a testharness.js-based test.
|
||||
FAIL Test evaluation order of modules assert_array_equals: expected property 2 to be "global-error" but got "microtask" (expected array ["step-1-1", "step-1-2", "global-error", "error", "microtask"] got ["step-1-1", "step-1-2", "microtask", "global-error", "error"])
|
||||
Harness: the test ran to completion.
|
||||
|
@ -1,5 +0,0 @@
|
||||
This is a testharness.js-based test.
|
||||
FAIL Promise resolved during #report-the-error assert_array_equals: expected property 1 to be "handler 2" but got "handler 1 promise" (expected array ["handler 1", "handler 2", "handler 1 promise", "handler 2 promise"] got ["handler 1", "handler 1 promise", "handler 2", "handler 2 promise"])
|
||||
PASS Promise resolved during event handlers other than error
|
||||
Harness: the test ran to completion.
|
||||
|
@ -1,4 +1,4 @@
|
||||
This is a testharness.js-based test.
|
||||
Harness Error. harness_status.status = 1 , harness_status.message = Uncaught
|
||||
Harness Error. harness_status.status = 1 , harness_status.message = Uncaught NetworkError: Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at 'http://web-platform.test:8001/wasm/jsapi/wasm-constants.js' failed to load.
|
||||
Harness: the test ran to completion.
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
This is a testharness.js-based test.
|
||||
Harness Error. harness_status.status = 1 , harness_status.message = Uncaught
|
||||
Harness Error. harness_status.status = 1 , harness_status.message = Uncaught NetworkError: Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at 'http://web-platform.test:8001/webtransport/quic/client-indication.sub.any.js' failed to load.
|
||||
Harness: the test ran to completion.
|
||||
|
||||
|
@ -1,13 +0,0 @@
|
||||
This is a testharness.js-based test.
|
||||
FAIL Throw DOMException-TypeError in toplevel: classic: listener assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
|
||||
FAIL Throw DOMException-TypeError in toplevel: classic: handler assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
|
||||
PASS Throw DOMException-TypeError in setTimeout-function: classic: listener
|
||||
PASS Throw DOMException-TypeError in setTimeout-function: classic: handler
|
||||
FAIL Throw DOMException-TypeError in setTimeout-string: classic: listener assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
|
||||
FAIL Throw DOMException-TypeError in setTimeout-string: classic: handler assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
|
||||
PASS Throw DOMException-TypeError in onmessage: classic: listener
|
||||
PASS Throw DOMException-TypeError in onmessage: classic: handler
|
||||
PASS Throw DOMException-TypeError in onerror: classic: listener
|
||||
PASS Throw DOMException-TypeError in onerror: classic: handler
|
||||
Harness: the test ran to completion.
|
||||
|
@ -3,8 +3,8 @@ FAIL Throw DOMException-TypeError in toplevel: module: listener assert_regexp_ma
|
||||
FAIL Throw DOMException-TypeError in toplevel: module: handler assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
|
||||
PASS Throw DOMException-TypeError in setTimeout-function: module: listener
|
||||
PASS Throw DOMException-TypeError in setTimeout-function: module: handler
|
||||
FAIL Throw DOMException-TypeError in setTimeout-string: module: listener assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
|
||||
FAIL Throw DOMException-TypeError in setTimeout-string: module: handler assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
|
||||
PASS Throw DOMException-TypeError in setTimeout-string: module: listener
|
||||
PASS Throw DOMException-TypeError in setTimeout-string: module: handler
|
||||
PASS Throw DOMException-TypeError in onmessage: module: listener
|
||||
PASS Throw DOMException-TypeError in onmessage: module: handler
|
||||
PASS Throw DOMException-TypeError in onerror: module: listener
|
||||
|
@ -1,15 +0,0 @@
|
||||
This is a testharness.js-based test.
|
||||
PASS Same-origin syntax error
|
||||
PASS Same-origin throw
|
||||
FAIL Cross-origin syntax error assert_throws_dom: function "function() {
|
||||
importScripts(crossOrigin +
|
||||
"/workers/modules/resources/syntax-error.js");
|
||||
}" threw null, not an object
|
||||
FAIL Cross-origin throw assert_throws_dom: function "function() {
|
||||
importScripts(crossOrigin +
|
||||
"/workers/modules/resources/throw.js");
|
||||
}" threw null, not an object
|
||||
PASS Redirect-to-cross-origin syntax error
|
||||
PASS Redirect-to-Cross-origin throw
|
||||
Harness: the test ran to completion.
|
||||
|
@ -1,21 +0,0 @@
|
||||
This is a testharness.js-based test.
|
||||
PASS Same-origin syntax error
|
||||
PASS Same-origin throw
|
||||
FAIL Cross-origin syntax error assert_throws_dom: function "function() {
|
||||
importScripts(crossOrigin +
|
||||
"/workers/modules/resources/syntax-error.js");
|
||||
}" threw null, not an object
|
||||
FAIL Cross-origin throw assert_throws_dom: function "function() {
|
||||
importScripts(crossOrigin +
|
||||
"/workers/modules/resources/throw.js");
|
||||
}" threw null, not an object
|
||||
FAIL Redirect-to-cross-origin syntax error assert_throws_dom: function "function() {
|
||||
importScripts(redirectToCrossOrigin +
|
||||
"/workers/modules/resources/syntax-error.js");
|
||||
}" threw null, not an object
|
||||
FAIL Redirect-to-Cross-origin throw assert_throws_dom: function "function() {
|
||||
importScripts(redirectToCrossOrigin +
|
||||
"/workers/modules/resources/throw.js");
|
||||
}" threw null, not an object
|
||||
Harness: the test ran to completion.
|
||||
|
@ -1,21 +0,0 @@
|
||||
This is a testharness.js-based test.
|
||||
PASS Same-origin syntax error
|
||||
PASS Same-origin throw
|
||||
FAIL Cross-origin syntax error assert_throws_dom: function "function() {
|
||||
importScripts(crossOrigin +
|
||||
"/workers/modules/resources/syntax-error.js");
|
||||
}" threw null, not an object
|
||||
FAIL Cross-origin throw assert_throws_dom: function "function() {
|
||||
importScripts(crossOrigin +
|
||||
"/workers/modules/resources/throw.js");
|
||||
}" threw null, not an object
|
||||
FAIL Redirect-to-cross-origin syntax error assert_throws_dom: function "function() {
|
||||
importScripts(redirectToCrossOrigin +
|
||||
"/workers/modules/resources/syntax-error.js");
|
||||
}" threw null, not an object
|
||||
FAIL Redirect-to-Cross-origin throw assert_throws_dom: function "function() {
|
||||
importScripts(redirectToCrossOrigin +
|
||||
"/workers/modules/resources/throw.js");
|
||||
}" threw null, not an object
|
||||
Harness: the test ran to completion.
|
||||
|
@ -1,7 +0,0 @@
|
||||
This is a testharness.js-based test.
|
||||
FAIL WorkerGlobalScope error event: error Cannot read property 'constructor' of null
|
||||
FAIL WorkerGlobalScope error event: message assert_not_equals: e.message should not be muted to 'Script error.' got disallowed value "Script error."
|
||||
FAIL WorkerGlobalScope error event: filename assert_equals: expected "http://web-platform.test:8001/workers/interfaces/WorkerUtils/importScripts/report-error-helper.js" but got ""
|
||||
FAIL WorkerGlobalScope error event: lineno assert_equals: expected 8 but got 0
|
||||
Harness: the test ran to completion.
|
||||
|
@ -1,7 +0,0 @@
|
||||
This is a testharness.js-based test.
|
||||
FAIL WorkerGlobalScope error event: error Cannot read property 'constructor' of null
|
||||
FAIL WorkerGlobalScope error event: message assert_not_equals: e.message should not be muted to 'Script error.' got disallowed value "Script error."
|
||||
FAIL WorkerGlobalScope error event: filename assert_equals: expected "http://web-platform.test:8001/workers/interfaces/WorkerUtils/importScripts/report-error-helper.js" but got ""
|
||||
FAIL WorkerGlobalScope error event: lineno assert_equals: expected 8 but got 0
|
||||
Harness: the test ran to completion.
|
||||
|
@ -1,7 +0,0 @@
|
||||
This is a testharness.js-based test.
|
||||
FAIL WorkerGlobalScope error event: error Cannot read property 'constructor' of null
|
||||
FAIL WorkerGlobalScope error event: message assert_not_equals: e.message should not be muted to 'Script error.' got disallowed value "Script error."
|
||||
FAIL WorkerGlobalScope error event: filename assert_equals: expected "http://web-platform.test:8001/workers/interfaces/WorkerUtils/importScripts/report-error-helper.js" but got ""
|
||||
FAIL WorkerGlobalScope error event: lineno assert_equals: expected 8 but got 0
|
||||
Harness: the test ran to completion.
|
||||
|
@ -1,7 +0,0 @@
|
||||
This is a testharness.js-based test.
|
||||
FAIL WorkerGlobalScope error event: error Cannot read property 'constructor' of null
|
||||
FAIL WorkerGlobalScope error event: message assert_not_equals: e.message should not be muted to 'Script error.' got disallowed value "Script error."
|
||||
FAIL WorkerGlobalScope error event: filename assert_equals: expected "http://web-platform.test:8001/workers/interfaces/WorkerUtils/importScripts/report-error-helper.js" but got ""
|
||||
FAIL WorkerGlobalScope error event: lineno assert_equals: expected 8 but got 0
|
||||
Harness: the test ran to completion.
|
||||
|
@ -1,7 +0,0 @@
|
||||
This is a testharness.js-based test.
|
||||
FAIL WorkerGlobalScope error event: error Cannot read property 'constructor' of null
|
||||
PASS WorkerGlobalScope error event: message
|
||||
PASS WorkerGlobalScope error event: filename
|
||||
PASS WorkerGlobalScope error event: lineno
|
||||
Harness: the test ran to completion.
|
||||
|
@ -1,7 +0,0 @@
|
||||
This is a testharness.js-based test.
|
||||
FAIL WorkerGlobalScope error event: error Cannot read property 'constructor' of null
|
||||
PASS WorkerGlobalScope error event: message
|
||||
PASS WorkerGlobalScope error event: filename
|
||||
PASS WorkerGlobalScope error event: lineno
|
||||
Harness: the test ran to completion.
|
||||
|
@ -1,7 +0,0 @@
|
||||
This is a testharness.js-based test.
|
||||
FAIL WorkerGlobalScope error event: error Cannot read property 'constructor' of null
|
||||
PASS WorkerGlobalScope error event: message
|
||||
PASS WorkerGlobalScope error event: filename
|
||||
PASS WorkerGlobalScope error event: lineno
|
||||
Harness: the test ran to completion.
|
||||
|
@ -1,7 +0,0 @@
|
||||
This is a testharness.js-based test.
|
||||
FAIL WorkerGlobalScope error event: error Cannot read property 'constructor' of null
|
||||
PASS WorkerGlobalScope error event: message
|
||||
PASS WorkerGlobalScope error event: filename
|
||||
PASS WorkerGlobalScope error event: lineno
|
||||
Harness: the test ran to completion.
|
||||
|
@ -1,7 +0,0 @@
|
||||
This is a testharness.js-based test.
|
||||
PASS WorkerGlobalScope error event: error
|
||||
PASS WorkerGlobalScope error event: message
|
||||
FAIL WorkerGlobalScope error event: filename assert_equals: expected "http://web-platform.test:8001/workers/modules/resources/syntax-error.js" but got "http://web-platform.test:8001/workers/interfaces/WorkerUtils/importScripts/report-error-helper.js"
|
||||
FAIL WorkerGlobalScope error event: lineno assert_equals: expected 1 but got 8
|
||||
Harness: the test ran to completion.
|
||||
|
@ -1,7 +0,0 @@
|
||||
This is a testharness.js-based test.
|
||||
PASS WorkerGlobalScope error event: error
|
||||
PASS WorkerGlobalScope error event: message
|
||||
FAIL WorkerGlobalScope error event: filename assert_equals: expected "http://web-platform.test:8001/workers/modules/resources/syntax-error.js" but got "http://web-platform.test:8001/workers/interfaces/WorkerUtils/importScripts/report-error-helper.js"
|
||||
FAIL WorkerGlobalScope error event: lineno assert_equals: expected 1 but got 8
|
||||
Harness: the test ran to completion.
|
||||
|
Reference in New Issue
Block a user