forked from mirrors/gecko-dev
Bug 1819287 - Make nsContentUtils::StringifyJSON more flexible; r=smaug
Differential Revision: https://phabricator.services.mozilla.com/D171215
This commit is contained in:
parent
92601c6d5a
commit
3f2d0f2321
10 changed files with 99 additions and 24 deletions
|
|
@ -133,7 +133,8 @@ void ConvertSerializedStackToJSON(UniquePtr<SerializedStackHolder> aStackHolder,
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::Rooted<JS::Value> convertedValue(cx, JS::ObjectValue(*converted));
|
JS::Rooted<JS::Value> convertedValue(cx, JS::ObjectValue(*converted));
|
||||||
if (!nsContentUtils::StringifyJSON(cx, convertedValue, aStackString)) {
|
if (!nsContentUtils::StringifyJSON(cx, convertedValue, aStackString,
|
||||||
|
UndefinedIsNullStringLiteral)) {
|
||||||
JS_ClearPendingException(cx);
|
JS_ClearPendingException(cx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10628,16 +10628,28 @@ static bool JSONCreator(const char16_t* aBuf, uint32_t aLen, void* aData) {
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
bool nsContentUtils::StringifyJSON(JSContext* aCx, JS::Handle<JS::Value> aValue,
|
bool nsContentUtils::StringifyJSON(JSContext* aCx, JS::Handle<JS::Value> aValue,
|
||||||
nsAString& aOutStr) {
|
nsAString& aOutStr, JSONBehavior aBehavior) {
|
||||||
MOZ_ASSERT(aCx);
|
MOZ_ASSERT(aCx);
|
||||||
aOutStr.Truncate();
|
switch (aBehavior) {
|
||||||
JS::Rooted<JS::Value> value(aCx, aValue);
|
case UndefinedIsNullStringLiteral: {
|
||||||
nsAutoString serializedValue;
|
aOutStr.Truncate();
|
||||||
NS_ENSURE_TRUE(JS_Stringify(aCx, &value, nullptr, JS::NullHandleValue,
|
JS::Rooted<JS::Value> value(aCx, aValue);
|
||||||
JSONCreator, &serializedValue),
|
nsAutoString serializedValue;
|
||||||
false);
|
NS_ENSURE_TRUE(JS_Stringify(aCx, &value, nullptr, JS::NullHandleValue,
|
||||||
aOutStr = serializedValue;
|
JSONCreator, &serializedValue),
|
||||||
return true;
|
false);
|
||||||
|
aOutStr = serializedValue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case UndefinedIsVoidString: {
|
||||||
|
aOutStr.SetIsVoid(true);
|
||||||
|
return JS::ToJSON(aCx, aValue, nullptr, JS::NullHandleValue, JSONCreator,
|
||||||
|
&aOutStr);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
MOZ_ASSERT_UNREACHABLE("Invalid value for aBehavior");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
|
|
|
||||||
|
|
@ -243,7 +243,11 @@ struct EventNameMapping {
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
enum class PreventDefaultResult : uint8_t { No, ByContent, ByChrome };
|
enum class PreventDefaultResult : uint8_t { No, ByContent, ByChrome };
|
||||||
|
|
||||||
|
namespace dom {
|
||||||
|
enum JSONBehavior { UndefinedIsNullStringLiteral, UndefinedIsVoidString };
|
||||||
}
|
}
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
class nsContentUtils {
|
class nsContentUtils {
|
||||||
friend class nsAutoScriptBlockerSuppressNodeRemoved;
|
friend class nsAutoScriptBlockerSuppressNodeRemoved;
|
||||||
|
|
@ -256,6 +260,7 @@ class nsContentUtils {
|
||||||
using EventMessage = mozilla::EventMessage;
|
using EventMessage = mozilla::EventMessage;
|
||||||
using TimeDuration = mozilla::TimeDuration;
|
using TimeDuration = mozilla::TimeDuration;
|
||||||
using Trusted = mozilla::Trusted;
|
using Trusted = mozilla::Trusted;
|
||||||
|
using JSONBehavior = mozilla::dom::JSONBehavior;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static nsresult Init();
|
static nsresult Init();
|
||||||
|
|
@ -3256,15 +3261,21 @@ class nsContentUtils {
|
||||||
static nsresult AnonymizeURI(nsIURI* aURI, nsCString& aAnonymizedURI);
|
static nsresult AnonymizeURI(nsIURI* aURI, nsCString& aAnonymizedURI);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serializes a JSON-like JS::Value into a string, returning the string "null"
|
* Serializes a JSON-like JS::Value into a string.
|
||||||
* where JSON.stringify would return undefined.
|
* Cases where JSON.stringify would return undefined are handled according to
|
||||||
|
* the |aBehavior| argument:
|
||||||
*
|
*
|
||||||
|
* - If it is |UndefinedIsNullStringLiteral|, the string "null" is returned.
|
||||||
|
* - If it is |UndefinedIsVoidString|, the void string is returned.
|
||||||
|
*
|
||||||
|
* The |UndefinedIsNullStringLiteral| case is likely not desirable, but is
|
||||||
|
* retained for now for historical reasons.
|
||||||
* Usage:
|
* Usage:
|
||||||
* nsAutoString serializedValue;
|
* nsAutoString serializedValue;
|
||||||
* nsContentUtils::StringifyJSON(cx, value, serializedValue);
|
* nsContentUtils::StringifyJSON(cx, value, serializedValue, behavior);
|
||||||
*/
|
*/
|
||||||
static bool StringifyJSON(JSContext* aCx, JS::Handle<JS::Value> aValue,
|
static bool StringifyJSON(JSContext* aCx, JS::Handle<JS::Value> aValue,
|
||||||
nsAString& aOutStr);
|
nsAString& aOutStr, JSONBehavior aBehavior);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the top level ancestor content document of aDocument hasn't
|
* Returns true if the top level ancestor content document of aDocument hasn't
|
||||||
|
|
|
||||||
|
|
@ -472,7 +472,9 @@ bool nsFrameMessageManager::GetParamsForMessage(JSContext* aCx,
|
||||||
// properly cases when interface is implemented in JS and used
|
// properly cases when interface is implemented in JS and used
|
||||||
// as a dictionary.
|
// as a dictionary.
|
||||||
nsAutoString json;
|
nsAutoString json;
|
||||||
NS_ENSURE_TRUE(nsContentUtils::StringifyJSON(aCx, v, json), false);
|
NS_ENSURE_TRUE(
|
||||||
|
nsContentUtils::StringifyJSON(aCx, v, json, UndefinedIsNullStringLiteral),
|
||||||
|
false);
|
||||||
NS_ENSURE_TRUE(!json.IsEmpty(), false);
|
NS_ENSURE_TRUE(!json.IsEmpty(), false);
|
||||||
|
|
||||||
JS::Rooted<JS::Value> val(aCx, JS::NullValue());
|
JS::Rooted<JS::Value> val(aCx, JS::NullValue());
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@
|
||||||
#include "mozilla/dom/ScriptSettings.h"
|
#include "mozilla/dom/ScriptSettings.h"
|
||||||
#include "mozilla/dom/SimpleGlobalObject.h"
|
#include "mozilla/dom/SimpleGlobalObject.h"
|
||||||
|
|
||||||
|
using namespace mozilla::dom;
|
||||||
|
|
||||||
struct IsURIInListMatch {
|
struct IsURIInListMatch {
|
||||||
nsLiteralCString pattern;
|
nsLiteralCString pattern;
|
||||||
bool firstMatch, secondMatch;
|
bool firstMatch, secondMatch;
|
||||||
|
|
@ -64,7 +66,8 @@ TEST(DOM_Base_ContentUtils, IsURIInList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DOM_Base_ContentUtils, StringifyJSON_EmptyValue)
|
TEST(DOM_Base_ContentUtils,
|
||||||
|
StringifyJSON_EmptyValue_UndefinedIsNullStringLiteral)
|
||||||
{
|
{
|
||||||
JS::Rooted<JSObject*> globalObject(
|
JS::Rooted<JSObject*> globalObject(
|
||||||
mozilla::dom::RootingCx(),
|
mozilla::dom::RootingCx(),
|
||||||
|
|
@ -76,11 +79,12 @@ TEST(DOM_Base_ContentUtils, StringifyJSON_EmptyValue)
|
||||||
nsAutoString serializedValue;
|
nsAutoString serializedValue;
|
||||||
|
|
||||||
ASSERT_TRUE(nsContentUtils::StringifyJSON(cx, JS::UndefinedHandleValue,
|
ASSERT_TRUE(nsContentUtils::StringifyJSON(cx, JS::UndefinedHandleValue,
|
||||||
serializedValue));
|
serializedValue,
|
||||||
|
UndefinedIsNullStringLiteral));
|
||||||
ASSERT_TRUE(serializedValue.EqualsLiteral("null"));
|
ASSERT_TRUE(serializedValue.EqualsLiteral("null"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DOM_Base_ContentUtils, StringifyJSON_Object)
|
TEST(DOM_Base_ContentUtils, StringifyJSON_Object_UndefinedIsNullStringLiteral)
|
||||||
{
|
{
|
||||||
JS::Rooted<JSObject*> globalObject(
|
JS::Rooted<JSObject*> globalObject(
|
||||||
mozilla::dom::RootingCx(),
|
mozilla::dom::RootingCx(),
|
||||||
|
|
@ -96,7 +100,47 @@ TEST(DOM_Base_ContentUtils, StringifyJSON_Object)
|
||||||
ASSERT_TRUE(JS_DefineProperty(cx, jsObj, "key1", valueStr, JSPROP_ENUMERATE));
|
ASSERT_TRUE(JS_DefineProperty(cx, jsObj, "key1", valueStr, JSPROP_ENUMERATE));
|
||||||
JS::Rooted<JS::Value> jsValue(cx, JS::ObjectValue(*jsObj));
|
JS::Rooted<JS::Value> jsValue(cx, JS::ObjectValue(*jsObj));
|
||||||
|
|
||||||
ASSERT_TRUE(nsContentUtils::StringifyJSON(cx, jsValue, serializedValue));
|
ASSERT_TRUE(nsContentUtils::StringifyJSON(cx, jsValue, serializedValue,
|
||||||
|
UndefinedIsNullStringLiteral));
|
||||||
|
|
||||||
|
ASSERT_TRUE(serializedValue.EqualsLiteral("{\"key1\":\"Hello World!\"}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DOM_Base_ContentUtils, StringifyJSON_EmptyValue_UndefinedIsVoidString)
|
||||||
|
{
|
||||||
|
JS::Rooted<JSObject*> globalObject(
|
||||||
|
mozilla::dom::RootingCx(),
|
||||||
|
mozilla::dom::SimpleGlobalObject::Create(
|
||||||
|
mozilla::dom::SimpleGlobalObject::GlobalType::BindingDetail));
|
||||||
|
mozilla::dom::AutoJSAPI jsAPI;
|
||||||
|
ASSERT_TRUE(jsAPI.Init(globalObject));
|
||||||
|
JSContext* cx = jsAPI.cx();
|
||||||
|
nsAutoString serializedValue;
|
||||||
|
|
||||||
|
ASSERT_TRUE(nsContentUtils::StringifyJSON(
|
||||||
|
cx, JS::UndefinedHandleValue, serializedValue, UndefinedIsVoidString));
|
||||||
|
|
||||||
|
ASSERT_TRUE(serializedValue.IsVoid());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DOM_Base_ContentUtils, StringifyJSON_Object_UndefinedIsVoidString)
|
||||||
|
{
|
||||||
|
JS::Rooted<JSObject*> globalObject(
|
||||||
|
mozilla::dom::RootingCx(),
|
||||||
|
mozilla::dom::SimpleGlobalObject::Create(
|
||||||
|
mozilla::dom::SimpleGlobalObject::GlobalType::BindingDetail));
|
||||||
|
mozilla::dom::AutoJSAPI jsAPI;
|
||||||
|
ASSERT_TRUE(jsAPI.Init(globalObject));
|
||||||
|
JSContext* cx = jsAPI.cx();
|
||||||
|
nsAutoString serializedValue;
|
||||||
|
|
||||||
|
JS::Rooted<JSObject*> jsObj(cx, JS_NewPlainObject(cx));
|
||||||
|
JS::Rooted<JSString*> valueStr(cx, JS_NewStringCopyZ(cx, "Hello World!"));
|
||||||
|
ASSERT_TRUE(JS_DefineProperty(cx, jsObj, "key1", valueStr, JSPROP_ENUMERATE));
|
||||||
|
JS::Rooted<JS::Value> jsValue(cx, JS::ObjectValue(*jsObj));
|
||||||
|
|
||||||
|
ASSERT_TRUE(nsContentUtils::StringifyJSON(cx, jsValue, serializedValue,
|
||||||
|
UndefinedIsVoidString));
|
||||||
|
|
||||||
ASSERT_TRUE(serializedValue.EqualsLiteral("{\"key1\":\"Hello World!\"}"));
|
ASSERT_TRUE(serializedValue.EqualsLiteral("{\"key1\":\"Hello World!\"}"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,8 @@ nsresult GetAsString(const RefPtr<Promise>& aPromise, nsAString& aString) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case Promise::PromiseState::Resolved: {
|
case Promise::PromiseState::Resolved: {
|
||||||
if (nsContentUtils::StringifyJSON(cx, vp, aString)) {
|
if (nsContentUtils::StringifyJSON(cx, vp, aString,
|
||||||
|
UndefinedIsNullStringLiteral)) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,8 @@ void DOMLocalization::SetAttributes(
|
||||||
if (aArgs.WasPassed() && aArgs.Value()) {
|
if (aArgs.WasPassed() && aArgs.Value()) {
|
||||||
nsAutoString data;
|
nsAutoString data;
|
||||||
JS::Rooted<JS::Value> val(aCx, JS::ObjectValue(*aArgs.Value()));
|
JS::Rooted<JS::Value> val(aCx, JS::ObjectValue(*aArgs.Value()));
|
||||||
if (!nsContentUtils::StringifyJSON(aCx, val, data)) {
|
if (!nsContentUtils::StringifyJSON(aCx, val, data,
|
||||||
|
UndefinedIsNullStringLiteral)) {
|
||||||
aRv.NoteJSContextException(aCx);
|
aRv.NoteJSContextException(aCx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,8 @@ nsresult SerializeFromJSObject(JSContext* aCx, JS::Handle<JSObject*> aObject,
|
||||||
nsresult SerializeFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aValue,
|
nsresult SerializeFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aValue,
|
||||||
nsAString& aSerializedValue) {
|
nsAString& aSerializedValue) {
|
||||||
aSerializedValue.Truncate();
|
aSerializedValue.Truncate();
|
||||||
NS_ENSURE_TRUE(nsContentUtils::StringifyJSON(aCx, aValue, aSerializedValue),
|
NS_ENSURE_TRUE(nsContentUtils::StringifyJSON(aCx, aValue, aSerializedValue,
|
||||||
|
UndefinedIsNullStringLiteral),
|
||||||
NS_ERROR_XPC_BAD_CONVERT_JS);
|
NS_ERROR_XPC_BAD_CONVERT_JS);
|
||||||
NS_ENSURE_TRUE(!aSerializedValue.IsEmpty(), NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(!aSerializedValue.IsEmpty(), NS_ERROR_FAILURE);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
|
||||||
|
|
@ -1128,7 +1128,8 @@ MOZ_CAN_RUN_SCRIPT
|
||||||
static void SetSessionData(JSContext* aCx, Element* aElement,
|
static void SetSessionData(JSContext* aCx, Element* aElement,
|
||||||
JS::MutableHandle<JS::Value> aObject) {
|
JS::MutableHandle<JS::Value> aObject) {
|
||||||
nsAutoString data;
|
nsAutoString data;
|
||||||
if (nsContentUtils::StringifyJSON(aCx, aObject, data)) {
|
if (nsContentUtils::StringifyJSON(aCx, aObject, data,
|
||||||
|
UndefinedIsNullStringLiteral)) {
|
||||||
SetElementAsString(aElement, data);
|
SetElementAsString(aElement, data);
|
||||||
} else {
|
} else {
|
||||||
JS_ClearPendingException(aCx);
|
JS_ClearPendingException(aCx);
|
||||||
|
|
|
||||||
|
|
@ -230,7 +230,8 @@ class UntrustedModulesFixture : public TelemetryTestFixture {
|
||||||
serializer.GetObject(&jsval);
|
serializer.GetObject(&jsval);
|
||||||
|
|
||||||
nsAutoString json;
|
nsAutoString json;
|
||||||
EXPECT_TRUE(nsContentUtils::StringifyJSON(cx.GetJSContext(), jsval, json));
|
EXPECT_TRUE(nsContentUtils::StringifyJSON(
|
||||||
|
cx.GetJSContext(), jsval, json, dom::UndefinedIsNullStringLiteral));
|
||||||
|
|
||||||
JS::Rooted<JSObject*> re(
|
JS::Rooted<JSObject*> re(
|
||||||
cx.GetJSContext(),
|
cx.GetJSContext(),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue