diff options
author | 2022-03-27 02:42:02 -0700 | |
---|---|---|
committer | 2022-03-27 02:45:30 -0700 | |
commit | 309350e74cf0bf854c0148b627f6df8b5282ad2f (patch) | |
tree | e698660375ef137b1b16b06ba5c474fed18ce65b | |
parent | 0132b7164e956d56bf74dd8c45ad4cf90769961b (diff) | |
download | bun-309350e74cf0bf854c0148b627f6df8b5282ad2f.tar.gz bun-309350e74cf0bf854c0148b627f6df8b5282ad2f.tar.zst bun-309350e74cf0bf854c0148b627f6df8b5282ad2f.zip |
[bun.js] begin the webkit-ing
30 files changed, 3196 insertions, 42 deletions
diff --git a/src/javascript/jsc/bindings/BunBuiltinNames.h b/src/javascript/jsc/bindings/BunBuiltinNames.h index 708a37381..58c039cef 100644 --- a/src/javascript/jsc/bindings/BunBuiltinNames.h +++ b/src/javascript/jsc/bindings/BunBuiltinNames.h @@ -41,6 +41,10 @@ using namespace JSC; macro(filePath) \ macro(format) \ macro(get) \ + macro(hash) \ + macro(host) \ + macro(hostname) \ + macro(href) \ macro(isAbsolute) \ macro(isPaused) \ macro(isWindows) \ @@ -51,9 +55,12 @@ using namespace JSC; macro(on) \ macro(once) \ macro(options) \ + macro(origin) \ macro(parse) \ + macro(password) \ macro(patch) \ macro(path) \ + macro(pathname) \ macro(pause) \ macro(pid) \ macro(pipe) \ @@ -62,12 +69,15 @@ using namespace JSC; macro(ppid) \ macro(prependEventListener) \ macro(process) \ + macro(protocol) \ macro(put) \ macro(read) \ macro(relative) \ macro(removeEventListener) \ macro(resolve) \ macro(resume) \ + macro(search) \ + macro(searchParams) \ macro(sep) \ macro(syscall) \ macro(title) \ @@ -77,6 +87,7 @@ using namespace JSC; macro(unpipe) \ macro(unshift) \ macro(url) \ + macro(username) \ macro(version) \ macro(versions) \ macro(write) \ diff --git a/src/javascript/jsc/bindings/BunClientData.cpp b/src/javascript/jsc/bindings/BunClientData.cpp index 21db7cb7f..0bda7dd69 100644 --- a/src/javascript/jsc/bindings/BunClientData.cpp +++ b/src/javascript/jsc/bindings/BunClientData.cpp @@ -2,6 +2,7 @@ #include "BunClientData.h" #include "root.h" +#include "JSDOMURL.h" #include <JavaScriptCore/FastMallocAlignedMemoryAllocator.h> #include <JavaScriptCore/HeapInlines.h> #include <JavaScriptCore/IsoHeapCellType.h> @@ -15,10 +16,35 @@ namespace Bun { using namespace JSC; +using namespace WebCore; + +class ExtendedDOMClientIsoSubspaces; +class ExtendedDOMIsoSubspaces; + +#define CLIENT_ISO_SUBSPACE_INIT(subspace) subspace(m_heapData->subspace) +JSHeapData::JSHeapData(Heap& heap) + : m_domNamespaceObjectSpace ISO_SUBSPACE_INIT(heap, heap.cellHeapCellType, JSDOMObject) + +{ +} JSVMClientData::JSVMClientData(VM& vm) : m_builtinNames(vm) + , m_heapData(JSHeapData::ensureHeapData(vm.heap)) +{ +} + +JSHeapData* JSHeapData::ensureHeapData(Heap& heap) { + if (!Options::useGlobalGC()) + return new JSHeapData(heap); + + static JSHeapData* singleton = nullptr; + static std::once_flag onceFlag; + std::call_once(onceFlag, [&] { + singleton = new JSHeapData(heap); + }); + return singleton; } JSVMClientData::~JSVMClientData() {} @@ -28,7 +54,7 @@ void JSVMClientData::create(VM* vm) JSVMClientData* clientData = new JSVMClientData(*vm); vm->clientData = clientData; // ~VM deletes this pointer. - // vm->heap.addMarkingConstraint(makeUnique<BunGCOutputConstraint>(*vm, *clientData)); + // vm->heap.addMarkingConstraint(makeUnique<BunGCOutputConstraint>(*vm, *clientData)); // vm->m_typedArrayController = adoptRef(new WebCoreTypedArrayController( // type == WorkerThreadType::DedicatedWorker || type == WorkerThreadType::Worklet)); diff --git a/src/javascript/jsc/bindings/BunClientData.h b/src/javascript/jsc/bindings/BunClientData.h index 6e3747bb1..fc48148cd 100644 --- a/src/javascript/jsc/bindings/BunClientData.h +++ b/src/javascript/jsc/bindings/BunClientData.h @@ -3,12 +3,49 @@ #include "BunBuiltinNames.h" #include "root.h" #include <JavaScriptCore/BuiltinUtils.h> +#include <JavaScriptCore/IsoSubspacePerVM.h> +#include <JavaScriptCore/JSDestructibleObjectHeapCellType.h> #include <wtf/HashSet.h> #include <wtf/RefPtr.h> namespace Bun { using namespace JSC; +enum class UseCustomHeapCellType { Yes, + No }; + +class JSHeapData { + WTF_MAKE_NONCOPYABLE(JSHeapData); + WTF_MAKE_FAST_ALLOCATED; + friend class JSVMClientData; + +public: + JSHeapData(JSC::Heap&); + + static JSHeapData* ensureHeapData(JSC::Heap&); + + Lock& lock() { return m_lock; } + // ExtendedDOMIsoSubspaces& subspaces() { return *m_subspaces.get(); } + + Vector<JSC::IsoSubspace*>& outputConstraintSpaces() { return m_outputConstraintSpaces; } + + template<typename Func> + void forEachOutputConstraintSpace(const Func& func) + { + for (auto* space : m_outputConstraintSpaces) + func(*space); + } + + JSC::IsoSubspace m_domNamespaceObjectSpace; + +private: + Lock m_lock; + +private: + // std::unique_ptr<ExtendedDOMIsoSubspaces> m_subspaces; + Vector<JSC::IsoSubspace*> m_outputConstraintSpaces; +}; + class JSVMClientData : public JSC::VM::ClientData { WTF_MAKE_NONCOPYABLE(JSVMClientData); WTF_MAKE_FAST_ALLOCATED; @@ -20,20 +57,35 @@ public: static void create(JSC::VM*); + JSHeapData& heapData() { return *m_heapData; } BunBuiltinNames& builtinNames() { return m_builtinNames; } + // ExtendedDOMClientIsoSubspaces& clientSubspaces() { return *m_clientSubspaces.get(); } // Vector<JSC::IsoSubspace *> &outputConstraintSpaces() { return m_outputConstraintSpaces; } - // template <typename Func> void forEachOutputConstraintSpace(const Func &func) { - // for (auto *space : m_outputConstraintSpaces) func(*space); + // template<typename Func> void forEachOutputConstraintSpace(const Func& func) + // { + // for (auto* space : m_outputConstraintSpaces) + // func(*space); // } private: BunBuiltinNames m_builtinNames; + JSHeapData* m_heapData; + // Vector<JSC::IsoSubspace *> m_outputConstraintSpaces; }; +template<typename T, UseCustomHeapCellType useCustomHeapCellType, typename GetClient, typename SetClient, typename GetServer, typename SetServer> +ALWAYS_INLINE JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm, GetClient getClient, SetClient setClient, GetServer getServer, SetServer setServer, JSC::HeapCellType& (*getCustomHeapCellType)(JSHeapData&) = nullptr) +{ + static NeverDestroyed<JSC::IsoSubspacePerVM> perVM([](JSC::Heap& heap) { + return ISO_SUBSPACE_PARAMETERS(heap.destructibleObjectHeapCellType, T); + }); + return &perVM.get().clientIsoSubspaceforVM(vm); +} + static JSVMClientData* clientData(JSC::VM& vm) { return static_cast<Bun::JSVMClientData*>(vm.clientData); diff --git a/src/javascript/jsc/bindings/BunGCOutputConstraint.cpp b/src/javascript/jsc/bindings/BunGCOutputConstraint.cpp index bc99ef2e2..53f4bbb90 100644 --- a/src/javascript/jsc/bindings/BunGCOutputConstraint.cpp +++ b/src/javascript/jsc/bindings/BunGCOutputConstraint.cpp @@ -14,34 +14,40 @@ // using namespace JSC; -// BunGCOutputConstraint::BunGCOutputConstraint(VM &vm, Bun::JSVMClientData &clientData) -// : MarkingConstraint("Domo", "DOM Output", ConstraintVolatility::SeldomGreyed, -// ConstraintConcurrency::Concurrent, ConstraintParallelism::Parallel), -// m_vm(vm), -// m_clientData(clientData), -// m_lastExecutionVersion(vm.heap.mutatorExecutionVersion()) {} - -// template <typename Visitor> void BunGCOutputConstraint::executeImplImpl(Visitor &visitor) { -// Heap &heap = m_vm.heap; - -// if (heap.mutatorExecutionVersion() == m_lastExecutionVersion) return; - -// m_lastExecutionVersion = heap.mutatorExecutionVersion(); - -// m_clientData.forEachOutputConstraintSpace([&](Subspace &subspace) { -// auto func = [](Visitor &visitor, HeapCell *heapCell, HeapCell::Kind) { -// SetRootMarkReasonScope rootScope(visitor, RootMarkReason::DOMGCOutput); -// JSCell *cell = static_cast<JSCell *>(heapCell); -// cell->methodTable(visitor.vm())->visitOutputConstraints(cell, visitor); -// }; - -// RefPtr<SharedTask<void(Visitor &)>> task = -// subspace.template forEachMarkedCellInParallel<Visitor>(func); -// visitor.addParallelConstraintTask(task); -// }); +// BunGCOutputConstraint::BunGCOutputConstraint(VM& vm, Bun::JSVMClientData& clientData) +// : MarkingConstraint("Domo", "DOM Output", ConstraintVolatility::SeldomGreyed, +// ConstraintConcurrency::Concurrent, ConstraintParallelism::Parallel) +// , m_vm(vm) +// , m_clientData(clientData) +// , m_lastExecutionVersion(vm.heap.mutatorExecutionVersion()) +// { // } -// void BunGCOutputConstraint::executeImpl(AbstractSlotVisitor &visitor) { executeImplImpl(visitor); -// } void BunGCOutputConstraint::executeImpl(SlotVisitor &visitor) { executeImplImpl(visitor); } +// template<typename Visitor> void BunGCOutputConstraint::executeImplImpl(Visitor& visitor) +// { +// Heap& heap = m_vm.heap; + +// if (heap.mutatorExecutionVersion() == m_lastExecutionVersion) +// return; + +// m_lastExecutionVersion = heap.mutatorExecutionVersion(); + +// m_clientData.forEachOutputConstraintSpace([&](Subspace& subspace) { +// auto func = [](Visitor& visitor, HeapCell* heapCell, HeapCell::Kind) { +// SetRootMarkReasonScope rootScope(visitor, RootMarkReason::DOMGCOutput); +// JSCell* cell = static_cast<JSCell*>(heapCell); +// cell->methodTable(visitor.vm())->visitOutputConstraints(cell, visitor); +// }; + +// RefPtr<SharedTask<void(Visitor&)>> task = subspace.template forEachMarkedCellInParallel<Visitor>(func); +// visitor.addParallelConstraintTask(task); +// }); +// } + +// void BunGCOutputConstraint::executeImpl(AbstractSlotVisitor& visitor) +// { +// executeImplImpl(visitor); +// } +// void BunGCOutputConstraint::executeImpl(SlotVisitor& visitor) { executeImplImpl(visitor); } // } // namespace Bun diff --git a/src/javascript/jsc/bindings/BunGCOutputConstraint.h b/src/javascript/jsc/bindings/BunGCOutputConstraint.h index 521b0da8c..003f110b4 100644 --- a/src/javascript/jsc/bindings/BunGCOutputConstraint.h +++ b/src/javascript/jsc/bindings/BunGCOutputConstraint.h @@ -13,22 +13,22 @@ // class JSVMClientData; // class BunGCOutputConstraint : public JSC::MarkingConstraint { -// WTF_MAKE_FAST_ALLOCATED; +// WTF_MAKE_FAST_ALLOCATED; -// public: -// BunGCOutputConstraint(JSC::VM &, Bun::JSVMClientData &); -// ~BunGCOutputConstraint(){}; +// public: +// BunGCOutputConstraint(JSC::VM&, Bun::JSVMClientData&); +// ~BunGCOutputConstraint() {}; -// protected: -// void executeImpl(JSC::AbstractSlotVisitor &) override; -// void executeImpl(JSC::SlotVisitor &) override; +// protected: +// void executeImpl(JSC::AbstractSlotVisitor&) override; +// void executeImpl(JSC::SlotVisitor&) override; -// private: -// template <typename Visitor> void executeImplImpl(Visitor &); +// private: +// template<typename Visitor> void executeImplImpl(Visitor&); -// JSC::VM &m_vm; -// JSVMClientData &m_clientData; -// uint64_t m_lastExecutionVersion; +// JSC::VM& m_vm; +// JSVMClientData& m_clientData; +// uint64_t m_lastExecutionVersion; // }; // } // namespace Bun diff --git a/src/javascript/jsc/bindings/DOMException.cpp b/src/javascript/jsc/bindings/DOMException.cpp new file mode 100644 index 000000000..232fb83fe --- /dev/null +++ b/src/javascript/jsc/bindings/DOMException.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2011 Google 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. + * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY GOOGLE 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 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. + */ + +#include "DOMException.h" + +#include "Exception.h" + +namespace WebCore { + +// This array needs to be kept in sync with the ExceptionCode enumeration. +// http://heycam.github.io/webidl/#idl-DOMException-error-names +static const DOMException::Description descriptions[] = { + { "IndexSizeError"_s, "The index is not in the allowed range."_s, 1 }, + { "HierarchyRequestError"_s, "The operation would yield an incorrect node tree."_s, 3 }, + { "WrongDocumentError"_s, "The object is in the wrong document."_s, 4 }, + { "InvalidCharacterError"_s, "The string contains invalid characters."_s, 5 }, + { "NoModificationAllowedError"_s, "The object can not be modified."_s, 7 }, + { "NotFoundError"_s, "The object can not be found here."_s, 8 }, + { "NotSupportedError"_s, "The operation is not supported."_s, 9 }, + { "InUseAttributeError"_s, "The attribute is in use."_s, 10 }, + { "InvalidStateError"_s, "The object is in an invalid state."_s, 11 }, + { "SyntaxError"_s, "The string did not match the expected pattern."_s, 12 }, + { "InvalidModificationError"_s, " The object can not be modified in this way."_s, 13 }, + { "NamespaceError"_s, "The operation is not allowed by Namespaces in XML."_s, 14 }, + { "InvalidAccessError"_s, "The object does not support the operation or argument."_s, 15 }, + { "TypeMismatchError"_s, "The type of an object was incompatible with the expected type of the parameter associated to the object."_s, 17 }, + { "SecurityError"_s, "The operation is insecure."_s, 18 }, + { "NetworkError"_s, " A network error occurred."_s, 19 }, + { "AbortError"_s, "The operation was aborted."_s, 20 }, + { "URLMismatchError"_s, "The given URL does not match another URL."_s, 21 }, + { "QuotaExceededError"_s, "The quota has been exceeded."_s, 22 }, + { "TimeoutError"_s, "The operation timed out."_s, 23 }, + { "InvalidNodeTypeError"_s, "The supplied node is incorrect or has an incorrect ancestor for this operation."_s, 24 }, + { "DataCloneError"_s, "The object can not be cloned."_s, 25 }, + { "EncodingError"_s, "The encoding operation (either encoded or decoding) failed."_s, 0 }, + { "NotReadableError"_s, "The I/O read operation failed."_s, 0 }, + { "UnknownError"_s, "The operation failed for an unknown transient reason (e.g. out of memory)."_s, 0 }, + { "ConstraintError"_s, "A mutation operation in a transaction failed because a constraint was not satisfied."_s, 0 }, + { "DataError"_s, "Provided data is inadequate."_s, 0 }, + { "TransactionInactiveError"_s, "A request was placed against a transaction which is currently not active, or which is finished."_s, 0 }, + { "ReadOnlyError"_s, "The mutating operation was attempted in a \"readonly\" transaction."_s, 0 }, + { "VersionError"_s, "An attempt was made to open a database using a lower version than the existing version."_s, 0 }, + { "OperationError"_s, "The operation failed for an operation-specific reason."_s, 0 }, + { "NotAllowedError"_s, "The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission."_s, 0 } +}; +static_assert(!IndexSizeError, "This table needs to be kept in sync with DOMException names in ExceptionCode enumeration"); +static_assert(NotAllowedError == WTF_ARRAY_LENGTH(descriptions) - 1, "This table needs to be kept in sync with DOMException names in ExceptionCode enumeration"); + +auto DOMException::description(ExceptionCode ec) -> const Description& +{ + if (ec < WTF_ARRAY_LENGTH(descriptions)) + return descriptions[ec]; + + static const Description emptyDescription { ASCIILiteral::null(), ASCIILiteral::null(), 0 }; + return emptyDescription; +} + +static DOMException::LegacyCode legacyCodeFromName(const String& name) +{ + for (auto& description : descriptions) { + if (description.name == name) + return description.legacyCode; + } + return 0; +} + +Ref<DOMException> DOMException::create(ExceptionCode ec, const String& message) +{ + auto& description = DOMException::description(ec); + return adoptRef(*new DOMException(description.legacyCode, description.name, !message.isEmpty() ? message : description.message)); +} + +Ref<DOMException> DOMException::create(const String& message, const String& name) +{ + return adoptRef(*new DOMException(legacyCodeFromName(name), name, message)); +} + +Ref<DOMException> DOMException::create(const Exception& exception) +{ + auto& description = DOMException::description(exception.code()); + return adoptRef(*new DOMException(description.legacyCode, description.name, exception.message().isEmpty() ? description.message : exception.message())); +} + +DOMException::DOMException(LegacyCode legacyCode, const String& name, const String& message) + : m_legacyCode(legacyCode) + , m_name(name) + , m_message(message) +{ +} + +} // namespace WebCore diff --git a/src/javascript/jsc/bindings/DOMException.h b/src/javascript/jsc/bindings/DOMException.h new file mode 100644 index 000000000..b764393c1 --- /dev/null +++ b/src/javascript/jsc/bindings/DOMException.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2007, 2008 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. + * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 +#include "root.h" + +#include "ExceptionCode.h" +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class Exception; + +class DOMException : public RefCounted<DOMException> { +public: + static Ref<DOMException> create(ExceptionCode, const String& message = emptyString()); + static Ref<DOMException> create(const Exception&); + + // For DOM bindings. + static Ref<DOMException> create(const String& message, const String& name); + + using LegacyCode = uint8_t; + LegacyCode legacyCode() const { return m_legacyCode; } + + String name() const { return m_name; } + String message() const { return m_message; } + + struct Description { + const ASCIILiteral name; + const ASCIILiteral message; + LegacyCode legacyCode; + }; + + WEBCORE_EXPORT static const Description& description(ExceptionCode); + + static ASCIILiteral name(ExceptionCode ec) { return description(ec).name; } + static ASCIILiteral message(ExceptionCode ec) { return description(ec).message; } + +protected: + DOMException(LegacyCode, const String& name, const String& message); + +private: + LegacyCode m_legacyCode; + String m_name; + String m_message; +}; + +} // namespace WebCore diff --git a/src/javascript/jsc/bindings/DOMFormData.cpp b/src/javascript/jsc/bindings/DOMFormData.cpp new file mode 100644 index 000000000..54c629f37 --- /dev/null +++ b/src/javascript/jsc/bindings/DOMFormData.cpp @@ -0,0 +1,180 @@ +// /* +// * Copyright (C) 2010 Google 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: +// * +// * * Redistributions of source code must retain the above copyright +// * notice, this list of conditions and the following disclaimer. +// * * 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. +// * * Neither the name of Google Inc. nor the names of its +// * contributors may be used to endorse or promote products derived from +// * this software without specific prior written permission. +// * +// * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// * OWNER OR 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. +// */ + +// #include "config.h" +// #include "DOMFormData.h" + +// #include "Document.h" +// #include "HTMLFormControlElement.h" +// #include "HTMLFormElement.h" + +// namespace WebCore { + +// DOMFormData::DOMFormData(const PAL::TextEncoding& encoding) +// : m_encoding(encoding) +// { +// } + +// ExceptionOr<Ref<DOMFormData>> DOMFormData::create(HTMLFormElement* form) +// { +// auto formData = adoptRef(*new DOMFormData); +// if (!form) +// return formData; + +// auto result = form->constructEntryList(WTFMove(formData), nullptr); + +// if (!result) +// return Exception { InvalidStateError, "Already constructing Form entry list."_s }; + +// return result.releaseNonNull(); +// } + +// Ref<DOMFormData> DOMFormData::create(const PAL::TextEncoding& encoding) +// { +// return adoptRef(*new DOMFormData(encoding)); +// } + +// Ref<DOMFormData> DOMFormData::clone() const +// { +// auto newFormData = adoptRef(*new DOMFormData(this->encoding())); +// newFormData->m_items = m_items; + +// return newFormData; +// } + +// // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#create-an-entry +// static auto createStringEntry(const String& name, const String& value) -> DOMFormData::Item +// { +// return { +// replaceUnpairedSurrogatesWithReplacementCharacter(String(name)), +// replaceUnpairedSurrogatesWithReplacementCharacter(String(value)), +// }; +// } + +// void DOMFormData::append(const String& name, const String& value) +// { +// m_items.append(createStringEntry(name, value)); +// } + +// void DOMFormData::append(const String& name, Blob& blob, const String& filename) +// { +// m_items.append(createFileEntry(name, blob, filename)); +// } + +// void DOMFormData::remove(const String& name) +// { +// m_items.removeAllMatching([&name](const auto& item) { +// return item.name == name; +// }); +// } + +// auto DOMFormData::get(const String& name) -> std::optional<FormDataEntryValue> +// { +// for (auto& item : m_items) { +// if (item.name == name) +// return item.data; +// } + +// return std::nullopt; +// } + +// auto DOMFormData::getAll(const String& name) -> Vector<FormDataEntryValue> +// { +// Vector<FormDataEntryValue> result; + +// for (auto& item : m_items) { +// if (item.name == name) +// result.append(item.data); +// } + +// return result; +// } + +// bool DOMFormData::has(const String& name) +// { +// for (auto& item : m_items) { +// if (item.name == name) +// return true; +// } + +// return false; +// } + +// void DOMFormData::set(const String& name, const String& value) +// { +// set(name, { name, value }); +// } + +// void DOMFormData::set(const String& name, Blob& blob, const String& filename) +// { +// set(name, createFileEntry(name, blob, filename)); +// } + +// void DOMFormData::set(const String& name, Item&& item) +// { +// std::optional<size_t> initialMatchLocation; + +// // Find location of the first item with a matching name. +// for (size_t i = 0; i < m_items.size(); ++i) { +// if (name == m_items[i].name) { +// initialMatchLocation = i; +// break; +// } +// } + +// if (initialMatchLocation) { +// m_items[*initialMatchLocation] = WTFMove(item); + +// m_items.removeAllMatching([&name](const auto& item) { +// return item.name == name; +// }, +// *initialMatchLocation + 1); +// return; +// } + +// m_items.append(WTFMove(item)); +// } + +// DOMFormData::Iterator::Iterator(DOMFormData& target) +// : m_target(target) +// { +// } + +// std::optional<KeyValuePair<String, DOMFormData::FormDataEntryValue>> DOMFormData::Iterator::next() +// { +// auto& items = m_target->items(); +// if (m_index >= items.size()) +// return std::nullopt; + +// auto& item = items[m_index++]; +// return makeKeyValuePair(item.name, item.data); +// } + +// } // namespace WebCore diff --git a/src/javascript/jsc/bindings/DOMFormData.h b/src/javascript/jsc/bindings/DOMFormData.h new file mode 100644 index 000000000..9592afdbe --- /dev/null +++ b/src/javascript/jsc/bindings/DOMFormData.h @@ -0,0 +1,89 @@ +// /* +// * Copyright (C) 2010 Google 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: +// * +// * * Redistributions of source code must retain the above copyright +// * notice, this list of conditions and the following disclaimer. +// * * 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. +// * * Neither the name of Google Inc. nor the names of its +// * contributors may be used to endorse or promote products derived from +// * this software without specific prior written permission. +// * +// * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// * OWNER OR 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 + +// #include "File.h" +// #include <pal/text/TextEncoding.h> +// #include <variant> +// #include <wtf/RefCounted.h> +// #include <wtf/text/WTFString.h> + +// namespace WebCore { + +// template<typename> class ExceptionOr; +// class HTMLFormElement; + +// class DOMFormData : public RefCounted<DOMFormData> { +// public: +// using FormDataEntryValue = std::variant<RefPtr<File>, String>; + +// struct Item { +// String name; +// FormDataEntryValue data; +// }; + +// static ExceptionOr<Ref<DOMFormData>> create(HTMLFormElement*); +// static Ref<DOMFormData> create(const PAL::TextEncoding&); + +// const Vector<Item>& items() const { return m_items; } +// const PAL::TextEncoding& encoding() const { return m_encoding; } + +// void append(const String& name, const String& value); +// void append(const String& name, Blob&, const String& filename = { }); +// void remove(const String& name); +// std::optional<FormDataEntryValue> get(const String& name); +// Vector<FormDataEntryValue> getAll(const String& name); +// bool has(const String& name); +// void set(const String& name, const String& value); +// void set(const String& name, Blob&, const String& filename = { }); +// Ref<DOMFormData> clone() const; + +// class Iterator { +// public: +// explicit Iterator(DOMFormData&); +// std::optional<KeyValuePair<String, FormDataEntryValue>> next(); + +// private: +// Ref<DOMFormData> m_target; +// size_t m_index { 0 }; +// }; +// Iterator createIterator() { return Iterator { *this }; } + +// private: +// explicit DOMFormData(const PAL::TextEncoding& = PAL::UTF8Encoding()); + +// void set(const String& name, Item&&); + +// PAL::TextEncoding m_encoding; +// Vector<Item> m_items; +// }; + +// } // namespace WebCore diff --git a/src/javascript/jsc/bindings/DOMURL.cpp b/src/javascript/jsc/bindings/DOMURL.cpp new file mode 100644 index 000000000..8b437b5b7 --- /dev/null +++ b/src/javascript/jsc/bindings/DOMURL.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann <hausmann@kde.org> + * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010, 2014 Apple Inc. All rights reserved. + * (C) 2006 Graham Dennis (graham.dennis@gmail.com) + * Copyright (C) 2011 Google Inc. All rights reserved. + * Copyright (C) 2012 Motorola Mobility Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "DOMURL.h" + +// #include "ActiveDOMObject.h" +// #include "Blob.h" +// #include "BlobURL.h" +// #include "MemoryCache.h" +// #include "PublicURLManager.h" +// #include "ResourceRequest.h" +#include "URLSearchParams.h" +// #include <wtf/MainThread.h> + +namespace WebCore { + +inline DOMURL::DOMURL(URL&& completeURL, const URL& baseURL) + : m_baseURL(baseURL) + , m_url(WTFMove(completeURL)) +{ +} + +ExceptionOr<Ref<DOMURL>> DOMURL::create(const String& url, const URL& base) +{ + ASSERT(base.isValid() || base.isNull()); + URL completeURL { base, url }; + if (!completeURL.isValid()) + return Exception { TypeError }; + return adoptRef(*new DOMURL(WTFMove(completeURL), base)); +} + +ExceptionOr<Ref<DOMURL>> DOMURL::create(const String& url, const String& base) +{ + URL baseURL { URL {}, base }; + if (!base.isNull() && !baseURL.isValid()) + return Exception { TypeError }; + return create(url, baseURL); +} + +ExceptionOr<Ref<DOMURL>> DOMURL::create(const String& url, const DOMURL& base) +{ + return create(url, base.href()); +} + +DOMURL::~DOMURL() = default; + +ExceptionOr<void> DOMURL::setHref(const String& url) +{ + URL completeURL { URL {}, url }; + if (!completeURL.isValid()) + return Exception { TypeError }; + m_url = WTFMove(completeURL); + if (m_searchParams) + m_searchParams->updateFromAssociatedURL(); + return {}; +} + +void DOMURL::setQuery(const String& query) +{ + m_url.setQuery(query); +} + +// String DOMURL::createObjectURL(Blob& blob) +// { +// return createPublicURL(scriptExecutionContext, blob); +// } + +// String DOMURL::createPublicURL(URLRegistrable& registrable) +// { +// URL publicURL = BlobURL::createPublicURL(scriptExecutionContext.securityOrigin()); +// if (publicURL.isEmpty()) +// return String(); + +// scriptExecutionContext.publicURLManager().registerURL(publicURL, registrable); + +// return publicURL.string(); +// } + +URLSearchParams& DOMURL::searchParams() +{ + if (!m_searchParams) + m_searchParams = URLSearchParams::create(search(), this); + return *m_searchParams; +} + +// void DOMURL::revokeObjectURL(const String& urlString) +// { +// // URL url(URL(), urlString); +// // ResourceRequest request(url); +// // request.setDomainForCachePartition(scriptExecutionContext.domainForCachePartition()); + +// // MemoryCache::removeRequestFromSessionCaches(scriptExecutionContext, request); + +// // scriptExecutionContext.publicURLManager().revoke(url); +// } + +} // namespace WebCore diff --git a/src/javascript/jsc/bindings/DOMURL.h b/src/javascript/jsc/bindings/DOMURL.h new file mode 100644 index 000000000..aa7c1eddf --- /dev/null +++ b/src/javascript/jsc/bindings/DOMURL.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * Copyright (C) 2012 Motorola Mobility Inc. + * + * 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 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 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 + +#include "root.h" + +#include "ExceptionOr.h" +#include "URLDecomposition.h" +#include <wtf/URL.h> +#include <wtf/WeakPtr.h> + +namespace WebCore { + +class URLSearchParams; + +class DOMURL final : public RefCounted<DOMURL>, public CanMakeWeakPtr<DOMURL>, public URLDecomposition { +public: + static ExceptionOr<Ref<DOMURL>> create(const String& url, const String& base); + static ExceptionOr<Ref<DOMURL>> create(const String& url, const DOMURL& base); + ~DOMURL(); + + const URL& href() const { return m_url; } + ExceptionOr<void> setHref(const String&); + void setQuery(const String&); + + URLSearchParams& searchParams(); + + const String& toJSON() const { return m_url.string(); } + + // static String createObjectURL(ScriptExecutionContext&, Blob&); + // static void revokeObjectURL(ScriptExecutionContext&, const String&); + + // static String createPublicURL(ScriptExecutionContext&, URLRegistrable&); + +private: + static ExceptionOr<Ref<DOMURL>> create(const String& url, const URL& base); + DOMURL(URL&& completeURL, const URL& baseURL); + + URL fullURL() const final { return m_url; } + void setFullURL(const URL& fullURL) final { setHref(fullURL.string()); } + + URL m_baseURL; + URL m_url; + RefPtr<URLSearchParams> m_searchParams; +}; + +} // namespace WebCore diff --git a/src/javascript/jsc/bindings/Exception.h b/src/javascript/jsc/bindings/Exception.h new file mode 100644 index 000000000..e14b1e01a --- /dev/null +++ b/src/javascript/jsc/bindings/Exception.h @@ -0,0 +1,67 @@ +/* + +Copyright (C) 2016 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 + +#include "root.h" + +#include "ExceptionCode.h" +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class Exception { +public: + explicit Exception(ExceptionCode, String = {}); + + ExceptionCode code() const { return m_code; } + const String& message() const { return m_message; } + String&& releaseMessage() { return WTFMove(m_message); } + + Exception isolatedCopy() const + { + return Exception { m_code, m_message.isolatedCopy() }; + } + +private: + ExceptionCode m_code; + String m_message; +}; + +Exception isolatedCopy(Exception&&); + +inline Exception::Exception(ExceptionCode code, String message) + : m_code { code } + , m_message { WTFMove(message) } +{ +} + +inline Exception isolatedCopy(Exception&& value) +{ + return Exception { value.code(), value.releaseMessage().isolatedCopy() }; +} + +} diff --git a/src/javascript/jsc/bindings/ExceptionCode.h b/src/javascript/jsc/bindings/ExceptionCode.h new file mode 100644 index 000000000..d63691db1 --- /dev/null +++ b/src/javascript/jsc/bindings/ExceptionCode.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2006-2020 Apple Inc. All rights reserved. + * + * 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 + */ + +#pragma once + +#include "root.h" + +#include <wtf/EnumTraits.h> + +namespace WebCore { + +enum ExceptionCode { + // DOMException error names (https://webidl.spec.whatwg.org/#idl-DOMException-error-names). + // Those need to be kept in sync with the array in DOMException.cpp. + IndexSizeError, // Deprecated. Use RangeError instead. + HierarchyRequestError, + WrongDocumentError, + InvalidCharacterError, + NoModificationAllowedError, + NotFoundError, + NotSupportedError, + InUseAttributeError, + InvalidStateError, + SyntaxError, + InvalidModificationError, + NamespaceError, + InvalidAccessError, // Deprecated. use NotAllowedError instead. + TypeMismatchError, // Deprecated. Use TypeError instead. + SecurityError, + NetworkError, + AbortError, + URLMismatchError, + QuotaExceededError, + TimeoutError, + InvalidNodeTypeError, + DataCloneError, + EncodingError, + NotReadableError, + UnknownError, + ConstraintError, + DataError, + TransactionInactiveError, + ReadonlyError, + VersionError, + OperationError, + NotAllowedError, + + // Simple exceptions (https://webidl.spec.whatwg.org/#idl-exceptions). + RangeError, + TypeError, + JSSyntaxError, // Different from DOM SYNTAX_ERR. + + // Non-standard error. + StackOverflowError, + OutOfMemoryError, + + // Used to indicate to the bindings that a JS exception was thrown below and it should be propagated. + ExistingExceptionError, +}; + +} // namespace WebCore + +namespace WTF { + +template<> struct EnumTraits<WebCore::ExceptionCode> { + using values = EnumValues< + WebCore::ExceptionCode, + WebCore::ExceptionCode::IndexSizeError, + WebCore::ExceptionCode::HierarchyRequestError, + WebCore::ExceptionCode::WrongDocumentError, + WebCore::ExceptionCode::InvalidCharacterError, + WebCore::ExceptionCode::NoModificationAllowedError, + WebCore::ExceptionCode::NotFoundError, + WebCore::ExceptionCode::NotSupportedError, + WebCore::ExceptionCode::InUseAttributeError, + WebCore::ExceptionCode::InvalidStateError, + WebCore::ExceptionCode::SyntaxError, + WebCore::ExceptionCode::InvalidModificationError, + WebCore::ExceptionCode::NamespaceError, + WebCore::ExceptionCode::InvalidAccessError, + WebCore::ExceptionCode::TypeMismatchError, + WebCore::ExceptionCode::SecurityError, + WebCore::ExceptionCode::NetworkError, + WebCore::ExceptionCode::AbortError, + WebCore::ExceptionCode::URLMismatchError, + WebCore::ExceptionCode::QuotaExceededError, + WebCore::ExceptionCode::TimeoutError, + WebCore::ExceptionCode::InvalidNodeTypeError, + WebCore::ExceptionCode::DataCloneError, + WebCore::ExceptionCode::EncodingError, + WebCore::ExceptionCode::NotReadableError, + WebCore::ExceptionCode::UnknownError, + WebCore::ExceptionCode::ConstraintError, + WebCore::ExceptionCode::DataError, + WebCore::ExceptionCode::TransactionInactiveError, + WebCore::ExceptionCode::ReadonlyError, + WebCore::ExceptionCode::VersionError, + WebCore::ExceptionCode::OperationError, + WebCore::ExceptionCode::NotAllowedError, + WebCore::ExceptionCode::RangeError, + WebCore::ExceptionCode::TypeError, + WebCore::ExceptionCode::JSSyntaxError, + WebCore::ExceptionCode::StackOverflowError, + WebCore::ExceptionCode::ExistingExceptionError>; +}; + +} // namespace WTF diff --git a/src/javascript/jsc/bindings/ExceptionOr.h b/src/javascript/jsc/bindings/ExceptionOr.h new file mode 100644 index 000000000..6ffd93fe1 --- /dev/null +++ b/src/javascript/jsc/bindings/ExceptionOr.h @@ -0,0 +1,239 @@ +/* + +Copyright (C) 2016-2017 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 + +#include "root.h" + +#include "Exception.h" +#include <wtf/CrossThreadCopier.h> +#include <wtf/Expected.h> +#include <wtf/StdLibExtras.h> + +namespace WebCore { + +template<typename T> class ExceptionOr { +public: + using ReturnType = T; + + ExceptionOr(Exception&&); + ExceptionOr(ReturnType&&); + template<typename OtherType> ExceptionOr(const OtherType&, typename std::enable_if<std::is_scalar<OtherType>::value && std::is_convertible<OtherType, ReturnType>::value>::type* = nullptr); + + bool hasException() const; + const Exception& exception() const; + Exception releaseException(); + const ReturnType& returnValue() const; + ReturnType releaseReturnValue(); + +private: + Expected<ReturnType, Exception> m_value; +#if ASSERT_ENABLED + bool m_wasReleased { false }; +#endif +}; + +template<typename T> class ExceptionOr<T&> { +public: + using ReturnType = T&; + using ReturnReferenceType = T; + + ExceptionOr(Exception&&); + ExceptionOr(ReturnReferenceType&); + + bool hasException() const; + const Exception& exception() const; + Exception releaseException(); + const ReturnReferenceType& returnValue() const; + ReturnReferenceType& releaseReturnValue(); + +private: + ExceptionOr<ReturnReferenceType*> m_value; +}; + +template<> class ExceptionOr<void> { +public: + using ReturnType = void; + + ExceptionOr(Exception&&); + ExceptionOr() = default; + + bool hasException() const; + const Exception& exception() const; + Exception releaseException(); + +private: + Expected<void, Exception> m_value; +#if ASSERT_ENABLED + bool m_wasReleased { false }; +#endif +}; + +ExceptionOr<void> isolatedCopy(ExceptionOr<void>&&); + +template<typename ReturnType> inline ExceptionOr<ReturnType>::ExceptionOr(Exception&& exception) + : m_value(makeUnexpected(WTFMove(exception))) +{ +} + +template<typename ReturnType> inline ExceptionOr<ReturnType>::ExceptionOr(ReturnType&& returnValue) + : m_value(WTFMove(returnValue)) +{ +} + +template<typename ReturnType> template<typename OtherType> inline ExceptionOr<ReturnType>::ExceptionOr(const OtherType& returnValue, typename std::enable_if<std::is_scalar<OtherType>::value && std::is_convertible<OtherType, ReturnType>::value>::type*) + : m_value(static_cast<ReturnType>(returnValue)) +{ +} + +template<typename ReturnType> inline bool ExceptionOr<ReturnType>::hasException() const +{ + return !m_value.has_value(); +} + +template<typename ReturnType> inline const Exception& ExceptionOr<ReturnType>::exception() const +{ + ASSERT(!m_wasReleased); + return m_value.error(); +} + +template<typename ReturnType> inline Exception ExceptionOr<ReturnType>::releaseException() +{ + ASSERT(!std::exchange(m_wasReleased, true)); + return WTFMove(m_value.error()); +} + +template<typename ReturnType> inline const ReturnType& ExceptionOr<ReturnType>::returnValue() const +{ + ASSERT(!m_wasReleased); + return m_value.value(); +} + +template<typename ReturnType> inline ReturnType ExceptionOr<ReturnType>::releaseReturnValue() +{ + ASSERT(!std::exchange(m_wasReleased, true)); + return WTFMove(m_value.value()); +} + +template<typename ReturnReferenceType> inline ExceptionOr<ReturnReferenceType&>::ExceptionOr(Exception&& exception) + : m_value(WTFMove(exception)) +{ +} + +template<typename ReturnReferenceType> inline ExceptionOr<ReturnReferenceType&>::ExceptionOr(ReturnReferenceType& returnValue) + : m_value(&returnValue) +{ +} + +template<typename ReturnReferenceType> inline bool ExceptionOr<ReturnReferenceType&>::hasException() const +{ + return m_value.hasException(); +} + +template<typename ReturnReferenceType> inline const Exception& ExceptionOr<ReturnReferenceType&>::exception() const +{ + return m_value.exception(); +} + +template<typename ReturnReferenceType> inline Exception ExceptionOr<ReturnReferenceType&>::releaseException() +{ + return m_value.releaseException(); +} + +template<typename ReturnReferenceType> inline const ReturnReferenceType& ExceptionOr<ReturnReferenceType&>::returnValue() const +{ + return *m_value.returnValue(); +} + +template<typename ReturnReferenceType> inline ReturnReferenceType& ExceptionOr<ReturnReferenceType&>::releaseReturnValue() +{ + return *m_value.releaseReturnValue(); +} + +inline ExceptionOr<void>::ExceptionOr(Exception&& exception) + : m_value(makeUnexpected(WTFMove(exception))) +{ +} + +inline bool ExceptionOr<void>::hasException() const +{ + return !m_value.has_value(); +} + +inline const Exception& ExceptionOr<void>::exception() const +{ + ASSERT(!m_wasReleased); + return m_value.error(); +} + +inline Exception ExceptionOr<void>::releaseException() +{ + ASSERT(!std::exchange(m_wasReleased, true)); + return WTFMove(m_value.error()); +} + +inline ExceptionOr<void> isolatedCopy(ExceptionOr<void>&& value) +{ + if (value.hasException()) + return isolatedCopy(value.releaseException()); + return {}; +} + +template<typename T> inline constexpr bool IsExceptionOr = WTF::IsTemplate<std::decay_t<T>, ExceptionOr>::value; + +template<typename T, bool isExceptionOr = IsExceptionOr<T>> struct TypeOrExceptionOrUnderlyingTypeImpl; +template<typename T> struct TypeOrExceptionOrUnderlyingTypeImpl<T, true> { + using Type = typename T::ReturnType; +}; +template<typename T> struct TypeOrExceptionOrUnderlyingTypeImpl<T, false> { + using Type = T; +}; +template<typename T> using TypeOrExceptionOrUnderlyingType = typename TypeOrExceptionOrUnderlyingTypeImpl<T>::Type; + +} + +namespace WTF { +template<typename T> struct CrossThreadCopierBase<false, false, WebCore::ExceptionOr<T>> { + typedef WebCore::ExceptionOr<T> Type; + static Type copy(const Type& source) + { + if (source.hasException()) + return crossThreadCopy(source.exception()); + return crossThreadCopy(source.returnValue()); + } +}; + +template<> struct CrossThreadCopierBase<false, false, WebCore::ExceptionOr<void>> { + typedef WebCore::ExceptionOr<void> Type; + static Type copy(const Type& source) + { + if (source.hasException()) + return crossThreadCopy(source.exception()); + return {}; + } +}; + +} diff --git a/src/javascript/jsc/bindings/IDLTypes.h b/src/javascript/jsc/bindings/IDLTypes.h new file mode 100644 index 000000000..b597fb280 --- /dev/null +++ b/src/javascript/jsc/bindings/IDLTypes.h @@ -0,0 +1,403 @@ +/* + * Copyright (C) 2016 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 + +#include "StringAdaptors.h" +#include <JavaScriptCore/HandleTypes.h> +#include <JavaScriptCore/Strong.h> +#include <variant> +#include <wtf/Brigand.h> +#include <wtf/StdLibExtras.h> +#include <wtf/URL.h> +#include <wtf/WallTime.h> + +#if ENABLE(WEBGL) +#include "WebGLAny.h" +#endif + +namespace JSC { +class ArrayBuffer; +class ArrayBufferView; +class DataView; +class JSValue; +class JSObject; +} + +namespace WebCore { + +class IDBKey; +class IDBKeyData; +class IDBValue; +class JSWindowProxy; +class DOMPromise; +class ScheduledAction; + +#if ENABLE(WEBGL) +class WebGLExtension; +#endif + +template<typename T> +struct IDLType { + using ImplementationType = T; + using StorageType = T; + using SequenceStorageType = T; + + using ParameterType = T; + using NullableParameterType = std::optional<ImplementationType>; + + using InnerParameterType = T; + using NullableInnerParameterType = std::optional<ImplementationType>; + + using NullableType = std::optional<ImplementationType>; + static NullableType nullValue() { return std::nullopt; } + static bool isNullValue(const NullableType& value) { return !value; } + static ImplementationType extractValueFromNullable(const NullableType& value) { return value.value(); } +}; + +// IDLUnsupportedType is a special type that serves as a base class for currently unsupported types. +struct IDLUnsupportedType : IDLType<void> { +}; + +// IDLNull is a special type for use as a subtype in an IDLUnion that is nullable. +struct IDLNull : IDLType<std::nullptr_t> { +}; + +struct IDLAny : IDLType<JSC::Strong<JSC::Unknown>> { + using SequenceStorageType = JSC::JSValue; + using ParameterType = JSC::JSValue; + using NullableParameterType = JSC::JSValue; + + using NullableType = JSC::Strong<JSC::Unknown>; + static inline std::nullptr_t nullValue() { return nullptr; } + template<typename U> static inline bool isNullValue(U&& value) { return !value; } + template<typename U> static inline U&& extractValueFromNullable(U&& value) { return std::forward<U>(value); } +}; + +struct IDLUndefined : IDLType<void> { +}; + +struct IDLBoolean : IDLType<bool> { +}; + +template<typename NumericType> struct IDLNumber : IDLType<NumericType> { +}; + +template<typename IntegerType> struct IDLInteger : IDLNumber<IntegerType> { +}; +struct IDLByte : IDLInteger<int8_t> { +}; +struct IDLOctet : IDLInteger<uint8_t> { +}; +struct IDLShort : IDLInteger<int16_t> { +}; +struct IDLUnsignedShort : IDLInteger<uint16_t> { +}; +struct IDLLong : IDLInteger<int32_t> { +}; +struct IDLUnsignedLong : IDLInteger<uint32_t> { +}; +struct IDLLongLong : IDLInteger<int64_t> { +}; +struct IDLUnsignedLongLong : IDLInteger<uint64_t> { +}; + +template<typename T> struct IDLClampAdaptor : IDLInteger<typename T::ImplementationType> { + using InnerType = T; +}; + +template<typename T> struct IDLEnforceRangeAdaptor : IDLInteger<typename T::ImplementationType> { + using InnerType = T; +}; + +template<typename FloatingPointType> struct IDLFloatingPoint : IDLNumber<FloatingPointType> { +}; +struct IDLFloat : IDLFloatingPoint<float> { +}; +struct IDLUnrestrictedFloat : IDLFloatingPoint<float> { +}; +struct IDLDouble : IDLFloatingPoint<double> { +}; +struct IDLUnrestrictedDouble : IDLFloatingPoint<double> { +}; + +template<typename StringType> struct IDLString : IDLType<StringType> { + using ParameterType = const StringType&; + using NullableParameterType = const StringType&; + + using NullableType = StringType; + static StringType nullValue() { return StringType(); } + static bool isNullValue(const StringType& value) { return value.isNull(); } + static bool isNullValue(const UncachedString& value) { return value.string.isNull(); } + static bool isNullValue(const OwnedString& value) { return value.string.isNull(); } + static bool isNullValue(const URL& value) { return value.isNull(); } + template<typename U> static U&& extractValueFromNullable(U&& value) { return std::forward<U>(value); } +}; +struct IDLDOMString : IDLString<String> { +}; +struct IDLByteString : IDLString<String> { +}; +struct IDLUSVString : IDLString<String> { +}; + +template<typename T> struct IDLLegacyNullToEmptyStringAdaptor : IDLString<String> { + using InnerType = T; +}; + +template<typename T> struct IDLAtomStringAdaptor : IDLString<AtomString> { + using InnerType = T; +}; + +template<typename T> struct IDLRequiresExistingAtomStringAdaptor : IDLString<AtomString> { + using InnerType = T; +}; + +template<typename T> struct IDLAllowSharedAdaptor : T { + using InnerType = T; +}; + +struct IDLObject : IDLType<JSC::Strong<JSC::JSObject>> { + using NullableType = JSC::Strong<JSC::JSObject>; + + static inline NullableType nullValue() { return {}; } + template<typename U> static inline bool isNullValue(U&& value) { return !value; } + template<typename U> static inline U&& extractValueFromNullable(U&& value) { return std::forward<U>(value); } +}; + +template<typename T> struct IDLWrapper : IDLType<RefPtr<T>> { + using RawType = T; + + using StorageType = Ref<T>; + + using ParameterType = T&; + using NullableParameterType = T*; + + using InnerParameterType = Ref<T>; + using NullableInnerParameterType = RefPtr<T>; + + using NullableType = RefPtr<T>; + static inline std::nullptr_t nullValue() { return nullptr; } + template<typename U> static inline bool isNullValue(U&& value) { return !value; } + template<typename U> static inline U&& extractValueFromNullable(U&& value) { return std::forward<U>(value); } +}; + +template<typename T> struct IDLInterface : IDLWrapper<T> { +}; +template<typename T> struct IDLCallbackInterface : IDLWrapper<T> { +}; +template<typename T> struct IDLCallbackFunction : IDLWrapper<T> { +}; + +template<typename T> struct IDLDictionary : IDLType<T> { + using ParameterType = const T&; + using NullableParameterType = const T&; +}; + +template<typename T> struct IDLEnumeration : IDLType<T> { +}; + +template<typename T> struct IDLNullable : IDLType<typename T::NullableType> { + using InnerType = T; + + using ParameterType = typename T::NullableParameterType; + using NullableParameterType = typename T::NullableParameterType; + + using InnerParameterType = typename T::NullableInnerParameterType; + using NullableInnerParameterType = typename T::NullableInnerParameterType; + + using NullableType = typename T::NullableType; + static inline auto nullValue() -> decltype(T::nullValue()) { return T::nullValue(); } + template<typename U> static inline bool isNullValue(U&& value) { return T::isNullValue(std::forward<U>(value)); } + template<typename U> static inline auto extractValueFromNullable(U&& value) -> decltype(T::extractValueFromNullable(std::forward<U>(value))) { return T::extractValueFromNullable(std::forward<U>(value)); } +}; + +template<typename T> struct IDLSequence : IDLType<Vector<typename T::ImplementationType>> { + using InnerType = T; + + using ParameterType = const Vector<typename T::InnerParameterType>&; + using NullableParameterType = const std::optional<Vector<typename T::InnerParameterType>>&; +}; + +template<typename T> struct IDLFrozenArray : IDLType<Vector<typename T::ImplementationType>> { + using InnerType = T; + + using ParameterType = const Vector<typename T::ImplementationType>&; + using NullableParameterType = const std::optional<Vector<typename T::ImplementationType>>&; +}; + +template<typename K, typename V> struct IDLRecord : IDLType<Vector<KeyValuePair<typename K::ImplementationType, typename V::ImplementationType>>> { + using KeyType = K; + using ValueType = V; + + using ParameterType = const Vector<KeyValuePair<typename K::ImplementationType, typename V::ImplementationType>>&; + using NullableParameterType = const std::optional<Vector<KeyValuePair<typename K::ImplementationType, typename V::ImplementationType>>>&; +}; + +template<typename T> struct IDLPromise : IDLWrapper<DOMPromise> { + using InnerType = T; +}; + +struct IDLError : IDLUnsupportedType { +}; +struct IDLDOMException : IDLUnsupportedType { +}; + +template<typename... Ts> +struct IDLUnion : IDLType<std::variant<typename Ts::ImplementationType...>> { + using TypeList = brigand::list<Ts...>; + + using ParameterType = const std::variant<typename Ts::ImplementationType...>&; + using NullableParameterType = const std::optional<std::variant<typename Ts::ImplementationType...>>&; +}; + +template<typename T> struct IDLBufferSource : IDLWrapper<T> { +}; + +struct IDLArrayBuffer : IDLBufferSource<JSC::ArrayBuffer> { +}; +// NOTE: WebIDL defines ArrayBufferView as an IDL union of all the TypedArray types. +// and DataView. For convience in our implementation, we give it a distinct +// type that maps to the shared based class of all those classes. +struct IDLArrayBufferView : IDLBufferSource<JSC::ArrayBufferView> { +}; +struct IDLDataView : IDLBufferSource<JSC::DataView> { +}; + +template<typename T> struct IDLTypedArray : IDLBufferSource<T> { +}; +// NOTE: The specific typed array types are IDLTypedArray specialized on the typed array +// implementation type, e.g. IDLFloat64Array is IDLTypedArray<JSC::Float64Array> + +// Non-WebIDL extensions + +struct IDLDate : IDLType<WallTime> { + using NullableType = WallTime; + static WallTime nullValue() { return WallTime::nan(); } + static bool isNullValue(WallTime value) { return std::isnan(value); } + static WallTime extractValueFromNullable(WallTime value) { return value; } +}; + +struct IDLJSON : IDLType<String> { + using ParameterType = const String&; + using NullableParameterType = const String&; + + using NullableType = String; + static String nullValue() { return String(); } + static bool isNullValue(const String& value) { return value.isNull(); } + template<typename U> static U&& extractValueFromNullable(U&& value) { return std::forward<U>(value); } +}; + +struct IDLScheduledAction : IDLType<std::unique_ptr<ScheduledAction>> { +}; +template<typename T> struct IDLSerializedScriptValue : IDLWrapper<T> { +}; +template<typename T> struct IDLEventListener : IDLWrapper<T> { +}; + +struct IDLIDBKey : IDLWrapper<IDBKey> { +}; +struct IDLIDBKeyData : IDLWrapper<IDBKeyData> { +}; +struct IDLIDBValue : IDLWrapper<IDBValue> { +}; + +#if ENABLE(WEBGL) +struct IDLWebGLAny : IDLType<WebGLAny> { +}; +struct IDLWebGLExtension : IDLWrapper<WebGLExtension> { +}; +#endif + +// Helper predicates + +template<typename T> +struct IsIDLInterface : public std::integral_constant<bool, WTF::IsTemplate<T, IDLInterface>::value> { +}; + +template<typename T> +struct IsIDLDictionary : public std::integral_constant<bool, WTF::IsTemplate<T, IDLDictionary>::value> { +}; + +template<typename T> +struct IsIDLEnumeration : public std::integral_constant<bool, WTF::IsTemplate<T, IDLEnumeration>::value> { +}; + +template<typename T> +struct IsIDLSequence : public std::integral_constant<bool, WTF::IsTemplate<T, IDLSequence>::value> { +}; + +template<typename T> +struct IsIDLFrozenArray : public std::integral_constant<bool, WTF::IsTemplate<T, IDLFrozenArray>::value> { +}; + +template<typename T> +struct IsIDLRecord : public std::integral_constant<bool, WTF::IsTemplate<T, IDLRecord>::value> { +}; + +template<typename T> +struct IsIDLString : public std::integral_constant<bool, WTF::IsBaseOfTemplate<IDLString, T>::value> { +}; + +template<typename T> +struct IsIDLStringOrEnumeration : public std::integral_constant<bool, WTF::IsBaseOfTemplate<IDLString, T>::value || WTF::IsTemplate<T, IDLEnumeration>::value> { +}; + +template<typename T> +struct IsIDLNumber : public std::integral_constant<bool, WTF::IsBaseOfTemplate<IDLNumber, T>::value> { +}; + +template<typename T> +struct IsIDLInteger : public std::integral_constant<bool, WTF::IsBaseOfTemplate<IDLInteger, T>::value> { +}; + +template<typename T> +struct IsIDLFloatingPoint : public std::integral_constant<bool, WTF::IsBaseOfTemplate<IDLFloatingPoint, T>::value> { +}; + +template<typename T> +struct IsIDLTypedArray : public std::integral_constant<bool, WTF::IsBaseOfTemplate<IDLTypedArray, T>::value> { +}; + +template<typename T> +struct IsIDLTypedArrayAllowShared : public std::integral_constant<bool, WTF::IsBaseOfTemplate<IDLTypedArray, T>::value && WTF::IsBaseOfTemplate<IDLAllowSharedAdaptor, T>::value> { +}; + +template<typename T> +struct IsIDLArrayBuffer : public std::integral_constant<bool, std::is_base_of<IDLArrayBuffer, T>::value> { +}; + +template<typename T> +struct IsIDLArrayBufferView : public std::integral_constant<bool, std::is_base_of<IDLArrayBufferView, T>::value> { +}; + +template<typename T> +struct IsIDLArrayBufferAllowShared : public std::integral_constant<bool, std::is_base_of<IDLAllowSharedAdaptor<IDLArrayBuffer>, T>::value> { +}; + +template<typename T> +struct IsIDLArrayBufferViewAllowShared : public std::integral_constant<bool, std::is_base_of<IDLAllowSharedAdaptor<IDLArrayBufferView>, T>::value> { +}; + +} // namespace WebCore 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 diff --git a/src/javascript/jsc/bindings/JSDOMExceptionHandling.h b/src/javascript/jsc/bindings/JSDOMExceptionHandling.h new file mode 100644 index 000000000..275dc4032 --- /dev/null +++ b/src/javascript/jsc/bindings/JSDOMExceptionHandling.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2003-2017 Apple Inc. All rights reserved. + * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> + * Copyright (C) 2009 Google, Inc. All rights reserved. + * Copyright (C) 2012 Ericsson AB. All rights reserved. + * 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 + */ + +#pragma once + +#include "ExceptionDetails.h" +#include "ExceptionOr.h" +#include <JavaScriptCore/ThrowScope.h> + +namespace JSC { +class CatchScope; +} + +namespace WebCore { + +class CachedScript; +class DeferredPromise; +class JSDOMGlobalObject; + +void throwAttributeTypeError(JSC::JSGlobalObject&, JSC::ThrowScope&, const char* interfaceName, const char* attributeName, const char* expectedType); + +void throwDataCloneError(JSC::JSGlobalObject&, JSC::ThrowScope&); +void throwDOMSyntaxError(JSC::JSGlobalObject&, JSC::ThrowScope&, ASCIILiteral); // Not the same as a JavaScript syntax error. +void throwInvalidStateError(JSC::JSGlobalObject&, JSC::ThrowScope&, ASCIILiteral); +WEBCORE_EXPORT void throwNonFiniteTypeError(JSC::JSGlobalObject&, JSC::ThrowScope&); +void throwNotSupportedError(JSC::JSGlobalObject&, JSC::ThrowScope&, ASCIILiteral); +void throwSecurityError(JSC::JSGlobalObject&, JSC::ThrowScope&, const String& message); +WEBCORE_EXPORT void throwSequenceTypeError(JSC::JSGlobalObject&, JSC::ThrowScope&); + +WEBCORE_EXPORT JSC::EncodedJSValue throwArgumentMustBeEnumError(JSC::JSGlobalObject&, JSC::ThrowScope&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedValues); +WEBCORE_EXPORT JSC::EncodedJSValue throwArgumentMustBeFunctionError(JSC::JSGlobalObject&, JSC::ThrowScope&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName); +WEBCORE_EXPORT JSC::EncodedJSValue throwArgumentMustBeObjectError(JSC::JSGlobalObject&, JSC::ThrowScope&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName); +WEBCORE_EXPORT JSC::EncodedJSValue throwArgumentTypeError(JSC::JSGlobalObject&, JSC::ThrowScope&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedType); +WEBCORE_EXPORT JSC::EncodedJSValue throwRequiredMemberTypeError(JSC::JSGlobalObject&, JSC::ThrowScope&, const char* memberName, const char* dictionaryName, const char* expectedType); +JSC::EncodedJSValue throwConstructorScriptExecutionContextUnavailableError(JSC::JSGlobalObject&, JSC::ThrowScope&, const char* interfaceName); + +String makeThisTypeErrorMessage(const char* interfaceName, const char* attributeName); +String makeUnsupportedIndexedSetterErrorMessage(const char* interfaceName); + +WEBCORE_EXPORT JSC::EncodedJSValue throwThisTypeError(JSC::JSGlobalObject&, JSC::ThrowScope&, const char* interfaceName, const char* functionName); + +WEBCORE_EXPORT JSC::EncodedJSValue rejectPromiseWithGetterTypeError(JSC::JSGlobalObject&, const JSC::ClassInfo*, JSC::PropertyName attributeName); +WEBCORE_EXPORT JSC::EncodedJSValue rejectPromiseWithThisTypeError(DeferredPromise&, const char* interfaceName, const char* operationName); +WEBCORE_EXPORT JSC::EncodedJSValue rejectPromiseWithThisTypeError(JSC::JSGlobalObject&, const char* interfaceName, const char* operationName); + +String retrieveErrorMessageWithoutName(JSC::JSGlobalObject&, JSC::VM&, JSC::JSValue exception, JSC::CatchScope&); +String retrieveErrorMessage(JSC::JSGlobalObject&, JSC::VM&, JSC::JSValue exception, JSC::CatchScope&); +// WEBCORE_EXPORT void reportException(JSC::JSGlobalObject*, JSC::JSValue exception, CachedScript* = nullptr, bool = false); +// WEBCORE_EXPORT void reportException(JSC::JSGlobalObject*, JSC::Exception*, CachedScript* = nullptr, bool = false, ExceptionDetails* = nullptr); +void reportCurrentException(JSC::JSGlobalObject*); + +JSC::JSValue createDOMException(JSC::JSGlobalObject&, Exception&&); +JSC::JSValue createDOMException(JSC::JSGlobalObject*, ExceptionCode, const String& = emptyString()); + +// Convert a DOM implementation exception into a JavaScript exception in the execution lexicalGlobalObject. +WEBCORE_EXPORT void propagateExceptionSlowPath(JSC::JSGlobalObject&, JSC::ThrowScope&, Exception&&); + +ALWAYS_INLINE void propagateException(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& throwScope, Exception&& exception) +{ + if (throwScope.exception()) + return; + propagateExceptionSlowPath(lexicalGlobalObject, throwScope, WTFMove(exception)); +} + +inline void propagateException(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& throwScope, ExceptionOr<void>&& value) +{ + if (UNLIKELY(value.hasException())) + propagateException(lexicalGlobalObject, throwScope, value.releaseException()); +} + +template<typename Functor> void invokeFunctorPropagatingExceptionIfNecessary(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& throwScope, Functor&& functor) +{ + using ReturnType = std::invoke_result_t<Functor>; + + if constexpr (IsExceptionOr<ReturnType>) { + auto result = functor(); + if (UNLIKELY(result.hasException())) + propagateException(lexicalGlobalObject, throwScope, result.releaseException()); + } else + functor(); +} + +} // namespace WebCore diff --git a/src/javascript/jsc/bindings/JSDOMURL.cpp b/src/javascript/jsc/bindings/JSDOMURL.cpp new file mode 100644 index 000000000..05a77957e --- /dev/null +++ b/src/javascript/jsc/bindings/JSDOMURL.cpp @@ -0,0 +1,321 @@ +#include "root.h" + +#include "JSDOMURL.h" +#include <JavaScriptCore/JSMicrotask.h> +#include <JavaScriptCore/ObjectConstructor.h> + +namespace WebCore { +using namespace JSC; +using namespace Bun; +using JSGlobalObject = JSC::JSGlobalObject; +using JSValue = JSC::JSValue; +using JSString = JSC::JSString; +using JSModuleLoader = JSC::JSModuleLoader; +using JSModuleRecord = JSC::JSModuleRecord; +using Identifier = JSC::Identifier; +using SourceOrigin = JSC::SourceOrigin; +using JSObject = JSC::JSObject; +using JSNonFinalObject = JSC::JSNonFinalObject; +namespace JSCastingHelpers = JSC::JSCastingHelpers; + +JSC_DEFINE_CUSTOM_GETTER(DOMURL__href_get, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + auto* thisObject = JSC::jsDynamicCast<JSDOMURL*>(lexicalGlobalObject->vm(), JSC::JSValue::decode(thisValue)); + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto& impl = thisObject->wrapped(); + RETURN_IF_EXCEPTION(throwScope, {}); + + return JSValue::encode(JSC::jsStringWithCache(vm, impl.href().string())); +} + +JSC_DEFINE_CUSTOM_GETTER(DOMURL__protocol_get, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + auto* thisObject = JSC::jsDynamicCast<JSDOMURL*>(lexicalGlobalObject->vm(), JSC::JSValue::decode(thisValue)); + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto& impl = thisObject->wrapped(); + RETURN_IF_EXCEPTION(throwScope, {}); + + return JSValue::encode(JSC::jsStringWithCache(vm, impl.protocol())); +} +JSC_DEFINE_CUSTOM_GETTER(DOMURL__username_get, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + auto* thisObject = JSC::jsDynamicCast<JSDOMURL*>(lexicalGlobalObject->vm(), JSC::JSValue::decode(thisValue)); + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto& impl = thisObject->wrapped(); + RETURN_IF_EXCEPTION(throwScope, {}); + return JSValue::encode(JSC::jsStringWithCache(vm, impl.username())); +} +JSC_DEFINE_CUSTOM_GETTER(DOMURL__password_get, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + auto* thisObject = JSC::jsDynamicCast<JSDOMURL*>(lexicalGlobalObject->vm(), JSC::JSValue::decode(thisValue)); + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto& impl = thisObject->wrapped(); + RETURN_IF_EXCEPTION(throwScope, {}); + return JSValue::encode(JSC::jsStringWithCache(vm, impl.password())); +} +JSC_DEFINE_CUSTOM_GETTER(DOMURL__host_get, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + auto* thisObject = JSC::jsDynamicCast<JSDOMURL*>(lexicalGlobalObject->vm(), JSC::JSValue::decode(thisValue)); + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto& impl = thisObject->wrapped(); + RETURN_IF_EXCEPTION(throwScope, {}); + return JSValue::encode(JSC::jsStringWithCache(vm, impl.host())); +} +JSC_DEFINE_CUSTOM_GETTER(DOMURL__hostname_get, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + auto* thisObject = JSC::jsDynamicCast<JSDOMURL*>(lexicalGlobalObject->vm(), JSC::JSValue::decode(thisValue)); + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto& impl = thisObject->wrapped(); + RETURN_IF_EXCEPTION(throwScope, {}); + return JSValue::encode(JSC::jsStringWithCache(vm, impl.hostname())); +} +JSC_DEFINE_CUSTOM_GETTER(DOMURL__port_get, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + auto* thisObject = JSC::jsDynamicCast<JSDOMURL*>(lexicalGlobalObject->vm(), JSC::JSValue::decode(thisValue)); + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto& impl = thisObject->wrapped(); + RETURN_IF_EXCEPTION(throwScope, {}); + return JSValue::encode(JSC::jsStringWithCache(vm, impl.port())); +} +JSC_DEFINE_CUSTOM_GETTER(DOMURL__pathname_get, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + auto* thisObject = JSC::jsDynamicCast<JSDOMURL*>(lexicalGlobalObject->vm(), JSC::JSValue::decode(thisValue)); + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto& impl = thisObject->wrapped(); + RETURN_IF_EXCEPTION(throwScope, {}); + return JSValue::encode(JSC::jsStringWithCache(vm, impl.pathname())); +} +JSC_DEFINE_CUSTOM_GETTER(DOMURL__hash_get, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + auto* thisObject = JSC::jsDynamicCast<JSDOMURL*>(lexicalGlobalObject->vm(), JSC::JSValue::decode(thisValue)); + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto& impl = thisObject->wrapped(); + RETURN_IF_EXCEPTION(throwScope, {}); + return JSValue::encode(JSC::jsStringWithCache(vm, impl.hash())); +} + +JSC_DEFINE_CUSTOM_GETTER(DOMURL__search_get, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + auto* thisObject = JSC::jsDynamicCast<JSDOMURL*>(lexicalGlobalObject->vm(), JSC::JSValue::decode(thisValue)); + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto& impl = thisObject->wrapped(); + RETURN_IF_EXCEPTION(throwScope, {}); + return JSValue::encode(JSC::jsStringWithCache(vm, impl.search())); +} + +JSC_DEFINE_CUSTOM_SETTER(DOMURL__protocol_set, + (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, + JSC::EncodedJSValue value, JSC::PropertyName)) +{ + auto* thisObject = JSC::jsDynamicCast<JSDOMURL*>(lexicalGlobalObject->vm(), JSC::JSValue::decode(thisValue)); + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto& impl = thisObject->wrapped(); + invokeFunctorPropagatingExceptionIfNecessary(lexicalGlobalObject, throwScope, [&] { + return impl.setProtocol(JSC::JSValue::decode(value).toWTFString(lexicalGlobalObject)); + }); + + return true; +} +JSC_DEFINE_CUSTOM_SETTER(DOMURL__username_set, + (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, + JSC::EncodedJSValue value, JSC::PropertyName)) +{ + auto* thisObject = JSC::jsDynamicCast<JSDOMURL*>(lexicalGlobalObject->vm(), JSC::JSValue::decode(thisValue)); + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto& impl = thisObject->wrapped(); + + invokeFunctorPropagatingExceptionIfNecessary(lexicalGlobalObject, throwScope, [&] { + return impl.setUsername(JSC::JSValue::decode(value).toWTFString(lexicalGlobalObject)); + }); + + return true; +} + +JSC_DEFINE_CUSTOM_SETTER(DOMURL__href_set, + (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, + JSC::EncodedJSValue value, JSC::PropertyName)) +{ + auto* thisObject = JSC::jsDynamicCast<JSDOMURL*>(lexicalGlobalObject->vm(), JSC::JSValue::decode(thisValue)); + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto& impl = thisObject->wrapped(); + + invokeFunctorPropagatingExceptionIfNecessary(lexicalGlobalObject, throwScope, [&] { + return impl.setHref(JSC::JSValue::decode(value).toWTFString(lexicalGlobalObject)); + }); + + return true; +} + +JSC_DEFINE_CUSTOM_SETTER(DOMURL__password_set, + (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, + JSC::EncodedJSValue value, JSC::PropertyName)) +{ + auto* thisObject = JSC::jsDynamicCast<JSDOMURL*>(lexicalGlobalObject->vm(), JSC::JSValue::decode(thisValue)); + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto& impl = thisObject->wrapped(); + invokeFunctorPropagatingExceptionIfNecessary(lexicalGlobalObject, throwScope, [&] { + return impl.setPassword(JSC::JSValue::decode(value).toWTFString(lexicalGlobalObject)); + }); + + return true; +} +JSC_DEFINE_CUSTOM_SETTER(DOMURL__host_set, + (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, + JSC::EncodedJSValue value, JSC::PropertyName)) +{ + auto* thisObject = JSC::jsDynamicCast<JSDOMURL*>(lexicalGlobalObject->vm(), JSC::JSValue::decode(thisValue)); + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto& impl = thisObject->wrapped(); + invokeFunctorPropagatingExceptionIfNecessary(lexicalGlobalObject, throwScope, [&] { + return impl.setHost(JSC::JSValue::decode(value).toWTFString(lexicalGlobalObject)); + }); + + return true; +} +JSC_DEFINE_CUSTOM_SETTER(DOMURL__hostname_set, + (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, + JSC::EncodedJSValue value, JSC::PropertyName)) +{ + auto* thisObject = JSC::jsDynamicCast<JSDOMURL*>(lexicalGlobalObject->vm(), JSC::JSValue::decode(thisValue)); + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto& impl = thisObject->wrapped(); + invokeFunctorPropagatingExceptionIfNecessary(lexicalGlobalObject, throwScope, [&] { + return impl.setHostname(JSC::JSValue::decode(value).toWTFString(lexicalGlobalObject)); + }); + + return true; +} +JSC_DEFINE_CUSTOM_SETTER(DOMURL__port_set, + (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, + JSC::EncodedJSValue value, JSC::PropertyName)) +{ + auto* thisObject = JSC::jsDynamicCast<JSDOMURL*>(lexicalGlobalObject->vm(), JSC::JSValue::decode(thisValue)); + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto& impl = thisObject->wrapped(); + invokeFunctorPropagatingExceptionIfNecessary(lexicalGlobalObject, throwScope, [&] { + return impl.setPort(JSC::JSValue::decode(value).toWTFString(lexicalGlobalObject)); + }); + + return true; +} +JSC_DEFINE_CUSTOM_SETTER(DOMURL__pathname_set, + (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, + JSC::EncodedJSValue value, JSC::PropertyName)) +{ + auto* thisObject = JSC::jsDynamicCast<JSDOMURL*>(lexicalGlobalObject->vm(), JSC::JSValue::decode(thisValue)); + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto& impl = thisObject->wrapped(); + invokeFunctorPropagatingExceptionIfNecessary(lexicalGlobalObject, throwScope, [&] { + return impl.setPathname(JSC::JSValue::decode(value).toWTFString(lexicalGlobalObject)); + }); + + return true; +} +JSC_DEFINE_CUSTOM_SETTER(DOMURL__hash_set, + (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, + JSC::EncodedJSValue value, JSC::PropertyName)) +{ + auto* thisObject = JSC::jsDynamicCast<JSDOMURL*>(lexicalGlobalObject->vm(), JSC::JSValue::decode(thisValue)); + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto& impl = thisObject->wrapped(); + invokeFunctorPropagatingExceptionIfNecessary(lexicalGlobalObject, throwScope, [&] { + return impl.setHash(JSC::JSValue::decode(value).toWTFString(lexicalGlobalObject)); + }); + + return true; +} + +JSC_DEFINE_CUSTOM_SETTER(DOMURL__search_set, + (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, + JSC::EncodedJSValue value, JSC::PropertyName)) +{ + auto* thisObject = JSC::jsDynamicCast<JSDOMURL*>(lexicalGlobalObject->vm(), JSC::JSValue::decode(thisValue)); + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto& impl = thisObject->wrapped(); + invokeFunctorPropagatingExceptionIfNecessary(lexicalGlobalObject, throwScope, [&] { + return impl.setSearch(JSC::JSValue::decode(value).toWTFString(lexicalGlobalObject)); + }); + + return true; +} + +void JSDOMURL::finishCreation(JSC::VM& vm) +{ + Base::finishCreation(vm); + auto clientData = Bun::clientData(vm); + + putDirectCustomAccessor(vm, clientData->builtinNames().protocolPublicName(), + JSC::CustomGetterSetter::create(vm, DOMURL__protocol_get, DOMURL__protocol_set), + static_cast<unsigned>(JSC::PropertyAttribute::CustomValue)); + + putDirectCustomAccessor(vm, clientData->builtinNames().usernamePublicName(), + JSC::CustomGetterSetter::create(vm, DOMURL__username_get, DOMURL__username_set), + static_cast<unsigned>(JSC::PropertyAttribute::CustomValue)); + + putDirectCustomAccessor(vm, clientData->builtinNames().hrefPublicName(), + JSC::CustomGetterSetter::create(vm, DOMURL__href_get, DOMURL__href_set), + static_cast<unsigned>(JSC::PropertyAttribute::CustomValue)); + + putDirectCustomAccessor(vm, clientData->builtinNames().passwordPublicName(), + JSC::CustomGetterSetter::create(vm, DOMURL__password_get, DOMURL__password_set), + static_cast<unsigned>(JSC::PropertyAttribute::CustomValue)); + + putDirectCustomAccessor(vm, clientData->builtinNames().hostPublicName(), + JSC::CustomGetterSetter::create(vm, DOMURL__host_get, DOMURL__host_set), + static_cast<unsigned>(JSC::PropertyAttribute::CustomValue)); + + putDirectCustomAccessor(vm, clientData->builtinNames().hostnamePublicName(), + JSC::CustomGetterSetter::create(vm, DOMURL__hostname_get, DOMURL__hostname_set), + static_cast<unsigned>(JSC::PropertyAttribute::CustomValue)); + + putDirectCustomAccessor(vm, clientData->builtinNames().portPublicName(), + JSC::CustomGetterSetter::create(vm, DOMURL__port_get, DOMURL__port_set), + static_cast<unsigned>(JSC::PropertyAttribute::CustomValue)); + + putDirectCustomAccessor(vm, clientData->builtinNames().pathnamePublicName(), + JSC::CustomGetterSetter::create(vm, DOMURL__pathname_get, DOMURL__pathname_set), + static_cast<unsigned>(JSC::PropertyAttribute::CustomValue)); + + putDirectCustomAccessor(vm, clientData->builtinNames().hashPublicName(), + JSC::CustomGetterSetter::create(vm, DOMURL__hash_get, DOMURL__hash_set), + static_cast<unsigned>(JSC::PropertyAttribute::CustomValue)); + + putDirectCustomAccessor(vm, clientData->builtinNames().searchPublicName(), + JSC::CustomGetterSetter::create(vm, DOMURL__search_get, DOMURL__search_set), + static_cast<unsigned>(JSC::PropertyAttribute::CustomValue)); +} + +JSC::GCClient::IsoSubspace* JSDOMURL::subspaceForImpl(JSC::VM& vm) +{ + return Bun::subspaceForImpl<JSDOMURL, UseCustomHeapCellType::No>( + vm, + // this is a placeholder + [](auto& spaces) { return spaces.m_clientSubspaceForExposedToWorkerAndWindow.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForExposedToWorkerAndWindow = WTFMove(space); }, + [](auto& spaces) { return spaces.m_subspaceForExposedToWorkerAndWindow.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForExposedToWorkerAndWindow = WTFMove(space); }); +} + +const ClassInfo JSDOMURL::s_info = { "JSDOMURL", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSDOMURL) }; + +} diff --git a/src/javascript/jsc/bindings/JSDOMURL.h b/src/javascript/jsc/bindings/JSDOMURL.h new file mode 100644 index 000000000..edbb280c4 --- /dev/null +++ b/src/javascript/jsc/bindings/JSDOMURL.h @@ -0,0 +1,52 @@ +#pragma once + +#include "BunBuiltinNames.h" +#include "BunClientData.h" +#include "DOMURL.h" +#include "JSDOMWrapper.h" +#include "root.h" + +namespace WebCore { + +using namespace WebCore; +using namespace JSC; + +class JSDOMURL : public JSDOMWrapper<DOMURL> { + using Base = JSDOMWrapper<DOMURL>; + +public: + JSDOMURL(JSC::Structure* structure, JSC::JSGlobalObject& global, DOMURL& domURL) + : Base(structure, global, domURL) + { + } + + DECLARE_INFO; + + static constexpr unsigned StructureFlags = Base::StructureFlags; + + template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if constexpr (mode == JSC::SubspaceAccess::Concurrently) + return nullptr; + return subspaceForImpl(vm); + } + static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); + + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, + JSC::JSValue prototype) + { + return JSC::Structure::create(vm, globalObject, prototype, + JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); + } + + static JSDOMURL* create(JSC::Structure* structure, JSC::JSGlobalObject* global, Ref<DOMURL> domURL) + { + JSDOMURL* accessor = new (NotNull, JSC::allocateCell<JSDOMURL>(global->vm())) JSDOMURL(structure, *global, WTFMove(domURL)); + accessor->finishCreation(global->vm()); + return accessor; + } + + void finishCreation(JSC::VM& vm); +}; + +} // namespace Zig
\ No newline at end of file diff --git a/src/javascript/jsc/bindings/JSDOMWrapper.cpp b/src/javascript/jsc/bindings/JSDOMWrapper.cpp new file mode 100644 index 000000000..5fbb4238e --- /dev/null +++ b/src/javascript/jsc/bindings/JSDOMWrapper.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010-2018 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. + */ + +#include "JSDOMWrapper.h" +#include "root.h" + +#include "BunBuiltinNames.h" + +// #include "DOMWindow.h" +// #include "DOMWrapperWorld.h" +// #include "JSDOMWindow.h" +// #include "JSRemoteDOMWindow.h" +// #include "SerializedScriptValue.h" +// #include <JavaScriptCore/Error.h> + +namespace WebCore { + +STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSDOMObject); + +JSDOMObject::JSDOMObject(JSC::Structure* structure, JSC::JSGlobalObject& globalObject) + : Base(globalObject.vm(), structure) +{ + // ASSERT(scriptExecutionContext() || globalObject.classInfo(globalObject.vm()) == JSRemoteDOMWindow::info()); +} + +// JSC::JSValue cloneAcrossWorlds(JSC::JSGlobalObject& lexicalGlobalObject, const JSDOMObject& owner, JSC::JSValue value) +// { +// if (isWorldCompatible(lexicalGlobalObject, value)) +// return value; +// // FIXME: Is it best to handle errors by returning null rather than throwing an exception? +// auto serializedValue = SerializedScriptValue::create(lexicalGlobalObject, value, SerializationErrorMode::NonThrowing); +// if (!serializedValue) +// return JSC::jsNull(); +// // FIXME: Why is owner->globalObject() better than lexicalGlobalObject.lexicalGlobalObject() here? +// // Unlike this, isWorldCompatible uses lexicalGlobalObject.lexicalGlobalObject(); should the two match? +// return serializedValue->deserialize(lexicalGlobalObject, owner.globalObject()); +// } + +} // namespace WebCore diff --git a/src/javascript/jsc/bindings/JSDOMWrapper.h b/src/javascript/jsc/bindings/JSDOMWrapper.h new file mode 100644 index 000000000..ad374ec2d --- /dev/null +++ b/src/javascript/jsc/bindings/JSDOMWrapper.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2003-2018 Apple Inc. All rights reserved. + * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> + * Copyright (C) 2009 Google, Inc. All rights reserved. + * + * 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 + */ + +#pragma once +#include "root.h" + +#include "NodeConstants.h" +#include "ZigGlobalObject.h" +#include <JavaScriptCore/JSDestructibleObject.h> +#include <wtf/SignedPtr.h> + +namespace WebCore { +using namespace Zig; +using JSDOMGlobalObject = Zig::GlobalObject; + +class ScriptExecutionContext; + +// JSC allows us to extend JSType. If the highest 3 bits are set, we can add any Object types and they are +// recognized as OtherObj in JSC. And we encode Node type into JSType if the given JSType is subclass of Node. +// offset | 7 | 6 | 5 | 4 3 2 1 0 | +// value | 1 | 1 | 1 | Non-node DOM types | +// If the given JSType is a subclass of Node, the format is the following. +// offset | 7 | 6 | 5 | 4 | 3 2 1 0 | +// value | 1 | 1 | 1 | 1 | NodeType | + +static const uint8_t JSDOMWrapperType = 0b11101110; +static const uint8_t JSEventType = 0b11101111; +static const uint8_t JSNodeType = 0b11110000; +static const uint8_t JSNodeTypeMask = 0b00001111; +static const uint8_t JSTextNodeType = JSNodeType | NodeConstants::TEXT_NODE; +static const uint8_t JSProcessingInstructionNodeType = JSNodeType | NodeConstants::PROCESSING_INSTRUCTION_NODE; +static const uint8_t JSDocumentTypeNodeType = JSNodeType | NodeConstants::DOCUMENT_TYPE_NODE; +static const uint8_t JSDocumentFragmentNodeType = JSNodeType | NodeConstants::DOCUMENT_FRAGMENT_NODE; +static const uint8_t JSDocumentWrapperType = JSNodeType | NodeConstants::DOCUMENT_NODE; +static const uint8_t JSCommentNodeType = JSNodeType | NodeConstants::COMMENT_NODE; +static const uint8_t JSCDATASectionNodeType = JSNodeType | NodeConstants::CDATA_SECTION_NODE; +static const uint8_t JSAttrNodeType = JSNodeType | NodeConstants::ATTRIBUTE_NODE; +static const uint8_t JSElementType = 0b11110000 | NodeConstants::ELEMENT_NODE; + +static_assert(JSDOMWrapperType > JSC::LastJSCObjectType, "JSC::JSType offers the highest bit."); +static_assert(NodeConstants::LastNodeType <= JSNodeTypeMask, "NodeType should be represented in 4bit."); + +class JSDOMObject : public JSC::JSDestructibleObject { +public: + typedef JSC::JSDestructibleObject Base; + + template<typename, JSC::SubspaceAccess> + static void subspaceFor(JSC::VM&) { RELEASE_ASSERT_NOT_REACHED(); } + + JSDOMGlobalObject* globalObject() const { return JSC::jsCast<JSDOMGlobalObject*>(JSC::JSNonFinalObject::globalObject()); } + // ScriptExecutionContext* scriptExecutionContext() const { return globalObject()->scriptExecutionContext(); } + +protected: + WEBCORE_EXPORT JSDOMObject(JSC::Structure*, JSC::JSGlobalObject&); +}; + +template<typename ImplementationClass, typename PtrTraits = RawPtrTraits<ImplementationClass>> +class JSDOMWrapper : public JSDOMObject { +public: + using Base = JSDOMObject; + using DOMWrapped = ImplementationClass; + + ImplementationClass& wrapped() const { return m_wrapped; } + static ptrdiff_t offsetOfWrapped() { return OBJECT_OFFSETOF(JSDOMWrapper, m_wrapped); } + constexpr static bool hasCustomPtrTraits() { return !std::is_same_v<PtrTraits, RawPtrTraits<ImplementationClass>>; }; + +protected: + JSDOMWrapper(JSC::Structure* structure, JSC::JSGlobalObject& globalObject, Ref<ImplementationClass>&& impl) + : Base(structure, globalObject) + , m_wrapped(WTFMove(impl)) + { + } + +private: + Ref<ImplementationClass, PtrTraits> m_wrapped; +}; + +template<typename ImplementationClass> struct JSDOMWrapperConverterTraits; + +JSC::JSValue cloneAcrossWorlds(JSC::JSGlobalObject&, const JSDOMObject& owner, JSC::JSValue); + +} // namespace WebCore diff --git a/src/javascript/jsc/bindings/MarkingConstraint.cpp b/src/javascript/jsc/bindings/MarkingConstraint.cpp new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/javascript/jsc/bindings/MarkingConstraint.cpp diff --git a/src/javascript/jsc/bindings/NodeConstants.h b/src/javascript/jsc/bindings/NodeConstants.h new file mode 100644 index 000000000..ebbdc7812 --- /dev/null +++ b/src/javascript/jsc/bindings/NodeConstants.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2016 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. ``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 + * 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 + +namespace WebCore { + +struct NodeConstants { + enum NodeType { + ELEMENT_NODE = 1, + ATTRIBUTE_NODE = 2, + TEXT_NODE = 3, + CDATA_SECTION_NODE = 4, + PROCESSING_INSTRUCTION_NODE = 7, + COMMENT_NODE = 8, + DOCUMENT_NODE = 9, + DOCUMENT_TYPE_NODE = 10, + DOCUMENT_FRAGMENT_NODE = 11, + }; + + enum DeprecatedNodeType { + ENTITY_REFERENCE_NODE = 5, + ENTITY_NODE = 6, + NOTATION_NODE = 12, + }; + + static const uint8_t LastNodeType = NOTATION_NODE; +}; + +} // namespace WebCore::NodeType diff --git a/src/javascript/jsc/bindings/StringAdaptors.h b/src/javascript/jsc/bindings/StringAdaptors.h new file mode 100644 index 000000000..cceaa3a3b --- /dev/null +++ b/src/javascript/jsc/bindings/StringAdaptors.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2017 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 + +#include <wtf/text/WTFString.h> + +namespace WebCore { + +// This exists to communicate to the bindings that this string is not a good candidate +// for caching. +// Forces the use of the jsString() converter (rather than the normal jsStringWithCache()). +struct UncachedString { + String string; +}; + +// This exists to communicate to the bindings that this string is owned by another +// object and therefore that collecting the JSString wrapper is unlikely to save memory. +// Forces the use of the jsOwnedString() converter (rather than the normal jsStringWithCache()). +struct OwnedString { + String string; +}; + +} diff --git a/src/javascript/jsc/bindings/URLDecomposition.cpp b/src/javascript/jsc/bindings/URLDecomposition.cpp new file mode 100644 index 000000000..2be72c0c6 --- /dev/null +++ b/src/javascript/jsc/bindings/URLDecomposition.cpp @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2014-2020 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 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 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. + */ + +#include "URLDecomposition.h" + +#include <wtf/text/StringToIntegerConversion.h> + +namespace WebCore { + +String URLDecomposition::origin() const +{ + return fullURL().hostAndPort(); +} + +String URLDecomposition::protocol() const +{ + auto fullURL = this->fullURL(); + if (WTF::protocolIsJavaScript(fullURL.string())) + return "javascript:"_s; + return makeString(fullURL.protocol(), ':'); +} + +void URLDecomposition::setProtocol(StringView value) +{ + URL copy = fullURL(); + copy.setProtocol(value); + setFullURL(copy); +} + +String URLDecomposition::username() const +{ + return fullURL().encodedUser().toString(); +} + +void URLDecomposition::setUsername(StringView user) +{ + auto fullURL = this->fullURL(); + if (fullURL.host().isEmpty() || fullURL.cannotBeABaseURL() || fullURL.protocolIs("file")) + return; + fullURL.setUser(user); + setFullURL(fullURL); +} + +String URLDecomposition::password() const +{ + return fullURL().encodedPassword().toString(); +} + +void URLDecomposition::setPassword(StringView password) +{ + auto fullURL = this->fullURL(); + if (fullURL.host().isEmpty() || fullURL.cannotBeABaseURL() || fullURL.protocolIs("file")) + return; + fullURL.setPassword(password); + setFullURL(fullURL); +} + +String URLDecomposition::host() const +{ + return fullURL().hostAndPort(); +} + +static unsigned countASCIIDigits(StringView string) +{ + unsigned length = string.length(); + for (unsigned count = 0; count < length; ++count) { + if (!isASCIIDigit(string[count])) + return count; + } + return length; +} + +void URLDecomposition::setHost(StringView value) +{ + auto fullURL = this->fullURL(); + if (value.isEmpty() && !fullURL.protocolIs("file") && fullURL.hasSpecialScheme()) + return; + + size_t separator = value.reverseFind(':'); + if (!separator) + return; + + if (fullURL.cannotBeABaseURL() || !fullURL.canSetHostOrPort()) + return; + + // No port if no colon or rightmost colon is within the IPv6 section. + size_t ipv6Separator = value.reverseFind(']'); + if (separator == notFound || (ipv6Separator != notFound && ipv6Separator > separator)) + fullURL.setHost(value); + else { + // Multiple colons are acceptable only in case of IPv6. + if (value.find(':') != separator && ipv6Separator == notFound) + return; + unsigned portLength = countASCIIDigits(value.substring(separator + 1)); + if (!portLength) { + fullURL.setHost(value.substring(0, separator)); + } else { + auto portNumber = parseInteger<uint16_t>(value.substring(separator + 1, portLength)); + if (portNumber && WTF::isDefaultPortForProtocol(*portNumber, fullURL.protocol())) + fullURL.setHostAndPort(value.substring(0, separator)); + else + fullURL.setHostAndPort(value.substring(0, separator + 1 + portLength)); + } + } + if (fullURL.isValid()) + setFullURL(fullURL); +} + +String URLDecomposition::hostname() const +{ + return fullURL().host().toString(); +} + +static StringView removeAllLeadingSolidusCharacters(StringView string) +{ + unsigned i; + unsigned length = string.length(); + for (i = 0; i < length; ++i) { + if (string[i] != '/') + break; + } + return string.substring(i); +} + +void URLDecomposition::setHostname(StringView value) +{ + auto fullURL = this->fullURL(); + auto host = removeAllLeadingSolidusCharacters(value); + if (host.isEmpty() && !fullURL.protocolIs("file") && fullURL.hasSpecialScheme()) + return; + if (fullURL.cannotBeABaseURL() || !fullURL.canSetHostOrPort()) + return; + fullURL.setHost(host); + if (fullURL.isValid()) + setFullURL(fullURL); +} + +String URLDecomposition::port() const +{ + auto port = fullURL().port(); + if (!port) + return emptyString(); + return String::number(*port); +} + +// Outer optional is whether we could parse at all. Inner optional is "no port specified". +static std::optional<std::optional<uint16_t>> parsePort(StringView string, StringView protocol) +{ + // https://url.spec.whatwg.org/#port-state with state override given. + uint32_t port { 0 }; + bool foundDigit = false; + for (size_t i = 0; i < string.length(); ++i) { + auto c = string[i]; + // https://infra.spec.whatwg.org/#ascii-tab-or-newline + if (c == 0x0009 || c == 0x000A || c == 0x000D) + continue; + if (isASCIIDigit(c)) { + port = port * 10 + c - '0'; + foundDigit = true; + if (port > std::numeric_limits<uint16_t>::max()) + return std::nullopt; + continue; + } + if (!foundDigit) + return std::nullopt; + break; + } + if (!foundDigit || WTF::isDefaultPortForProtocol(static_cast<uint16_t>(port), protocol)) + return std::optional<uint16_t> { std::nullopt }; + return { { static_cast<uint16_t>(port) } }; +} + +void URLDecomposition::setPort(StringView value) +{ + auto fullURL = this->fullURL(); + if (fullURL.host().isEmpty() || fullURL.cannotBeABaseURL() || fullURL.protocolIs("file") || !fullURL.canSetHostOrPort()) + return; + auto port = parsePort(value, fullURL.protocol()); + if (!port) + return; + fullURL.setPort(*port); + setFullURL(fullURL); +} + +String URLDecomposition::pathname() const +{ + return fullURL().path().toString(); +} + +void URLDecomposition::setPathname(StringView value) +{ + auto fullURL = this->fullURL(); + if (fullURL.cannotBeABaseURL() || !fullURL.canSetPathname()) + return; + fullURL.setPath(value); + setFullURL(fullURL); +} + +String URLDecomposition::search() const +{ + auto fullURL = this->fullURL(); + return fullURL.query().isEmpty() ? emptyString() : fullURL.queryWithLeadingQuestionMark().toString(); +} + +void URLDecomposition::setSearch(const String& value) +{ + auto fullURL = this->fullURL(); + if (value.isEmpty()) { + // If the given value is the empty string, set url's query to null. + fullURL.setQuery({}); + } else { + String newSearch = value; + // Make sure that '#' in the query does not leak to the hash. + fullURL.setQuery(newSearch.replaceWithLiteral('#', "%23")); + } + setFullURL(fullURL); +} + +String URLDecomposition::hash() const +{ + auto fullURL = this->fullURL(); + return fullURL.fragmentIdentifier().isEmpty() ? emptyString() : fullURL.fragmentIdentifierWithLeadingNumberSign().toString(); +} + +void URLDecomposition::setHash(StringView value) +{ + auto fullURL = this->fullURL(); + if (value.isEmpty()) + fullURL.removeFragmentIdentifier(); + else + fullURL.setFragmentIdentifier(value.startsWith('#') ? value.substring(1) : value); + setFullURL(fullURL); +} + +} diff --git a/src/javascript/jsc/bindings/URLDecomposition.h b/src/javascript/jsc/bindings/URLDecomposition.h new file mode 100644 index 000000000..bf9473dcb --- /dev/null +++ b/src/javascript/jsc/bindings/URLDecomposition.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2014-2020 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 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 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 + +#include "root.h" + +#include <wtf/URL.h> + +#include <wtf/Forward.h> + +namespace WebCore { + +class URLDecomposition { +public: + String origin() const; + + WEBCORE_EXPORT String protocol() const; + void setProtocol(StringView); + + String username() const; + void setUsername(StringView); + + String password() const; + void setPassword(StringView); + + WEBCORE_EXPORT String host() const; + void setHost(StringView); + + WEBCORE_EXPORT String hostname() const; + void setHostname(StringView); + + WEBCORE_EXPORT String port() const; + void setPort(StringView); + + WEBCORE_EXPORT String pathname() const; + void setPathname(StringView); + + WEBCORE_EXPORT String search() const; + void setSearch(const String&); + + WEBCORE_EXPORT String hash() const; + void setHash(StringView); + +protected: + virtual ~URLDecomposition() = default; + +private: + virtual URL fullURL() const = 0; + virtual void setFullURL(const URL&) = 0; +}; + +} // namespace WebCore diff --git a/src/javascript/jsc/bindings/URLSearchParams.cpp b/src/javascript/jsc/bindings/URLSearchParams.cpp new file mode 100644 index 000000000..11d86bceb --- /dev/null +++ b/src/javascript/jsc/bindings/URLSearchParams.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2016 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. ``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 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * 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. + */ + +#include "URLSearchParams.h" + +#include "DOMURL.h" +#include <wtf/URLParser.h> + +namespace WebCore { + +URLSearchParams::URLSearchParams(const String& init, DOMURL* associatedURL) + : m_associatedURL(associatedURL) + , m_pairs(init.startsWith('?') ? WTF::URLParser::parseURLEncodedForm(StringView(init).substring(1)) : WTF::URLParser::parseURLEncodedForm(init)) +{ +} + +URLSearchParams::URLSearchParams(const Vector<KeyValuePair<String, String>>& pairs) + : m_pairs(pairs) +{ +} + +ExceptionOr<Ref<URLSearchParams>> URLSearchParams::create(std::variant<Vector<Vector<String>>, Vector<KeyValuePair<String, String>>, String>&& variant) +{ + auto visitor = WTF::makeVisitor([&](const Vector<Vector<String>>& vector) -> ExceptionOr<Ref<URLSearchParams>> { + Vector<KeyValuePair<String, String>> pairs; + for (const auto& pair : vector) { + if (pair.size() != 2) + return Exception { TypeError }; + pairs.append({pair[0], pair[1]}); + } + return adoptRef(*new URLSearchParams(WTFMove(pairs))); }, [&](const Vector<KeyValuePair<String, String>>& pairs) -> ExceptionOr<Ref<URLSearchParams>> { return adoptRef(*new URLSearchParams(pairs)); }, [&](const String& string) -> ExceptionOr<Ref<URLSearchParams>> { return adoptRef(*new URLSearchParams(string, nullptr)); }); + return std::visit(visitor, variant); +} + +String URLSearchParams::get(const String& name) const +{ + for (const auto& pair : m_pairs) { + if (pair.key == name) + return pair.value; + } + return String(); +} + +bool URLSearchParams::has(const String& name) const +{ + for (const auto& pair : m_pairs) { + if (pair.key == name) + return true; + } + return false; +} + +void URLSearchParams::sort() +{ + std::stable_sort(m_pairs.begin(), m_pairs.end(), [](const auto& a, const auto& b) { + return WTF::codePointCompareLessThan(a.key, b.key); + }); + updateURL(); +} + +void URLSearchParams::set(const String& name, const String& value) +{ + for (auto& pair : m_pairs) { + if (pair.key != name) + continue; + if (pair.value != value) + pair.value = value; + bool skippedFirstMatch = false; + m_pairs.removeAllMatching([&](const auto& pair) { + if (pair.key == name) { + if (skippedFirstMatch) + return true; + skippedFirstMatch = true; + } + return false; + }); + updateURL(); + return; + } + m_pairs.append({ name, value }); + updateURL(); +} + +void URLSearchParams::append(const String& name, const String& value) +{ + m_pairs.append({ name, value }); + updateURL(); +} + +Vector<String> URLSearchParams::getAll(const String& name) const +{ + Vector<String> values; + values.reserveInitialCapacity(m_pairs.size()); + for (const auto& pair : m_pairs) { + if (pair.key == name) + values.uncheckedAppend(pair.value); + } + values.shrinkToFit(); + return values; +} + +void URLSearchParams::remove(const String& name) +{ + m_pairs.removeAllMatching([&](const auto& pair) { + return pair.key == name; + }); + updateURL(); +} + +String URLSearchParams::toString() const +{ + return WTF::URLParser::serialize(m_pairs); +} + +void URLSearchParams::updateURL() +{ + if (m_associatedURL) + m_associatedURL->setQuery(WTF::URLParser::serialize(m_pairs)); +} + +void URLSearchParams::updateFromAssociatedURL() +{ + ASSERT(m_associatedURL); + String search = m_associatedURL->search(); + m_pairs = search.startsWith('?') ? WTF::URLParser::parseURLEncodedForm(StringView(search).substring(1)) : WTF::URLParser::parseURLEncodedForm(search); +} + +std::optional<KeyValuePair<String, String>> URLSearchParams::Iterator::next() +{ + auto& pairs = m_target->pairs(); + if (m_index >= pairs.size()) + return std::nullopt; + + auto& pair = pairs[m_index++]; + return KeyValuePair<String, String> { pair.key, pair.value }; +} + +URLSearchParams::Iterator::Iterator(URLSearchParams& params) + : m_target(params) +{ +} + +} diff --git a/src/javascript/jsc/bindings/URLSearchParams.h b/src/javascript/jsc/bindings/URLSearchParams.h new file mode 100644 index 000000000..a3c6c3171 --- /dev/null +++ b/src/javascript/jsc/bindings/URLSearchParams.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2016 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. ``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 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * 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 +#include "root.h" + +#include "ExceptionOr.h" +#include <variant> +#include <wtf/Vector.h> +#include <wtf/WeakPtr.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class DOMURL; + +class URLSearchParams : public RefCounted<URLSearchParams> { +public: + static ExceptionOr<Ref<URLSearchParams>> create(std::variant<Vector<Vector<String>>, Vector<KeyValuePair<String, String>>, String>&&); + static Ref<URLSearchParams> create(const String& string, DOMURL* associatedURL) + { + return adoptRef(*new URLSearchParams(string, associatedURL)); + } + + void append(const String& name, const String& value); + void remove(const String& name); + String get(const String& name) const; + Vector<String> getAll(const String& name) const; + bool has(const String& name) const; + void set(const String& name, const String& value); + String toString() const; + void updateFromAssociatedURL(); + void sort(); + + class Iterator { + public: + explicit Iterator(URLSearchParams&); + std::optional<KeyValuePair<String, String>> next(); + + private: + Ref<URLSearchParams> m_target; + size_t m_index { 0 }; + }; + Iterator createIterator() { return Iterator { *this }; } + +private: + const Vector<KeyValuePair<String, String>>& pairs() const { return m_pairs; } + URLSearchParams(const String&, DOMURL*); + URLSearchParams(const Vector<KeyValuePair<String, String>>&); + void updateURL(); + + WeakPtr<DOMURL> m_associatedURL; + Vector<KeyValuePair<String, String>> m_pairs; +}; + +} // namespace WebCore diff --git a/src/javascript/jsc/bindings/ZigGlobalObject.cpp b/src/javascript/jsc/bindings/ZigGlobalObject.cpp index ad1c23da5..fd43fcaeb 100644 --- a/src/javascript/jsc/bindings/ZigGlobalObject.cpp +++ b/src/javascript/jsc/bindings/ZigGlobalObject.cpp @@ -75,6 +75,8 @@ #include "ZigSourceProvider.h" +#include "JSDOMURL.h" + using JSGlobalObject = JSC::JSGlobalObject; using Exception = JSC::Exception; using JSValue = JSC::JSValue; @@ -699,6 +701,14 @@ void GlobalObject::installAPIGlobals(JSClassRef* globals, int count) JSC::CustomGetterSetter::create(vm(), property_lazyProcessGetter, property_lazyProcessSetter), PropertyAttribute::DontDelete | JSC::PropertyAttribute::CustomAccessor | 0); + auto domURL = WebCore::DOMURL::create("https://example.com/"_s, WTF::String()); + auto url = WebCore::JSDOMURL::create( + WebCore::JSDOMURL::createStructure(vm(), this, objectPrototype()), + this, + domURL.returnValue().get()); + + this->putDirect(vm(), clientData->builtinNames().urlPublicName(), JSC::JSValue(url), JSC::PropertyAttribute::DontDelete | 0); + extraStaticGlobals.releaseBuffer(); } diff --git a/src/javascript/jsc/bindings/root.h b/src/javascript/jsc/bindings/root.h index 4577ab0fd..0d120977e 100644 --- a/src/javascript/jsc/bindings/root.h +++ b/src/javascript/jsc/bindings/root.h @@ -40,8 +40,10 @@ #if defined(BUILDING_JavaScriptCore) || defined(STATICALLY_LINKED_WITH_JavaScriptCore) #define JS_EXPORT_PRIVATE WTF_EXPORT_DECLARATION +#define WEBCORE_EXPORT WTF_EXPORT_DECLARATION #else #define JS_EXPORT_PRIVATE WTF_IMPORT_DECLARATION +#define WEBCORE_EXPORT WTF_IMPORT_DECLARATION #endif #endif |