Bug 1387788 - Remove [deprecated] methods from nsIJSON. r=Ehsan

MozReview-Commit-ID: 9OsQacbPsFo

--HG--
extra : rebase_source : 8c905a48306e957026af9dd8fcbf83eae41b8a38
This commit is contained in:
Masatoshi Kimura 2017-08-06 10:25:15 +09:00
parent 407f690fc8
commit 706ca23396
7 changed files with 3 additions and 383 deletions

View File

@ -6,7 +6,6 @@
#include "domstubs.idl"
interface nsIInputStream;
interface nsIOutputStream;
interface nsIScriptGlobalObject;
[ptr] native JSValPtr(JS::Value);
@ -22,34 +21,6 @@ interface nsIScriptGlobalObject;
[scriptable, uuid(083aebb0-7790-43b2-ae81-9e404e626236)]
interface nsIJSON : nsISupports
{
/**
* New users should use JSON.stringify!
* The encode() method is only present for backward compatibility.
* encode() is not a conforming JSON stringify implementation!
*/
[deprecated,implicit_jscontext,optional_argc]
AString encode([optional] in jsval value);
/**
* New users should use JSON.stringify.
* You may also want to have a look at nsIConverterOutputStream.
*
* The encodeToStream() method is only present for backward compatibility.
* encodeToStream() is not a conforming JSON stringify implementation!
*/
[deprecated,implicit_jscontext,optional_argc]
void encodeToStream(in nsIOutputStream stream,
in string charset,
in boolean writeBOM,
[optional] in jsval value);
/**
* New users should use JSON.parse!
* The decode() method is only present for backward compatibility.
*/
[deprecated,implicit_jscontext]
jsval decode(in AString str);
[implicit_jscontext]
jsval decodeFromStream(in nsIInputStream stream,
in long contentLength);

View File

@ -4,9 +4,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsJSON.h"
#include "jsapi.h"
#include "js/CharacterEncoding.h"
#include "nsJSON.h"
#include "nsIXPConnect.h"
#include "nsIXPCScriptable.h"
#include "nsStreamUtils.h"
@ -43,109 +44,6 @@ nsJSON::~nsJSON()
{
}
enum DeprecationWarning { EncodeWarning, DecodeWarning };
static nsresult
WarnDeprecatedMethod(DeprecationWarning warning)
{
return nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("DOM Core"), nullptr,
nsContentUtils::eDOM_PROPERTIES,
warning == EncodeWarning
? "nsIJSONEncodeDeprecatedWarning"
: "nsIJSONDecodeDeprecatedWarning");
}
NS_IMETHODIMP
nsJSON::Encode(JS::Handle<JS::Value> aValue, JSContext* cx, uint8_t aArgc,
nsAString &aJSON)
{
// This function should only be called from JS.
nsresult rv = WarnDeprecatedMethod(EncodeWarning);
if (NS_FAILED(rv))
return rv;
if (aArgc == 0) {
aJSON.SetIsVoid(true);
return NS_OK;
}
nsJSONWriter writer;
rv = EncodeInternal(cx, aValue, &writer);
// FIXME: bug 408838. Get exception types sorted out
if (NS_SUCCEEDED(rv) || rv == NS_ERROR_INVALID_ARG) {
rv = NS_OK;
// if we didn't consume anything, it's not JSON, so return null
if (!writer.DidWrite()) {
aJSON.SetIsVoid(true);
} else {
writer.FlushBuffer();
aJSON.Append(writer.mOutputString);
}
}
return rv;
}
static const char UTF8BOM[] = "\xEF\xBB\xBF";
static nsresult CheckCharset(const char* aCharset)
{
// Check that the charset is permissible
if (!(strcmp(aCharset, "UTF-8") == 0)) {
return NS_ERROR_INVALID_ARG;
}
return NS_OK;
}
NS_IMETHODIMP
nsJSON::EncodeToStream(nsIOutputStream *aStream,
const char* aCharset,
const bool aWriteBOM,
JS::Handle<JS::Value> val,
JSContext* cx,
uint8_t aArgc)
{
// This function should only be called from JS.
NS_ENSURE_ARG(aStream);
nsresult rv;
rv = CheckCharset(aCharset);
NS_ENSURE_SUCCESS(rv, rv);
// Check to see if we have a buffered stream
nsCOMPtr<nsIOutputStream> bufferedStream;
// FIXME: bug 408514.
// NS_OutputStreamIsBuffered(aStream) asserts on file streams...
//if (!NS_OutputStreamIsBuffered(aStream)) {
rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedStream),
aStream, 4096);
NS_ENSURE_SUCCESS(rv, rv);
// aStream = bufferedStream;
//}
uint32_t ignored;
if (aWriteBOM) {
rv = aStream->Write(UTF8BOM, 3, &ignored);
NS_ENSURE_SUCCESS(rv, rv);
}
nsJSONWriter writer(bufferedStream);
if (aArgc == 0) {
return NS_OK;
}
rv = EncodeInternal(cx, val, &writer);
NS_ENSURE_SUCCESS(rv, rv);
rv = bufferedStream->Flush();
return rv;
}
static bool
WriteCallback(const char16_t *buf, uint32_t len, void *data)
{
@ -181,60 +79,6 @@ nsJSON::EncodeFromJSVal(JS::Value *value, JSContext *cx, nsAString &result)
return NS_OK;
}
nsresult
nsJSON::EncodeInternal(JSContext* cx, const JS::Value& aValue,
nsJSONWriter* writer)
{
// Backward compatibility:
// nsIJSON does not allow to serialize anything other than objects
if (!aValue.isObject()) {
return NS_ERROR_INVALID_ARG;
}
JS::Rooted<JSObject*> obj(cx, &aValue.toObject());
/* Backward compatibility:
* Manually call toJSON if implemented by the object and check that
* the result is still an object
* Note: It is perfectly fine to not implement toJSON, so it is
* perfectly fine for GetMethod to fail
*/
JS::Rooted<JS::Value> val(cx, aValue);
JS::Rooted<JS::Value> toJSON(cx);
if (JS_GetProperty(cx, obj, "toJSON", &toJSON) &&
toJSON.isObject() && JS::IsCallable(&toJSON.toObject())) {
// If toJSON is implemented, it must not throw
if (!JS_CallFunctionValue(cx, obj, toJSON, JS::HandleValueArray::empty(), &val)) {
if (JS_IsExceptionPending(cx))
// passing NS_OK will throw the pending exception
return NS_OK;
// No exception, but still failed
return NS_ERROR_FAILURE;
}
// Backward compatibility:
// nsIJSON does not allow to serialize anything other than objects
if (val.isPrimitive())
return NS_ERROR_INVALID_ARG;
}
// GetMethod may have thrown
else if (JS_IsExceptionPending(cx))
// passing NS_OK will throw the pending exception
return NS_OK;
// Backward compatibility:
// function shall not pass, just "plain" objects and arrays
JSType type = JS_TypeOfValue(cx, val);
if (type == JSTYPE_FUNCTION)
return NS_ERROR_INVALID_ARG;
// We're good now; try to stringify
if (!JS_Stringify(cx, &val, nullptr, JS::NullHandleValue, WriteCallback, writer))
return NS_ERROR_FAILURE;
return NS_OK;
}
nsJSONWriter::nsJSONWriter() : mStream(nullptr),
mBuffer(nullptr),
@ -329,25 +173,6 @@ nsJSONWriter::WriteToStream(nsIOutputStream* aStream,
}
}
NS_IMETHODIMP
nsJSON::Decode(const nsAString& json, JSContext* cx,
JS::MutableHandle<JS::Value> aRetval)
{
nsresult rv = WarnDeprecatedMethod(DecodeWarning);
if (NS_FAILED(rv))
return rv;
const char16_t *data = json.BeginReading();
uint32_t len = json.Length();
nsCOMPtr<nsIInputStream> stream;
rv = NS_NewByteInputStream(getter_AddRefs(stream),
reinterpret_cast<const char*>(data),
len * sizeof(char16_t),
NS_ASSIGNMENT_DEPEND);
NS_ENSURE_SUCCESS(rv, rv);
return DecodeInternal(cx, stream, len, false, aRetval);
}
NS_IMETHODIMP
nsJSON::DecodeFromStream(nsIInputStream *aStream, int32_t aContentLength,
JSContext* cx, JS::MutableHandle<JS::Value> aRetval)

View File

@ -42,7 +42,7 @@ protected:
mozilla::UniquePtr<mozilla::Encoder> mEncoder;
};
class nsJSON : public nsIJSON
class nsJSON final : public nsIJSON
{
public:
nsJSON();
@ -53,10 +53,6 @@ public:
protected:
virtual ~nsJSON();
nsresult EncodeInternal(JSContext* cx,
const JS::Value& val,
nsJSONWriter* writer);
nsresult DecodeInternal(JSContext* cx,
nsIInputStream* aStream,
int32_t aContentLength,

File diff suppressed because one or more lines are too long

View File

@ -1,136 +0,0 @@
var Ci = Components.interfaces;
var Cc = Components.classes;
var nativeJSON = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
var workingDir = dirSvc.get("TmpD", Ci.nsIFile);
var outputName = "json-test-output";
var outputDir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
outputDir.initWithFile(workingDir);
outputDir.append(outputName);
if (!outputDir.exists()) {
outputDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o777);
} else if (!outputDir.isDirectory()) {
do_throw(outputName + " is not a directory?")
}
function testStringEncode()
{
var obj1 = {a:1};
var obj2 = {foo:"bar"};
do_check_eq(nativeJSON.encode(obj1), '{"a":1}');
do_check_eq(nativeJSON.encode(obj2), '{"foo":"bar"}');
do_check_eq(nativeJSON.encode(), null);
// useless roots are dropped
do_check_eq(nativeJSON.encode(null), null);
do_check_eq(nativeJSON.encode(""), null);
do_check_eq(nativeJSON.encode(undefined), null);
do_check_eq(nativeJSON.encode(5), null);
do_check_eq(nativeJSON.encode(function(){}), null);
do_check_eq(nativeJSON.encode(dump), null);
// All other testing should occur in js/src/tests/ecma_5/JSON/ using
// the otherwise-exactly-identical JSON.stringify.
}
function testToJSON() {
var obj1 = {a:1};
var obj2 = {foo:"bar"};
do_check_eq(nativeJSON.encode({toJSON: () => obj1}), '{"a":1}');
do_check_eq(nativeJSON.encode({toJSON: () => obj2}), '{"foo":"bar"}');
do_check_eq(nativeJSON.encode({toJSON: () => null}), null);
do_check_eq(nativeJSON.encode({toJSON: () => ""}), null);
do_check_eq(nativeJSON.encode({toJSON: () => undefined }), null);
do_check_eq(nativeJSON.encode({toJSON: () => 5}), null);
do_check_eq(nativeJSON.encode({toJSON: () => function(){}}), null);
do_check_eq(nativeJSON.encode({toJSON: () => dump}), null);
}
function testThrowingToJSON() {
var obj1 = {
"b": 1,
"c": 2,
toJSON: function() { throw("uh oh"); }
};
try {
var y = nativeJSON.encode(obj1);
throw "didn't throw";
} catch (ex) {
do_check_eq(ex, "uh oh");
}
var obj2 = {
"b": 1,
"c": 2,
get toJSON() { throw("crash and burn"); }
};
try {
var y = nativeJSON.encode(obj2);
throw "didn't throw";
} catch (ex) {
do_check_eq(ex, "crash and burn");
}
}
function testOutputStreams() {
function writeToFile(obj, charset, writeBOM) {
var jsonFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
jsonFile.initWithFile(outputDir);
jsonFile.append("test.json");
jsonFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
var stream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
try {
stream.init(jsonFile, 0x04 | 0x08 | 0x20, 0o600, 0); // write, create, truncate
nativeJSON.encodeToStream(stream, charset, writeBOM, obj);
} finally {
stream.close();
}
return jsonFile;
}
var pairs = [
["{}", {}],
['{"foo":"bar"}', {"foo":"bar"}],
['{"null":null}', {"null":null}],
['{"five":5}', {"five":5}],
['{"true":true}', {"true":true}],
['{"x":{"y":"z"}}', {"x":{"y":"z"}}],
['{"w":{"x":{"y":"z"}}}', {"w":{"x":{"y":"z"}}}],
["[]", []],
['[1,2,3]', [1,2,3]],
['[1,null,3]',[1,,3]],
];
for (var i = 0; i < pairs.length; i++)
{
var pair = pairs[i];
if (pair[1] && (typeof pair[1] == "object")) {
var utf8File = writeToFile(pair[1], "UTF-8", false);
// all ascii with no BOMs, so this will work
do_check_eq(utf8File.fileSize, pair[0].length);
}
}
// check BOMs
// the clone() calls are there to work around -- bug 410005
var f = writeToFile({},"UTF-8", true).clone();
do_check_eq(f.fileSize, 5);
outputDir.remove(true);
}
function run_test()
{
testStringEncode();
testToJSON();
testThrowingToJSON();
testOutputStreams();
}

View File

@ -4,7 +4,5 @@ support-files =
decodeFromStream-01.json
decodeFromStream-small.json
[test_decode_long_input.js]
[test_decodeFromStream.js]
[test_encode.js]

View File

@ -60,8 +60,6 @@ CreateAttributeNSWarning=Use of document.createAttributeNS() is deprecated. Use
NodeValueWarning=Use of attributes nodeValue attribute is deprecated. Use value instead.
TextContentWarning=Use of attributes textContent attribute is deprecated. Use value instead.
EnablePrivilegeWarning=Use of enablePrivilege is deprecated. Please use code that runs with the system principal (e.g. an extension) instead.
nsIJSONDecodeDeprecatedWarning=nsIJSON.decode is deprecated. Please use JSON.parse instead.
nsIJSONEncodeDeprecatedWarning=nsIJSON.encode is deprecated. Please use JSON.stringify instead.
FullscreenDeniedDisabled=Request for fullscreen was denied because Fullscreen API is disabled by user preference.
FullscreenDeniedFocusedPlugin=Request for fullscreen was denied because a windowed plugin is focused.
FullscreenDeniedHidden=Request for fullscreen was denied because the document is no longer visible.