https://bugs.webkit.org/show_bug.cgi?id=219378
Reviewed by Devin Rousso.
Source/WebCore:
Covered by existing Web Inspector layout tests.
* bindings/js/ScriptController.h: Make evaluateInWorld public and exported.
* inspector/InspectorFrontendAPIDispatcher.h:
* inspector/InspectorFrontendAPIDispatcher.cpp:
(WebCore::InspectorFrontendAPIDispatcher::evaluateOrQueueExpression):
(WebCore::InspectorFrontendAPIDispatcher::evaluateExpression):
Evaluate and pass along the result whether it's a value or exception.
* inspector/InspectorFrontendClientLocal.h:
* inspector/InspectorFrontendClientLocal.cpp:
(WebCore::InspectorFrontendClientLocal::evaluationResultToBoolean):
(WebCore::InspectorFrontendClientLocal::isDebuggingEnabled):
(WebCore::InspectorFrontendClientLocal::isTimelineProfilingEnabled):
(WebCore::InspectorFrontendClientLocal::isProfilingJavaScript):
Refactor the common code to take an EvaluationResult and figure out if the value is true or falsy.
* platform/Logging.h: Add an Inspector logging channel, for logging errors.
Source/WebKit:
The underlying method used for frontend expression evaluations is
ScriptController::evaluateIgnoringExceptions. This method calls
evaluateInWorld and returns nullopt if an exception happens.
Switch to using evaluateInWorld directly and using the existing ValueOrException
type from in WebCore. Change our EvaluationResult type to use ValueOrException
in place of JSC::JSValue. ValueOrException is Expected<JSC::JSValue, ExceptionDetails>
so this is exposing more error information in addition to the JSC::JSValue.
* Platform/Logging.h: Add 'Inspector' log channel for WebKit.framework.
* WebProcess/Inspector/WebInspectorUIExtensionController.cpp:
(WebKit::WebInspectorUIExtensionController::WebInspectorUIExtensionController):
(WebKit::WebInspectorUIExtensionController::~WebInspectorUIExtensionController):
Remove unnecessary debugging code that was accidentally left in/commented out.
* WebProcess/Inspector/WebInspectorUIExtensionController.h:
(WebKit::WebInspectorUIExtensionController::parseInspectorExtensionErrorFromResult): Deleted.
(WebKit::WebInspectorUIExtensionController::parseInspectorExtensionErrorFromEvaluationResult): Added.
(WebKit::WebInspectorUIExtensionController::registerExtension):
(WebKit::WebInspectorUIExtensionController::unregisterExtension):
Adapt to using the new result type. Use the InspectorExtensionID type where possible.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@270453
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2020-12-04 Brian Burg <bburg@apple.com>
+
+ Web Inspector: InspectorFrontendAPIDispatcher should not ignore all exceptions
+ https://bugs.webkit.org/show_bug.cgi?id=219378
+
+ Reviewed by Devin Rousso.
+
+ Covered by existing Web Inspector layout tests.
+
+ * bindings/js/ScriptController.h: Make evaluateInWorld public and exported.
+
+ * inspector/InspectorFrontendAPIDispatcher.h:
+ * inspector/InspectorFrontendAPIDispatcher.cpp:
+ (WebCore::InspectorFrontendAPIDispatcher::evaluateOrQueueExpression):
+ (WebCore::InspectorFrontendAPIDispatcher::evaluateExpression):
+ Evaluate and pass along the result whether it's a value or exception.
+
+ * inspector/InspectorFrontendClientLocal.h:
+ * inspector/InspectorFrontendClientLocal.cpp:
+ (WebCore::InspectorFrontendClientLocal::evaluationResultToBoolean):
+ (WebCore::InspectorFrontendClientLocal::isDebuggingEnabled):
+ (WebCore::InspectorFrontendClientLocal::isTimelineProfilingEnabled):
+ (WebCore::InspectorFrontendClientLocal::isProfilingJavaScript):
+ Refactor the common code to take an EvaluationResult and figure out if the value is true or falsy.
+
+ * platform/Logging.h: Add an Inspector logging channel, for logging errors.
+
2020-12-04 Zalan Bujtas <zalan@apple.com>
[LFC][Floats] FloatAvoider does not need to keep a pointer to Layout::Box around.
WEBCORE_EXPORT JSC::JSValue executeUserAgentScriptInWorldIgnoringException(DOMWrapperWorld&, const String& script, bool forceUserGesture);
WEBCORE_EXPORT ValueOrException executeUserAgentScriptInWorld(DOMWrapperWorld&, const String& script, bool forceUserGesture);
WEBCORE_EXPORT void executeAsynchronousUserAgentScriptInWorld(DOMWrapperWorld&, RunJavaScriptParameters&&, ResolveFunction&&);
+ ValueOrException evaluateInWorld(const ScriptSourceCode&, DOMWrapperWorld&);
JSC::JSValue evaluateIgnoringException(const ScriptSourceCode&);
JSC::JSValue evaluateInWorldIgnoringException(const ScriptSourceCode&, DOMWrapperWorld&);
private:
ValueOrException executeUserAgentScriptInWorldInternal(DOMWrapperWorld&, RunJavaScriptParameters&&);
ValueOrException executeScriptInWorld(DOMWrapperWorld&, RunJavaScriptParameters&&);
- ValueOrException evaluateInWorld(const ScriptSourceCode&, DOMWrapperWorld&);
ValueOrException callInWorld(RunJavaScriptParameters&&, DOMWrapperWorld&);
void setupModuleScriptHandlers(LoadableModuleScript&, JSC::JSInternalPromise&, DOMWrapperWorld&);
return;
}
- JSC::JSValue result = evaluateExpression(expression);
+ ValueOrException result = evaluateExpression(expression);
if (optionalResultHandler)
optionalResultHandler(result);
}
}
}
-JSC::JSValue InspectorFrontendAPIDispatcher::evaluateExpression(const String& expression)
+ValueOrException InspectorFrontendAPIDispatcher::evaluateExpression(const String& expression)
{
ASSERT(m_frontendPage);
ASSERT(!m_suspended);
ASSERT(m_queuedEvaluations.isEmpty());
JSC::SuspendExceptionScope scope(&m_frontendPage->inspectorController().vm());
- return m_frontendPage->mainFrame().script().evaluateIgnoringException(ScriptSourceCode(expression));
+ return m_frontendPage->mainFrame().script().evaluateInWorld(ScriptSourceCode(expression), mainThreadNormalWorld());
}
void InspectorFrontendAPIDispatcher::evaluateExpressionForTesting(const String& expression)
#pragma once
-#include <JavaScriptCore/JSCJSValue.h>
#include <wtf/CompletionHandler.h>
#include <wtf/Expected.h>
#include <wtf/JSONValues.h>
#include <wtf/WeakPtr.h>
#include <wtf/text/WTFString.h>
+namespace JSC {
+class JSGlobalObject;
+class JSValue;
+}
+
namespace WebCore {
class Page;
+struct ExceptionDetails;
class InspectorFrontendAPIDispatcher final : public RefCounted<InspectorFrontendAPIDispatcher> {
public:
enum class EvaluationError { ExecutionSuspended, ContextDestroyed };
- using EvaluationResult = Expected<JSC::JSValue, EvaluationError>;
+ using ValueOrException = Expected<JSC::JSValue, ExceptionDetails>;
+ using EvaluationResult = Expected<ValueOrException, EvaluationError>;
using EvaluationResultHandler = CompletionHandler<void(EvaluationResult)>;
enum class UnsuspendSoon { Yes, No };
void evaluateOrQueueExpression(const String&, EvaluationResultHandler&& handler = { });
void evaluateQueuedExpressions();
void invalidateQueuedExpressions();
- JSC::JSValue evaluateExpression(const String&);
+ ValueOrException evaluateExpression(const String&);
WeakPtr<Page> m_frontendPage;
Vector<std::pair<String, EvaluationResultHandler>> m_queuedEvaluations;
#include "Chrome.h"
#include "DOMWrapperWorld.h"
#include "Document.h"
+#include "ExceptionDetails.h"
#include "FloatRect.h"
#include "Frame.h"
#include "FrameLoadRequest.h"
#include "InspectorController.h"
#include "InspectorFrontendHost.h"
#include "InspectorPageAgent.h"
+#include "Logging.h"
#include "Page.h"
#include "ScriptController.h"
#include "ScriptSourceCode.h"
setAttachedWindowHeight(constrainedAttachedWindowHeight(preferredHeight, inspectedPageHeight));
}
-bool InspectorFrontendClientLocal::isDebuggingEnabled()
+Optional<bool> InspectorFrontendClientLocal::evaluationResultToBoolean(InspectorFrontendAPIDispatcher::EvaluationResult result)
{
- auto result = m_frontendAPIDispatcher->dispatchCommandWithResultSync("isDebuggingEnabled"_s);
- return result && result.value().toBoolean(m_frontendAPIDispatcher->frontendGlobalObject());
+ if (!result)
+ return WTF::nullopt;
+
+ auto valueOrException = result.value();
+ if (!valueOrException) {
+ LOG(Inspector, "Encountered exception while evaluating upon the frontend: %s", valueOrException.error().message.utf8().data());
+ return WTF::nullopt;
+ }
+ return valueOrException.value().toBoolean(m_frontendAPIDispatcher->frontendGlobalObject());
+}
+
+bool InspectorFrontendClientLocal::isDebuggingEnabled()
+{
+ return evaluationResultToBoolean(m_frontendAPIDispatcher->dispatchCommandWithResultSync("isDebuggingEnabled"_s)).valueOr(false);
}
void InspectorFrontendClientLocal::setDebuggingEnabled(bool enabled)
bool InspectorFrontendClientLocal::isTimelineProfilingEnabled()
{
- auto result = m_frontendAPIDispatcher->dispatchCommandWithResultSync("isTimelineProfilingEnabled"_s);
- return result && result.value().toBoolean(m_frontendAPIDispatcher->frontendGlobalObject());
+ return evaluationResultToBoolean(m_frontendAPIDispatcher->dispatchCommandWithResultSync("isTimelineProfilingEnabled"_s)).valueOr(false);
}
void InspectorFrontendClientLocal::setTimelineProfilingEnabled(bool enabled)
bool InspectorFrontendClientLocal::isProfilingJavaScript()
{
- auto result = m_frontendAPIDispatcher->dispatchCommandWithResultSync("isProfilingJavaScript"_s);
- return result && result.value().toBoolean(m_frontendAPIDispatcher->frontendGlobalObject());
+ return evaluationResultToBoolean(m_frontendAPIDispatcher->dispatchCommandWithResultSync("isProfilingJavaScript"_s)).valueOr(false);
}
void InspectorFrontendClientLocal::startProfilingJavaScript()
private:
friend class FrontendMenuProvider;
+ Optional<bool> evaluationResultToBoolean(InspectorFrontendAPIDispatcher::EvaluationResult);
InspectorController* m_inspectedPageController { nullptr };
Page* m_frontendPage { nullptr };
M(Images) \
M(IndexedDB) \
M(IndexedDBOperations) \
+ M(Inspector) \
M(Layers) \
M(Layout) \
M(FormattingContextLayout) \
+2020-12-04 Brian Burg <bburg@apple.com>
+
+ Web Inspector: InspectorFrontendAPIDispatcher should not ignore all exceptions
+ https://bugs.webkit.org/show_bug.cgi?id=219378
+
+ Reviewed by Devin Rousso.
+
+ The underlying method used for frontend expression evaluations is
+ ScriptController::evaluateIgnoringExceptions. This method calls
+ evaluateInWorld and returns nullopt if an exception happens.
+
+ Switch to using evaluateInWorld directly and using the existing ValueOrException
+ type from in WebCore. Change our EvaluationResult type to use ValueOrException
+ in place of JSC::JSValue. ValueOrException is Expected<JSC::JSValue, ExceptionDetails>
+ so this is exposing more error information in addition to the JSC::JSValue.
+
+ * Platform/Logging.h: Add 'Inspector' log channel for WebKit.framework.
+
+ * WebProcess/Inspector/WebInspectorUIExtensionController.cpp:
+ (WebKit::WebInspectorUIExtensionController::WebInspectorUIExtensionController):
+ (WebKit::WebInspectorUIExtensionController::~WebInspectorUIExtensionController):
+ Remove unnecessary debugging code that was accidentally left in/commented out.
+
+ * WebProcess/Inspector/WebInspectorUIExtensionController.h:
+ (WebKit::WebInspectorUIExtensionController::parseInspectorExtensionErrorFromResult): Deleted.
+ (WebKit::WebInspectorUIExtensionController::parseInspectorExtensionErrorFromEvaluationResult): Added.
+ (WebKit::WebInspectorUIExtensionController::registerExtension):
+ (WebKit::WebInspectorUIExtensionController::unregisterExtension):
+ Adapt to using the new result type. Use the InspectorExtensionID type where possible.
+
2020-12-04 Kate Cheney <katherine_cheney@apple.com>
Create API to enable/disable text interaction gestures in WKWebView
M(Images) \
M(IncrementalPDF) \
M(IncrementalPDFVerbose) \
+ M(Inspector) \
M(IndexedDB) \
M(KeyHandling) \
M(Layers) \
#if ENABLE(INSPECTOR_EXTENSIONS)
+#include "Logging.h"
#include "WebInspectorUI.h"
#include "WebInspectorUIExtensionControllerMessages.h"
#include "WebInspectorUIExtensionControllerMessagesReplies.h"
#include "WebPage.h"
#include "WebProcess.h"
+#include <JavaScriptCore/JSCInlines.h>
+#include <WebCore/ExceptionDetails.h>
#include <WebCore/InspectorFrontendAPIDispatcher.h>
namespace WebKit {
Page* page = inspectorFrontend.frontendPage();
ASSERT(page);
-// WTFReportBacktrace();
WebProcess::singleton().addMessageReceiver(Messages::WebInspectorUIExtensionController::messageReceiverName(), WebPage::fromCorePage(*page).identifier(), *this);
}
WebInspectorUIExtensionController::~WebInspectorUIExtensionController()
{
-// WTFReportBacktrace();
WebProcess::singleton().removeMessageReceiver(*this);
}
-Optional<InspectorExtensionError> WebInspectorUIExtensionController::parseInspectorExtensionErrorFromResult(JSC::JSValue result)
+Optional<InspectorExtensionError> WebInspectorUIExtensionController::parseInspectorExtensionErrorFromEvaluationResult(InspectorFrontendAPIDispatcher::EvaluationResult result)
{
+ if (!result.has_value()) {
+ switch (result.error()) {
+ case WebCore::InspectorFrontendAPIDispatcher::EvaluationError::ContextDestroyed:
+ return InspectorExtensionError::ContextDestroyed;
+ case WebCore::InspectorFrontendAPIDispatcher::EvaluationError::ExecutionSuspended:
+ return InspectorExtensionError::InternalError;
+ }
+ }
+
ASSERT(m_frontendClient);
auto globalObject = m_frontendClient->frontendAPIDispatcher().frontendGlobalObject();
if (!globalObject)
return InspectorExtensionError::ContextDestroyed;
+ auto valueOrException = result.value();
+ if (!valueOrException.has_value()) {
+ LOG(Inspector, "Encountered exception while evaluating upon the frontend: %s", valueOrException.error().message.utf8().data());
+ return InspectorExtensionError::InternalError;
+ }
+
// If the evaluation result is a string, the frontend returned an error string.
+ // If there was a JS exception, log it and return error code InternalError.
// Anything else (falsy values, objects, arrays, DOM, etc.) is interpreted as success.
- if (result.isString()) {
- auto resultString = result.toWTFString(globalObject);
+ JSC::JSValue scriptValue = valueOrException.value();
+ if (scriptValue.isString()) {
+ auto resultString = scriptValue.toWTFString(globalObject);
if (resultString == "ContextDestroyed"_s)
return InspectorExtensionError::ContextDestroyed;
if (resultString == "InternalError"_s)
// WebInspectorUIExtensionController IPC messages.
-void WebInspectorUIExtensionController::registerExtension(const String& extensionID, const String& displayName, CompletionHandler<void(Expected<bool, InspectorExtensionError>)>&& completionHandler)
+void WebInspectorUIExtensionController::registerExtension(const InspectorExtensionID& extensionID, const String& displayName, CompletionHandler<void(Expected<bool, InspectorExtensionError>)>&& completionHandler)
{
if (!m_frontendClient) {
completionHandler(makeUnexpected(InspectorExtensionError::InvalidRequest));
return;
}
- if (auto parsedError = weakThis->parseInspectorExtensionErrorFromResult(result.value())) {
+ if (auto parsedError = weakThis->parseInspectorExtensionErrorFromEvaluationResult(result)) {
completionHandler(makeUnexpected(parsedError.value()));
return;
}
});
}
-void WebInspectorUIExtensionController::unregisterExtension(const String& extensionID, CompletionHandler<void(Expected<bool, InspectorExtensionError>)>&& completionHandler)
+void WebInspectorUIExtensionController::unregisterExtension(const InspectorExtensionID& extensionID, CompletionHandler<void(Expected<bool, InspectorExtensionError>)>&& completionHandler)
{
if (!m_frontendClient) {
completionHandler(makeUnexpected(InspectorExtensionError::InvalidRequest));
return;
}
- if (auto parsedError = weakThis->parseInspectorExtensionErrorFromResult(result.value())) {
+ if (auto parsedError = weakThis->parseInspectorExtensionErrorFromEvaluationResult(result.value())) {
completionHandler(makeUnexpected(parsedError.value()));
return;
}
#include "Connection.h"
#include "InspectorExtensionTypes.h"
#include "MessageReceiver.h"
+#include <WebCore/InspectorFrontendAPIDispatcher.h>
#include <wtf/Forward.h>
#include <wtf/Noncopyable.h>
#include <wtf/URL.h>
namespace JSC {
class JSValue;
+class JSObject;
}
namespace WebCore {
void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
// WebInspectorUIExtensionController IPC messages.
- void registerExtension(const String& extensionID, const String& displayName, CompletionHandler<void(Expected<bool, InspectorExtensionError>)>&&);
- void unregisterExtension(const String& extensionID, CompletionHandler<void(Expected<bool, InspectorExtensionError>)>&&);
+ void registerExtension(const InspectorExtensionID&, const String& displayName, CompletionHandler<void(Expected<bool, InspectorExtensionError>)>&&);
+ void unregisterExtension(const InspectorExtensionID&, CompletionHandler<void(Expected<bool, InspectorExtensionError>)>&&);
private:
- Optional<InspectorExtensionError> parseInspectorExtensionErrorFromResult(JSC::JSValue result);
+ Optional<InspectorExtensionError> parseInspectorExtensionErrorFromEvaluationResult(WebCore::InspectorFrontendAPIDispatcher::EvaluationResult);
WeakPtr<WebCore::InspectorFrontendClient> m_frontendClient;
};