Title: [272684] trunk/Source
Revision
272684
Author
bb...@apple.com
Date
2021-02-10 13:34:27 -0800 (Wed, 10 Feb 2021)

Log Message

[Cocoa] Web Inspector: add support for evaluating script on the inspected page via _WKInspectorExtension
https://bugs.webkit.org/show_bug.cgi?id=221567
<rdar://71208534>

Reviewed by Devin Rousso.

Source/WebCore:

This patch adds support for handling returned Promise values in an intelligent way.
If a callback was supplied, then wait for the promise to settle and invoke the
callback with its settled result. To support this, the dispatcher keeps a map of
unfulfilled DOMPromises and the callback that is chained to the DOMPromise.

* inspector/InspectorFrontendAPIDispatcher.h:
* inspector/InspectorFrontendAPIDispatcher.cpp:
(WebCore::InspectorFrontendAPIDispatcher::~InspectorFrontendAPIDispatcher):
(WebCore::InspectorFrontendAPIDispatcher::reset):
Clear the pending responses map when destructing or resetting the dispatcher.

(WebCore::InspectorFrontendAPIDispatcher::frontendGlobalObject):
Upgrade from JSGlobalObject to JSDOMGlobalObject, which is needed to call JSDOMPromise methods.

(WebCore::InspectorFrontendAPIDispatcher::evaluateOrQueueExpression):
The meat of this patch. Chain a Function onto the JSDOMPromise. Inside the lambda function,
try to look up and invoke the corresponding EvaluationResultHandler for this evaluation result.

(WebCore::InspectorFrontendAPIDispatcher::invalidatePendingResponses):
Since these are CompletionHandlers we need to call them one way or another.

Source/WebInspectorUI:

This patch adds InspectorFrontendAPI.evaluateScriptForExtension().

* UserInterface/Controllers/WebInspectorExtensionController.js:
(WI.WebInspectorExtensionController.prototype.evaluateScriptForExtension):
Translate arguments into a corresponding RuntimeAgent.evaluate invocation.
The parameters are not yet implemented, and will be filled in by a subsequent patch.

* UserInterface/Models/WebInspectorExtension.js: Add new error enum value.

* UserInterface/Protocol/InspectorFrontendAPI.js:
(InspectorFrontendAPI.evaluateScriptForExtension):
Plumbing.

Source/WebKit:

This patch adds a new method to _WKInspectorExtension which is used to implement
`browser.devtools.inspectedWindow.eval` in the Web Extensions API.

* Shared/InspectorExtensionTypes.h:
* Shared/InspectorExtensionTypes.cpp:
(WebKit::inspectorExtensionErrorToString):
Add enum value NotImplemented.

* UIProcess/API/APIInspectorExtension.h:
* UIProcess/API/APIInspectorExtension.cpp:
(API::InspectorExtension::evaluateScript):
Plumbing.

* UIProcess/API/Cocoa/WKWebViewInternal.h:
* UIProcess/API/Cocoa/WKWebView.mm:
(nsErrorFromExceptionDetails):
Move this helper up near the top as it is now exposed via <WebKit/WKWebViewInternal.h>.

* UIProcess/API/Cocoa/_WKInspectorExtension.h:
* UIProcess/API/Cocoa/_WKInspectorExtension.mm:
(-[_WKInspectorExtension evaluateScript:frameURL:contextSecurityOrigin:useContentScriptContext:completionHandler:]):
Add new method to evaluate script in the inspected page. The semantics of the parameters
are intended to match those of `browser.devtools.inspectedWindow.eval`.

* UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.h:
* UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.cpp:
(WebKit::WebInspectorUIExtensionControllerProxy::evaluateScriptForExtension):
Plumbing.

* WebProcess/Inspector/WebInspectorUIExtensionController.h:
* WebProcess/Inspector/WebInspectorUIExtensionController.messages.in:
Add new message for evaluateScript.

* WebProcess/Inspector/WebInspectorUIExtensionController.cpp:
(WebKit::WebInspectorUIExtensionController::parseInspectorExtensionErrorFromEvaluationResult):
Support the new error enum value.

(WebKit::WebInspectorUIExtensionController::unregisterExtension):
(WebKit::WebInspectorUIExtensionController::createTabForExtension):
Drive-by, simplify this by passing the EvaluationResult value without unwrapping.

(WebKit::WebInspectorUIExtensionController::evaluateScriptForExtension):
This is the meat of the patch. Call out to InspectorFrontendAPI.evaluateScriptForExtension.
Inspect the return value and invoke the completion handler with the result or an error.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (272683 => 272684)


--- trunk/Source/WebCore/ChangeLog	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebCore/ChangeLog	2021-02-10 21:34:27 UTC (rev 272684)
@@ -1,3 +1,32 @@
+2021-02-10  BJ Burg  <bb...@apple.com>
+
+        [Cocoa] Web Inspector: add support for evaluating script on the inspected page via _WKInspectorExtension
+        https://bugs.webkit.org/show_bug.cgi?id=221567
+        <rdar://71208534>
+
+        Reviewed by Devin Rousso.
+
+        This patch adds support for handling returned Promise values in an intelligent way.
+        If a callback was supplied, then wait for the promise to settle and invoke the
+        callback with its settled result. To support this, the dispatcher keeps a map of
+        unfulfilled DOMPromises and the callback that is chained to the DOMPromise.
+
+        * inspector/InspectorFrontendAPIDispatcher.h:
+        * inspector/InspectorFrontendAPIDispatcher.cpp:
+        (WebCore::InspectorFrontendAPIDispatcher::~InspectorFrontendAPIDispatcher):
+        (WebCore::InspectorFrontendAPIDispatcher::reset):
+        Clear the pending responses map when destructing or resetting the dispatcher.
+
+        (WebCore::InspectorFrontendAPIDispatcher::frontendGlobalObject):
+        Upgrade from JSGlobalObject to JSDOMGlobalObject, which is needed to call JSDOMPromise methods.
+
+        (WebCore::InspectorFrontendAPIDispatcher::evaluateOrQueueExpression):
+        The meat of this patch. Chain a Function onto the JSDOMPromise. Inside the lambda function,
+        try to look up and invoke the corresponding EvaluationResultHandler for this evaluation result.
+
+        (WebCore::InspectorFrontendAPIDispatcher::invalidatePendingResponses):
+        Since these are CompletionHandlers we need to call them one way or another.
+
 2021-02-10  Alexey Proskuryakov  <a...@apple.com>
 
         Do not differentiate between Release and Production via ENABLE_DEVELOPER_MODE

Modified: trunk/Source/WebCore/inspector/InspectorFrontendAPIDispatcher.cpp (272683 => 272684)


--- trunk/Source/WebCore/inspector/InspectorFrontendAPIDispatcher.cpp	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebCore/inspector/InspectorFrontendAPIDispatcher.cpp	2021-02-10 21:34:27 UTC (rev 272684)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014-2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,6 +28,7 @@
 
 #include "Frame.h"
 #include "InspectorController.h"
+#include "JSDOMPromise.h"
 #include "Page.h"
 #include "ScriptController.h"
 #include "ScriptDisallowedScope.h"
@@ -36,11 +37,9 @@
 #include <_javascript_Core/FrameTracers.h>
 #include <wtf/RunLoop.h>
 
-
 namespace WebCore {
 
 using EvaluationError = InspectorFrontendAPIDispatcher::EvaluationError;
-using EvaluationResultHandler = CompletionHandler<Expected<JSC::JSValue, EvaluationError>>;
 
 InspectorFrontendAPIDispatcher::InspectorFrontendAPIDispatcher(Page& frontendPage)
     : m_frontendPage(makeWeakPtr(frontendPage))
@@ -50,6 +49,7 @@
 InspectorFrontendAPIDispatcher::~InspectorFrontendAPIDispatcher()
 {
     invalidateQueuedExpressions();
+    invalidatePendingResponses();
 }
 
 void InspectorFrontendAPIDispatcher::reset()
@@ -58,6 +58,7 @@
     m_suspended = false;
 
     invalidateQueuedExpressions();
+    invalidatePendingResponses();
 }
 
 void InspectorFrontendAPIDispatcher::frontendLoaded()
@@ -101,7 +102,7 @@
         evaluateQueuedExpressions();
 }
 
-JSC::JSGlobalObject* InspectorFrontendAPIDispatcher::frontendGlobalObject()
+JSDOMGlobalObject* InspectorFrontendAPIDispatcher::frontendGlobalObject()
 {
     if (!m_frontendPage)
         return nullptr;
@@ -166,8 +167,56 @@
     }
 
     ValueOrException result = evaluateExpression(_expression_);
-    if (optionalResultHandler)
+    if (!optionalResultHandler)
+        return;
+
+    if (!result.has_value()) {
         optionalResultHandler(result);
+        return;
+    }
+
+    JSDOMGlobalObject* globalObject = frontendGlobalObject();
+    if (!globalObject) {
+        optionalResultHandler(makeUnexpected(EvaluationError::ContextDestroyed));
+        return;
+    }
+        
+    auto& vm = globalObject->vm();
+    auto* castedPromise = jsDynamicCast<JSPromise*>(vm, result.value());
+    if (!castedPromise) {
+        // Simple case: result is NOT a promise, just return the JSValue.
+        optionalResultHandler(result);
+        return;
+    }
+
+    // If the result is a promise, call the result handler when the promise settles.
+    Ref<DOMPromise> promise = DOMPromise::create(*globalObject, *castedPromise);
+    m_pendingResponses.set(promise.copyRef(), WTFMove(optionalResultHandler));
+    auto isRegistered = promise->whenSettled([promise = promise.copyRef(), weakThis = makeWeakPtr(*this)] {
+        // If `this` is cleared or the responses map is empty, then the promise settled
+        // beyond the time when we care about its result. Ignore late-settled promises.
+        // We clear out completion handlers for pending responses during teardown.
+        if (!weakThis)
+            return;
+
+        auto strongThis = makeRef(*weakThis);
+        if (!strongThis->m_pendingResponses.size())
+            return;
+
+        EvaluationResultHandler resultHandler = strongThis->m_pendingResponses.take(promise);
+        ASSERT(resultHandler);
+        
+        JSDOMGlobalObject* globalObject = strongThis->frontendGlobalObject();
+        if (!globalObject) {
+            resultHandler(makeUnexpected(EvaluationError::ContextDestroyed));
+            return;
+        }
+
+        resultHandler({ promise->promise()->result(globalObject->vm()) });
+    });
+
+    if (isRegistered == DOMPromise::IsCallbackRegistered::No)
+        optionalResultHandler(makeUnexpected(EvaluationError::InternalError));
 }
 
 void InspectorFrontendAPIDispatcher::invalidateQueuedExpressions()
@@ -180,6 +229,16 @@
     }
 }
 
+void InspectorFrontendAPIDispatcher::invalidatePendingResponses()
+{
+    auto pendingResponses = std::exchange(m_pendingResponses, { });
+    for (auto& callback : pendingResponses.values())
+        callback(makeUnexpected(EvaluationError::ContextDestroyed));
+
+    // No more pending responses should have been added while erroring out the callbacks.
+    ASSERT(m_pendingResponses.isEmpty());
+}
+
 void InspectorFrontendAPIDispatcher::evaluateQueuedExpressions()
 {
     // If the frontend page has been deallocated, then there is nothing to do.

Modified: trunk/Source/WebCore/inspector/InspectorFrontendAPIDispatcher.h (272683 => 272684)


--- trunk/Source/WebCore/inspector/InspectorFrontendAPIDispatcher.h	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebCore/inspector/InspectorFrontendAPIDispatcher.h	2021-02-10 21:34:27 UTC (rev 272684)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014-2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -33,18 +33,21 @@
 #include <wtf/text/WTFString.h>
 
 namespace JSC {
-class JSGlobalObject;
 class JSValue;
 }
 
 namespace WebCore {
 
+class DOMPromise;
+class JSDOMGlobalObject;
 class Page;
 struct ExceptionDetails;
 
-class InspectorFrontendAPIDispatcher final : public RefCounted<InspectorFrontendAPIDispatcher> {
+class InspectorFrontendAPIDispatcher final
+    : public RefCounted<InspectorFrontendAPIDispatcher>
+    , public CanMakeWeakPtr<InspectorFrontendAPIDispatcher> {
 public:
-    enum class EvaluationError { ExecutionSuspended, ContextDestroyed };
+    enum class EvaluationError { ExecutionSuspended, ContextDestroyed, InternalError };
     using ValueOrException = Expected<JSC::JSValue, ExceptionDetails>;
     using EvaluationResult = Expected<ValueOrException, EvaluationError>;
     using EvaluationResultHandler = CompletionHandler<void(EvaluationResult)>;
@@ -75,9 +78,9 @@
 
     WEBCORE_EXPORT void evaluateExpressionForTesting(const String&);
     
-    // Convenience method to obtain a JSGlobalObject for the frontend page.
+    // Convenience method to obtain a JSDOMGlobalObject for the frontend page.
     // This is used to convert between C++ values and frontend JSC::JSValue objects.
-    WEBCORE_EXPORT JSC::JSGlobalObject* frontendGlobalObject();
+    WEBCORE_EXPORT JSDOMGlobalObject* frontendGlobalObject();
 private:
     WEBCORE_EXPORT InspectorFrontendAPIDispatcher(Page&);
 
@@ -84,10 +87,12 @@
     void evaluateOrQueueExpression(const String&, EvaluationResultHandler&& handler = { });
     void evaluateQueuedExpressions();
     void invalidateQueuedExpressions();
+    void invalidatePendingResponses();
     ValueOrException evaluateExpression(const String&);
 
     WeakPtr<Page> m_frontendPage;
     Vector<std::pair<String, EvaluationResultHandler>> m_queuedEvaluations;
+    HashMap<Ref<DOMPromise>, EvaluationResultHandler> m_pendingResponses;
     bool m_frontendLoaded { false };
     bool m_suspended { false };
 };

Modified: trunk/Source/WebInspectorUI/ChangeLog (272683 => 272684)


--- trunk/Source/WebInspectorUI/ChangeLog	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebInspectorUI/ChangeLog	2021-02-10 21:34:27 UTC (rev 272684)
@@ -1,3 +1,24 @@
+2021-02-10  BJ Burg  <bb...@apple.com>
+
+        [Cocoa] Web Inspector: add support for evaluating script on the inspected page via _WKInspectorExtension
+        https://bugs.webkit.org/show_bug.cgi?id=221567
+        <rdar://71208534>
+
+        Reviewed by Devin Rousso.
+
+        This patch adds InspectorFrontendAPI.evaluateScriptForExtension().
+
+        * UserInterface/Controllers/WebInspectorExtensionController.js:
+        (WI.WebInspectorExtensionController.prototype.evaluateScriptForExtension):
+        Translate arguments into a corresponding RuntimeAgent.evaluate invocation.
+        The parameters are not yet implemented, and will be filled in by a subsequent patch.
+
+        * UserInterface/Models/WebInspectorExtension.js: Add new error enum value.
+
+        * UserInterface/Protocol/InspectorFrontendAPI.js:
+        (InspectorFrontendAPI.evaluateScriptForExtension):
+        Plumbing.
+
 2021-02-10  Alexey Proskuryakov  <a...@apple.com>
 
         Do not differentiate between Release and Production via ENABLE_DEVELOPER_MODE

Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/WebInspectorExtensionController.js (272683 => 272684)


--- trunk/Source/WebInspectorUI/UserInterface/Controllers/WebInspectorExtensionController.js	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/WebInspectorExtensionController.js	2021-02-10 21:34:27 UTC (rev 272684)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2020-2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -85,6 +85,47 @@
         // The calling convention is to return an error string or a result object.
         return {extensionTabID};
     }
+
+    evaluateScriptForExtension(extensionID, scriptSource, {frameURL, contextSecurityOrigin, useContentScriptContext} = {})
+    {
+        let extension = this._extensionForExtensionIDMap.get(extensionID);
+        if (!extension) {
+            WI.reportInternalError("Unable to evaluate script for extension with unknown ID: " + extensionID);
+            return WI.WebInspectorExtension.ErrorCode.InvalidRequest;
+        }
+
+        // FIXME: <rdar://problem/74180355> implement execution context selection options
+        if (frameURL) {
+            WI.reportInternalError("evaluateScriptForExtension: the 'frameURL' option is not yet implemented.");
+            return WI.WebInspectorExtension.ErrorCode.NotImplemented;
+        }
+
+        if (contextSecurityOrigin) {
+            WI.reportInternalError("evaluateScriptForExtension: the 'contextSecurityOrigin' option is not yet implemented.");
+            return WI.WebInspectorExtension.ErrorCode.NotImplemented;
+        }
+
+        if (useContentScriptContext) {
+            WI.reportInternalError("evaluateScriptForExtension: the 'useContentScriptContext' option is not yet implemented.");
+            return WI.WebInspectorExtension.ErrorCode.NotImplemented;
+        }
+
+        let evaluationContext = WI.runtimeManager.activeExecutionContext;
+        return evaluationContext.target.RuntimeAgent.evaluate.invoke({
+            _expression_: scriptSource,
+            objectGroup: "extension-evaluation",
+            includeCommandLineAPI: true,
+            returnByValue: true,
+            generatePreview: false,
+            saveResult: false,
+            contextId: evaluationContext.id,
+        }).then((payload) => {
+            let resultOrError = payload.result;
+            let wasThrown = payload.wasThrown;
+            let {type, value} = resultOrError;
+            return wasThrown ? {"error": resultOrError.description} : {"result": value};
+        }).catch((error) => error.description);
+     }
 };
 
 WI.WebInspectorExtensionController.Event = {

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/WebInspectorExtension.js (272683 => 272684)


--- trunk/Source/WebInspectorUI/UserInterface/Models/WebInspectorExtension.js	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/WebInspectorExtension.js	2021-02-10 21:34:27 UTC (rev 272684)
@@ -46,4 +46,5 @@
     InternalError: "InternalError",
     InvalidRequest: "InvalidRequest",
     RegistrationFailed: "RegistrationFailed",
+    NotImplemented: "NotImplemented",
 };

Modified: trunk/Source/WebInspectorUI/UserInterface/Protocol/InspectorFrontendAPI.js (272683 => 272684)


--- trunk/Source/WebInspectorUI/UserInterface/Protocol/InspectorFrontendAPI.js	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebInspectorUI/UserInterface/Protocol/InspectorFrontendAPI.js	2021-02-10 21:34:27 UTC (rev 272684)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -216,4 +216,12 @@
     {
         return WI.sharedApp.extensionController.createTabForExtension(extensionID, tabName, tabIconURL, sourceURL);
     },
+
+    // Returns a string (WI.WebInspectorExtension.ErrorCode) if an error occurred that prevented evaluation.
+    // Returns an object with a 'result' key and value that is the result of the script evaluation.
+    // Returns an object with an 'error' key and value in the case that an exception was thrown.
+    evaluateScriptForExtension(extensionID, scriptSource, {frameURL, contextSecurityOrigin, useContentScriptContext} = {})
+    {
+        return WI.sharedApp.extensionController.evaluateScriptForExtension(extensionID, scriptSource, {frameURL, contextSecurityOrigin, useContentScriptContext});
+    }
 };

Modified: trunk/Source/WebKit/ChangeLog (272683 => 272684)


--- trunk/Source/WebKit/ChangeLog	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebKit/ChangeLog	2021-02-10 21:34:27 UTC (rev 272684)
@@ -1,3 +1,56 @@
+2021-02-10  BJ Burg  <bb...@apple.com>
+
+        [Cocoa] Web Inspector: add support for evaluating script on the inspected page via _WKInspectorExtension
+        https://bugs.webkit.org/show_bug.cgi?id=221567
+        <rdar://71208534>
+
+        Reviewed by Devin Rousso.
+
+        This patch adds a new method to _WKInspectorExtension which is used to implement
+        `browser.devtools.inspectedWindow.eval` in the Web Extensions API.
+
+        * Shared/InspectorExtensionTypes.h:
+        * Shared/InspectorExtensionTypes.cpp:
+        (WebKit::inspectorExtensionErrorToString):
+        Add enum value NotImplemented.
+
+        * UIProcess/API/APIInspectorExtension.h:
+        * UIProcess/API/APIInspectorExtension.cpp:
+        (API::InspectorExtension::evaluateScript):
+        Plumbing.
+
+        * UIProcess/API/Cocoa/WKWebViewInternal.h:
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (nsErrorFromExceptionDetails):
+        Move this helper up near the top as it is now exposed via <WebKit/WKWebViewInternal.h>.
+
+        * UIProcess/API/Cocoa/_WKInspectorExtension.h:
+        * UIProcess/API/Cocoa/_WKInspectorExtension.mm:
+        (-[_WKInspectorExtension evaluateScript:frameURL:contextSecurityOrigin:useContentScriptContext:completionHandler:]):
+        Add new method to evaluate script in the inspected page. The semantics of the parameters
+        are intended to match those of `browser.devtools.inspectedWindow.eval`.
+
+        * UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.h:
+        * UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.cpp:
+        (WebKit::WebInspectorUIExtensionControllerProxy::evaluateScriptForExtension):
+        Plumbing.
+
+        * WebProcess/Inspector/WebInspectorUIExtensionController.h:
+        * WebProcess/Inspector/WebInspectorUIExtensionController.messages.in:
+        Add new message for evaluateScript.
+
+        * WebProcess/Inspector/WebInspectorUIExtensionController.cpp:
+        (WebKit::WebInspectorUIExtensionController::parseInspectorExtensionErrorFromEvaluationResult):
+        Support the new error enum value.
+
+        (WebKit::WebInspectorUIExtensionController::unregisterExtension):
+        (WebKit::WebInspectorUIExtensionController::createTabForExtension):
+        Drive-by, simplify this by passing the EvaluationResult value without unwrapping.
+
+        (WebKit::WebInspectorUIExtensionController::evaluateScriptForExtension):
+        This is the meat of the patch. Call out to InspectorFrontendAPI.evaluateScriptForExtension.
+        Inspect the return value and invoke the completion handler with the result or an error.
+
 2021-02-10  Kimmo Kinnunen  <kkinnu...@apple.com>
 
         WebGL IPC messages are delivered out of order

Modified: trunk/Source/WebKit/Shared/InspectorExtensionTypes.cpp (272683 => 272684)


--- trunk/Source/WebKit/Shared/InspectorExtensionTypes.cpp	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebKit/Shared/InspectorExtensionTypes.cpp	2021-02-10 21:34:27 UTC (rev 272684)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2020-2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -43,6 +43,8 @@
         return "ContextDestroyed"_s;
     case InspectorExtensionError::RegistrationFailed:
         return "RegistrationFailed"_s;
+    case InspectorExtensionError::NotImplemented:
+        return "NotImplemented"_s;
     }
 
     ASSERT_NOT_REACHED();

Modified: trunk/Source/WebKit/Shared/InspectorExtensionTypes.h (272683 => 272684)


--- trunk/Source/WebKit/Shared/InspectorExtensionTypes.h	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebKit/Shared/InspectorExtensionTypes.h	2021-02-10 21:34:27 UTC (rev 272684)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2020-2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,10 +29,20 @@
 
 #if ENABLE(INSPECTOR_EXTENSIONS)
 
+namespace API {
+class SerializedScriptValue;
+}
+
+namespace WebCore {
+struct ExceptionDetails;
+}
+
 namespace WebKit {
+enum class InspectorExtensionError : uint8_t;
 
 using InspectorExtensionTabID = WTF::String;
 using InspectorExtensionID = WTF::String;
+using InspectorExtensionEvaluationResult = Expected<Expected<RefPtr<API::SerializedScriptValue>, WebCore::ExceptionDetails>, InspectorExtensionError>;
 
 enum class InspectorExtensionError : uint8_t {
     ContextDestroyed,
@@ -39,6 +49,7 @@
     InternalError,
     InvalidRequest,
     RegistrationFailed,
+    NotImplemented,
 };
 
 WTF::String inspectorExtensionErrorToString(InspectorExtensionError);
@@ -53,7 +64,8 @@
         WebKit::InspectorExtensionError::ContextDestroyed,
         WebKit::InspectorExtensionError::InternalError,
         WebKit::InspectorExtensionError::InvalidRequest,
-        WebKit::InspectorExtensionError::RegistrationFailed
+        WebKit::InspectorExtensionError::RegistrationFailed,
+        WebKit::InspectorExtensionError::NotImplemented
     >;
 };
 

Modified: trunk/Source/WebKit/UIProcess/API/APIInspectorExtension.cpp (272683 => 272684)


--- trunk/Source/WebKit/UIProcess/API/APIInspectorExtension.cpp	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebKit/UIProcess/API/APIInspectorExtension.cpp	2021-02-10 21:34:27 UTC (rev 272684)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2020-2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -30,6 +30,7 @@
 
 #include "InspectorExtensionTypes.h"
 #include "WebInspectorUIExtensionControllerProxy.h"
+#include <WebCore/ExceptionDetails.h>
 
 namespace API {
 
@@ -54,6 +55,16 @@
     m_extensionControllerProxy->createTabForExtension(m_identifier, tabName, tabIconURL, sourceURL, WTFMove(completionHandler));
 }
 
+void InspectorExtension::evaluateScript(const WTF::String& scriptSource, const Optional<WTF::URL>& frameURL, const Optional<WTF::URL>& contextSecurityOrigin, const Optional<bool>& useContentScriptContext, WTF::CompletionHandler<void(WebKit::InspectorExtensionEvaluationResult)>&& completionHandler)
+{
+    if (!m_extensionControllerProxy) {
+        completionHandler(makeUnexpected(WebKit::InspectorExtensionError::ContextDestroyed));
+        return;
+    }
+
+    m_extensionControllerProxy->evaluateScriptForExtension(m_identifier, scriptSource, frameURL, contextSecurityOrigin, useContentScriptContext, WTFMove(completionHandler));
+}
+
 } // namespace API
 
 #endif // ENABLE(INSPECTOR_EXTENSIONS)

Modified: trunk/Source/WebKit/UIProcess/API/APIInspectorExtension.h (272683 => 272684)


--- trunk/Source/WebKit/UIProcess/API/APIInspectorExtension.h	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebKit/UIProcess/API/APIInspectorExtension.h	2021-02-10 21:34:27 UTC (rev 272684)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2020-2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -47,6 +47,7 @@
     const WTF::String& identifier() const { return m_identifier; }
 
     void createTab(const WTF::String& tabName, const WTF::URL& tabIconURL, const WTF::URL& sourceURL, WTF::CompletionHandler<void(Expected<WebKit::InspectorExtensionTabID, WebKit::InspectorExtensionError>)>&&);
+    void evaluateScript(const WTF::String& scriptSource, const Optional<WTF::URL>& frameURL, const Optional<WTF::URL>& contextSecurityOrigin, const Optional<bool>& useContentScriptContext, WTF::CompletionHandler<void(WebKit::InspectorExtensionEvaluationResult)>&&);
 
 private:
     InspectorExtension(const WTF::String& identifier, WebKit::WebInspectorUIExtensionControllerProxy&);

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm (272683 => 272684)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm	2021-02-10 21:34:27 UTC (rev 272684)
@@ -205,6 +205,34 @@
     return pageToViewMap().get(&page);
 }
 
+RetainPtr<NSError> nsErrorFromExceptionDetails(const WebCore::ExceptionDetails& details)
+{
+    auto userInfo = adoptNS([[NSMutableDictionary alloc] init]);
+
+    WKErrorCode errorCode;
+    switch (details.type) {
+    case WebCore::ExceptionDetails::Type::InvalidTargetFrame:
+        errorCode = WKErrorJavaScriptInvalidFrameTarget;
+        break;
+    case WebCore::ExceptionDetails::Type::Script:
+        errorCode = WKErrorJavaScriptExceptionOccurred;
+        break;
+    case WebCore::ExceptionDetails::Type::AppBoundDomain:
+        errorCode = WKErrorJavaScriptAppBoundDomain;
+        break;
+    }
+
+    [userInfo setObject:localizedDescriptionForErrorCode(errorCode) forKey:NSLocalizedDescriptionKey];
+    [userInfo setObject:details.message forKey:_WKJavaScriptExceptionMessageErrorKey];
+    [userInfo setObject:@(details.lineNumber) forKey:_WKJavaScriptExceptionLineNumberErrorKey];
+    [userInfo setObject:@(details.columnNumber) forKey:_WKJavaScriptExceptionColumnNumberErrorKey];
+
+    if (!details.sourceURL.isEmpty())
+        [userInfo setObject:[NSURL _web_URLWithWTFString:details.sourceURL] forKey:_WKJavaScriptExceptionSourceURLErrorKey];
+
+    return adoptNS([[NSError alloc] initWithDomain:WKErrorDomain code:errorCode userInfo:userInfo.get()]);
+}
+
 @implementation WKWebView
 
 - (instancetype)initWithFrame:(CGRect)frame
@@ -961,34 +989,6 @@
     });
 }
 
-static RetainPtr<NSError> nsErrorFromExceptionDetails(const WebCore::ExceptionDetails& details)
-{
-    auto userInfo = adoptNS([[NSMutableDictionary alloc] init]);
-
-    WKErrorCode errorCode;
-    switch (details.type) {
-    case WebCore::ExceptionDetails::Type::InvalidTargetFrame:
-        errorCode = WKErrorJavaScriptInvalidFrameTarget;
-        break;
-    case WebCore::ExceptionDetails::Type::Script:
-        errorCode = WKErrorJavaScriptExceptionOccurred;
-        break;
-    case WebCore::ExceptionDetails::Type::AppBoundDomain:
-        errorCode = WKErrorJavaScriptAppBoundDomain;
-        break;
-    }
-
-    [userInfo setObject:localizedDescriptionForErrorCode(errorCode) forKey:NSLocalizedDescriptionKey];
-    [userInfo setObject:details.message forKey:_WKJavaScriptExceptionMessageErrorKey];
-    [userInfo setObject:@(details.lineNumber) forKey:_WKJavaScriptExceptionLineNumberErrorKey];
-    [userInfo setObject:@(details.columnNumber) forKey:_WKJavaScriptExceptionColumnNumberErrorKey];
-
-    if (!details.sourceURL.isEmpty())
-        [userInfo setObject:[NSURL _web_URLWithWTFString:details.sourceURL] forKey:_WKJavaScriptExceptionSourceURLErrorKey];
-
-    return adoptNS([[NSError alloc] initWithDomain:WKErrorDomain code:errorCode userInfo:userInfo.get()]);
-}
-
 - (void)_evaluateJavaScript:(NSString *)_javascript_String asAsyncFunction:(BOOL)asAsyncFunction withSourceURL:(NSURL *)sourceURL withArguments:(NSDictionary<NSString *, id> *)arguments forceUserGesture:(BOOL)forceUserGesture inFrame:(WKFrameInfo *)frame inWorld:(WKContentWorld *)world completionHandler:(void (^)(id, NSError *))completionHandler
 {
     auto handler = adoptNS([completionHandler copy]);

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h (272683 => 272684)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h	2021-02-10 21:34:27 UTC (rev 272684)
@@ -67,6 +67,7 @@
 }
 
 namespace WebCore {
+struct ExceptionDetails;
 enum class WheelScrollGestureState : uint8_t;
 }
 
@@ -281,6 +282,7 @@
 @end
 
 WKWebView* fromWebPageProxy(WebKit::WebPageProxy&);
+RetainPtr<NSError> nsErrorFromExceptionDetails(const WebCore::ExceptionDetails&);
 
 #if ENABLE(FULLSCREEN_API) && PLATFORM(IOS_FAMILY)
 @interface WKWebView (FullScreenAPI_Internal)

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtension.h (272683 => 272684)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtension.h	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtension.h	2021-02-10 21:34:27 UTC (rev 272684)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2020-2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -48,6 +48,19 @@
  */
 - (void)createTabWithName:(NSString *)tabName tabIconURL:(NSURL *)tabIconURL sourceURL:(NSURL *)sourceURL completionHandler:(void(^)(NSError * _Nullable, NSString * _Nullable inspectorTabID))completionHandler;
 
+/**
+ * @abstract Evaluates _javascript_ in the context of the inspected page on behalf of the _WKInspectorExtension.
+ * @param scriptSource The _javascript_ code to be evaluated.
+ * @param frameURL URL for the frame in which to evaluate the script. If nil is passed, the main frame will be used.
+ * @param contextSecurityOrigin If specified, evaluate the script in the content script context of a different security origin.
+ * @param usesContentScriptContext If YES, evaluate the script in the context of the extension's content scripts.
+ * @param completionHandler A block to invoke when the operation completes or fails.
+ * @discussion The completionHandler is passed an NSJSONSerialization-compatible NSObject representing the evaluation result, or an error.
+ * scriptSource is treated as a top-level evaluation. By default, the script is evaluated in the inspected page's script context.
+ * The inspected page ultimately controls its execution context and the result of this evaluation. Thus, the result shall be treated as untrusted input.
+ */
+- (void)evaluateScript:(NSString *)scriptSource frameURL:(NSURL *)frameURL contextSecurityOrigin:(NSURL *)contextSecurityOrigin useContentScriptContext:(BOOL)useContentScriptContext completionHandler:(void(^)(NSError * _Nullable, NSDictionary * _Nullable result))completionHandler;
+
 @property (readonly, nonatomic) NSString *extensionID;
 
 @end

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtension.mm (272683 => 272684)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtension.mm	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtension.mm	2021-02-10 21:34:27 UTC (rev 272684)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2020-2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,6 +27,7 @@
 #import "_WKInspectorExtensionInternal.h"
 
 #import "WKError.h"
+#import "WKWebViewInternal.h"
 #import <wtf/BlockPtr.h>
 #import <wtf/URL.h>
 
@@ -60,6 +61,27 @@
     });
 }
 
+- (void)evaluateScript:(NSString *)scriptSource frameURL:(NSURL *)frameURL contextSecurityOrigin:(NSURL *)contextSecurityOrigin useContentScriptContext:(BOOL)useContentScriptContext completionHandler:(void(^)(NSError *, NSDictionary *))completionHandler
+{
+    Optional<URL> optionalFrameURL = frameURL ? makeOptional(URL(frameURL)) : WTF::nullopt;
+    Optional<URL> optionalContextSecurityOrigin = contextSecurityOrigin ? makeOptional(URL(contextSecurityOrigin)) : WTF::nullopt;
+    _extension->evaluateScript(scriptSource, optionalFrameURL, optionalContextSecurityOrigin, useContentScriptContext, [protectedSelf = retainPtr(self), capturedBlock = makeBlockPtr(WTFMove(completionHandler))] (WebKit::InspectorExtensionEvaluationResult&& result) mutable {
+        if (!result) {
+            capturedBlock([NSError errorWithDomain:WKErrorDomain code:WKErrorUnknown userInfo:@{ NSLocalizedFailureReasonErrorKey: inspectorExtensionErrorToString(result.error())}], nil);
+            return;
+        }
+        
+        auto valueOrException = result.value();
+        if (!valueOrException) {
+            capturedBlock(nsErrorFromExceptionDetails(valueOrException.error()).get(), nil);
+            return;
+        }
+
+        id body = API::SerializedScriptValue::deserialize(valueOrException.value()->internalRepresentation(), 0);
+        capturedBlock(nil, body);
+    });
+}
+
 // MARK: Properties.
 
 - (NSString *)extensionID

Modified: trunk/Source/WebKit/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.cpp (272683 => 272684)


--- trunk/Source/WebKit/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.cpp	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebKit/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.cpp	2021-02-10 21:34:27 UTC (rev 272684)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2020-2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -110,6 +110,33 @@
     });
 }
 
+void WebInspectorUIExtensionControllerProxy::evaluateScriptForExtension(const InspectorExtensionID& extensionID, const String& scriptSource, const Optional<WTF::URL>& frameURL, const Optional<WTF::URL>& contextSecurityOrigin, const Optional<bool>& useContentScriptContext, WTF::CompletionHandler<void(InspectorExtensionEvaluationResult)>&& completionHandler)
+{
+    whenFrontendHasLoaded([weakThis = makeWeakPtr(this), extensionID, scriptSource, frameURL, contextSecurityOrigin, useContentScriptContext, completionHandler = WTFMove(completionHandler)] () mutable {
+        if (!weakThis || !weakThis->m_inspectorPage) {
+            completionHandler(makeUnexpected(InspectorExtensionError::ContextDestroyed));
+            return;
+        }
+
+        weakThis->m_inspectorPage->sendWithAsyncReply(Messages::WebInspectorUIExtensionController::EvaluateScriptForExtension {extensionID, scriptSource, frameURL, contextSecurityOrigin, useContentScriptContext}, [completionHandler = WTFMove(completionHandler)](const IPC::DataReference& dataReference, const Optional<WebCore::ExceptionDetails>& details, const Optional<InspectorExtensionError> error) mutable {
+            if (error) {
+                completionHandler(makeUnexpected(error.value()));
+                return;
+            }
+
+            if (details) {
+                Expected<RefPtr<API::SerializedScriptValue>, WebCore::ExceptionDetails> returnedValue = makeUnexpected(details.value());
+                return completionHandler({ returnedValue });
+            }
+
+            Vector<uint8_t> data;
+            data.reserveInitialCapacity(dataReference.size());
+            data.append(dataReference.data(), dataReference.size());
+            completionHandler({ { API::SerializedScriptValue::adopt(WTFMove(data)).ptr() } });
+        });
+    });
+}
+
 } // namespace WebKit
 
 #endif // ENABLE(INSPECTOR_EXTENSIONS)

Modified: trunk/Source/WebKit/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.h (272683 => 272684)


--- trunk/Source/WebKit/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.h	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebKit/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.h	2021-02-10 21:34:27 UTC (rev 272684)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2020-2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,6 +31,7 @@
 #include "MessageReceiver.h"
 #include <wtf/Expected.h>
 #include <wtf/Forward.h>
+#include <wtf/URL.h>
 #include <wtf/WeakPtr.h>
 
 namespace WebKit {
@@ -50,6 +51,7 @@
     void registerExtension(const InspectorExtensionID&, const String& displayName, WTF::CompletionHandler<void(Expected<bool, InspectorExtensionError>)>&&);
     void unregisterExtension(const InspectorExtensionID&, WTF::CompletionHandler<void(Expected<bool, InspectorExtensionError>)>&&);
     void createTabForExtension(const InspectorExtensionID&, const String& tabName, const URL& tabIconURL, const URL& sourceURL, WTF::CompletionHandler<void(Expected<InspectorExtensionTabID, InspectorExtensionError>)>&&);
+    void evaluateScriptForExtension(const InspectorExtensionID&, const String& scriptSource, const Optional<URL>& frameURL, const Optional<URL>& contextSecurityOrigin, const Optional<bool>& useContentScriptContext, WTF::CompletionHandler<void(InspectorExtensionEvaluationResult)>&&);
 
     // Notifications.
     void inspectorFrontendLoaded();

Modified: trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.cpp (272683 => 272684)


--- trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.cpp	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.cpp	2021-02-10 21:34:27 UTC (rev 272684)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2020-2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -34,9 +34,11 @@
 #include "WebInspectorUIExtensionControllerMessagesReplies.h"
 #include "WebPage.h"
 #include "WebProcess.h"
+#include <_javascript_Core/APICast.h>
 #include <_javascript_Core/JSCInlines.h>
 #include <WebCore/ExceptionDetails.h>
 #include <WebCore/InspectorFrontendAPIDispatcher.h>
+#include <WebCore/SerializedScriptValue.h>
 
 namespace WebKit {
 
@@ -62,6 +64,8 @@
             return InspectorExtensionError::ContextDestroyed;
         case WebCore::InspectorFrontendAPIDispatcher::EvaluationError::ExecutionSuspended:
             return InspectorExtensionError::InternalError;
+        case WebCore::InspectorFrontendAPIDispatcher::EvaluationError::InternalError:
+            return InspectorExtensionError::InternalError;
         }
     }
 
@@ -90,6 +94,8 @@
             return InspectorExtensionError::InvalidRequest;
         if (resultString == "RegistrationFailed"_s)
             return InspectorExtensionError::RegistrationFailed;
+        if (resultString == "NotImplemented"_s)
+            return InspectorExtensionError::NotImplemented;
 
         ASSERT_NOT_REACHED();
         return InspectorExtensionError::InternalError;
@@ -140,7 +146,7 @@
             return;
         }
 
-        if (auto parsedError = weakThis->parseInspectorExtensionErrorFromEvaluationResult(result.value())) {
+        if (auto parsedError = weakThis->parseInspectorExtensionErrorFromEvaluationResult(result)) {
             completionHandler(makeUnexpected(parsedError.value()));
             return;
         }
@@ -153,11 +159,11 @@
 {
     if (!result)
         return nullptr;
-    
+
     auto valueOrException = result.value();
     if (!valueOrException.has_value())
         return nullptr;
-    
+
     return valueOrException.value().getObject();
 }
 
@@ -180,7 +186,7 @@
             return;
         }
 
-        if (auto parsedError = weakThis->parseInspectorExtensionErrorFromEvaluationResult(result.value())) {
+        if (auto parsedError = weakThis->parseInspectorExtensionErrorFromEvaluationResult(result)) {
             completionHandler(makeUnexpected(parsedError.value()));
             return;
         }
@@ -204,6 +210,77 @@
     });
 }
 
+void WebInspectorUIExtensionController::evaluateScriptForExtension(const InspectorExtensionID& extensionID, const String& scriptSource, const Optional<URL>& frameURL, const Optional<URL>& contextSecurityOrigin, const Optional<bool>& useContentScriptContext, CompletionHandler<void(const IPC::DataReference&, const Optional<WebCore::ExceptionDetails>&, const Optional<InspectorExtensionError>&)>&& completionHandler)
+{
+    if (!m_frontendClient) {
+        completionHandler({ }, WTF::nullopt, InspectorExtensionError::InvalidRequest);
+        return;
+    }
+
+    Ref<JSON::Object> optionalArguments = JSON::Object::create();
+    if (frameURL)
+        optionalArguments->setString("frameURL"_s, frameURL->string());
+    if (contextSecurityOrigin)
+        optionalArguments->setString("contextSecurityOrigin"_s, contextSecurityOrigin->string());
+    if (useContentScriptContext)
+        optionalArguments->setBoolean("useContentScriptContext"_s, *useContentScriptContext);
+
+    Vector<Ref<JSON::Value>> arguments {
+        JSON::Value::create(extensionID),
+        JSON::Value::create(scriptSource),
+        WTFMove(optionalArguments)
+    };
+
+    m_frontendClient->frontendAPIDispatcher().dispatchCommandWithResultAsync("evaluateScriptForExtension"_s, WTFMove(arguments), [weakThis = makeWeakPtr(this), completionHandler = WTFMove(completionHandler)](InspectorFrontendAPIDispatcher::EvaluationResult&& result) mutable {
+        if (!weakThis) {
+            completionHandler({ }, WTF::nullopt, InspectorExtensionError::ContextDestroyed);
+            return;
+        }
+
+        auto* frontendGlobalObject = weakThis->m_frontendClient->frontendAPIDispatcher().frontendGlobalObject();
+        if (!frontendGlobalObject) {
+            completionHandler({ }, WTF::nullopt, InspectorExtensionError::ContextDestroyed);
+            return;
+        }
+
+        if (auto parsedError = weakThis->parseInspectorExtensionErrorFromEvaluationResult(result)) {
+            auto exceptionDetails = result.value().error();
+            LOG(Inspector, "Internal error encountered while evaluating upon the frontend: at %s:%d:%d: %s", exceptionDetails.sourceURL.utf8().data(), exceptionDetails.lineNumber, exceptionDetails.columnNumber, exceptionDetails.message.utf8().data());
+            completionHandler({ }, WTF::nullopt, parsedError);
+            return;
+        }
+
+        // Expected result is either an ErrorString or {result: <any>}.
+        auto objectResult = weakThis->unwrapEvaluationResultAsObject(result);
+        if (!objectResult) {
+            LOG(Inspector, "Unexpected non-object value returned from InspectorFrontendAPI.createTabForExtension().");
+            completionHandler({ }, WTF::nullopt, InspectorExtensionError::InternalError);
+            return;
+        }
+        ASSERT(result.value());
+
+        JSC::JSValue errorPayload = objectResult->get(frontendGlobalObject, JSC::Identifier::fromString(frontendGlobalObject->vm(), "error"_s));
+        if (!errorPayload.isUndefined()) {
+            if (!errorPayload.isString()) {
+                completionHandler({ }, WTF::nullopt, InspectorExtensionError::InternalError);
+                return;
+            }
+
+            completionHandler({ }, ExceptionDetails { errorPayload.toWTFString(frontendGlobalObject) }, WTF::nullopt);
+            return;
+        }
+
+        JSC::JSValue resultPayload = objectResult->get(frontendGlobalObject, JSC::Identifier::fromString(frontendGlobalObject->vm(), "result"_s));
+        RefPtr<SerializedScriptValue> serializedResultValue = SerializedScriptValue::create(*frontendGlobalObject, resultPayload);
+        if (!serializedResultValue) {
+            completionHandler({ }, WTF::nullopt, InspectorExtensionError::InternalError);
+            return;
+        }
+
+        completionHandler(serializedResultValue->data(), WTF::nullopt, WTF::nullopt);
+    });
+}
+
 } // namespace WebKit
 
 #endif // ENABLE(INSPECTOR_EXTENSIONS)

Modified: trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.h (272683 => 272684)


--- trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.h	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.h	2021-02-10 21:34:27 UTC (rev 272684)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2020-2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -64,7 +64,8 @@
     // WebInspectorUIExtensionController IPC messages.
     void registerExtension(const InspectorExtensionID&, const String& displayName, CompletionHandler<void(Expected<bool, InspectorExtensionError>)>&&);
     void unregisterExtension(const InspectorExtensionID&, CompletionHandler<void(Expected<bool, InspectorExtensionError>)>&&);
-    void createTabForExtension(const InspectorExtensionID&, const String& tabName, const URL& tabIconURL, const URL& sourceURL, WTF::CompletionHandler<void(Expected<InspectorExtensionTabID, InspectorExtensionError>)>&&);
+    void createTabForExtension(const InspectorExtensionID&, const String& tabName, const URL& tabIconURL, const URL& sourceURL, CompletionHandler<void(Expected<InspectorExtensionTabID, InspectorExtensionError>)>&&);
+    void evaluateScriptForExtension(const InspectorExtensionID&, const String& scriptSource, const Optional<URL>& frameURL, const Optional<URL>& contextSecurityOrigin, const Optional<bool>& useContentScriptContext, CompletionHandler<void(const IPC::DataReference&, const Optional<WebCore::ExceptionDetails>&, const Optional<InspectorExtensionError>&)>&&);
 
 private:
     JSC::JSObject* unwrapEvaluationResultAsObject(WebCore::InspectorFrontendAPIDispatcher::EvaluationResult);

Modified: trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.messages.in (272683 => 272684)


--- trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.messages.in	2021-02-10 21:27:48 UTC (rev 272683)
+++ trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.messages.in	2021-02-10 21:34:27 UTC (rev 272684)
@@ -1,4 +1,4 @@
-# Copyright (C) 2020 Apple Inc. All rights reserved.
+# Copyright (C) 2020-2021 Apple Inc. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
@@ -27,6 +27,7 @@
     UnregisterExtension(String extensionID) -> (Expected<bool, WebKit::InspectorExtensionError> result) Async
 
     CreateTabForExtension(String extensionID, String tabName, URL tabIconURL, URL sourceURL) -> (Expected<String, WebKit::InspectorExtensionError> result) Async
+    EvaluateScriptForExtension(String extensionID, String scriptSource, Optional<URL> frameURL, Optional<URL> contextSecurityOrigin, Optional<bool> useContentScriptContext) -> (IPC::DataReference resultData, Optional<WebCore::ExceptionDetails> details, Optional<WebKit::InspectorExtensionError> error) Async
 }
 
 #endif // ENABLE(INSPECTOR_EXTENSIONS)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to