aboutsummaryrefslogtreecommitdiff
path: root/src/javascript/jsc/bindings/JSDOMExceptionHandling.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/javascript/jsc/bindings/JSDOMExceptionHandling.cpp')
-rw-r--r--src/javascript/jsc/bindings/JSDOMExceptionHandling.cpp260
1 files changed, 260 insertions, 0 deletions
diff --git a/src/javascript/jsc/bindings/JSDOMExceptionHandling.cpp b/src/javascript/jsc/bindings/JSDOMExceptionHandling.cpp
new file mode 100644
index 000000000..84f387bef
--- /dev/null
+++ b/src/javascript/jsc/bindings/JSDOMExceptionHandling.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2004-2021 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Samuel Weinig <sam@webkit.org>
+ * Copyright (C) 2013 Michael Pruett <michael@68k.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "root.h"
+
+#include "DOMException.h"
+#include "JSDOMException.h"
+#include "JSDOMExceptionHandling.h"
+
+#include <JavaScriptCore/ErrorHandlingScope.h>
+#include <JavaScriptCore/Exception.h>
+#include <JavaScriptCore/ExceptionHelpers.h>
+#include <JavaScriptCore/ScriptCallStack.h>
+#include <JavaScriptCore/ScriptCallStackFactory.h>
+
+namespace WebCore {
+using namespace JSC;
+
+String retrieveErrorMessageWithoutName(JSGlobalObject& lexicalGlobalObject, VM& vm, JSValue exception, CatchScope& catchScope)
+{
+ // FIXME: <http://webkit.org/b/115087> Web Inspector: WebCore::reportException should not evaluate JavaScript handling exceptions
+ // If this is a custom exception object, call toString on it to try and get a nice string representation for the exception.
+ String errorMessage;
+ if (auto* error = jsDynamicCast<ErrorInstance*>(vm, exception))
+ errorMessage = error->sanitizedMessageString(&lexicalGlobalObject);
+ else if (auto* error = jsDynamicCast<JSDOMException*>(vm, exception))
+ errorMessage = error->wrapped().message();
+ else
+ errorMessage = exception.toWTFString(&lexicalGlobalObject);
+
+ // We need to clear any new exception that may be thrown in the toString() call above.
+ // reportException() is not supposed to be making new exceptions.
+ catchScope.clearException();
+ vm.clearLastException();
+ return errorMessage;
+}
+
+String retrieveErrorMessage(JSGlobalObject& lexicalGlobalObject, VM& vm, JSValue exception, CatchScope& catchScope)
+{
+ // FIXME: <http://webkit.org/b/115087> Web Inspector: WebCore::reportException should not evaluate JavaScript handling exceptions
+ // If this is a custom exception object, call toString on it to try and get a nice string representation for the exception.
+ String errorMessage;
+ if (auto* error = jsDynamicCast<ErrorInstance*>(vm, exception))
+ errorMessage = error->sanitizedToString(&lexicalGlobalObject);
+ else
+ errorMessage = exception.toWTFString(&lexicalGlobalObject);
+
+ // We need to clear any new exception that may be thrown in the toString() call above.
+ // reportException() is not supposed to be making new exceptions.
+ catchScope.clearException();
+ vm.clearLastException();
+ return errorMessage;
+}
+
+void reportCurrentException(JSGlobalObject* lexicalGlobalObject)
+{
+ VM& vm = lexicalGlobalObject->vm();
+ auto scope = DECLARE_CATCH_SCOPE(vm);
+ auto* exception = scope.exception();
+ scope.clearException();
+ reportException(lexicalGlobalObject, exception);
+}
+
+JSValue createDOMException(JSGlobalObject* lexicalGlobalObject, ExceptionCode ec, const String& message)
+{
+ VM& vm = lexicalGlobalObject->vm();
+ if (UNLIKELY(vm.hasPendingTerminationException()))
+ return jsUndefined();
+
+ switch (ec) {
+ case ExistingExceptionError:
+ return jsUndefined();
+
+ // FIXME: Handle other WebIDL exception types.
+ case TypeError:
+ if (message.isEmpty())
+ return createTypeError(lexicalGlobalObject);
+ return createTypeError(lexicalGlobalObject, message);
+
+ case RangeError:
+ if (message.isEmpty())
+ return createRangeError(lexicalGlobalObject, "Bad value"_s);
+ return createRangeError(lexicalGlobalObject, message);
+
+ case JSSyntaxError:
+ if (message.isEmpty())
+ return createSyntaxError(lexicalGlobalObject);
+ return createSyntaxError(lexicalGlobalObject, message);
+
+ case StackOverflowError:
+ return createStackOverflowError(lexicalGlobalObject);
+
+ case OutOfMemoryError:
+ return createOutOfMemoryError(lexicalGlobalObject);
+
+ default: {
+ // FIXME: All callers to createDOMException need to pass in the correct global object.
+ // For now, we're going to assume the lexicalGlobalObject. Which is wrong in cases like this:
+ // frames[0].document.createElement(null, null); // throws an exception which should have the subframe's prototypes.
+ // https://bugs.webkit.org/show_bug.cgi?id=222229
+ JSDOMGlobalObject* globalObject = deprecatedGlobalObjectForPrototype(lexicalGlobalObject);
+ JSValue errorObject = toJS(lexicalGlobalObject, globalObject, DOMException::create(ec, message));
+
+ ASSERT(errorObject);
+ addErrorInfo(lexicalGlobalObject, asObject(errorObject), true);
+ return errorObject;
+ }
+ }
+ return {};
+}
+
+JSValue createDOMException(JSGlobalObject& lexicalGlobalObject, Exception&& exception)
+{
+ return createDOMException(&lexicalGlobalObject, exception.code(), exception.releaseMessage());
+}
+
+void propagateExceptionSlowPath(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& throwScope, Exception&& exception)
+{
+ throwScope.assertNoExceptionExceptTermination();
+ throwException(&lexicalGlobalObject, throwScope, createDOMException(lexicalGlobalObject, WTFMove(exception)));
+}
+
+static EncodedJSValue throwTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, const String& errorMessage)
+{
+ return throwVMTypeError(&lexicalGlobalObject, scope, errorMessage);
+}
+
+template<typename... StringTypes> static String makeArgumentTypeErrorMessage(unsigned argumentIndex, const char* argumentName, const char* interfaceName, const char* functionName, StringTypes... strings)
+{
+ return makeString(
+ "Argument ", argumentIndex + 1, " ('", argumentName, "') to ",
+ functionName ? std::make_tuple(interfaceName, ".", functionName) : std::make_tuple("the ", interfaceName, " constructor"),
+ " must be ", strings...);
+}
+
+void throwNotSupportedError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, ASCIILiteral message)
+{
+ scope.assertNoExceptionExceptTermination();
+ throwException(&lexicalGlobalObject, scope, createDOMException(&lexicalGlobalObject, NotSupportedError, message));
+}
+
+void throwInvalidStateError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, ASCIILiteral message)
+{
+ scope.assertNoExceptionExceptTermination();
+ throwException(&lexicalGlobalObject, scope, createDOMException(&lexicalGlobalObject, InvalidStateError, message));
+}
+
+void throwSecurityError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, const String& message)
+{
+ scope.assertNoExceptionExceptTermination();
+ throwException(&lexicalGlobalObject, scope, createDOMException(&lexicalGlobalObject, SecurityError, message));
+}
+
+JSC::EncodedJSValue throwArgumentMustBeEnumError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedValues)
+{
+ return throwVMTypeError(&lexicalGlobalObject, scope, makeArgumentTypeErrorMessage(argumentIndex, argumentName, functionInterfaceName, functionName, "one of: ", expectedValues));
+}
+
+JSC::EncodedJSValue throwArgumentMustBeFunctionError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, unsigned argumentIndex, const char* argumentName, const char* interfaceName, const char* functionName)
+{
+ return throwVMTypeError(&lexicalGlobalObject, scope, makeArgumentTypeErrorMessage(argumentIndex, argumentName, interfaceName, functionName, "a function"));
+}
+
+JSC::EncodedJSValue throwArgumentMustBeObjectError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, unsigned argumentIndex, const char* argumentName, const char* interfaceName, const char* functionName)
+{
+ return throwVMTypeError(&lexicalGlobalObject, scope, makeArgumentTypeErrorMessage(argumentIndex, argumentName, interfaceName, functionName, "an object"));
+}
+
+JSC::EncodedJSValue throwArgumentTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedType)
+{
+ return throwVMTypeError(&lexicalGlobalObject, scope, makeArgumentTypeErrorMessage(argumentIndex, argumentName, functionInterfaceName, functionName, "an instance of ", expectedType));
+}
+
+void throwAttributeTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, const char* interfaceName, const char* attributeName, const char* expectedType)
+{
+ throwTypeError(lexicalGlobalObject, scope, makeString("The ", interfaceName, '.', attributeName, " attribute must be an instance of ", expectedType));
+}
+
+JSC::EncodedJSValue throwRequiredMemberTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, const char* memberName, const char* dictionaryName, const char* expectedType)
+{
+ return throwVMTypeError(&lexicalGlobalObject, scope, makeString("Member ", dictionaryName, '.', memberName, " is required and must be an instance of ", expectedType));
+}
+
+JSC::EncodedJSValue throwConstructorScriptExecutionContextUnavailableError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, const char* interfaceName)
+{
+ return throwVMError(&lexicalGlobalObject, scope, createReferenceError(&lexicalGlobalObject, makeString(interfaceName, " constructor associated execution context is unavailable")));
+}
+
+void throwSequenceTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope)
+{
+ throwTypeError(lexicalGlobalObject, scope, "Value is not a sequence"_s);
+}
+
+void throwNonFiniteTypeError(JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope)
+{
+ throwTypeError(&lexicalGlobalObject, scope, "The provided value is non-finite"_s);
+}
+
+JSC::EncodedJSValue rejectPromiseWithGetterTypeError(JSC::JSGlobalObject& lexicalGlobalObject, const JSC::ClassInfo* classInfo, JSC::PropertyName attributeName)
+{
+ return createRejectedPromiseWithTypeError(lexicalGlobalObject, JSC::makeDOMAttributeGetterTypeErrorMessage(classInfo->className, String(attributeName.uid())), RejectedPromiseWithTypeErrorCause::NativeGetter);
+}
+
+String makeThisTypeErrorMessage(const char* interfaceName, const char* functionName)
+{
+ return makeString("Can only call ", interfaceName, '.', functionName, " on instances of ", interfaceName);
+}
+
+String makeUnsupportedIndexedSetterErrorMessage(const char* interfaceName)
+{
+ return makeString("Failed to set an indexed property on ", interfaceName, ": Indexed property setter is not supported.");
+}
+
+EncodedJSValue throwThisTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, const char* interfaceName, const char* functionName)
+{
+ return throwTypeError(lexicalGlobalObject, scope, makeThisTypeErrorMessage(interfaceName, functionName));
+}
+
+JSC::EncodedJSValue rejectPromiseWithThisTypeError(DeferredPromise& promise, const char* interfaceName, const char* methodName)
+{
+ promise.reject(TypeError, makeThisTypeErrorMessage(interfaceName, methodName));
+ return JSValue::encode(jsUndefined());
+}
+
+JSC::EncodedJSValue rejectPromiseWithThisTypeError(JSC::JSGlobalObject& lexicalGlobalObject, const char* interfaceName, const char* methodName)
+{
+ return createRejectedPromiseWithTypeError(lexicalGlobalObject, makeThisTypeErrorMessage(interfaceName, methodName), RejectedPromiseWithTypeErrorCause::InvalidThis);
+}
+
+void throwDOMSyntaxError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, ASCIILiteral message)
+{
+ scope.assertNoExceptionExceptTermination();
+ throwException(&lexicalGlobalObject, scope, createDOMException(&lexicalGlobalObject, SyntaxError, message));
+}
+
+void throwDataCloneError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope)
+{
+ scope.assertNoExceptionExceptTermination();
+ throwException(&lexicalGlobalObject, scope, createDOMException(&lexicalGlobalObject, DataCloneError));
+}
+
+} // namespace WebCore