Bug 1819287 - Make nsContentUtils::StringifyJSON more flexible; r=smaug

Differential Revision: https://phabricator.services.mozilla.com/D171215
This commit is contained in:
Ms2ger 2023-03-02 15:47:40 +00:00
Родитель 92601c6d5a
Коммит 3f2d0f2321
10 изменённых файлов: 99 добавлений и 24 удалений

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

@ -133,7 +133,8 @@ void ConvertSerializedStackToJSON(UniquePtr<SerializedStackHolder> aStackHolder,
}
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);
return;
}

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

@ -10628,16 +10628,28 @@ static bool JSONCreator(const char16_t* aBuf, uint32_t aLen, void* aData) {
/* static */
bool nsContentUtils::StringifyJSON(JSContext* aCx, JS::Handle<JS::Value> aValue,
nsAString& aOutStr) {
nsAString& aOutStr, JSONBehavior aBehavior) {
MOZ_ASSERT(aCx);
aOutStr.Truncate();
JS::Rooted<JS::Value> value(aCx, aValue);
nsAutoString serializedValue;
NS_ENSURE_TRUE(JS_Stringify(aCx, &value, nullptr, JS::NullHandleValue,
JSONCreator, &serializedValue),
false);
aOutStr = serializedValue;
return true;
switch (aBehavior) {
case UndefinedIsNullStringLiteral: {
aOutStr.Truncate();
JS::Rooted<JS::Value> value(aCx, aValue);
nsAutoString serializedValue;
NS_ENSURE_TRUE(JS_Stringify(aCx, &value, nullptr, JS::NullHandleValue,
JSONCreator, &serializedValue),
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 */

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

@ -243,7 +243,11 @@ struct EventNameMapping {
namespace mozilla {
enum class PreventDefaultResult : uint8_t { No, ByContent, ByChrome };
namespace dom {
enum JSONBehavior { UndefinedIsNullStringLiteral, UndefinedIsVoidString };
}
} // namespace mozilla
class nsContentUtils {
friend class nsAutoScriptBlockerSuppressNodeRemoved;
@ -256,6 +260,7 @@ class nsContentUtils {
using EventMessage = mozilla::EventMessage;
using TimeDuration = mozilla::TimeDuration;
using Trusted = mozilla::Trusted;
using JSONBehavior = mozilla::dom::JSONBehavior;
public:
static nsresult Init();
@ -3256,15 +3261,21 @@ class nsContentUtils {
static nsresult AnonymizeURI(nsIURI* aURI, nsCString& aAnonymizedURI);
/**
* Serializes a JSON-like JS::Value into a string, returning the string "null"
* where JSON.stringify would return undefined.
* Serializes a JSON-like JS::Value into a string.
* 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:
* nsAutoString serializedValue;
* nsContentUtils::StringifyJSON(cx, value, serializedValue);
* nsContentUtils::StringifyJSON(cx, value, serializedValue, behavior);
*/
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

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

@ -472,7 +472,9 @@ bool nsFrameMessageManager::GetParamsForMessage(JSContext* aCx,
// properly cases when interface is implemented in JS and used
// as a dictionary.
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);
JS::Rooted<JS::Value> val(aCx, JS::NullValue());

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

@ -14,6 +14,8 @@
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/SimpleGlobalObject.h"
using namespace mozilla::dom;
struct IsURIInListMatch {
nsLiteralCString pattern;
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(
mozilla::dom::RootingCx(),
@ -76,11 +79,12 @@ TEST(DOM_Base_ContentUtils, StringifyJSON_EmptyValue)
nsAutoString serializedValue;
ASSERT_TRUE(nsContentUtils::StringifyJSON(cx, JS::UndefinedHandleValue,
serializedValue));
serializedValue,
UndefinedIsNullStringLiteral));
ASSERT_TRUE(serializedValue.EqualsLiteral("null"));
}
TEST(DOM_Base_ContentUtils, StringifyJSON_Object)
TEST(DOM_Base_ContentUtils, StringifyJSON_Object_UndefinedIsNullStringLiteral)
{
JS::Rooted<JSObject*> globalObject(
mozilla::dom::RootingCx(),
@ -96,7 +100,47 @@ TEST(DOM_Base_ContentUtils, StringifyJSON_Object)
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));
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!\"}"));
}

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

@ -48,7 +48,8 @@ nsresult GetAsString(const RefPtr<Promise>& aPromise, nsAString& aString) {
}
case Promise::PromiseState::Resolved: {
if (nsContentUtils::StringifyJSON(cx, vp, aString)) {
if (nsContentUtils::StringifyJSON(cx, vp, aString,
UndefinedIsNullStringLiteral)) {
return NS_OK;
}

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

@ -142,7 +142,8 @@ void DOMLocalization::SetAttributes(
if (aArgs.WasPassed() && aArgs.Value()) {
nsAutoString data;
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);
return;
}

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

@ -22,7 +22,8 @@ nsresult SerializeFromJSObject(JSContext* aCx, JS::Handle<JSObject*> aObject,
nsresult SerializeFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aValue,
nsAString& aSerializedValue) {
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_ENSURE_TRUE(!aSerializedValue.IsEmpty(), NS_ERROR_FAILURE);
return NS_OK;

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

@ -1128,7 +1128,8 @@ MOZ_CAN_RUN_SCRIPT
static void SetSessionData(JSContext* aCx, Element* aElement,
JS::MutableHandle<JS::Value> aObject) {
nsAutoString data;
if (nsContentUtils::StringifyJSON(aCx, aObject, data)) {
if (nsContentUtils::StringifyJSON(aCx, aObject, data,
UndefinedIsNullStringLiteral)) {
SetElementAsString(aElement, data);
} else {
JS_ClearPendingException(aCx);

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

@ -230,7 +230,8 @@ class UntrustedModulesFixture : public TelemetryTestFixture {
serializer.GetObject(&jsval);
nsAutoString json;
EXPECT_TRUE(nsContentUtils::StringifyJSON(cx.GetJSContext(), jsval, json));
EXPECT_TRUE(nsContentUtils::StringifyJSON(
cx.GetJSContext(), jsval, json, dom::UndefinedIsNullStringLiteral));
JS::Rooted<JSObject*> re(
cx.GetJSContext(),