⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 283276 in webkit


Ignore:
Timestamp:
Sep 29, 2021, 4:28:22 PM (5 years ago)
Author:
BJ Burg
Message:

[Cocoa] add _WKInspectorExtension SPI to evaluate script on an extension tab
https://bugs.webkit.org/show_bug.cgi?id=230646
<rdar://problem/83420328>

Reviewed by Devin Rousso.

Source/WebCore:

Exercised by new API test: WKInspectorExtension.CanEvaluateScriptInExtensionTab

  • inspector/InspectorFrontendHost.h:
  • inspector/InspectorFrontendHost.idl:
  • inspector/InspectorFrontendHost.cpp:

(WebCore::InspectorFrontendHost::evaluateScriptInExtensionTab):
Find the global object that corresponds to the passed-in <iframe> and
try to evaluate scriptSource in the mainThreadNormalWorld() of that <iframe>.

  • html/HTMLIFrameElement.idl: Add [JSGenerateToNativeObject] so that

it's possible to pass HTMLIFrameElement to the IDL function and convert it
to the native object (HTMLIFrameElement&) from a JSValue.

Source/WebInspectorUI:

Add a new InspectorFrontendAPI method to evaluate script on an iframe within
Web Inspector. This in turn calls out to InspectorFrontendHost to do the actual evaluation.
Otherwise, the CSP policy set by the tab content may block any such evaluation
if the 'script-src' directive does not include 'unsafe-eval'.

  • UserInterface/Protocol/InspectorFrontendAPI.js:

(InspectorFrontendAPI.showExtensionTab):
(InspectorFrontendAPI.evaluateScriptInExtensionTab):
Call through to the WebInspectorExtensionController method.

  • UserInterface/Controllers/WebInspectorExtensionController.js:

(WI.WebInspectorExtensionController.prototype.evaluateScriptInExtensionTab): Added.
Try to get the <iframe> for a extensionTabID, and use InspectorFrontendHost to
evaluate script in the context of the <iframe>. Be sure to correctly wrap the result.

  • UserInterface/Views/WebInspectorExtensionTabContentView.js:

(WI.WebInspectorExtensionTabContentView):
(WI.WebInspectorExtensionTabContentView.prototype.get iframeElement):
(WI.WebInspectorExtensionTabContentView.shouldSaveTab):
(WI.WebInspectorExtensionTabContentView.prototype.initialLayout): Deleted.
While writing the API test, I saw that the first evaluation frequently failed
because the <iframe> did not exist. Change this class so that the <iframe>
is created in the constructor. Add a getter for the <iframe> element.

(WI.WebInspectorExtensionTabContentView.prototype._extensionFrameDidLoad):
(WI.WebInspectorExtensionTabContentView.prototype._maybeDispatchDidShowExtensionTab):
While writing this patch, it became apparent that didShowExtensionTab() was being
called prior to the iframe actually completing its initial load. Then, the test
would try to evaluate script on about:blank instead of the actual tab content.
To fix this, require that the <iframe> be attached and have fired the onload event
before we notify clients that it has been 'shown'.

  • UserInterface/Main.html:

Adjust the default CSP policy to not mention img-src. This allows ports such as
Cocoa to set their own img-src CSP directive. These changes are necessary to allow
images to load from custom URL schemes.

  • UserInterface/Views/TabBrowser.js:

(WI.TabBrowser.prototype.bestTabContentViewForRepresentedObject):
The new API test exposes a bug in this assertion, namely, that it does not account
for the situation where a tab does not wish to be saved. In that case, the displayed
WebInspectorExtensionTabContentView is *not* at index 0 of WI.TabBrowser.recentTabContentViews.
This is correctly handled with a special case in WI.TabBrowser._tabBarItemSelected,
so incorporate that logic into the assertion.

Source/WebKit:

Add new testing API for evaluating script expressions in the context of a
tab created by _WKInspectorExtension. For the most part, this is implemented
in the same way as the -evaluateScript: method, but the script is evaluated
within the Web Inspector frontend itself rather than in the inspected page.

To avoid CSP issues, the actual evaluation is performed on subframes using a
new InspectorFrontendHost method which takes an <iframe> and script source.

Along the way, tweak Web Inspector's CSP policy to allow loading images from
custom URL schemes as specified using _WKInspectorConfiguration. This is so
that tab icons from the test-resource: scheme can be loaded in the main frame
of Web Inspector's WKWebView under testing situations.

  • SourcesCocoa.txt:
  • WebKit.xcodeproj/project.pbxproj:

Add new files.

  • UIProcess/API/APIInspectorExtension.h:
  • UIProcess/API/APIInspectorExtension.cpp:

(API::InspectorExtension::evaluateScriptInExtensionTab):
Based on evaluateScript(). Call through to the shared extension controller.

  • UIProcess/API/Cocoa/_WKInspectorExtensionPrivateForTesting.h: Added.
  • UIProcess/API/Cocoa/_WKInspectorExtensionTesting.mm: Added.

(-[_WKInspectorExtension _evaluateScript:inExtensionTabWithIdentifier:completionHandler:]):
Added. Call through to the shared extension controller.

  • UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.h:
  • UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.cpp:

(WebKit::WebInspectorUIExtensionControllerProxy::evaluateScriptInExtensionTab):
Based on evaluateScript(). Send IPC to the Inspector WebProcess.

  • WebProcess/Inspector/WebInspectorUIExtensionController.h:
  • WebProcess/Inspector/WebInspectorUIExtensionController.messages.in:
  • WebProcess/Inspector/WebInspectorUIExtensionController.cpp:

(WebKit::WebInspectorUIExtensionController::evaluateScriptInExtensionTab):
Based on evaluateScriptForExtension. Call into the frontend API
which will perform the actual evaluation on the <iframe> contentWindow.

  • UIProcess/Inspector/mac/WKInspectorResourceURLSchemeHandler.mm:

(-[WKInspectorResourceURLSchemeHandler webView:startURLSchemeTask:]):
Specify the list of custom protocols as allowable sources for 'img-src'.
The 'img-src' directive also includes 'file: blob: resource:' as allowable
sources, since this was the previous CSP policy defined in Main.html.

  • UIProcess/Cocoa/GroupActivities/GroupActivitiesSessionNotifier.mm:

Fix UnifiedSources fallout by including a missing header.

Tools:

Add a new test to exercise the SPI. The test sets up an _WKInspectorExtension,
creates a tab, evaluates script on the tab, and later reads back the stored value.

Notably, this test would fail if the extension tab is not currently showing.
This is a bug and will be addressed as part of https://bugs.webkit.org/show_bug.cgi?id=230758.

  • TestWebKitAPI/SourcesCocoa.txt:
  • TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:

Add new files.

  • TestWebKitAPI/Tests/WebKitCocoa/InspectorExtension-basic-tab.html:

Add inline <script> to set window._secretValue. This is checked by the API test.

  • TestWebKitAPI/Tests/WebKitCocoa/WKInspectorExtension.mm: Added.

(resetGlobalState):
(-[UIDelegateForTestingInspectorExtension _webView:didAttachLocalInspector:]):
(-[UIDelegateForTestingInspectorExtension _webView:configurationForLocalInspector:]):
(-[InspectorExtensionDelegateForTestingInspectorExtension inspectorExtension:didShowTabWithIdentifier:]):
(-[InspectorExtensionDelegateForTestingInspectorExtension inspectorExtension:didHideTabWithIdentifier:]):
(TEST):

  • TestWebKitAPI/Tests/WebKitCocoa/WKInspectorExtensionDelegate.mm:

(-[UIDelegateForTestingInspectorExtensionDelegate _webView:configurationForLocalInspector:]):
(TEST):
Adopt fixes from WKInspectorExtension that allow extension tab content and icons to load.

  • TestWebKitAPI/cocoa/TestInspectorURLSchemeHandler.h: Added.
  • TestWebKitAPI/cocoa/TestInspectorURLSchemeHandler.mm: Copied from Source/WebKit/UIProcess/Inspector/mac/WKInspectorResourceURLSchemeHandler.mm.

(-[TestInspectorURLSchemeHandler webView:startURLSchemeTask:]):
(-[TestInspectorURLSchemeHandler webView:stopURLSchemeTask:]):
Add a simple URLSchemeHandler which allows serving test resources from the TestWebKitAPI.resources directory.
This is necessary to test _WKInspectorExtension tabs, which must load their content from a custom URL scheme.

  • TestWebKitAPI/cocoa/TestWKWebView.mm:

Fix UnifiedSources fallout by adding a missing include.

Location:
trunk
Files:
3 added
29 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r283275 r283276  
     12021-09-29  BJ Burg  <bburg@apple.com>
     2
     3        [Cocoa] add _WKInspectorExtension SPI to evaluate script on an extension tab
     4        https://bugs.webkit.org/show_bug.cgi?id=230646
     5        <rdar://problem/83420328>
     6
     7        Reviewed by Devin Rousso.
     8
     9        Exercised by new API test: WKInspectorExtension.CanEvaluateScriptInExtensionTab
     10
     11        * inspector/InspectorFrontendHost.h:
     12        * inspector/InspectorFrontendHost.idl:
     13        * inspector/InspectorFrontendHost.cpp:
     14        (WebCore::InspectorFrontendHost::evaluateScriptInExtensionTab):
     15        Find the global object that corresponds to the passed-in <iframe> and
     16        try to evaluate scriptSource in the mainThreadNormalWorld() of that <iframe>.
     17
     18        * html/HTMLIFrameElement.idl: Add [JSGenerateToNativeObject] so that
     19        it's possible to pass HTMLIFrameElement to the IDL function and convert it
     20        to the native object (HTMLIFrameElement&) from a JSValue.
     21
    1222021-09-29  Alan Bujtas  <zalan@apple.com>
    223
  • trunk/Source/WebCore/html/HTMLIFrameElement.idl

    r274832 r283276  
    2020
    2121[
    22     Exposed=Window
     22    Exposed=Window,
     23    JSGenerateToNativeObject
    2324] interface HTMLIFrameElement : HTMLElement {
    2425    [Reflect, CEReactions=NotNeeded] attribute DOMString align;
  • trunk/Source/WebCore/inspector/InspectorFrontendHost.cpp

    r281182 r283276  
    4343#include "FocusController.h"
    4444#include "Frame.h"
     45#include "HTMLIFrameElement.h"
    4546#include "HitTestResult.h"
    4647#include "InspectorController.h"
     
    7071
    7172using namespace Inspector;
     73using ValueOrException = Expected<JSC::JSValue, ExceptionDetails>;
    7274
    7375#if ENABLE(CONTEXT_MENUS)
     
    707709    m_client->didHideExtensionTab(extensionID, extensionTabID);
    708710}
     711
     712ExceptionOr<JSC::JSValue> InspectorFrontendHost::evaluateScriptInExtensionTab(HTMLIFrameElement& extensionFrameElement, const String& scriptSource)
     713{
     714    Frame* frame = extensionFrameElement.contentFrame();
     715    if (!frame)
     716        return Exception { InvalidStateError, "Unable to find global object for <iframe>"_s };
     717
     718    Ref<Frame> protectedFrame(*frame);
     719
     720    JSDOMGlobalObject* frameGlobalObject = frame->script().globalObject(mainThreadNormalWorld());
     721    if (!frameGlobalObject)
     722        return Exception { InvalidStateError, "Unable to find global object for <iframe>"_s };
     723
     724    JSC::SuspendExceptionScope scope(&frameGlobalObject->vm());
     725    ValueOrException result = frame->script().evaluateInWorld(ScriptSourceCode(scriptSource), mainThreadNormalWorld());
     726   
     727    if (!result)
     728        return Exception { InvalidStateError, result.error().message };
     729
     730    return WTFMove(result.value());
     731}
     732
    709733#endif // ENABLE(INSPECTOR_EXTENSIONS)
    710734
  • trunk/Source/WebCore/inspector/InspectorFrontendHost.h

    r278253 r283276  
    3131#include "ContextMenu.h"
    3232#include "ContextMenuProvider.h"
     33#include "ExceptionOr.h"
    3334#include <wtf/RefCounted.h>
    3435#include <wtf/Vector.h>
     
    4041class Event;
    4142class FrontendMenuProvider;
     43class HTMLIFrameElement;
    4244class InspectorFrontendClient;
    4345class Page;
     
    142144    void didShowExtensionTab(const String& extensionID, const String& extensionTabID);
    143145    void didHideExtensionTab(const String& extensionID, const String& extensionTabID);
     146    ExceptionOr<JSC::JSValue> evaluateScriptInExtensionTab(HTMLIFrameElement& extensionFrame, const String& scriptSource);
    144147#endif
    145148
  • trunk/Source/WebCore/inspector/InspectorFrontendHost.idl

    r275982 r283276  
    11/*
    2  * Copyright (C) 2007-2020 Apple Inc. All rights reserved.
     2 * Copyright (C) 2007-2021 Apple Inc. All rights reserved.
    33 * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
    44 * Copyright (C) 2009 Google Inc. All rights reserved.
     
    101101    [Conditional=INSPECTOR_EXTENSIONS] undefined didShowExtensionTab(DOMString extensionID, DOMString extensionTabID);
    102102    [Conditional=INSPECTOR_EXTENSIONS] undefined didHideExtensionTab(DOMString extensionID, DOMString extensionTabID);
     103    [Conditional=INSPECTOR_EXTENSIONS] any evaluateScriptInExtensionTab(HTMLIFrameElement extensionFrame, DOMString scriptSource);
    103104};
    104105
  • trunk/Source/WebInspectorUI/ChangeLog

    r283212 r283276  
     12021-09-29  BJ Burg  <bburg@apple.com>
     2
     3        [Cocoa] add _WKInspectorExtension SPI to evaluate script on an extension tab
     4        https://bugs.webkit.org/show_bug.cgi?id=230646
     5        <rdar://problem/83420328>
     6
     7        Reviewed by Devin Rousso.
     8
     9        Add a new InspectorFrontendAPI method to evaluate script on an iframe within
     10        Web Inspector. This in turn calls out to InspectorFrontendHost to do the actual evaluation.
     11        Otherwise, the CSP policy set by the tab content may block any such evaluation
     12        if the 'script-src' directive does not include 'unsafe-eval'.
     13
     14        * UserInterface/Protocol/InspectorFrontendAPI.js:
     15        (InspectorFrontendAPI.showExtensionTab):
     16        (InspectorFrontendAPI.evaluateScriptInExtensionTab):
     17        Call through to the WebInspectorExtensionController method.
     18
     19        * UserInterface/Controllers/WebInspectorExtensionController.js:
     20        (WI.WebInspectorExtensionController.prototype.evaluateScriptInExtensionTab): Added.
     21        Try to get the <iframe> for a extensionTabID, and use InspectorFrontendHost to
     22        evaluate script in the context of the <iframe>. Be sure to correctly wrap the result.
     23
     24        * UserInterface/Views/WebInspectorExtensionTabContentView.js:
     25        (WI.WebInspectorExtensionTabContentView):
     26        (WI.WebInspectorExtensionTabContentView.prototype.get iframeElement):
     27        (WI.WebInspectorExtensionTabContentView.shouldSaveTab):
     28        (WI.WebInspectorExtensionTabContentView.prototype.initialLayout): Deleted.
     29        While writing the API test, I saw that the first evaluation frequently failed
     30        because the <iframe> did not exist. Change this class so that the <iframe>
     31        is created in the constructor. Add a getter for the <iframe> element.
     32
     33        (WI.WebInspectorExtensionTabContentView.prototype._extensionFrameDidLoad):
     34        (WI.WebInspectorExtensionTabContentView.prototype._maybeDispatchDidShowExtensionTab):
     35        While writing this patch, it became apparent that didShowExtensionTab() was being
     36        called prior to the iframe actually completing its initial load. Then, the test
     37        would try to evaluate script on about:blank instead of the actual tab content.
     38        To fix this, require that the <iframe> be attached and have fired the `onload` event
     39        before we notify clients that it has been 'shown'.
     40
     41        * UserInterface/Main.html:
     42        Adjust the default CSP policy to not mention img-src. This allows ports such as
     43        Cocoa to set their own img-src CSP directive. These changes are necessary to allow
     44        images to load from custom URL schemes.
     45
     46        * UserInterface/Views/TabBrowser.js:
     47        (WI.TabBrowser.prototype.bestTabContentViewForRepresentedObject):
     48        The new API test exposes a bug in this assertion, namely, that it does not account
     49        for the situation where a tab does not wish to be saved. In that case, the displayed
     50        WebInspectorExtensionTabContentView is *not* at index 0 of WI.TabBrowser.recentTabContentViews.
     51        This is correctly handled with a special case in WI.TabBrowser._tabBarItemSelected,
     52        so incorporate that logic into the assertion.
     53
    1542021-09-28  BJ Burg  <bburg@apple.com>
    255
  • trunk/Source/WebInspectorUI/UserInterface/Controllers/WebInspectorExtensionController.js

    r283196 r283276  
    171171        }
    172172    }
     173
     174    evaluateScriptInExtensionTab(extensionTabID, scriptSource)
     175    {
     176        let tabContentView = this._extensionTabContentViewForExtensionTabIDMap.get(extensionTabID);
     177        if (!tabContentView) {
     178            WI.reportInternalError("Unable to evaluate with unknown extensionTabID: " + extensionTabID);
     179            return WI.WebInspectorExtension.ErrorCode.InvalidRequest;
     180        }
     181
     182        let iframe = tabContentView.iframeElement;
     183        if (!(iframe instanceof HTMLIFrameElement)) {
     184            WI.reportInternalError("Unable to evaluate without an <iframe> for extensionTabID: " + extensionTabID);
     185            return WI.WebInspectorExtension.ErrorCode.InvalidRequest;
     186        }
     187
     188        try {
     189            return {result: InspectorFrontendHost.evaluateScriptInExtensionTab(iframe, scriptSource)};
     190        } catch (error) {
     191            return {error: error.message};
     192        }
     193    }
    173194};
    174195
  • trunk/Source/WebInspectorUI/UserInterface/Main.html

    r281663 r283276  
    2828    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    2929    <!--
    30         Note that some WebKit ports may set custom 'frame-src' and 'connect-src' directives via HTTP response header.
     30        Note that some WebKit ports may set custom 'frame-src', 'img-src', and 'connect-src' directives via HTTP response header.
    3131        The combined CSP policy requires a request to be allowed by both directive lists, so 'default-src' is omitted.
    3232    -->
    33     <meta http-equiv="Content-Security-Policy" content="img-src * file: blob: resource:; media-src * blob:; font-src * blob:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' data:; object-src 'none'">
     33    <meta http-equiv="Content-Security-Policy" content="media-src * blob:; font-src * blob:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' data:; object-src 'none'">
    3434
    3535    <link rel="stylesheet" href="External/CodeMirror/codemirror.css">
  • trunk/Source/WebInspectorUI/UserInterface/Protocol/InspectorFrontendAPI.js

    r283212 r283276  
    236236    {
    237237        return WI.sharedApp.extensionController.showExtensionTab(extensionTabID);
    238     }
     238    },
     239
     240    // Returns a string (WI.WebInspectorExtension.ErrorCode) if an error occurred that prevented evaluation.
     241    // Returns an object with a 'result' key and value that is the result of the script evaluation.
     242    // Returns an object with an 'error' key and value in the case that an exception was thrown.
     243    evaluateScriptInExtensionTab(extensionTabID, scriptSource)
     244    {
     245        return WI.sharedApp.extensionController.evaluateScriptInExtensionTab(extensionTabID, scriptSource);
     246    },
    239247};
  • trunk/Source/WebInspectorUI/UserInterface/Views/TabBrowser.js

    r268691 r283276  
    121121    bestTabContentViewForRepresentedObject(representedObject, options = {})
    122122    {
    123         console.assert(!this.selectedTabContentView || this.selectedTabContentView === this._recentTabContentViews[0]);
     123        let shouldSaveTab = this.selectedTabContentView?.constructor.shouldSaveTab() || this.selectedTabContentView?.constructor.shouldPinTab();
     124        console.assert(!this.selectedTabContentView || this.selectedTabContentView === this._recentTabContentViews[0] || !shouldSaveTab);
    124125
    125126        let tabContentView = this._recentTabContentViews.find((tabContentView) => tabContentView.type === options.preferredTabType);
  • trunk/Source/WebInspectorUI/UserInterface/Views/WebInspectorExtensionTabContentView.js

    r273522 r283276  
    4040        this._tabInfo = tabInfo;
    4141        this._sourceURL = sourceURL;
     42
     43        // FIXME: the <iframe>'s document is implicitly reloaded when this
     44        // content view's element is detached and later re-attached to the DOM.
     45        // This is a bug and will be addressed in <https://webkit.org/b/230758>.
     46        this._iframeElement = this.element.appendChild(document.createElement("iframe"));
     47        this._iframeElement.addEventListener("load", this._extensionFrameDidLoad.bind(this));
     48        this._iframeElement.src = this._sourceURL;
     49
     50        this._frameContentDidLoad = false;
    4251    }
    4352
     
    4554
    4655    get extensionTabID() { return this._extensionTabID; }
     56    get iframeElement() { return this._iframeElement; }
    4757
    4858    get type()
     
    6070        super.attached();
    6171
    62         if (InspectorFrontendHost.supportsWebExtensions)
    63             InspectorFrontendHost.didShowExtensionTab(this._extension.extensionID, this._extensionTabID);
     72        this._maybeDispatchDidShowExtensionTab();
    6473    }
    6574
     
    7988    static shouldSaveTab() { return false; }
    8089
    81     // Protected
     90    // Private
    8291
    83     initialLayout()
     92    _extensionFrameDidLoad()
    8493    {
    85         super.initialLayout();
     94        this._frameContentDidLoad = true;
     95        this._maybeDispatchDidShowExtensionTab();
     96    }
    8697
    87         let iframeElement = this.element.appendChild(document.createElement("iframe"));
    88         iframeElement.src = this._sourceURL;
     98    _maybeDispatchDidShowExtensionTab()
     99    {
     100        if (!this._frameContentDidLoad || !this.element.isConnected)
     101            return;
     102
     103        if (InspectorFrontendHost.supportsWebExtensions)
     104            InspectorFrontendHost.didShowExtensionTab(this._extension.extensionID, this._extensionTabID);
    89105    }
    90106};
  • trunk/Source/WebKit/ChangeLog

    r283274 r283276  
     12021-09-29  BJ Burg  <bburg@apple.com>
     2
     3        [Cocoa] add _WKInspectorExtension SPI to evaluate script on an extension tab
     4        https://bugs.webkit.org/show_bug.cgi?id=230646
     5        <rdar://problem/83420328>
     6
     7        Reviewed by Devin Rousso.
     8
     9        Add new testing API for evaluating script expressions in the context of a
     10        tab created by _WKInspectorExtension. For the most part, this is implemented
     11        in the same way as the -evaluateScript: method, but the script is evaluated
     12        within the Web Inspector frontend itself rather than in the inspected page.
     13
     14        To avoid CSP issues, the actual evaluation is performed on subframes using a
     15        new InspectorFrontendHost method which takes an <iframe> and script source.
     16
     17        Along the way, tweak Web Inspector's CSP policy to allow loading images from
     18        custom URL schemes as specified using _WKInspectorConfiguration. This is so
     19        that tab icons from the test-resource: scheme can be loaded in the main frame
     20        of Web Inspector's WKWebView under testing situations.
     21
     22        * SourcesCocoa.txt:
     23        * WebKit.xcodeproj/project.pbxproj:
     24        Add new files.
     25
     26        * UIProcess/API/APIInspectorExtension.h:
     27        * UIProcess/API/APIInspectorExtension.cpp:
     28        (API::InspectorExtension::evaluateScriptInExtensionTab):
     29        Based on evaluateScript(). Call through to the shared extension controller.
     30
     31        * UIProcess/API/Cocoa/_WKInspectorExtensionPrivateForTesting.h: Added.
     32        * UIProcess/API/Cocoa/_WKInspectorExtensionTesting.mm: Added.
     33        (-[_WKInspectorExtension _evaluateScript:inExtensionTabWithIdentifier:completionHandler:]):
     34        Added. Call through to the shared extension controller.
     35
     36        * UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.h:
     37        * UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.cpp:
     38        (WebKit::WebInspectorUIExtensionControllerProxy::evaluateScriptInExtensionTab):
     39        Based on evaluateScript(). Send IPC to the Inspector WebProcess.
     40
     41        * WebProcess/Inspector/WebInspectorUIExtensionController.h:
     42        * WebProcess/Inspector/WebInspectorUIExtensionController.messages.in:
     43        * WebProcess/Inspector/WebInspectorUIExtensionController.cpp:
     44        (WebKit::WebInspectorUIExtensionController::evaluateScriptInExtensionTab):
     45        Based on evaluateScriptForExtension. Call into the frontend API
     46        which will perform the actual evaluation on the <iframe> contentWindow.
     47
     48        * UIProcess/Inspector/mac/WKInspectorResourceURLSchemeHandler.mm:
     49        (-[WKInspectorResourceURLSchemeHandler webView:startURLSchemeTask:]):
     50        Specify the list of custom protocols as allowable sources for 'img-src'.
     51        The 'img-src' directive also includes 'file: blob: resource:' as allowable
     52        sources, since this was the previous CSP policy defined in Main.html.
     53
     54        * UIProcess/Cocoa/GroupActivities/GroupActivitiesSessionNotifier.mm:
     55        Fix UnifiedSources fallout by including a missing header.
     56
    1572021-09-29  Chris Dumez  <cdumez@apple.com>
    258
  • trunk/Source/WebKit/SourcesCocoa.txt

    r282230 r283276  
    289289UIProcess/API/Cocoa/_WKInspectorDebuggableInfo.mm
    290290UIProcess/API/Cocoa/_WKInspectorExtension.mm
     291UIProcess/API/Cocoa/_WKInspectorExtensionTesting.mm
    291292UIProcess/API/Cocoa/_WKInspectorWindow.mm
    292293UIProcess/API/Cocoa/_WKInternalDebugFeature.mm
  • trunk/Source/WebKit/UIProcess/API/APIInspectorExtension.cpp

    r282889 r283276  
    8282}
    8383
     84// For testing.
     85
     86void InspectorExtension::evaluateScriptInExtensionTab(const Inspector::ExtensionTabID& extensionTabID, const WTF::String& scriptSource, WTF::CompletionHandler<void(Inspector::ExtensionEvaluationResult)>&& completionHandler)
     87{
     88    if (!m_extensionControllerProxy) {
     89        completionHandler(makeUnexpected(Inspector::ExtensionError::ContextDestroyed));
     90        return;
     91    }
     92
     93    m_extensionControllerProxy->evaluateScriptInExtensionTab(extensionTabID, scriptSource, WTFMove(completionHandler));
     94}
     95
    8496} // namespace API
    8597
  • trunk/Source/WebKit/UIProcess/API/APIInspectorExtension.h

    r278253 r283276  
    5050    void createTab(const WTF::String& tabName, const WTF::URL& tabIconURL, const WTF::URL& sourceURL, WTF::CompletionHandler<void(Expected<Inspector::ExtensionTabID, Inspector::ExtensionError>)>&&);
    5151    void evaluateScript(const WTF::String& scriptSource, const std::optional<WTF::URL>& frameURL, const std::optional<WTF::URL>& contextSecurityOrigin, const std::optional<bool>& useContentScriptContext, WTF::CompletionHandler<void(Inspector::ExtensionEvaluationResult)>&&);
    52     void reloadIgnoringCache(const std::optional<bool>& ignoreCache, const std::optional<WTF::String>& userAgent, const std::optional<WTF::String>& injectedScript,  WTF::CompletionHandler<void(Inspector::ExtensionEvaluationResult)>&&);
     52    void reloadIgnoringCache(const std::optional<bool>& ignoreCache, const std::optional<WTF::String>& userAgent, const std::optional<WTF::String>& injectedScript, WTF::CompletionHandler<void(Inspector::ExtensionEvaluationResult)>&&);
     53
     54    // For testing.
     55    void evaluateScriptInExtensionTab(const Inspector::ExtensionTabID&, const WTF::String& scriptSource, WTF::CompletionHandler<void(Inspector::ExtensionEvaluationResult)>&&);
    5356
    5457    InspectorExtensionClient* client() const { return m_client.get(); }
  • trunk/Source/WebKit/UIProcess/Cocoa/GroupActivities/GroupActivitiesSessionNotifier.mm

    r279133 r283276  
    2929#if ENABLE(MEDIA_SESSION_COORDINATOR) && HAVE(GROUP_ACTIVITIES)
    3030
     31#import "GroupActivitiesCoordinator.h"
    3132#import "WKGroupSession.h"
    3233#import "WebPageProxy.h"
  • trunk/Source/WebKit/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.cpp

    r283220 r283276  
    200200}
    201201
     202// API for testing.
     203
     204void WebInspectorUIExtensionControllerProxy::evaluateScriptInExtensionTab(const Inspector::ExtensionTabID& extensionTabID, const String& scriptSource, WTF::CompletionHandler<void(Inspector::ExtensionEvaluationResult)>&& completionHandler)
     205{
     206    whenFrontendHasLoaded([weakThis = makeWeakPtr(this), extensionTabID, scriptSource, completionHandler = WTFMove(completionHandler)] () mutable {
     207        if (!weakThis || !weakThis->m_inspectorPage) {
     208            completionHandler(makeUnexpected(Inspector::ExtensionError::ContextDestroyed));
     209            return;
     210        }
     211
     212        weakThis->m_inspectorPage->sendWithAsyncReply(Messages::WebInspectorUIExtensionController::EvaluateScriptInExtensionTab {extensionTabID, scriptSource}, [completionHandler = WTFMove(completionHandler)](const IPC::DataReference& dataReference, const std::optional<WebCore::ExceptionDetails>& details, const std::optional<Inspector::ExtensionError>& error) mutable {
     213            if (error) {
     214                completionHandler(makeUnexpected(error.value()));
     215                return;
     216            }
     217
     218            if (details) {
     219                Expected<RefPtr<API::SerializedScriptValue>, WebCore::ExceptionDetails> returnedValue = makeUnexpected(details.value());
     220                return completionHandler({ returnedValue });
     221            }
     222
     223            completionHandler({ { API::SerializedScriptValue::adopt({ dataReference.data(), dataReference.size() }).ptr() } });
     224        });
     225    });
     226}
    202227
    203228// WebInspectorUIExtensionControllerProxy IPC messages.
  • trunk/Source/WebKit/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.h

    r283220 r283276  
    6363    void showExtensionTab(const Inspector::ExtensionTabID&, CompletionHandler<void(Expected<void, Inspector::ExtensionError>)>&&);
    6464
     65    // API for testing.
     66    void evaluateScriptInExtensionTab(const Inspector::ExtensionTabID&, const String& scriptSource, WTF::CompletionHandler<void(Inspector::ExtensionEvaluationResult)>&&);
     67
    6568    // WebInspectorUIExtensionControllerProxy IPC messages.
    6669    void didShowExtensionTab(const Inspector::ExtensionID&, const Inspector::ExtensionTabID&);
  • trunk/Source/WebKit/UIProcess/Inspector/mac/WKInspectorResourceURLSchemeHandler.mm

    r276514 r283276  
    123123        // Allow fetches for resources that use a registered custom URL scheme.
    124124        if (_allowedURLSchemesForCSP && [self.mainResourceURLsForCSP containsObject:requestURL]) {
    125             NSString *stringForCSPPolicy = [NSString stringWithFormat:@"connect-src * %@:", [_allowedURLSchemesForCSP.get().allObjects componentsJoinedByString:@": "]];
     125            NSString *listOfCustomProtocols = [NSString stringWithFormat:@"%@:", [_allowedURLSchemesForCSP.get().allObjects componentsJoinedByString:@": "]];
     126            NSString *stringForCSPPolicy = [NSString stringWithFormat:@"connect-src * %@; img-src * file: blob: resource: %@", listOfCustomProtocols, listOfCustomProtocols];
    126127            [headerFields setObject:stringForCSPPolicy forKey:@"Content-Security-Policy"];
    127128        }
  • trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj

    r283271 r283276  
    15761576                99C3AE2D1DADA6AD00AF5C16 /* WebAutomationSessionMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 99C3AE2C1DADA6A700AF5C16 /* WebAutomationSessionMacros.h */; };
    15771577                99C607EB26FA9D4900A0953F /* _WKInspectorIBActions.h in Headers */ = {isa = PBXBuildFile; fileRef = 99C607EA26FA9D4800A0953F /* _WKInspectorIBActions.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1578                99C607F026FB91E800A0953F /* _WKInspectorExtensionPrivateForTesting.h in Headers */ = {isa = PBXBuildFile; fileRef = 99C607EE26FB91E800A0953F /* _WKInspectorExtensionPrivateForTesting.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1579                99C607F126FB91E900A0953F /* _WKInspectorExtensionTesting.mm in Sources */ = {isa = PBXBuildFile; fileRef = 99C607EF26FB91E800A0953F /* _WKInspectorExtensionTesting.mm */; };
    15781580                99C81D5A1C20E7E2005C4C82 /* AutomationClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 99C81D551C20DFBE005C4C82 /* AutomationClient.h */; };
    15791581                99C81D5D1C21F38B005C4C82 /* APIAutomationClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 99C81D5B1C20E817005C4C82 /* APIAutomationClient.h */; };
     
    51265128                99C3AE2C1DADA6A700AF5C16 /* WebAutomationSessionMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebAutomationSessionMacros.h; sourceTree = "<group>"; };
    51275129                99C607EA26FA9D4800A0953F /* _WKInspectorIBActions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKInspectorIBActions.h; sourceTree = "<group>"; };
     5130                99C607EE26FB91E800A0953F /* _WKInspectorExtensionPrivateForTesting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKInspectorExtensionPrivateForTesting.h; sourceTree = "<group>"; };
     5131                99C607EF26FB91E800A0953F /* _WKInspectorExtensionTesting.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = _WKInspectorExtensionTesting.mm; sourceTree = "<group>"; };
    51285132                99C81D551C20DFBE005C4C82 /* AutomationClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AutomationClient.h; sourceTree = "<group>"; };
    51295133                99C81D561C20DFBE005C4C82 /* AutomationClient.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AutomationClient.mm; sourceTree = "<group>"; };
     
    82158219                                997965A2253128C700B31AE3 /* _WKInspectorExtensionHost.h */,
    82168220                                99B16755252BB7E10073140E /* _WKInspectorExtensionInternal.h */,
     8221                                99C607EE26FB91E800A0953F /* _WKInspectorExtensionPrivateForTesting.h */,
     8222                                99C607EF26FB91E800A0953F /* _WKInspectorExtensionTesting.mm */,
    82178223                                99C607EA26FA9D4800A0953F /* _WKInspectorIBActions.h */,
    82188224                                5CAFDE442130843600B1F7E1 /* _WKInspectorInternal.h */,
     
    1200412010                                997965A3253128C700B31AE3 /* _WKInspectorExtensionHost.h in Headers */,
    1200512011                                99B16758252BB7E10073140E /* _WKInspectorExtensionInternal.h in Headers */,
     12012                                99C607F026FB91E800A0953F /* _WKInspectorExtensionPrivateForTesting.h in Headers */,
    1200612013                                99C607EB26FA9D4900A0953F /* _WKInspectorIBActions.h in Headers */,
    1200712014                                5CAFDE472130846A00B1F7E1 /* _WKInspectorInternal.h in Headers */,
     
    1440414411                                5790A66725679CEA0077C5A7 /* _WKAuthenticatorSelectionCriteria.mm in Sources */,
    1440514412                                5CBD595C2280EDF4002B22AA /* _WKCustomHeaderFields.mm in Sources */,
     14413                                99C607F126FB91E900A0953F /* _WKInspectorExtensionTesting.mm in Sources */,
    1440614414                                5790A67525679F740077C5A7 /* _WKPublicKeyCredentialCreationOptions.mm in Sources */,
    1440714415                                5790A66D25679EB70077C5A7 /* _WKPublicKeyCredentialDescriptor.mm in Sources */,
  • trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.cpp

    r283220 r283276  
    6060}
    6161
    62 std::optional<Inspector::ExtensionError> WebInspectorUIExtensionController::parseExtensionErrorFromEvaluationResult(InspectorFrontendAPIDispatcher::EvaluationResult result)
     62std::optional<Inspector::ExtensionError> WebInspectorUIExtensionController::parseExtensionErrorFromEvaluationResult(InspectorFrontendAPIDispatcher::EvaluationResult result) const
    6363{
    6464    if (!result) {
     
    159159}
    160160
    161 JSC::JSObject* WebInspectorUIExtensionController::unwrapEvaluationResultAsObject(InspectorFrontendAPIDispatcher::EvaluationResult result)
     161JSC::JSObject* WebInspectorUIExtensionController::unwrapEvaluationResultAsObject(InspectorFrontendAPIDispatcher::EvaluationResult result) const
    162162{
    163163    if (!result)
     
    360360}
    361361
     362// WebInspectorUIExtensionController IPC messages for testing.
     363
     364void WebInspectorUIExtensionController::evaluateScriptInExtensionTab(const Inspector::ExtensionTabID& extensionTabID, const String& scriptSource, CompletionHandler<void(const IPC::DataReference&, const std::optional<WebCore::ExceptionDetails>&, const std::optional<Inspector::ExtensionError>&)>&& completionHandler)
     365{
     366    if (!m_frontendClient) {
     367        completionHandler({ }, std::nullopt, Inspector::ExtensionError::InvalidRequest);
     368        return;
     369    }
     370
     371    Vector<Ref<JSON::Value>> arguments {
     372        JSON::Value::create(extensionTabID),
     373        JSON::Value::create(scriptSource),
     374    };
     375
     376    m_frontendClient->frontendAPIDispatcher().dispatchCommandWithResultAsync("evaluateScriptInExtensionTab"_s, WTFMove(arguments), [weakThis = makeWeakPtr(this), completionHandler = WTFMove(completionHandler)](InspectorFrontendAPIDispatcher::EvaluationResult&& result) mutable {
     377        if (!weakThis) {
     378            completionHandler({ }, std::nullopt, Inspector::ExtensionError::ContextDestroyed);
     379            return;
     380        }
     381
     382        auto* frontendGlobalObject = weakThis->m_frontendClient->frontendAPIDispatcher().frontendGlobalObject();
     383        if (!frontendGlobalObject) {
     384            completionHandler({ }, std::nullopt, Inspector::ExtensionError::ContextDestroyed);
     385            return;
     386        }
     387
     388        if (auto parsedError = weakThis->parseExtensionErrorFromEvaluationResult(result)) {
     389            if (!result.value().has_value()) {
     390                auto exceptionDetails = result.value().error();
     391                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());
     392            } else
     393                LOG(Inspector, "Internal error encountered while evaluating upon the frontend.");
     394
     395            completionHandler({ }, std::nullopt, parsedError);
     396            return;
     397        }
     398
     399        // Expected result is either an ErrorString or {result: <any>} or {error: string}.
     400        auto objectResult = weakThis->unwrapEvaluationResultAsObject(result);
     401        if (!objectResult) {
     402            LOG(Inspector, "Unexpected non-object value returned from InspectorFrontendAPI.createTabForExtension().");
     403            completionHandler({ }, std::nullopt, Inspector::ExtensionError::InternalError);
     404            return;
     405        }
     406        ASSERT(result.has_value());
     407
     408        JSC::JSValue errorPayload = objectResult->get(frontendGlobalObject, JSC::Identifier::fromString(frontendGlobalObject->vm(), "error"_s));
     409        if (!errorPayload.isUndefined()) {
     410            if (!errorPayload.isString()) {
     411                completionHandler({ }, std::nullopt, Inspector::ExtensionError::InternalError);
     412                return;
     413            }
     414
     415            completionHandler({ }, ExceptionDetails { errorPayload.toWTFString(frontendGlobalObject) }, std::nullopt);
     416            return;
     417        }
     418
     419        JSC::JSValue resultPayload = objectResult->get(frontendGlobalObject, JSC::Identifier::fromString(frontendGlobalObject->vm(), "result"_s));
     420        auto serializedResultValue = SerializedScriptValue::create(*frontendGlobalObject, resultPayload);
     421        if (!serializedResultValue) {
     422            completionHandler({ }, std::nullopt, Inspector::ExtensionError::InternalError);
     423            return;
     424        }
     425
     426        completionHandler(serializedResultValue->data(), std::nullopt, std::nullopt);
     427    });
     428}
     429
    362430void WebInspectorUIExtensionController::didShowExtensionTab(const Inspector::ExtensionID& extensionID, const Inspector::ExtensionTabID& extensionTabID)
    363431{
  • trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.h

    r283220 r283276  
    7171    void showExtensionTab(const Inspector::ExtensionTabID&, CompletionHandler<void(Expected<void, Inspector::ExtensionError>)>&&);
    7272
     73    // WebInspectorUIExtensionController IPC messages for testing.
     74    void evaluateScriptInExtensionTab(const Inspector::ExtensionTabID&, const String& scriptSource, CompletionHandler<void(const IPC::DataReference&, const std::optional<WebCore::ExceptionDetails>&, const std::optional<Inspector::ExtensionError>&)>&&);
     75
    7376    // Callbacks from the frontend.
    7477    void didShowExtensionTab(const Inspector::ExtensionID&, const Inspector::ExtensionTabID&);
     
    7679
    7780private:
    78     JSC::JSObject* unwrapEvaluationResultAsObject(WebCore::InspectorFrontendAPIDispatcher::EvaluationResult);
    79     std::optional<Inspector::ExtensionError> parseExtensionErrorFromEvaluationResult(WebCore::InspectorFrontendAPIDispatcher::EvaluationResult);
     81    JSC::JSObject* unwrapEvaluationResultAsObject(WebCore::InspectorFrontendAPIDispatcher::EvaluationResult) const;
     82    std::optional<Inspector::ExtensionError> parseExtensionErrorFromEvaluationResult(WebCore::InspectorFrontendAPIDispatcher::EvaluationResult) const;
    8083
    8184    WeakPtr<WebCore::InspectorFrontendClient> m_frontendClient;
  • trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.messages.in

    r283220 r283276  
    3131    ReloadForExtension(String extensionID, std::optional<bool> ignoreCache, std::optional<String> userAgent, std::optional<String> injectedScript) -> (std::optional<Inspector::ExtensionError> error) Async
    3232    ShowExtensionTab(String extensionTabIdentifier) -> (Expected<void, Inspector::ExtensionError> result) Async
     33   
     34    // For testing.
     35    EvaluateScriptInExtensionTab(String extensionTabID, String scriptSource) -> (IPC::DataReference resultData, std::optional<WebCore::ExceptionDetails> details, std::optional<Inspector::ExtensionError> error) Async
    3336}
    3437
  • trunk/Tools/ChangeLog

    r283272 r283276  
     12021-09-29  BJ Burg  <bburg@apple.com>
     2
     3        [Cocoa] add _WKInspectorExtension SPI to evaluate script on an extension tab
     4        https://bugs.webkit.org/show_bug.cgi?id=230646
     5        <rdar://problem/83420328>
     6
     7        Reviewed by Devin Rousso.
     8
     9        Add a new test to exercise the SPI. The test sets up an _WKInspectorExtension,
     10        creates a tab, evaluates script on the tab, and later reads back the stored value.
     11
     12        Notably, this test would fail if the extension tab is not currently showing.
     13        This is a bug and will be addressed as part of https://bugs.webkit.org/show_bug.cgi?id=230758.
     14
     15        * TestWebKitAPI/SourcesCocoa.txt:
     16        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
     17        Add new files.
     18
     19        * TestWebKitAPI/Tests/WebKitCocoa/InspectorExtension-basic-tab.html:
     20        Add inline <script> to set window._secretValue. This is checked by the API test.
     21
     22        * TestWebKitAPI/Tests/WebKitCocoa/WKInspectorExtension.mm: Added.
     23        (resetGlobalState):
     24        (-[UIDelegateForTestingInspectorExtension _webView:didAttachLocalInspector:]):
     25        (-[UIDelegateForTestingInspectorExtension _webView:configurationForLocalInspector:]):
     26        (-[InspectorExtensionDelegateForTestingInspectorExtension inspectorExtension:didShowTabWithIdentifier:]):
     27        (-[InspectorExtensionDelegateForTestingInspectorExtension inspectorExtension:didHideTabWithIdentifier:]):
     28        (TEST):
     29
     30        * TestWebKitAPI/Tests/WebKitCocoa/WKInspectorExtensionDelegate.mm:
     31        (-[UIDelegateForTestingInspectorExtensionDelegate _webView:configurationForLocalInspector:]):
     32        (TEST):
     33        Adopt fixes from WKInspectorExtension that allow extension tab content and icons to load.
     34
     35        * TestWebKitAPI/cocoa/TestInspectorURLSchemeHandler.h: Added.
     36        * TestWebKitAPI/cocoa/TestInspectorURLSchemeHandler.mm: Copied from Source/WebKit/UIProcess/Inspector/mac/WKInspectorResourceURLSchemeHandler.mm.
     37        (-[TestInspectorURLSchemeHandler webView:startURLSchemeTask:]):
     38        (-[TestInspectorURLSchemeHandler webView:stopURLSchemeTask:]):
     39        Add a simple URLSchemeHandler which allows serving test resources from the TestWebKitAPI.resources directory.
     40        This is necessary to test _WKInspectorExtension tabs, which must load their content from a custom URL scheme.
     41
     42        * TestWebKitAPI/cocoa/TestWKWebView.mm:
     43        Fix UnifiedSources fallout by adding a missing include.
     44
    1452021-09-29  Alex Christensen  <achristensen@webkit.org>
    246
  • trunk/Tools/TestWebKitAPI/SourcesCocoa.txt

    r280015 r283276  
    2828cocoa/TestCocoa.mm
    2929cocoa/TestDownloadDelegate.mm
     30cocoa/TestInspectorURLSchemeHandler.mm
    3031cocoa/TestLegacyDownloadDelegate.mm
    3132cocoa/TestNavigationDelegate.mm
  • trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj

    r283196 r283276  
    894894                999B7EE32551C63B00F450A4 /* WKInspectorExtensionHost.mm in Sources */ = {isa = PBXBuildFile; fileRef = 999B7EE22551C63B00F450A4 /* WKInspectorExtensionHost.mm */; };
    895895                99B4F9C624EDED9700022B82 /* WKInspectorDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 99B4F9C524EDED9600022B82 /* WKInspectorDelegate.mm */; };
     896                99C607ED26FB90AC00A0953F /* WKInspectorExtension.mm in Sources */ = {isa = PBXBuildFile; fileRef = 99C607EC26FB90AC00A0953F /* WKInspectorExtension.mm */; };
    896897                99E2846426F91F7F0003F1FA /* WKInspectorExtensionDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 99E2846326F91F7F0003F1FA /* WKInspectorExtensionDelegate.mm */; };
    897898                99E2846626F93DB50003F1FA /* InspectorExtension-TabIcon-30x30.png in Copy Resources */ = {isa = PBXBuildFile; fileRef = 99E2846526F93D760003F1FA /* InspectorExtension-TabIcon-30x30.png */; };
     
    15201521                                467C565321B5ED130057516D /* GetSessionCookie.html in Copy Resources */,
    15211522                                41661C662355E85E00D33C27 /* getUserMedia-webaudio.html in Copy Resources */,
    1522                                 074994421EA5034B000DA44D /* invalidDeviceIDHashSalts in Copy Resources */,
    15231523                                074994421EA5034B000DA44E /* getUserMedia.html in Copy Resources */,
    15241524                                074994521EA5034B000DA44E /* getUserMedia2.html in Copy Resources */,
     
    15791579                                99E2846826F941540003F1FA /* InspectorExtension-basic-tab.html in Copy Resources */,
    15801580                                99E2846626F93DB50003F1FA /* InspectorExtension-TabIcon-30x30.png in Copy Resources */,
     1581                                074994421EA5034B000DA44D /* invalidDeviceIDHashSalts in Copy Resources */,
    15811582                                57F56A5C1C7F8CC100F31D7E /* IsNavigationActionTrusted.html in Copy Resources */,
    15821583                                C9B4AD2C1ECA6F7F00F5FEA0 /* js-autoplay-audio.html in Copy Resources */,
     
    26252626                999B7EE22551C63B00F450A4 /* WKInspectorExtensionHost.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKInspectorExtensionHost.mm; sourceTree = "<group>"; };
    26262627                99B4F9C524EDED9600022B82 /* WKInspectorDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKInspectorDelegate.mm; sourceTree = "<group>"; };
     2628                99C607EC26FB90AC00A0953F /* WKInspectorExtension.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKInspectorExtension.mm; sourceTree = "<group>"; };
     2629                99C607F426FD5A1E00A0953F /* TestInspectorURLSchemeHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestInspectorURLSchemeHandler.h; path = cocoa/TestInspectorURLSchemeHandler.h; sourceTree = "<group>"; };
     2630                99C607F526FD5A1F00A0953F /* TestInspectorURLSchemeHandler.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = TestInspectorURLSchemeHandler.mm; path = cocoa/TestInspectorURLSchemeHandler.mm; sourceTree = "<group>"; };
    26272631                99E2846326F91F7F0003F1FA /* WKInspectorExtensionDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKInspectorExtensionDelegate.mm; sourceTree = "<group>"; };
    26282632                99E2846526F93D760003F1FA /* InspectorExtension-TabIcon-30x30.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "InspectorExtension-TabIcon-30x30.png"; sourceTree = "<group>"; };
     
    33243328                                DF6BC4702534E120008F63CC /* TestDownloadDelegate.h */,
    33253329                                DF6BC46F2534E120008F63CC /* TestDownloadDelegate.mm */,
     3330                                99C607F426FD5A1E00A0953F /* TestInspectorURLSchemeHandler.h */,
     3331                                99C607F526FD5A1F00A0953F /* TestInspectorURLSchemeHandler.mm */,
    33263332                                5C72E8CD244FFCE300381EB7 /* TestLegacyDownloadDelegate.h */,
    33273333                                5C72E8CE244FFCE400381EB7 /* TestLegacyDownloadDelegate.mm */,
     
    36673673                                51D124971E763AF8002B2820 /* WKHTTPCookieStore.mm */,
    36683674                                99B4F9C524EDED9600022B82 /* WKInspectorDelegate.mm */,
     3675                                99C607EC26FB90AC00A0953F /* WKInspectorExtension.mm */,
    36693676                                99E2846326F91F7F0003F1FA /* WKInspectorExtensionDelegate.mm */,
    36703677                                999B7EE22551C63B00F450A4 /* WKInspectorExtensionHost.mm */,
     
    45824589                        isa = PBXGroup;
    45834590                        children = (
     4591                                4A410F4D19AF7BEF002EBAB4 /* invalidDeviceIDHashSalts */,
    45844592                                C045F9461385C2F800C0F3CD /* 18-characters.html */,
    45854593                                1C2B81851C89252300A5529F /* Ahem.ttf */,
     
    46304638                                1CC80CE92474F1F7004DC489 /* idempotent-mode-autosizing-only-honors-percentages.html */,
    46314639                                CE3524F51B142BBB0028A7C5 /* input-focus-blur.html */,
    4632                                 4A410F4D19AF7BEF002EBAB4 /* invalidDeviceIDHashSalts */,
    46334640                                C9B4AD2B1ECA6F7600F5FEA0 /* js-autoplay-audio.html */,
    46344641                                C99B675B1E3971FC00FC6C80 /* js-play-with-controls.html */,
     
    59485955                                7CCE7F1D1A411AE600447C4C /* WKImageCreateCGImageCrash.cpp in Sources */,
    59495956                                99B4F9C624EDED9700022B82 /* WKInspectorDelegate.mm in Sources */,
     5957                                99C607ED26FB90AC00A0953F /* WKInspectorExtension.mm in Sources */,
    59505958                                99E2846426F91F7F0003F1FA /* WKInspectorExtensionDelegate.mm in Sources */,
    59515959                                999B7EE32551C63B00F450A4 /* WKInspectorExtensionHost.mm in Sources */,
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/InspectorExtension-basic-tab.html

    r283196 r283276  
    11<html>
     2<head>
     3<script>
     4    window._secretValue = {answer:42};
     5</script>
    26<body>
    37<h1>This is a test extension.</h1>
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKInspectorExtension.mm

    r283275 r283276  
    2626#import "config.h"
    2727
    28 #import "Test.h"
     28#if ENABLE(INSPECTOR_EXTENSIONS)
     29
     30#import "TestCocoa.h"
     31#import "TestInspectorURLSchemeHandler.h"
    2932#import "Utilities.h"
    3033#import <WebKit/WKPreferencesPrivate.h>
    3134#import <WebKit/WKWebViewPrivate.h>
    3235#import <WebKit/_WKInspector.h>
     36#import <WebKit/_WKInspectorConfiguration.h>
    3337#import <WebKit/_WKInspectorExtension.h>
    3438#import <WebKit/_WKInspectorExtensionDelegate.h>
     39#import <WebKit/_WKInspectorExtensionPrivateForTesting.h>
    3540#import <WebKit/_WKInspectorPrivateForTesting.h>
    3641#import <wtf/RetainPtr.h>
    37 
    38 #if ENABLE(INSPECTOR_EXTENSIONS)
    3942
    4043static bool didAttachLocalInspectorCalled = false;
     
    4245static bool didHideExtensionTabWasCalled = false;
    4346static bool pendingCallbackWasCalled = false;
     47static RetainPtr<TestInspectorURLSchemeHandler> sharedURLSchemeHandler;
    4448static RetainPtr<_WKInspectorExtension> sharedInspectorExtension;
    4549static RetainPtr<NSString> sharedExtensionTabIdentifier;
     
    5357}
    5458
    55 @interface UIDelegateForTestingInspectorExtensionDelegate : NSObject <WKUIDelegate>
     59@interface UIDelegateForTestingInspectorExtension : NSObject <WKUIDelegate>
    5660@end
    5761
    58 @implementation UIDelegateForTestingInspectorExtensionDelegate
     62@implementation UIDelegateForTestingInspectorExtension
    5963
    6064- (void)_webView:(WKWebView *)webView didAttachLocalInspector:(_WKInspector *)inspector
     
    6468}
    6569
     70- (_WKInspectorConfiguration *)_webView:(WKWebView *)webView configurationForLocalInspector:(_WKInspector *)inspector
     71{
     72    if (!sharedURLSchemeHandler)
     73        sharedURLSchemeHandler = adoptNS([[TestInspectorURLSchemeHandler alloc] init]);
     74
     75    auto inspectorConfiguration = adoptNS([[_WKInspectorConfiguration alloc] init]);
     76    [inspectorConfiguration setURLSchemeHandler:sharedURLSchemeHandler.get() forURLScheme:@"test-resource"];
     77    return inspectorConfiguration.autorelease();
     78}
     79
    6680@end
    6781
    6882
    69 @interface InspectorExtensionDelegateForTesting : NSObject <_WKInspectorExtensionDelegate>
     83@interface InspectorExtensionDelegateForTestingInspectorExtension : NSObject <_WKInspectorExtensionDelegate>
    7084@end
    7185
    72 @implementation InspectorExtensionDelegateForTesting {
     86@implementation InspectorExtensionDelegateForTestingInspectorExtension {
    7387}
    7488
     
    8599@end
    86100
    87 TEST(WKInspectorExtensionDelegate, ShowAndHideTabCallbacks)
     101TEST(WKInspectorExtension, CanEvaluateScriptInExtensionTab)
    88102{
    89103    resetGlobalState();
     
    92106    webViewConfiguration.get().preferences._developerExtrasEnabled = YES;
    93107    auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
    94     auto uiDelegate = adoptNS([UIDelegateForTestingInspectorExtensionDelegate new]);
     108    auto uiDelegate = adoptNS([UIDelegateForTestingInspectorExtension new]);
    95109
    96110    [webView setUIDelegate:uiDelegate.get()];
     
    114128    TestWebKitAPI::Util::run(&pendingCallbackWasCalled);
    115129
    116     auto extensionDelegate = adoptNS([InspectorExtensionDelegateForTesting new]);
     130    auto extensionDelegate = adoptNS([InspectorExtensionDelegateForTestingInspectorExtension new]);
    117131    [sharedInspectorExtension setDelegate:extensionDelegate.get()];
    118132
    119     // Create an extension tab.
    120     auto iconURL = [[NSBundle mainBundle] URLForResource:@"InspectorExtension-TabIcon-30x30" withExtension:@"png" subdirectory:@"TestWebKitAPI.resources"];
    121     auto sourceURL = [[NSBundle mainBundle] URLForResource:@"InspectorExtension-basic-tab" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
     133    // Create and show an extension tab.
     134    auto iconURL = [NSURL URLWithString:@"test-resource://FirstExtension/InspectorExtension-TabIcon-30x30.png"];
     135    auto sourceURL = [NSURL URLWithString:@"test-resource://FirstExtension/InspectorExtension-basic-tab.html"];
    122136
    123137    pendingCallbackWasCalled = false;
     
    131145    TestWebKitAPI::Util::run(&pendingCallbackWasCalled);
    132146
    133     // Force a known non-extension tab to be shown before showing the extension tab. Otherwise,
    134     // if the extension tab was already open, then this test would hang waiting for a didShow callback.
    135     [[webView _inspector] showConsole];
    136 
    137147    pendingCallbackWasCalled = false;
     148    didShowExtensionTabWasCalled = false;
    138149    [[webView _inspector] showExtensionTabWithIdentifier:sharedExtensionTabIdentifier.get() completionHandler:^(NSError * _Nullable error) {
    139150        EXPECT_NULL(error);
     
    144155    TestWebKitAPI::Util::run(&didShowExtensionTabWasCalled);
    145156
    146     [[webView _inspector] showConsole];
    147     TestWebKitAPI::Util::run(&didHideExtensionTabWasCalled);
     157    // Read back a value that is set in the <iframe>'s script context.
     158    pendingCallbackWasCalled = false;
     159    auto scriptSource2 = @"window._secretValue";
     160    [sharedInspectorExtension _evaluateScript:scriptSource2 inExtensionTabWithIdentifier:sharedExtensionTabIdentifier.get() completionHandler:^(NSError * _Nullable error, NSDictionary * _Nullable result) {
     161        EXPECT_NULL(error);
     162        EXPECT_NOT_NULL(result);
     163        EXPECT_NS_EQUAL(result[@"answer"], @42);
     164
     165        pendingCallbackWasCalled = true;
     166    }];
     167    TestWebKitAPI::Util::run(&pendingCallbackWasCalled);
     168
     169    // Check to see that script is actually being evaluated in the <iframe>'s script context.
     170    pendingCallbackWasCalled = false;
     171    auto scriptSource3 = @"window.top !== window";
     172    [sharedInspectorExtension _evaluateScript:scriptSource3 inExtensionTabWithIdentifier:sharedExtensionTabIdentifier.get() completionHandler:^(NSError * _Nullable error, NSDictionary * _Nullable result) {
     173        EXPECT_NULL(error);
     174        EXPECT_NOT_NULL(result);
     175        EXPECT_NS_EQUAL(result, @YES);
     176
     177        pendingCallbackWasCalled = true;
     178    }];
     179    TestWebKitAPI::Util::run(&pendingCallbackWasCalled);
    148180
    149181    // Unregister the test extension.
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKInspectorExtensionDelegate.mm

    r283196 r283276  
    2626#import "config.h"
    2727
     28#if ENABLE(INSPECTOR_EXTENSIONS)
     29
    2830#import "Test.h"
     31#import "TestInspectorURLSchemeHandler.h"
    2932#import "Utilities.h"
    3033#import <WebKit/WKPreferencesPrivate.h>
    3134#import <WebKit/WKWebViewPrivate.h>
    3235#import <WebKit/_WKInspector.h>
     36#import <WebKit/_WKInspectorConfiguration.h>
    3337#import <WebKit/_WKInspectorExtension.h>
    3438#import <WebKit/_WKInspectorExtensionDelegate.h>
     
    3640#import <wtf/RetainPtr.h>
    3741
    38 #if ENABLE(INSPECTOR_EXTENSIONS)
    39 
    4042static bool didAttachLocalInspectorCalled = false;
    4143static bool didShowExtensionTabWasCalled = false;
    4244static bool didHideExtensionTabWasCalled = false;
    4345static bool pendingCallbackWasCalled = false;
     46static RetainPtr<TestInspectorURLSchemeHandler> sharedURLSchemeHandler;
    4447static RetainPtr<_WKInspectorExtension> sharedInspectorExtension;
    4548static RetainPtr<NSString> sharedExtensionTabIdentifier;
     
    6265    EXPECT_EQ(webView._inspector, inspector);
    6366    didAttachLocalInspectorCalled = true;
     67}
     68
     69- (_WKInspectorConfiguration *)_webView:(WKWebView *)webView configurationForLocalInspector:(_WKInspector *)inspector
     70{
     71    if (!sharedURLSchemeHandler)
     72        sharedURLSchemeHandler = adoptNS([[TestInspectorURLSchemeHandler alloc] init]);
     73
     74    auto inspectorConfiguration = adoptNS([[_WKInspectorConfiguration alloc] init]);
     75    [inspectorConfiguration setURLSchemeHandler:sharedURLSchemeHandler.get() forURLScheme:@"test-resource"];
     76    return inspectorConfiguration.autorelease();
    6477}
    6578
     
    118131
    119132    // Create an extension tab.
    120     auto iconURL = [[NSBundle mainBundle] URLForResource:@"InspectorExtension-TabIcon-30x30" withExtension:@"png" subdirectory:@"TestWebKitAPI.resources"];
    121     auto sourceURL = [[NSBundle mainBundle] URLForResource:@"InspectorExtension-basic-tab" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
     133    auto iconURL = [NSURL URLWithString:@"test-resource://FirstExtension/InspectorExtension-TabIcon-30x30.png"];
     134    auto sourceURL = [NSURL URLWithString:@"test-resource://FirstExtension/InspectorExtension-basic-tab.html"];
    122135
    123136    pendingCallbackWasCalled = false;
     
    130143    }];
    131144    TestWebKitAPI::Util::run(&pendingCallbackWasCalled);
    132 
    133     // Force a known non-extension tab to be shown before showing the extension tab. Otherwise,
    134     // if the extension tab was already open, then this test would hang waiting for a didShow callback.
    135     [[webView _inspector] showConsole];
    136145
    137146    pendingCallbackWasCalled = false;
  • trunk/Tools/TestWebKitAPI/cocoa/TestInspectorURLSchemeHandler.mm

    r283275 r283276  
    2525
    2626#import "config.h"
    27 #import "WKInspectorResourceURLSchemeHandler.h"
     27#import "TestInspectorURLSchemeHandler.h"
    2828
    29 #if PLATFORM(MAC)
    30 
    31 #import "Logging.h"
    32 #import "WKURLSchemeTask.h"
    33 #import "WebInspectorUIProxy.h"
    34 #import "WebURLSchemeHandlerCocoa.h"
    3529#import <WebCore/MIMETypeRegistry.h>
     30#import <WebKit/WKURLSchemeTask.h>
    3631#import <wtf/Assertions.h>
    3732
    38 @implementation WKInspectorResourceURLSchemeHandler {
     33// Note: this class is a simplified version of WKResourceURLSchemeHandler for testing purposes.
     34
     35@implementation TestInspectorURLSchemeHandler {
    3936    RetainPtr<NSMapTable<id <WKURLSchemeTask>, NSOperation *>> _fileLoadOperations;
    4037    RetainPtr<NSBundle> _cachedBundle;
    4138    RetainPtr<NSOperationQueue> _operationQueue;
    42    
    43     RetainPtr<NSSet<NSString *>> _allowedURLSchemesForCSP;
    44     RetainPtr<NSSet<NSURL *>> _mainResourceURLsForCSP;
    45 }
    46 
    47 - (NSSet<NSString *> *)allowedURLSchemesForCSP
    48 {
    49     return _allowedURLSchemesForCSP.get();
    50 }
    51 
    52 - (void)setAllowedURLSchemesForCSP:(NSSet<NSString *> *)allowedURLSchemes
    53 {
    54     _allowedURLSchemesForCSP = adoptNS([allowedURLSchemes copy]);
    55 }
    56 
    57 - (NSSet<NSURL *> *)mainResourceURLsForCSP
    58 {
    59     if (!_mainResourceURLsForCSP)
    60         _mainResourceURLsForCSP = adoptNS([[NSSet alloc] initWithObjects:[NSURL URLWithString:WebKit::WebInspectorUIProxy::inspectorPageURL()], [NSURL URLWithString:WebKit::WebInspectorUIProxy::inspectorTestPageURL()], nil]);
    61 
    62     return _mainResourceURLsForCSP.get();
    6339}
    6440
     
    6743- (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask
    6844{
    69     if (!_cachedBundle) {
    70         _cachedBundle = [NSBundle bundleWithIdentifier:@"com.apple.WebInspectorUI"];
    71 
    72         // It is an error if WebInspectorUI has not already been soft-linked by the time
    73         // we load resources from it. And if soft-linking fails, we shouldn't start loads.
    74         RELEASE_ASSERT(_cachedBundle);
    75     }
     45    if (!_cachedBundle)
     46        _cachedBundle = [NSBundle mainBundle];
    7647
    7748    if (!_fileLoadOperations)
     
    9465
    9566        NSURL *requestURL = urlSchemeTask.request.URL;
    96         NSURL *fileURLForRequest = [_cachedBundle URLForResource:requestURL.relativePath withExtension:@""];
     67        NSURL *fileURLForRequest = [_cachedBundle URLForResource:requestURL.relativePath withExtension:@"" subdirectory:@"TestWebKitAPI.resources"];
    9768        if (!fileURLForRequest) {
    98             LOG_ERROR("Unable to find Web Inspector resource: %@", requestURL.absoluteString);
    9969            [urlSchemeTask didFailWithError:[NSError errorWithDomain:NSCocoaErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil]];
    10070            return;
     
    10474        NSData *fileData = [NSData dataWithContentsOfURL:fileURLForRequest options:0 error:&readError];
    10575        if (!fileData) {
    106             LOG_ERROR("Unable to read data for Web Inspector resource: %@", requestURL.absoluteString);
    10776            [urlSchemeTask didFailWithError:[NSError errorWithDomain:NSCocoaErrorDomain code:NSURLErrorResourceUnavailable userInfo:@{
    10877                NSUnderlyingErrorKey: readError,
     
    12089            @"Content-Type": mimeType,
    12190        }.mutableCopy);
    122 
    123         // Allow fetches for resources that use a registered custom URL scheme.
    124         if (_allowedURLSchemesForCSP && [self.mainResourceURLsForCSP containsObject:requestURL]) {
    125             NSString *stringForCSPPolicy = [NSString stringWithFormat:@"connect-src * %@:", [_allowedURLSchemesForCSP.get().allObjects componentsJoinedByString:@": "]];
    126             [headerFields setObject:stringForCSPPolicy forKey:@"Content-Security-Policy"];
    127         }
    12891
    12992        RetainPtr<NSHTTPURLResponse> urlResponse = adoptNS([[NSHTTPURLResponse alloc] initWithURL:urlSchemeTask.request.URL statusCode:200 HTTPVersion:nil headerFields:headerFields.get()]);
     
    149112
    150113@end
    151 
    152 #endif // PLATFORM(MAC)
  • trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm

    r281468 r283276  
    3434#import <WebKit/WKContentWorld.h>
    3535#import <WebKit/WKWebViewConfigurationPrivate.h>
     36#import <WebKit/WKWebViewPrivateForTesting.h>
    3637#import <WebKit/WebKitPrivate.h>
    3738#import <WebKit/_WKActivatedElementInfo.h>
Note: See TracChangeset for help on using the changeset viewer.