Bug 1561357 - Implement [Serializable] for DOMException r=smaug,sfink

Skipping stack serialization here as

* it's optional per the spec
* no WPT test exists
* Chrome doesn't support it either
* not sure how it's usable when transferred to other domain.

Differential Revision: https://phabricator.services.mozilla.com/D143625
This commit is contained in:
Kagami Sascha Rosylight 2022-04-19 19:31:27 +00:00
Родитель 6e33650078
Коммит 51a7018052
7 изменённых файлов: 99 добавлений и 10 удалений

Просмотреть файл

@ -19,6 +19,9 @@
#include "mozilla/dom/DOMExceptionBinding.h"
#include "mozilla/ErrorResult.h"
#include "js/TypeDecls.h"
#include "js/StructuredClone.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -182,6 +185,12 @@ Exception::Exception(const nsACString& aMessage, nsresult aResult,
}
}
Exception::Exception(nsCString&& aMessage, nsresult aResult, nsCString&& aName)
: mMessage(std::move(aMessage)),
mResult(aResult),
mName(std::move(aName)),
mHoldingJSVal(false) {}
Exception::~Exception() {
if (mHoldingJSVal) {
MOZ_ASSERT(NS_IsMainThread());
@ -324,6 +333,9 @@ DOMException::DOMException(nsresult aRv, const nsACString& aMessage,
const nsACString& aName, uint16_t aCode,
nsIStackFrame* aLocation)
: Exception(aMessage, aRv, aName, aLocation, nullptr), mCode(aCode) {}
DOMException::DOMException(nsresult aRv, nsCString&& aMessage,
nsCString&& aName, uint16_t aCode)
: Exception(std::move(aMessage), aRv, std::move(aName)), mCode(aCode) {}
void DOMException::ToString(JSContext* aCx, nsACString& aReturn) {
aReturn.Truncate();
@ -399,4 +411,54 @@ already_AddRefed<DOMException> DOMException::Create(
return inst.forget();
}
static bool ReadAsCString(JSContext* aCx, JSStructuredCloneReader* aReader,
nsCString& aString) {
JS::Rooted<JSString*> jsMessage(aCx);
if (!JS_ReadString(aReader, &jsMessage)) {
return false;
}
return AssignJSString(aCx, aString, jsMessage);
}
already_AddRefed<DOMException> DOMException::ReadStructuredClone(
JSContext* aCx, nsIGlobalObject* aGlobal,
JSStructuredCloneReader* aReader) {
uint32_t reserved;
nsresult rv;
nsCString message;
nsCString name;
uint16_t code;
if (!JS_ReadBytes(aReader, &reserved, 4) || !JS_ReadBytes(aReader, &rv, 4) ||
!ReadAsCString(aCx, aReader, message) ||
!ReadAsCString(aCx, aReader, name) || !JS_ReadBytes(aReader, &code, 2)) {
return nullptr;
};
return do_AddRef(
new DOMException(rv, std::move(message), std::move(name), code));
}
bool DOMException::WriteStructuredClone(
JSContext* aCx, JSStructuredCloneWriter* aWriter) const {
JS::Rooted<JS::Value> messageValue(aCx);
JS::Rooted<JS::Value> nameValue(aCx);
if (!NonVoidByteStringToJsval(aCx, mMessage, &messageValue) ||
!NonVoidByteStringToJsval(aCx, mName, &nameValue)) {
return false;
}
JS::Rooted<JSString*> message(aCx, messageValue.toString());
JS::Rooted<JSString*> name(aCx, nameValue.toString());
static_assert(sizeof(nsresult) == 4);
// A reserved field. Use this to indicate stack serialization support etc.
uint32_t reserved = 0;
return JS_WriteBytes(aWriter, &reserved, 4) &&
JS_WriteBytes(aWriter, &mResult, 4) &&
JS_WriteString(aWriter, message) && JS_WriteString(aWriter, name) &&
JS_WriteBytes(aWriter, &mCode, 2);
};
} // namespace mozilla::dom

Просмотреть файл

@ -24,6 +24,7 @@
#include "nsString.h"
#include "mozilla/dom/BindingDeclarations.h"
class nsIGlobalObject;
class nsIStackFrame;
nsresult NS_GetNameAndMessageForDOMNSResult(nsresult aNSResult,
@ -104,6 +105,7 @@ class Exception : public nsIException, public nsWrapperCache {
Exception(const nsACString& aMessage, nsresult aResult,
const nsACString& aName, nsIStackFrame* aLocation,
nsISupports* aData);
Exception(nsCString&& aMessage, nsresult aResult, nsCString&& aName);
protected:
virtual ~Exception();
@ -140,6 +142,8 @@ class DOMException : public Exception {
DOMException(nsresult aRv, const nsACString& aMessage,
const nsACString& aName, uint16_t aCode,
nsIStackFrame* aLocation = nullptr);
DOMException(nsresult aRv, nsCString&& aMessage, nsCString&& aName,
uint16_t aCode);
NS_INLINE_DECL_REFCOUNTING_INHERITED(DOMException, Exception)
@ -171,6 +175,12 @@ class DOMException : public Exception {
static already_AddRefed<DOMException> Create(nsresult aRv,
const nsACString& aMessage);
static already_AddRefed<DOMException> ReadStructuredClone(
JSContext* aCx, nsIGlobalObject* aGlobal,
JSStructuredCloneReader* aReader);
bool WriteStructuredClone(JSContext* aCx,
JSStructuredCloneWriter* aWriter) const;
protected:
virtual ~DOMException() = default;

Просмотреть файл

@ -96,7 +96,7 @@ enum StructuredCloneTags {
// IMPORTANT: Don't change the order of these enum values. You could break
// IDB.
EMPTY_SLOT_8,
SCTAG_DOM_DOMEXCEPTION,
// IMPORTANT: Don't change the order of these enum values. You could break
// IDB.

Просмотреть файл

@ -4,7 +4,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* http://dom.spec.whatwg.org/#exception-domexception
* https://webidl.spec.whatwg.org/#idl-DOMException
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
@ -31,7 +31,7 @@ interface mixin ExceptionMembers
readonly attribute DOMString filename;
// Valid line numbers begin at '1'. '0' indicates unknown.
readonly attribute unsigned long lineNumber;
// Valid column numbers begin at 0.
// Valid column numbers begin at 0.
// We don't have an unambiguous indicator for unknown.
readonly attribute unsigned long columnNumber;
@ -65,7 +65,8 @@ Exception includes ExceptionMembers;
// XXXkhuey this is an 'exception', not an interface, but we don't have any
// parser or codegen mechanisms for dealing with exceptions.
[ExceptionClass,
Exposed=(Window, Worker)]
Exposed=(Window, Worker),
Serializable]
interface DOMException {
constructor(optional DOMString message = "", optional DOMString name);

Просмотреть файл

@ -729,6 +729,9 @@ JS_PUBLIC_API bool JS_ReadUint32Pair(JSStructuredCloneReader* r, uint32_t* p1,
JS_PUBLIC_API bool JS_ReadBytes(JSStructuredCloneReader* r, void* p,
size_t len);
JS_PUBLIC_API bool JS_ReadString(JSStructuredCloneReader* r,
JS::MutableHandleString str);
JS_PUBLIC_API bool JS_ReadDouble(JSStructuredCloneReader* r, double* v);
JS_PUBLIC_API bool JS_ReadTypedArray(JSStructuredCloneReader* r,

Просмотреть файл

@ -477,6 +477,8 @@ struct JSStructuredCloneReader {
// Any value passed to JS_ReadStructuredClone.
void* closure;
friend bool JS_ReadString(JSStructuredCloneReader* r,
JS::MutableHandleString str);
friend bool JS_ReadTypedArray(JSStructuredCloneReader* r,
MutableHandleValue vp);
};
@ -3561,6 +3563,23 @@ JS_PUBLIC_API bool JS_ReadBytes(JSStructuredCloneReader* r, void* p,
return r->input().readBytes(p, len);
}
JS_PUBLIC_API bool JS_ReadString(JSStructuredCloneReader* r,
MutableHandleString str) {
uint32_t tag, data;
if (!r->input().readPair(&tag, &data)) {
return false;
}
if (tag == SCTAG_STRING) {
str.set(r->readString(data));
return true;
}
JS_ReportErrorNumberASCII(r->context(), GetErrorMessage, nullptr,
JSMSG_SC_BAD_SERIALIZED_DATA, "expected string");
return false;
}
JS_PUBLIC_API bool JS_ReadDouble(JSStructuredCloneReader* r, double* v) {
return r->input().readDouble(v);
}

Просмотреть файл

@ -5,15 +5,9 @@
[Error.message: getter is ignored when cloning]
expected: FAIL
[DOMException objects created by the UA can be cloned]
expected: FAIL
[EvalError objects can be cloned]
expected: FAIL
[DOMException objects can be cloned]
expected: FAIL
[URIError objects can be cloned]
expected: FAIL