Diff
Modified: trunk/Source/WebCore/ChangeLog (283275 => 283276)
--- trunk/Source/WebCore/ChangeLog 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebCore/ChangeLog 2021-09-29 23:28:22 UTC (rev 283276)
@@ -1,3 +1,24 @@
+2021-09-29 BJ Burg <[email protected]>
+
+ [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.
+
+ 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.
+
2021-09-29 Alan Bujtas <[email protected]>
[LFC][IFC] Use the first-line style when measuring text content when applicable
Modified: trunk/Source/WebCore/html/HTMLIFrameElement.idl (283275 => 283276)
--- trunk/Source/WebCore/html/HTMLIFrameElement.idl 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebCore/html/HTMLIFrameElement.idl 2021-09-29 23:28:22 UTC (rev 283276)
@@ -19,7 +19,8 @@
*/
[
- Exposed=Window
+ Exposed=Window,
+ JSGenerateToNativeObject
] interface HTMLIFrameElement : HTMLElement {
[Reflect, CEReactions=NotNeeded] attribute DOMString align;
[Reflect, CEReactions=NotNeeded] attribute DOMString frameBorder;
Modified: trunk/Source/WebCore/inspector/InspectorFrontendHost.cpp (283275 => 283276)
--- trunk/Source/WebCore/inspector/InspectorFrontendHost.cpp 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebCore/inspector/InspectorFrontendHost.cpp 2021-09-29 23:28:22 UTC (rev 283276)
@@ -42,6 +42,7 @@
#include "FloatRect.h"
#include "FocusController.h"
#include "Frame.h"
+#include "HTMLIFrameElement.h"
#include "HitTestResult.h"
#include "InspectorController.h"
#include "InspectorDebuggableType.h"
@@ -69,6 +70,7 @@
namespace WebCore {
using namespace Inspector;
+using ValueOrException = Expected<JSC::JSValue, ExceptionDetails>;
#if ENABLE(CONTEXT_MENUS)
class FrontendMenuProvider : public ContextMenuProvider {
@@ -706,6 +708,28 @@
m_client->didHideExtensionTab(extensionID, extensionTabID);
}
+
+ExceptionOr<JSC::JSValue> InspectorFrontendHost::evaluateScriptInExtensionTab(HTMLIFrameElement& extensionFrameElement, const String& scriptSource)
+{
+ Frame* frame = extensionFrameElement.contentFrame();
+ if (!frame)
+ return Exception { InvalidStateError, "Unable to find global object for <iframe>"_s };
+
+ Ref<Frame> protectedFrame(*frame);
+
+ JSDOMGlobalObject* frameGlobalObject = frame->script().globalObject(mainThreadNormalWorld());
+ if (!frameGlobalObject)
+ return Exception { InvalidStateError, "Unable to find global object for <iframe>"_s };
+
+ JSC::SuspendExceptionScope scope(&frameGlobalObject->vm());
+ ValueOrException result = frame->script().evaluateInWorld(ScriptSourceCode(scriptSource), mainThreadNormalWorld());
+
+ if (!result)
+ return Exception { InvalidStateError, result.error().message };
+
+ return WTFMove(result.value());
+}
+
#endif // ENABLE(INSPECTOR_EXTENSIONS)
Modified: trunk/Source/WebCore/inspector/InspectorFrontendHost.h (283275 => 283276)
--- trunk/Source/WebCore/inspector/InspectorFrontendHost.h 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebCore/inspector/InspectorFrontendHost.h 2021-09-29 23:28:22 UTC (rev 283276)
@@ -30,6 +30,7 @@
#include "ContextMenu.h"
#include "ContextMenuProvider.h"
+#include "ExceptionOr.h"
#include <wtf/RefCounted.h>
#include <wtf/Vector.h>
#include <wtf/text/WTFString.h>
@@ -39,6 +40,7 @@
class DOMWrapperWorld;
class Event;
class FrontendMenuProvider;
+class HTMLIFrameElement;
class InspectorFrontendClient;
class Page;
@@ -141,6 +143,7 @@
#if ENABLE(INSPECTOR_EXTENSIONS)
void didShowExtensionTab(const String& extensionID, const String& extensionTabID);
void didHideExtensionTab(const String& extensionID, const String& extensionTabID);
+ ExceptionOr<JSC::JSValue> evaluateScriptInExtensionTab(HTMLIFrameElement& extensionFrame, const String& scriptSource);
#endif
private:
Modified: trunk/Source/WebCore/inspector/InspectorFrontendHost.idl (283275 => 283276)
--- trunk/Source/WebCore/inspector/InspectorFrontendHost.idl 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebCore/inspector/InspectorFrontendHost.idl 2021-09-29 23:28:22 UTC (rev 283276)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007-2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2007-2021 Apple Inc. All rights reserved.
* Copyright (C) 2008 Matt Lilek <[email protected]>
* Copyright (C) 2009 Google Inc. All rights reserved.
*
@@ -100,6 +100,7 @@
readonly attribute boolean supportsWebExtensions;
[Conditional=INSPECTOR_EXTENSIONS] undefined didShowExtensionTab(DOMString extensionID, DOMString extensionTabID);
[Conditional=INSPECTOR_EXTENSIONS] undefined didHideExtensionTab(DOMString extensionID, DOMString extensionTabID);
+ [Conditional=INSPECTOR_EXTENSIONS] any evaluateScriptInExtensionTab(HTMLIFrameElement extensionFrame, DOMString scriptSource);
};
dictionary ContextMenuItem {
Modified: trunk/Source/WebInspectorUI/ChangeLog (283275 => 283276)
--- trunk/Source/WebInspectorUI/ChangeLog 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebInspectorUI/ChangeLog 2021-09-29 23:28:22 UTC (rev 283276)
@@ -1,3 +1,56 @@
+2021-09-29 BJ Burg <[email protected]>
+
+ [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.
+
+ 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.
+
2021-09-28 BJ Burg <[email protected]>
Web Inspector: add settings option for 'Show Mock Web Extension Tab' in engineering builds
Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/WebInspectorExtensionController.js (283275 => 283276)
--- trunk/Source/WebInspectorUI/UserInterface/Controllers/WebInspectorExtensionController.js 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/WebInspectorExtensionController.js 2021-09-29 23:28:22 UTC (rev 283276)
@@ -170,6 +170,27 @@
return WI.WebInspectorExtension.ErrorCode.InternalError;
}
}
+
+ evaluateScriptInExtensionTab(extensionTabID, scriptSource)
+ {
+ let tabContentView = this._extensionTabContentViewForExtensionTabIDMap.get(extensionTabID);
+ if (!tabContentView) {
+ WI.reportInternalError("Unable to evaluate with unknown extensionTabID: " + extensionTabID);
+ return WI.WebInspectorExtension.ErrorCode.InvalidRequest;
+ }
+
+ let iframe = tabContentView.iframeElement;
+ if (!(iframe instanceof HTMLIFrameElement)) {
+ WI.reportInternalError("Unable to evaluate without an <iframe> for extensionTabID: " + extensionTabID);
+ return WI.WebInspectorExtension.ErrorCode.InvalidRequest;
+ }
+
+ try {
+ return {result: InspectorFrontendHost.evaluateScriptInExtensionTab(iframe, scriptSource)};
+ } catch (error) {
+ return {error: error.message};
+ }
+ }
};
WI.WebInspectorExtensionController.Event = {
Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (283275 => 283276)
--- trunk/Source/WebInspectorUI/UserInterface/Main.html 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html 2021-09-29 23:28:22 UTC (rev 283276)
@@ -27,10 +27,10 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<!--
- Note that some WebKit ports may set custom 'frame-src' and 'connect-src' directives via HTTP response header.
+ Note that some WebKit ports may set custom 'frame-src', 'img-src', and 'connect-src' directives via HTTP response header.
The combined CSP policy requires a request to be allowed by both directive lists, so 'default-src' is omitted.
-->
- <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'">
+ <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'">
<link rel="stylesheet" href=""
Modified: trunk/Source/WebInspectorUI/UserInterface/Protocol/InspectorFrontendAPI.js (283275 => 283276)
--- trunk/Source/WebInspectorUI/UserInterface/Protocol/InspectorFrontendAPI.js 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebInspectorUI/UserInterface/Protocol/InspectorFrontendAPI.js 2021-09-29 23:28:22 UTC (rev 283276)
@@ -235,5 +235,13 @@
showExtensionTab(extensionTabID)
{
return WI.sharedApp.extensionController.showExtensionTab(extensionTabID);
- }
+ },
+
+ // 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.
+ evaluateScriptInExtensionTab(extensionTabID, scriptSource)
+ {
+ return WI.sharedApp.extensionController.evaluateScriptInExtensionTab(extensionTabID, scriptSource);
+ },
};
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TabBrowser.js (283275 => 283276)
--- trunk/Source/WebInspectorUI/UserInterface/Views/TabBrowser.js 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TabBrowser.js 2021-09-29 23:28:22 UTC (rev 283276)
@@ -120,7 +120,8 @@
bestTabContentViewForRepresentedObject(representedObject, options = {})
{
- console.assert(!this.selectedTabContentView || this.selectedTabContentView === this._recentTabContentViews[0]);
+ let shouldSaveTab = this.selectedTabContentView?.constructor.shouldSaveTab() || this.selectedTabContentView?.constructor.shouldPinTab();
+ console.assert(!this.selectedTabContentView || this.selectedTabContentView === this._recentTabContentViews[0] || !shouldSaveTab);
let tabContentView = this._recentTabContentViews.find((tabContentView) => tabContentView.type === options.preferredTabType);
if (tabContentView && tabContentView.canShowRepresentedObject(representedObject))
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/WebInspectorExtensionTabContentView.js (283275 => 283276)
--- trunk/Source/WebInspectorUI/UserInterface/Views/WebInspectorExtensionTabContentView.js 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/WebInspectorExtensionTabContentView.js 2021-09-29 23:28:22 UTC (rev 283276)
@@ -39,11 +39,21 @@
this._extensionTabID = extensionTabID;
this._tabInfo = tabInfo;
this._sourceURL = sourceURL;
+
+ // FIXME: the <iframe>'s document is implicitly reloaded when this
+ // content view's element is detached and later re-attached to the DOM.
+ // This is a bug and will be addressed in <https://webkit.org/b/230758>.
+ this._iframeElement = this.element.appendChild(document.createElement("iframe"));
+ this._iframeElement.addEventListener("load", this._extensionFrameDidLoad.bind(this));
+ this._iframeElement.src = ""
+
+ this._frameContentDidLoad = false;
}
// Public
get extensionTabID() { return this._extensionTabID; }
+ get iframeElement() { return this._iframeElement; }
get type()
{
@@ -59,8 +69,7 @@
{
super.attached();
- if (InspectorFrontendHost.supportsWebExtensions)
- InspectorFrontendHost.didShowExtensionTab(this._extension.extensionID, this._extensionTabID);
+ this._maybeDispatchDidShowExtensionTab();
}
detached()
@@ -78,14 +87,21 @@
static shouldSaveTab() { return false; }
- // Protected
+ // Private
- initialLayout()
+ _extensionFrameDidLoad()
{
- super.initialLayout();
+ this._frameContentDidLoad = true;
+ this._maybeDispatchDidShowExtensionTab();
+ }
- let iframeElement = this.element.appendChild(document.createElement("iframe"));
- iframeElement.src = ""
+ _maybeDispatchDidShowExtensionTab()
+ {
+ if (!this._frameContentDidLoad || !this.element.isConnected)
+ return;
+
+ if (InspectorFrontendHost.supportsWebExtensions)
+ InspectorFrontendHost.didShowExtensionTab(this._extension.extensionID, this._extensionTabID);
}
};
Modified: trunk/Source/WebKit/ChangeLog (283275 => 283276)
--- trunk/Source/WebKit/ChangeLog 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebKit/ChangeLog 2021-09-29 23:28:22 UTC (rev 283276)
@@ -1,3 +1,59 @@
+2021-09-29 BJ Burg <[email protected]>
+
+ [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.
+
+ 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.
+
2021-09-29 Chris Dumez <[email protected]>
Use isolated NSURLSessions for each first party registrable domain
Modified: trunk/Source/WebKit/SourcesCocoa.txt (283275 => 283276)
--- trunk/Source/WebKit/SourcesCocoa.txt 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebKit/SourcesCocoa.txt 2021-09-29 23:28:22 UTC (rev 283276)
@@ -288,6 +288,7 @@
UIProcess/API/Cocoa/_WKInspectorTesting.mm
UIProcess/API/Cocoa/_WKInspectorDebuggableInfo.mm
UIProcess/API/Cocoa/_WKInspectorExtension.mm
+UIProcess/API/Cocoa/_WKInspectorExtensionTesting.mm
UIProcess/API/Cocoa/_WKInspectorWindow.mm
UIProcess/API/Cocoa/_WKInternalDebugFeature.mm
UIProcess/API/Cocoa/_WKLinkIconParameters.mm
Modified: trunk/Source/WebKit/UIProcess/API/APIInspectorExtension.cpp (283275 => 283276)
--- trunk/Source/WebKit/UIProcess/API/APIInspectorExtension.cpp 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebKit/UIProcess/API/APIInspectorExtension.cpp 2021-09-29 23:28:22 UTC (rev 283276)
@@ -81,6 +81,18 @@
m_extensionControllerProxy->reloadForExtension(m_identifier, ignoreCache, userAgent, injectedScript, WTFMove(completionHandler));
}
+// For testing.
+
+void InspectorExtension::evaluateScriptInExtensionTab(const Inspector::ExtensionTabID& extensionTabID, const WTF::String& scriptSource, WTF::CompletionHandler<void(Inspector::ExtensionEvaluationResult)>&& completionHandler)
+{
+ if (!m_extensionControllerProxy) {
+ completionHandler(makeUnexpected(Inspector::ExtensionError::ContextDestroyed));
+ return;
+ }
+
+ m_extensionControllerProxy->evaluateScriptInExtensionTab(extensionTabID, scriptSource, WTFMove(completionHandler));
+}
+
} // namespace API
#endif // ENABLE(INSPECTOR_EXTENSIONS)
Modified: trunk/Source/WebKit/UIProcess/API/APIInspectorExtension.h (283275 => 283276)
--- trunk/Source/WebKit/UIProcess/API/APIInspectorExtension.h 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebKit/UIProcess/API/APIInspectorExtension.h 2021-09-29 23:28:22 UTC (rev 283276)
@@ -49,8 +49,11 @@
void createTab(const WTF::String& tabName, const WTF::URL& tabIconURL, const WTF::URL& sourceURL, WTF::CompletionHandler<void(Expected<Inspector::ExtensionTabID, Inspector::ExtensionError>)>&&);
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)>&&);
- void reloadIgnoringCache(const std::optional<bool>& ignoreCache, const std::optional<WTF::String>& userAgent, const std::optional<WTF::String>& injectedScript, WTF::CompletionHandler<void(Inspector::ExtensionEvaluationResult)>&&);
+ void reloadIgnoringCache(const std::optional<bool>& ignoreCache, const std::optional<WTF::String>& userAgent, const std::optional<WTF::String>& injectedScript, WTF::CompletionHandler<void(Inspector::ExtensionEvaluationResult)>&&);
+ // For testing.
+ void evaluateScriptInExtensionTab(const Inspector::ExtensionTabID&, const WTF::String& scriptSource, WTF::CompletionHandler<void(Inspector::ExtensionEvaluationResult)>&&);
+
InspectorExtensionClient* client() const { return m_client.get(); }
void setClient(UniqueRef<InspectorExtensionClient>&&);
Added: trunk/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtensionPrivateForTesting.h (0 => 283276)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtensionPrivateForTesting.h (rev 0)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtensionPrivateForTesting.h 2021-09-29 23:28:22 UTC (rev 283276)
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "_WKInspectorExtension.h"
+
+#if !TARGET_OS_IPHONE
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface _WKInspectorExtension (WKTesting)
+- (void)_evaluateScript:(NSString *)scriptSource inExtensionTabWithIdentifier:(NSString *)extensionTabIdentifier completionHandler:(void(^)(NSError * _Nullable, NSDictionary * _Nullable result))completionHandler;
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif // !TARGET_OS_IPHONE
Added: trunk/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtensionTesting.mm (0 => 283276)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtensionTesting.mm (rev 0)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtensionTesting.mm 2021-09-29 23:28:22 UTC (rev 283276)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+
+#if ENABLE(INSPECTOR_EXTENSIONS)
+
+#import "APISerializedScriptValue.h"
+#import "InspectorExtensionTypes.h"
+#import "WKError.h"
+#import "WKWebViewInternal.h"
+#import "_WKInspectorExtensionInternal.h"
+#import "_WKInspectorExtensionPrivateForTesting.h"
+#import <WebCore/ExceptionDetails.h>
+#import <WebCore/WebCoreObjCExtras.h>
+#import <wtf/BlockPtr.h>
+
+// This file exists to centralize all fragile code that is used by _WKInspectorExtension API tests.
+
+@implementation _WKInspectorExtension (WKTesting)
+
+- (void)_evaluateScript:(NSString *)scriptSource inExtensionTabWithIdentifier:(NSString *)extensionTabIdentifier completionHandler:(void(^)(NSError *, NSDictionary *))completionHandler
+{
+ _extension->evaluateScriptInExtensionTab(extensionTabIdentifier, scriptSource, [protectedSelf = retainPtr(self), capturedBlock = makeBlockPtr(WTFMove(completionHandler))] (Inspector::ExtensionEvaluationResult&& result) mutable {
+ if (!result) {
+ capturedBlock([NSError errorWithDomain:WKErrorDomain code:WKErrorUnknown userInfo:@{ NSLocalizedFailureReasonErrorKey: Inspector::extensionErrorToString(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);
+ });
+}
+
+@end
+
+#endif // ENABLE(INSPECTOR_EXTENSIONS)
Modified: trunk/Source/WebKit/UIProcess/Cocoa/GroupActivities/GroupActivitiesSessionNotifier.mm (283275 => 283276)
--- trunk/Source/WebKit/UIProcess/Cocoa/GroupActivities/GroupActivitiesSessionNotifier.mm 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebKit/UIProcess/Cocoa/GroupActivities/GroupActivitiesSessionNotifier.mm 2021-09-29 23:28:22 UTC (rev 283276)
@@ -28,6 +28,7 @@
#if ENABLE(MEDIA_SESSION_COORDINATOR) && HAVE(GROUP_ACTIVITIES)
+#import "GroupActivitiesCoordinator.h"
#import "WKGroupSession.h"
#import "WebPageProxy.h"
Modified: trunk/Source/WebKit/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.cpp (283275 => 283276)
--- trunk/Source/WebKit/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.cpp 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebKit/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.cpp 2021-09-29 23:28:22 UTC (rev 283276)
@@ -199,7 +199,32 @@
});
}
+// API for testing.
+void WebInspectorUIExtensionControllerProxy::evaluateScriptInExtensionTab(const Inspector::ExtensionTabID& extensionTabID, const String& scriptSource, WTF::CompletionHandler<void(Inspector::ExtensionEvaluationResult)>&& completionHandler)
+{
+ whenFrontendHasLoaded([weakThis = makeWeakPtr(this), extensionTabID, scriptSource, completionHandler = WTFMove(completionHandler)] () mutable {
+ if (!weakThis || !weakThis->m_inspectorPage) {
+ completionHandler(makeUnexpected(Inspector::ExtensionError::ContextDestroyed));
+ return;
+ }
+
+ 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 {
+ if (error) {
+ completionHandler(makeUnexpected(error.value()));
+ return;
+ }
+
+ if (details) {
+ Expected<RefPtr<API::SerializedScriptValue>, WebCore::ExceptionDetails> returnedValue = makeUnexpected(details.value());
+ return completionHandler({ returnedValue });
+ }
+
+ completionHandler({ { API::SerializedScriptValue::adopt({ dataReference.data(), dataReference.size() }).ptr() } });
+ });
+ });
+}
+
// WebInspectorUIExtensionControllerProxy IPC messages.
void WebInspectorUIExtensionControllerProxy::didShowExtensionTab(const Inspector::ExtensionID& extensionID, const Inspector::ExtensionTabID& extensionTabID)
Modified: trunk/Source/WebKit/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.h (283275 => 283276)
--- trunk/Source/WebKit/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.h 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebKit/UIProcess/Inspector/WebInspectorUIExtensionControllerProxy.h 2021-09-29 23:28:22 UTC (rev 283276)
@@ -62,6 +62,9 @@
void reloadForExtension(const Inspector::ExtensionID&, const std::optional<bool>& ignoreCache, const std::optional<String>& userAgent, const std::optional<String>& injectedScript, WTF::CompletionHandler<void(Inspector::ExtensionEvaluationResult)>&&);
void showExtensionTab(const Inspector::ExtensionTabID&, CompletionHandler<void(Expected<void, Inspector::ExtensionError>)>&&);
+ // API for testing.
+ void evaluateScriptInExtensionTab(const Inspector::ExtensionTabID&, const String& scriptSource, WTF::CompletionHandler<void(Inspector::ExtensionEvaluationResult)>&&);
+
// WebInspectorUIExtensionControllerProxy IPC messages.
void didShowExtensionTab(const Inspector::ExtensionID&, const Inspector::ExtensionTabID&);
void didHideExtensionTab(const Inspector::ExtensionID&, const Inspector::ExtensionTabID&);
Modified: trunk/Source/WebKit/UIProcess/Inspector/mac/WKInspectorResourceURLSchemeHandler.mm (283275 => 283276)
--- trunk/Source/WebKit/UIProcess/Inspector/mac/WKInspectorResourceURLSchemeHandler.mm 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebKit/UIProcess/Inspector/mac/WKInspectorResourceURLSchemeHandler.mm 2021-09-29 23:28:22 UTC (rev 283276)
@@ -122,7 +122,8 @@
// Allow fetches for resources that use a registered custom URL scheme.
if (_allowedURLSchemesForCSP && [self.mainResourceURLsForCSP containsObject:requestURL]) {
- NSString *stringForCSPPolicy = [NSString stringWithFormat:@"connect-src * %@:", [_allowedURLSchemesForCSP.get().allObjects componentsJoinedByString:@": "]];
+ NSString *listOfCustomProtocols = [NSString stringWithFormat:@"%@:", [_allowedURLSchemesForCSP.get().allObjects componentsJoinedByString:@": "]];
+ NSString *stringForCSPPolicy = [NSString stringWithFormat:@"connect-src * %@; img-src * file: blob: resource: %@", listOfCustomProtocols, listOfCustomProtocols];
[headerFields setObject:stringForCSPPolicy forKey:@"Content-Security-Policy"];
}
Modified: trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj (283275 => 283276)
--- trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj 2021-09-29 23:28:22 UTC (rev 283276)
@@ -1575,6 +1575,8 @@
99B16764252BBE620073140E /* WebInspectorUIExtensionController.h in Headers */ = {isa = PBXBuildFile; fileRef = 99B16761252BBE610073140E /* WebInspectorUIExtensionController.h */; };
99C3AE2D1DADA6AD00AF5C16 /* WebAutomationSessionMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 99C3AE2C1DADA6A700AF5C16 /* WebAutomationSessionMacros.h */; };
99C607EB26FA9D4900A0953F /* _WKInspectorIBActions.h in Headers */ = {isa = PBXBuildFile; fileRef = 99C607EA26FA9D4800A0953F /* _WKInspectorIBActions.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 99C607F026FB91E800A0953F /* _WKInspectorExtensionPrivateForTesting.h in Headers */ = {isa = PBXBuildFile; fileRef = 99C607EE26FB91E800A0953F /* _WKInspectorExtensionPrivateForTesting.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 99C607F126FB91E900A0953F /* _WKInspectorExtensionTesting.mm in Sources */ = {isa = PBXBuildFile; fileRef = 99C607EF26FB91E800A0953F /* _WKInspectorExtensionTesting.mm */; };
99C81D5A1C20E7E2005C4C82 /* AutomationClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 99C81D551C20DFBE005C4C82 /* AutomationClient.h */; };
99C81D5D1C21F38B005C4C82 /* APIAutomationClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 99C81D5B1C20E817005C4C82 /* APIAutomationClient.h */; };
99E714C51C124A0400665B3A /* _WKAutomationDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 99E714C11C1249E600665B3A /* _WKAutomationDelegate.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -5125,6 +5127,8 @@
99C3AE261DAD948500AF5C16 /* WebAutomationSessionCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebAutomationSessionCocoa.mm; sourceTree = "<group>"; };
99C3AE2C1DADA6A700AF5C16 /* WebAutomationSessionMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebAutomationSessionMacros.h; sourceTree = "<group>"; };
99C607EA26FA9D4800A0953F /* _WKInspectorIBActions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKInspectorIBActions.h; sourceTree = "<group>"; };
+ 99C607EE26FB91E800A0953F /* _WKInspectorExtensionPrivateForTesting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKInspectorExtensionPrivateForTesting.h; sourceTree = "<group>"; };
+ 99C607EF26FB91E800A0953F /* _WKInspectorExtensionTesting.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = _WKInspectorExtensionTesting.mm; sourceTree = "<group>"; };
99C81D551C20DFBE005C4C82 /* AutomationClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AutomationClient.h; sourceTree = "<group>"; };
99C81D561C20DFBE005C4C82 /* AutomationClient.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AutomationClient.mm; sourceTree = "<group>"; };
99C81D5B1C20E817005C4C82 /* APIAutomationClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APIAutomationClient.h; sourceTree = "<group>"; };
@@ -8214,6 +8218,8 @@
996B2BA025E2591100719379 /* _WKInspectorExtensionDelegate.h */,
997965A2253128C700B31AE3 /* _WKInspectorExtensionHost.h */,
99B16755252BB7E10073140E /* _WKInspectorExtensionInternal.h */,
+ 99C607EE26FB91E800A0953F /* _WKInspectorExtensionPrivateForTesting.h */,
+ 99C607EF26FB91E800A0953F /* _WKInspectorExtensionTesting.mm */,
99C607EA26FA9D4800A0953F /* _WKInspectorIBActions.h */,
5CAFDE442130843600B1F7E1 /* _WKInspectorInternal.h */,
9979CA57237F49F00039EC05 /* _WKInspectorPrivate.h */,
@@ -12003,6 +12009,7 @@
996B2BA125E2591100719379 /* _WKInspectorExtensionDelegate.h in Headers */,
997965A3253128C700B31AE3 /* _WKInspectorExtensionHost.h in Headers */,
99B16758252BB7E10073140E /* _WKInspectorExtensionInternal.h in Headers */,
+ 99C607F026FB91E800A0953F /* _WKInspectorExtensionPrivateForTesting.h in Headers */,
99C607EB26FA9D4900A0953F /* _WKInspectorIBActions.h in Headers */,
5CAFDE472130846A00B1F7E1 /* _WKInspectorInternal.h in Headers */,
9979CA58237F49F10039EC05 /* _WKInspectorPrivate.h in Headers */,
@@ -14403,6 +14410,7 @@
5790A6812567A1AC0077C5A7 /* _WKAuthenticatorResponse.mm in Sources */,
5790A66725679CEA0077C5A7 /* _WKAuthenticatorSelectionCriteria.mm in Sources */,
5CBD595C2280EDF4002B22AA /* _WKCustomHeaderFields.mm in Sources */,
+ 99C607F126FB91E900A0953F /* _WKInspectorExtensionTesting.mm in Sources */,
5790A67525679F740077C5A7 /* _WKPublicKeyCredentialCreationOptions.mm in Sources */,
5790A66D25679EB70077C5A7 /* _WKPublicKeyCredentialDescriptor.mm in Sources */,
5790A657256799DA0077C5A7 /* _WKPublicKeyCredentialEntity.mm in Sources */,
Modified: trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.cpp (283275 => 283276)
--- trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.cpp 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.cpp 2021-09-29 23:28:22 UTC (rev 283276)
@@ -59,7 +59,7 @@
WebProcess::singleton().removeMessageReceiver(Messages::WebInspectorUIExtensionController::messageReceiverName(), m_inspectorPageIdentifier);
}
-std::optional<Inspector::ExtensionError> WebInspectorUIExtensionController::parseExtensionErrorFromEvaluationResult(InspectorFrontendAPIDispatcher::EvaluationResult result)
+std::optional<Inspector::ExtensionError> WebInspectorUIExtensionController::parseExtensionErrorFromEvaluationResult(InspectorFrontendAPIDispatcher::EvaluationResult result) const
{
if (!result) {
switch (result.error()) {
@@ -158,7 +158,7 @@
});
}
-JSC::JSObject* WebInspectorUIExtensionController::unwrapEvaluationResultAsObject(InspectorFrontendAPIDispatcher::EvaluationResult result)
+JSC::JSObject* WebInspectorUIExtensionController::unwrapEvaluationResultAsObject(InspectorFrontendAPIDispatcher::EvaluationResult result) const
{
if (!result)
return nullptr;
@@ -359,6 +359,74 @@
});
}
+// WebInspectorUIExtensionController IPC messages for testing.
+
+void 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)
+{
+ if (!m_frontendClient) {
+ completionHandler({ }, std::nullopt, Inspector::ExtensionError::InvalidRequest);
+ return;
+ }
+
+ Vector<Ref<JSON::Value>> arguments {
+ JSON::Value::create(extensionTabID),
+ JSON::Value::create(scriptSource),
+ };
+
+ m_frontendClient->frontendAPIDispatcher().dispatchCommandWithResultAsync("evaluateScriptInExtensionTab"_s, WTFMove(arguments), [weakThis = makeWeakPtr(this), completionHandler = WTFMove(completionHandler)](InspectorFrontendAPIDispatcher::EvaluationResult&& result) mutable {
+ if (!weakThis) {
+ completionHandler({ }, std::nullopt, Inspector::ExtensionError::ContextDestroyed);
+ return;
+ }
+
+ auto* frontendGlobalObject = weakThis->m_frontendClient->frontendAPIDispatcher().frontendGlobalObject();
+ if (!frontendGlobalObject) {
+ completionHandler({ }, std::nullopt, Inspector::ExtensionError::ContextDestroyed);
+ return;
+ }
+
+ if (auto parsedError = weakThis->parseExtensionErrorFromEvaluationResult(result)) {
+ if (!result.value().has_value()) {
+ 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());
+ } else
+ LOG(Inspector, "Internal error encountered while evaluating upon the frontend.");
+
+ completionHandler({ }, std::nullopt, parsedError);
+ return;
+ }
+
+ // Expected result is either an ErrorString or {result: <any>} or {error: string}.
+ auto objectResult = weakThis->unwrapEvaluationResultAsObject(result);
+ if (!objectResult) {
+ LOG(Inspector, "Unexpected non-object value returned from InspectorFrontendAPI.createTabForExtension().");
+ completionHandler({ }, std::nullopt, Inspector::ExtensionError::InternalError);
+ return;
+ }
+ ASSERT(result.has_value());
+
+ JSC::JSValue errorPayload = objectResult->get(frontendGlobalObject, JSC::Identifier::fromString(frontendGlobalObject->vm(), "error"_s));
+ if (!errorPayload.isUndefined()) {
+ if (!errorPayload.isString()) {
+ completionHandler({ }, std::nullopt, Inspector::ExtensionError::InternalError);
+ return;
+ }
+
+ completionHandler({ }, ExceptionDetails { errorPayload.toWTFString(frontendGlobalObject) }, std::nullopt);
+ return;
+ }
+
+ JSC::JSValue resultPayload = objectResult->get(frontendGlobalObject, JSC::Identifier::fromString(frontendGlobalObject->vm(), "result"_s));
+ auto serializedResultValue = SerializedScriptValue::create(*frontendGlobalObject, resultPayload);
+ if (!serializedResultValue) {
+ completionHandler({ }, std::nullopt, Inspector::ExtensionError::InternalError);
+ return;
+ }
+
+ completionHandler(serializedResultValue->data(), std::nullopt, std::nullopt);
+ });
+}
+
void WebInspectorUIExtensionController::didShowExtensionTab(const Inspector::ExtensionID& extensionID, const Inspector::ExtensionTabID& extensionTabID)
{
WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorUIExtensionControllerProxy::DidShowExtensionTab { extensionID, extensionTabID }, m_inspectorPageIdentifier);
Modified: trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.h (283275 => 283276)
--- trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.h 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.h 2021-09-29 23:28:22 UTC (rev 283276)
@@ -70,13 +70,16 @@
void reloadForExtension(const Inspector::ExtensionID&, const std::optional<bool>& ignoreCache, const std::optional<String>& userAgent, const std::optional<String>& injectedScript, CompletionHandler<void(const std::optional<Inspector::ExtensionError>&)>&&);
void showExtensionTab(const Inspector::ExtensionTabID&, CompletionHandler<void(Expected<void, Inspector::ExtensionError>)>&&);
+ // WebInspectorUIExtensionController IPC messages for testing.
+ void evaluateScriptInExtensionTab(const Inspector::ExtensionTabID&, const String& scriptSource, CompletionHandler<void(const IPC::DataReference&, const std::optional<WebCore::ExceptionDetails>&, const std::optional<Inspector::ExtensionError>&)>&&);
+
// Callbacks from the frontend.
void didShowExtensionTab(const Inspector::ExtensionID&, const Inspector::ExtensionTabID&);
void didHideExtensionTab(const Inspector::ExtensionID&, const Inspector::ExtensionTabID&);
private:
- JSC::JSObject* unwrapEvaluationResultAsObject(WebCore::InspectorFrontendAPIDispatcher::EvaluationResult);
- std::optional<Inspector::ExtensionError> parseExtensionErrorFromEvaluationResult(WebCore::InspectorFrontendAPIDispatcher::EvaluationResult);
+ JSC::JSObject* unwrapEvaluationResultAsObject(WebCore::InspectorFrontendAPIDispatcher::EvaluationResult) const;
+ std::optional<Inspector::ExtensionError> parseExtensionErrorFromEvaluationResult(WebCore::InspectorFrontendAPIDispatcher::EvaluationResult) const;
WeakPtr<WebCore::InspectorFrontendClient> m_frontendClient;
WebCore::PageIdentifier m_inspectorPageIdentifier;
Modified: trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.messages.in (283275 => 283276)
--- trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.messages.in 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Source/WebKit/WebProcess/Inspector/WebInspectorUIExtensionController.messages.in 2021-09-29 23:28:22 UTC (rev 283276)
@@ -30,6 +30,9 @@
EvaluateScriptForExtension(String extensionID, String scriptSource, std::optional<URL> frameURL, std::optional<URL> contextSecurityOrigin, std::optional<bool> useContentScriptContext) -> (IPC::DataReference resultData, std::optional<WebCore::ExceptionDetails> details, std::optional<Inspector::ExtensionError> error) Async
ReloadForExtension(String extensionID, std::optional<bool> ignoreCache, std::optional<String> userAgent, std::optional<String> injectedScript) -> (std::optional<Inspector::ExtensionError> error) Async
ShowExtensionTab(String extensionTabIdentifier) -> (Expected<void, Inspector::ExtensionError> result) Async
+
+ // For testing.
+ EvaluateScriptInExtensionTab(String extensionTabID, String scriptSource) -> (IPC::DataReference resultData, std::optional<WebCore::ExceptionDetails> details, std::optional<Inspector::ExtensionError> error) Async
}
#endif // ENABLE(INSPECTOR_EXTENSIONS)
Modified: trunk/Tools/ChangeLog (283275 => 283276)
--- trunk/Tools/ChangeLog 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Tools/ChangeLog 2021-09-29 23:28:22 UTC (rev 283276)
@@ -1,3 +1,47 @@
+2021-09-29 BJ Burg <[email protected]>
+
+ [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.
+
+ 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.
+
2021-09-29 Alex Christensen <[email protected]>
Migrate _WKDownload tests from TCPServer to HTTPServer
Modified: trunk/Tools/TestWebKitAPI/SourcesCocoa.txt (283275 => 283276)
--- trunk/Tools/TestWebKitAPI/SourcesCocoa.txt 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Tools/TestWebKitAPI/SourcesCocoa.txt 2021-09-29 23:28:22 UTC (rev 283276)
@@ -27,6 +27,7 @@
cocoa/PlatformUtilitiesCocoa.mm
cocoa/TestCocoa.mm
cocoa/TestDownloadDelegate.mm
+cocoa/TestInspectorURLSchemeHandler.mm
cocoa/TestLegacyDownloadDelegate.mm
cocoa/TestNavigationDelegate.mm
cocoa/TestProtocol.mm
Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (283275 => 283276)
--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2021-09-29 23:28:22 UTC (rev 283276)
@@ -893,6 +893,7 @@
9999108B1F393C96008AD455 /* Copying.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9999108A1F393C8B008AD455 /* Copying.mm */; };
999B7EE32551C63B00F450A4 /* WKInspectorExtensionHost.mm in Sources */ = {isa = PBXBuildFile; fileRef = 999B7EE22551C63B00F450A4 /* WKInspectorExtensionHost.mm */; };
99B4F9C624EDED9700022B82 /* WKInspectorDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 99B4F9C524EDED9600022B82 /* WKInspectorDelegate.mm */; };
+ 99C607ED26FB90AC00A0953F /* WKInspectorExtension.mm in Sources */ = {isa = PBXBuildFile; fileRef = 99C607EC26FB90AC00A0953F /* WKInspectorExtension.mm */; };
99E2846426F91F7F0003F1FA /* WKInspectorExtensionDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 99E2846326F91F7F0003F1FA /* WKInspectorExtensionDelegate.mm */; };
99E2846626F93DB50003F1FA /* InspectorExtension-TabIcon-30x30.png in Copy Resources */ = {isa = PBXBuildFile; fileRef = 99E2846526F93D760003F1FA /* InspectorExtension-TabIcon-30x30.png */; };
99E2846826F941540003F1FA /* InspectorExtension-basic-tab.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 99E2846726F9413B0003F1FA /* InspectorExtension-basic-tab.html */; };
@@ -1519,7 +1520,6 @@
07E1F6A21FFC44FA0096C7EC /* getDisplayMedia.html in Copy Resources */,
467C565321B5ED130057516D /* GetSessionCookie.html in Copy Resources */,
41661C662355E85E00D33C27 /* getUserMedia-webaudio.html in Copy Resources */,
- 074994421EA5034B000DA44D /* invalidDeviceIDHashSalts in Copy Resources */,
074994421EA5034B000DA44E /* getUserMedia.html in Copy Resources */,
074994521EA5034B000DA44E /* getUserMedia2.html in Copy Resources */,
074994421EA5034B000DA45E /* getUserMediaAudioVideoCapture.html in Copy Resources */,
@@ -1578,6 +1578,7 @@
CE6D0EE32426B932002AD901 /* insert-text.html in Copy Resources */,
99E2846826F941540003F1FA /* InspectorExtension-basic-tab.html in Copy Resources */,
99E2846626F93DB50003F1FA /* InspectorExtension-TabIcon-30x30.png in Copy Resources */,
+ 074994421EA5034B000DA44D /* invalidDeviceIDHashSalts in Copy Resources */,
57F56A5C1C7F8CC100F31D7E /* IsNavigationActionTrusted.html in Copy Resources */,
C9B4AD2C1ECA6F7F00F5FEA0 /* js-autoplay-audio.html in Copy Resources */,
C99B675D1E39722000FC6C80 /* js-play-with-controls.html in Copy Resources */,
@@ -2624,6 +2625,9 @@
9999108A1F393C8B008AD455 /* Copying.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Copying.mm; sourceTree = "<group>"; };
999B7EE22551C63B00F450A4 /* WKInspectorExtensionHost.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKInspectorExtensionHost.mm; sourceTree = "<group>"; };
99B4F9C524EDED9600022B82 /* WKInspectorDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKInspectorDelegate.mm; sourceTree = "<group>"; };
+ 99C607EC26FB90AC00A0953F /* WKInspectorExtension.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKInspectorExtension.mm; sourceTree = "<group>"; };
+ 99C607F426FD5A1E00A0953F /* TestInspectorURLSchemeHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestInspectorURLSchemeHandler.h; path = cocoa/TestInspectorURLSchemeHandler.h; sourceTree = "<group>"; };
+ 99C607F526FD5A1F00A0953F /* TestInspectorURLSchemeHandler.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = TestInspectorURLSchemeHandler.mm; path = cocoa/TestInspectorURLSchemeHandler.mm; sourceTree = "<group>"; };
99E2846326F91F7F0003F1FA /* WKInspectorExtensionDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKInspectorExtensionDelegate.mm; sourceTree = "<group>"; };
99E2846526F93D760003F1FA /* InspectorExtension-TabIcon-30x30.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "InspectorExtension-TabIcon-30x30.png"; sourceTree = "<group>"; };
99E2846726F9413B0003F1FA /* InspectorExtension-basic-tab.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "InspectorExtension-basic-tab.html"; sourceTree = "<group>"; };
@@ -3323,6 +3327,8 @@
5CE7594722A883A500C12409 /* TestContextMenuDriver.mm */,
DF6BC4702534E120008F63CC /* TestDownloadDelegate.h */,
DF6BC46F2534E120008F63CC /* TestDownloadDelegate.mm */,
+ 99C607F426FD5A1E00A0953F /* TestInspectorURLSchemeHandler.h */,
+ 99C607F526FD5A1F00A0953F /* TestInspectorURLSchemeHandler.mm */,
5C72E8CD244FFCE300381EB7 /* TestLegacyDownloadDelegate.h */,
5C72E8CE244FFCE400381EB7 /* TestLegacyDownloadDelegate.mm */,
2D1C04A51D76298B000A6816 /* TestNavigationDelegate.h */,
@@ -3666,6 +3672,7 @@
370CE2291F57343400E7410B /* WKContentViewTargetForAction.mm */,
51D124971E763AF8002B2820 /* WKHTTPCookieStore.mm */,
99B4F9C524EDED9600022B82 /* WKInspectorDelegate.mm */,
+ 99C607EC26FB90AC00A0953F /* WKInspectorExtension.mm */,
99E2846326F91F7F0003F1FA /* WKInspectorExtensionDelegate.mm */,
999B7EE22551C63B00F450A4 /* WKInspectorExtensionHost.mm */,
A5A729F01F622A9A00DE5A28 /* WKNavigationResponse.mm */,
@@ -4581,6 +4588,7 @@
BC90977B125571AE00083756 /* Resources */ = {
isa = PBXGroup;
children = (
+ 4A410F4D19AF7BEF002EBAB4 /* invalidDeviceIDHashSalts */,
C045F9461385C2F800C0F3CD /* 18-characters.html */,
1C2B81851C89252300A5529F /* Ahem.ttf */,
93D3D19B17B1A7B000C7C415 /* all-content-in-one-iframe.html */,
@@ -4629,7 +4637,6 @@
BCBD372E125ABBE600D2C29F /* icon.png */,
1CC80CE92474F1F7004DC489 /* idempotent-mode-autosizing-only-honors-percentages.html */,
CE3524F51B142BBB0028A7C5 /* input-focus-blur.html */,
- 4A410F4D19AF7BEF002EBAB4 /* invalidDeviceIDHashSalts */,
C9B4AD2B1ECA6F7600F5FEA0 /* js-autoplay-audio.html */,
C99B675B1E3971FC00FC6C80 /* js-play-with-controls.html */,
55226A2E1EB969B600C36AD0 /* large-red-square-image.html */,
@@ -5947,6 +5954,7 @@
51D124981E763B02002B2820 /* WKHTTPCookieStore.mm in Sources */,
7CCE7F1D1A411AE600447C4C /* WKImageCreateCGImageCrash.cpp in Sources */,
99B4F9C624EDED9700022B82 /* WKInspectorDelegate.mm in Sources */,
+ 99C607ED26FB90AC00A0953F /* WKInspectorExtension.mm in Sources */,
99E2846426F91F7F0003F1FA /* WKInspectorExtensionDelegate.mm in Sources */,
999B7EE32551C63B00F450A4 /* WKInspectorExtensionHost.mm in Sources */,
A5A729F11F622AA700DE5A28 /* WKNavigationResponse.mm in Sources */,
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/InspectorExtension-basic-tab.html (283275 => 283276)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/InspectorExtension-basic-tab.html 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/InspectorExtension-basic-tab.html 2021-09-29 23:28:22 UTC (rev 283276)
@@ -1,4 +1,8 @@
<html>
+<head>
+<script>
+ window._secretValue = {answer:42};
+</script>
<body>
<h1>This is a test extension.</h1>
<p>In a normal extension, this area would show the extension's user interface.</p>
Copied: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKInspectorExtension.mm (from rev 283275, trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKInspectorExtensionDelegate.mm) (0 => 283276)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKInspectorExtension.mm (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKInspectorExtension.mm 2021-09-29 23:28:22 UTC (rev 283276)
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+
+#if ENABLE(INSPECTOR_EXTENSIONS)
+
+#import "TestCocoa.h"
+#import "TestInspectorURLSchemeHandler.h"
+#import "Utilities.h"
+#import <WebKit/WKPreferencesPrivate.h>
+#import <WebKit/WKWebViewPrivate.h>
+#import <WebKit/_WKInspector.h>
+#import <WebKit/_WKInspectorConfiguration.h>
+#import <WebKit/_WKInspectorExtension.h>
+#import <WebKit/_WKInspectorExtensionDelegate.h>
+#import <WebKit/_WKInspectorExtensionPrivateForTesting.h>
+#import <WebKit/_WKInspectorPrivateForTesting.h>
+#import <wtf/RetainPtr.h>
+
+static bool didAttachLocalInspectorCalled = false;
+static bool didShowExtensionTabWasCalled = false;
+static bool didHideExtensionTabWasCalled = false;
+static bool pendingCallbackWasCalled = false;
+static RetainPtr<TestInspectorURLSchemeHandler> sharedURLSchemeHandler;
+static RetainPtr<_WKInspectorExtension> sharedInspectorExtension;
+static RetainPtr<NSString> sharedExtensionTabIdentifier;
+
+static void resetGlobalState()
+{
+ didAttachLocalInspectorCalled = false;
+ didShowExtensionTabWasCalled = false;
+ didHideExtensionTabWasCalled = false;
+ pendingCallbackWasCalled = false;
+}
+
+@interface UIDelegateForTestingInspectorExtension : NSObject <WKUIDelegate>
+@end
+
+@implementation UIDelegateForTestingInspectorExtension
+
+- (void)_webView:(WKWebView *)webView didAttachLocalInspector:(_WKInspector *)inspector
+{
+ EXPECT_EQ(webView._inspector, inspector);
+ didAttachLocalInspectorCalled = true;
+}
+
+- (_WKInspectorConfiguration *)_webView:(WKWebView *)webView configurationForLocalInspector:(_WKInspector *)inspector
+{
+ if (!sharedURLSchemeHandler)
+ sharedURLSchemeHandler = adoptNS([[TestInspectorURLSchemeHandler alloc] init]);
+
+ auto inspectorConfiguration = adoptNS([[_WKInspectorConfiguration alloc] init]);
+ [inspectorConfiguration setURLSchemeHandler:sharedURLSchemeHandler.get() forURLScheme:@"test-resource"];
+ return inspectorConfiguration.autorelease();
+}
+
+@end
+
+
+@interface InspectorExtensionDelegateForTestingInspectorExtension : NSObject <_WKInspectorExtensionDelegate>
+@end
+
+@implementation InspectorExtensionDelegateForTestingInspectorExtension {
+}
+
+- (void)inspectorExtension:(_WKInspectorExtension *)extension didShowTabWithIdentifier:(NSString *)tabIdentifier
+{
+ didShowExtensionTabWasCalled = true;
+}
+
+- (void)inspectorExtension:(_WKInspectorExtension *)extension didHideTabWithIdentifier:(NSString *)tabIdentifier
+{
+ didHideExtensionTabWasCalled = true;
+}
+
+@end
+
+TEST(WKInspectorExtension, CanEvaluateScriptInExtensionTab)
+{
+ resetGlobalState();
+
+ auto webViewConfiguration = adoptNS([WKWebViewConfiguration new]);
+ webViewConfiguration.get().preferences._developerExtrasEnabled = YES;
+ auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
+ auto uiDelegate = adoptNS([UIDelegateForTestingInspectorExtension new]);
+
+ [webView setUIDelegate:uiDelegate.get()];
+ [webView loadHTMLString:@"<head><title>Test page to be inspected</title></head><body><p>Filler content</p></body>" baseURL:[NSURL URLWithString:@"http://example.com/"]];
+
+ [[webView _inspector] show];
+ TestWebKitAPI::Util::run(&didAttachLocalInspectorCalled);
+
+ auto extensionID = [NSUUID UUID].UUIDString;
+ auto extensionDisplayName = @"FirstExtension";
+
+ // Register the test extension.
+ pendingCallbackWasCalled = false;
+ [[webView _inspector] registerExtensionWithID:extensionID displayName:extensionDisplayName completionHandler:^(NSError * _Nullable error, _WKInspectorExtension * _Nullable extension) {
+ EXPECT_NULL(error);
+ EXPECT_NOT_NULL(extension);
+ sharedInspectorExtension = extension;
+
+ pendingCallbackWasCalled = true;
+ }];
+ TestWebKitAPI::Util::run(&pendingCallbackWasCalled);
+
+ auto extensionDelegate = adoptNS([InspectorExtensionDelegateForTestingInspectorExtension new]);
+ [sharedInspectorExtension setDelegate:extensionDelegate.get()];
+
+ // Create and show an extension tab.
+ auto iconURL = [NSURL URLWithString:@"test-resource://FirstExtension/InspectorExtension-TabIcon-30x30.png"];
+ auto sourceURL = [NSURL URLWithString:@"test-resource://FirstExtension/InspectorExtension-basic-tab.html"];
+
+ pendingCallbackWasCalled = false;
+ [sharedInspectorExtension createTabWithName:@"FirstExtension-Tab" tabIconURL:iconURL sourceURL:sourceURL completionHandler:^(NSError * _Nullable error, NSString * _Nullable extensionTabIdentifier) {
+ EXPECT_NULL(error);
+ EXPECT_NOT_NULL(extensionTabIdentifier);
+ sharedExtensionTabIdentifier = extensionTabIdentifier;
+
+ pendingCallbackWasCalled = true;
+ }];
+ TestWebKitAPI::Util::run(&pendingCallbackWasCalled);
+
+ pendingCallbackWasCalled = false;
+ didShowExtensionTabWasCalled = false;
+ [[webView _inspector] showExtensionTabWithIdentifier:sharedExtensionTabIdentifier.get() completionHandler:^(NSError * _Nullable error) {
+ EXPECT_NULL(error);
+
+ pendingCallbackWasCalled = true;
+ }];
+ TestWebKitAPI::Util::run(&pendingCallbackWasCalled);
+ TestWebKitAPI::Util::run(&didShowExtensionTabWasCalled);
+
+ // Read back a value that is set in the <iframe>'s script context.
+ pendingCallbackWasCalled = false;
+ auto scriptSource2 = @"window._secretValue";
+ [sharedInspectorExtension _evaluateScript:scriptSource2 inExtensionTabWithIdentifier:sharedExtensionTabIdentifier.get() completionHandler:^(NSError * _Nullable error, NSDictionary * _Nullable result) {
+ EXPECT_NULL(error);
+ EXPECT_NOT_NULL(result);
+ EXPECT_NS_EQUAL(result[@"answer"], @42);
+
+ pendingCallbackWasCalled = true;
+ }];
+ TestWebKitAPI::Util::run(&pendingCallbackWasCalled);
+
+ // Check to see that script is actually being evaluated in the <iframe>'s script context.
+ pendingCallbackWasCalled = false;
+ auto scriptSource3 = @"window.top !== window";
+ [sharedInspectorExtension _evaluateScript:scriptSource3 inExtensionTabWithIdentifier:sharedExtensionTabIdentifier.get() completionHandler:^(NSError * _Nullable error, NSDictionary * _Nullable result) {
+ EXPECT_NULL(error);
+ EXPECT_NOT_NULL(result);
+ EXPECT_NS_EQUAL(result, @YES);
+
+ pendingCallbackWasCalled = true;
+ }];
+ TestWebKitAPI::Util::run(&pendingCallbackWasCalled);
+
+ // Unregister the test extension.
+ pendingCallbackWasCalled = false;
+ [[webView _inspector] unregisterExtension:sharedInspectorExtension.get() completionHandler:^(NSError * _Nullable error) {
+ EXPECT_NULL(error);
+
+ pendingCallbackWasCalled = true;
+ }];
+ TestWebKitAPI::Util::run(&pendingCallbackWasCalled);
+}
+
+#endif // ENABLE(INSPECTOR_EXTENSIONS)
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKInspectorExtensionDelegate.mm (283275 => 283276)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKInspectorExtensionDelegate.mm 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKInspectorExtensionDelegate.mm 2021-09-29 23:28:22 UTC (rev 283276)
@@ -25,22 +25,25 @@
#import "config.h"
+#if ENABLE(INSPECTOR_EXTENSIONS)
+
#import "Test.h"
+#import "TestInspectorURLSchemeHandler.h"
#import "Utilities.h"
#import <WebKit/WKPreferencesPrivate.h>
#import <WebKit/WKWebViewPrivate.h>
#import <WebKit/_WKInspector.h>
+#import <WebKit/_WKInspectorConfiguration.h>
#import <WebKit/_WKInspectorExtension.h>
#import <WebKit/_WKInspectorExtensionDelegate.h>
#import <WebKit/_WKInspectorPrivateForTesting.h>
#import <wtf/RetainPtr.h>
-#if ENABLE(INSPECTOR_EXTENSIONS)
-
static bool didAttachLocalInspectorCalled = false;
static bool didShowExtensionTabWasCalled = false;
static bool didHideExtensionTabWasCalled = false;
static bool pendingCallbackWasCalled = false;
+static RetainPtr<TestInspectorURLSchemeHandler> sharedURLSchemeHandler;
static RetainPtr<_WKInspectorExtension> sharedInspectorExtension;
static RetainPtr<NSString> sharedExtensionTabIdentifier;
@@ -63,6 +66,16 @@
didAttachLocalInspectorCalled = true;
}
+- (_WKInspectorConfiguration *)_webView:(WKWebView *)webView configurationForLocalInspector:(_WKInspector *)inspector
+{
+ if (!sharedURLSchemeHandler)
+ sharedURLSchemeHandler = adoptNS([[TestInspectorURLSchemeHandler alloc] init]);
+
+ auto inspectorConfiguration = adoptNS([[_WKInspectorConfiguration alloc] init]);
+ [inspectorConfiguration setURLSchemeHandler:sharedURLSchemeHandler.get() forURLScheme:@"test-resource"];
+ return inspectorConfiguration.autorelease();
+}
+
@end
@@ -117,8 +130,8 @@
[sharedInspectorExtension setDelegate:extensionDelegate.get()];
// Create an extension tab.
- auto iconURL = [[NSBundle mainBundle] URLForResource:@"InspectorExtension-TabIcon-30x30" withExtension:@"png" subdirectory:@"TestWebKitAPI.resources"];
- auto sourceURL = [[NSBundle mainBundle] URLForResource:@"InspectorExtension-basic-tab" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+ auto iconURL = [NSURL URLWithString:@"test-resource://FirstExtension/InspectorExtension-TabIcon-30x30.png"];
+ auto sourceURL = [NSURL URLWithString:@"test-resource://FirstExtension/InspectorExtension-basic-tab.html"];
pendingCallbackWasCalled = false;
[sharedInspectorExtension createTabWithName:@"FirstExtension-Tab" tabIconURL:iconURL sourceURL:sourceURL completionHandler:^(NSError * _Nullable error, NSString * _Nullable extensionTabIdentifier) {
@@ -130,10 +143,6 @@
}];
TestWebKitAPI::Util::run(&pendingCallbackWasCalled);
- // Force a known non-extension tab to be shown before showing the extension tab. Otherwise,
- // if the extension tab was already open, then this test would hang waiting for a didShow callback.
- [[webView _inspector] showConsole];
-
pendingCallbackWasCalled = false;
[[webView _inspector] showExtensionTabWithIdentifier:sharedExtensionTabIdentifier.get() completionHandler:^(NSError * _Nullable error) {
EXPECT_NULL(error);
Added: trunk/Tools/TestWebKitAPI/cocoa/TestInspectorURLSchemeHandler.h (0 => 283276)
--- trunk/Tools/TestWebKitAPI/cocoa/TestInspectorURLSchemeHandler.h (rev 0)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestInspectorURLSchemeHandler.h 2021-09-29 23:28:22 UTC (rev 283276)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#import <WebKit/WKFoundation.h>
+#import <WebKit/WKURLSchemeHandler.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface TestInspectorURLSchemeHandler : NSObject <WKURLSchemeHandler>
+@end
+
+NS_ASSUME_NONNULL_END
Copied: trunk/Tools/TestWebKitAPI/cocoa/TestInspectorURLSchemeHandler.mm (from rev 283275, trunk/Source/WebKit/UIProcess/Inspector/mac/WKInspectorResourceURLSchemeHandler.mm) (0 => 283276)
--- trunk/Tools/TestWebKitAPI/cocoa/TestInspectorURLSchemeHandler.mm (rev 0)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestInspectorURLSchemeHandler.mm 2021-09-29 23:28:22 UTC (rev 283276)
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "TestInspectorURLSchemeHandler.h"
+
+#import <WebCore/MIMETypeRegistry.h>
+#import <WebKit/WKURLSchemeTask.h>
+#import <wtf/Assertions.h>
+
+// Note: this class is a simplified version of WKResourceURLSchemeHandler for testing purposes.
+
+@implementation TestInspectorURLSchemeHandler {
+ RetainPtr<NSMapTable<id <WKURLSchemeTask>, NSOperation *>> _fileLoadOperations;
+ RetainPtr<NSBundle> _cachedBundle;
+ RetainPtr<NSOperationQueue> _operationQueue;
+}
+
+// MARK - WKURLSchemeHandler Protocol
+
+- (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask
+{
+ if (!_cachedBundle)
+ _cachedBundle = [NSBundle mainBundle];
+
+ if (!_fileLoadOperations)
+ _fileLoadOperations = adoptNS([[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsStrongMemory capacity:5]);
+
+ if (!_operationQueue) {
+ _operationQueue = adoptNS([[NSOperationQueue alloc] init]);
+ _operationQueue.get().underlyingQueue = dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0);
+ _operationQueue.get().qualityOfService = NSOperationQualityOfServiceUserInteractive;
+
+ // The default value (NSOperationQueueDefaultMaxConcurrentOperationCount) results in a large number of threads
+ // that can exceed the soft limit if two Web Inspector instances are being loaded simultaneously.
+ _operationQueue.get().maxConcurrentOperationCount = 4;
+ }
+
+ NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [_fileLoadOperations removeObjectForKey:urlSchemeTask];
+ });
+
+ NSURL *requestURL = urlSchemeTask.request.URL;
+ NSURL *fileURLForRequest = [_cachedBundle URLForResource:requestURL.relativePath withExtension:@"" subdirectory:@"TestWebKitAPI.resources"];
+ if (!fileURLForRequest) {
+ [urlSchemeTask didFailWithError:[NSError errorWithDomain:NSCocoaErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil]];
+ return;
+ }
+
+ NSError *readError;
+ NSData *fileData = [NSData dataWithContentsOfURL:fileURLForRequest options:0 error:&readError];
+ if (!fileData) {
+ [urlSchemeTask didFailWithError:[NSError errorWithDomain:NSCocoaErrorDomain code:NSURLErrorResourceUnavailable userInfo:@{
+ NSUnderlyingErrorKey: readError,
+ }]];
+ return;
+ }
+
+ NSString *mimeType = WebCore::MIMETypeRegistry::mimeTypeForExtension(fileURLForRequest.pathExtension);
+ if (!mimeType)
+ mimeType = @"application/octet-stream";
+
+ RetainPtr<NSMutableDictionary> headerFields = adoptNS(@{
+ @"Access-Control-Allow-Origin": @"*",
+ @"Content-Length": [NSString stringWithFormat:@"%zu", (size_t)fileData.length],
+ @"Content-Type": mimeType,
+ }.mutableCopy);
+
+ RetainPtr<NSHTTPURLResponse> urlResponse = adoptNS([[NSHTTPURLResponse alloc] initWithURL:urlSchemeTask.request.URL statusCode:200 HTTPVersion:nil headerFields:headerFields.get()]);
+ [urlSchemeTask didReceiveResponse:urlResponse.get()];
+ [urlSchemeTask didReceiveData:fileData];
+ [urlSchemeTask didFinish];
+ }];
+
+ [_fileLoadOperations setObject:operation forKey:urlSchemeTask];
+ [_operationQueue addOperation:operation];
+}
+
+- (void)webView:(WKWebView *)webView stopURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask
+{
+ // Ensure that all blocks with pending removals are dispatched before doing a map lookup.
+ dispatch_async(dispatch_get_main_queue(), ^{
+ if (NSOperation *operation = [_fileLoadOperations objectForKey:urlSchemeTask]) {
+ [operation cancel];
+ [_fileLoadOperations removeObjectForKey:urlSchemeTask];
+ }
+ });
+}
+
+@end
Modified: trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm (283275 => 283276)
--- trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm 2021-09-29 23:27:35 UTC (rev 283275)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm 2021-09-29 23:28:22 UTC (rev 283276)
@@ -33,6 +33,7 @@
#import <WebKit/WKContentWorld.h>
#import <WebKit/WKWebViewConfigurationPrivate.h>
+#import <WebKit/WKWebViewPrivateForTesting.h>
#import <WebKit/WebKitPrivate.h>
#import <WebKit/_WKActivatedElementInfo.h>
#import <WebKit/_WKProcessPoolConfiguration.h>