From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: deepak1556 <hop2deep@gmail.com>
Date: Thu, 17 Oct 2019 18:00:32 -0700
Subject: feat: add hook to notify script ready from WorkerScriptController

In Off-the-main-thread fetch, the WorkerGlobalScope will be in a half
initialized state until the script is finished downloading.

Doc: https://docs.google.com/document/d/1JCv8TD2nPLNC2iRCp_D1OM4I3uTS0HoEobuTymaMqgw/edit

During this stage if the global object is transformed for ex: copying properties
in DidInitializeWorkerContextOnWorkerThread hook then an access to property like
location will result in a crash WorkerGlobalScope::Url() because the script has
not been set with response URL yet.

This issue cannot happen in chromium with existing usage, but can surface when an
embedder tries to integrate Node.js in the worker. Hence, this new hook is proposed
that clearly establishes the worker script is ready for evaluation with the scope
initialized.

diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h
index e4637fc393bafcdeac62cd4257f42451306dbeed..999288da0fdc7bb584469530d97638e0811b339d 100644
--- a/content/public/renderer/content_renderer_client.h
+++ b/content/public/renderer/content_renderer_client.h
@@ -392,6 +392,11 @@ class CONTENT_EXPORT ContentRendererClient {
   virtual void DidInitializeWorkerContextOnWorkerThread(
       v8::Local<v8::Context> context) {}
 
+  // Notifies that a worker script has been downloaded, scope initialized and
+  // ready for evaluation. This function is called from the worker thread.
+  virtual void WorkerScriptReadyForEvaluationOnWorkerThread(
+      v8::Local<v8::Context> context) {}
+
   // Notifies that a worker context will be destroyed. This function is called
   // from the worker thread.
   virtual void WillDestroyWorkerContextOnWorkerThread(
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 4bc3a5b081b3c518e105852c97119bcfdc099917..f9738ff0c1811f5ffcbcd70ecbcebdf74a8ff4b0 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -877,6 +877,12 @@ void RendererBlinkPlatformImpl::WorkerContextCreated(
       worker);
 }
 
+void RendererBlinkPlatformImpl::WorkerScriptReadyForEvaluation(
+    const v8::Local<v8::Context>& worker) {
+  GetContentClient()->renderer()->WorkerScriptReadyForEvaluationOnWorkerThread(
+      worker);
+}
+
 bool RendererBlinkPlatformImpl::AllowScriptExtensionForServiceWorker(
     const blink::WebSecurityOrigin& script_origin) {
   return GetContentClient()->renderer()->AllowScriptExtensionForServiceWorker(
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index 50ad183c039c492947c127fe1cafb6a908d1e65d..97c7bfb6cffac313c837f2e83266a353c64eefd7 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -192,6 +192,8 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl {
   void DidStartWorkerThread() override;
   void WillStopWorkerThread() override;
   void WorkerContextCreated(const v8::Local<v8::Context>& worker) override;
+  void WorkerScriptReadyForEvaluation(
+      const v8::Local<v8::Context>& worker) override;
   void WorkerContextWillDestroy(const v8::Local<v8::Context>& worker) override;
   bool AllowScriptExtensionForServiceWorker(
       const blink::WebSecurityOrigin& script_origin) override;
diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h
index 27cefad2c07d604acfdcb23181b3b8b14b3228c1..3d5b69a75656b159352920bb0bfaee8c82648da0 100644
--- a/third_party/blink/public/platform/platform.h
+++ b/third_party/blink/public/platform/platform.h
@@ -643,6 +643,8 @@ class BLINK_PLATFORM_EXPORT Platform {
   virtual void DidStartWorkerThread() {}
   virtual void WillStopWorkerThread() {}
   virtual void WorkerContextCreated(const v8::Local<v8::Context>& worker) {}
+  virtual void WorkerScriptReadyForEvaluation(
+      const v8::Local<v8::Context>& worker) {}
   virtual void WorkerContextWillDestroy(const v8::Local<v8::Context>& worker) {}
   virtual bool AllowScriptExtensionForServiceWorker(
       const WebSecurityOrigin& script_origin) {
diff --git a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
index 5103c2860f57f26c778a4383c037c8a2aed410b9..2416783199c0d34082c6b9acd544e524f33b9a56 100644
--- a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
+++ b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
@@ -272,6 +272,7 @@ void WorkerOrWorkletScriptController::PrepareForEvaluation() {
   V8PerContextData* per_context_data = script_state_->PerContextData();
   ignore_result(per_context_data->ConstructorForType(
       global_scope_->GetWrapperTypeInfo()));
+  Platform::Current()->WorkerScriptReadyForEvaluation(script_state_->GetContext());
 #else   // USE_BLINK_V8_BINDING_NEW_IDL_INTERFACE
   ScriptState::Scope scope(script_state_);
   v8::Local<v8::Context> context = script_state_->GetContext();
@@ -297,6 +298,8 @@ void WorkerOrWorkletScriptController::PrepareForEvaluation() {
   wrapper_type_info->InstallConditionalFeatures(
       context, *world_, global_object, v8::Local<v8::Object>(),
       v8::Local<v8::Function>(), global_interface_template);
+
+  Platform::Current()->WorkerScriptReadyForEvaluation(context);
 #endif  // USE_BLINK_V8_BINDING_NEW_IDL_INTERFACE
 }
 
