Bug 462774: Drop JSON.jsm. r=gavin, r=sayrer, sr=brendan, a1.9.1b2=beltzner

This commit is contained in:
Simon Bünzli 2008-11-17 13:57:43 +00:00
Родитель 0c7385d706
Коммит dfd58ccf16
4 изменённых файлов: 2 добавлений и 310 удалений

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

@ -584,6 +584,7 @@ components/nsXmlRpcClient.js
components/nsInterfaceInfoToIDL.js
components/nsScriptableIO.js
chrome/chromelist.txt
modules/JSON.jsm
#ifdef XP_MACOSX
LICENSE
extensions/inspector@mozilla.org/chrome/chromelist.txt

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

@ -1,178 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla code.
*
* The Initial Developer of the Original Code is
* Simon Bünzli <zeniko@gmail.com>
* Portions created by the Initial Developer are Copyright (C) 2006-2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/**
* Utilities for JavaScript code to handle JSON content.
* See http://www.json.org/ for comprehensive information about JSON.
*
* Import this module through
*
* Components.utils.import("resource://gre/modules/JSON.jsm");
*
* Usage:
*
* var newJSONString = JSONModule.toString( GIVEN_JAVASCRIPT_OBJECT );
* var newJavaScriptObject = JSONModule.fromString( GIVEN_JSON_STRING );
*
* Note: For your own safety, Objects/Arrays returned by
* JSONModule.fromString aren't instanceof Object/Array.
*/
var EXPORTED_SYMBOLS = ["JSONModule"];
// The following code is a loose adaption of Douglas Crockford's code
// from http://www.json.org/json.js (public domain'd)
// Notable differences:
// * Unserializable values such as |undefined| or functions aren't
// silently dropped but always lead to a TypeError.
// * An optional key blacklist has been added to JSON.toString
var JSONModule = {
/**
* Converts a JavaScript object into a JSON string.
*
* @param aJSObject is the object to be converted
* @param aKeysToDrop is an optional array of keys which will be
* ignored in all objects during the serialization
* @return the object's JSON representation
*
* Note: aJSObject MUST not contain cyclic references.
*/
toString: function JSON_toString(aJSObject, aKeysToDrop) {
// we use a single string builder for efficiency reasons
var pieces = [];
// this recursive function walks through all objects and appends their
// JSON representation (in one or several pieces) to the string builder
function append_piece(aObj) {
if (typeof aObj == "string") {
aObj = aObj.replace(/[\\"\x00-\x1F\u0080-\uFFFF]/g, function($0) {
// use the special escape notation if one exists, otherwise
// produce a general unicode escape sequence
switch ($0) {
case "\b": return "\\b";
case "\t": return "\\t";
case "\n": return "\\n";
case "\f": return "\\f";
case "\r": return "\\r";
case '"': return '\\"';
case "\\": return "\\\\";
}
return "\\u" + ("0000" + $0.charCodeAt(0).toString(16)).slice(-4);
});
pieces.push('"' + aObj + '"')
}
else if (typeof aObj == "boolean") {
pieces.push(aObj ? "true" : "false");
}
else if (typeof aObj == "number" && isFinite(aObj)) {
// there is no representation for infinite numbers or for NaN!
pieces.push(aObj.toString());
}
else if (aObj === null) {
pieces.push("null");
}
// if it looks like an array, treat it as such - this is required
// for all arrays from either outside this module or a sandbox
else if (aObj instanceof Array ||
typeof aObj == "object" && "length" in aObj &&
(aObj.length === 0 || aObj[aObj.length - 1] !== undefined)) {
pieces.push("[");
for (var i = 0; i < aObj.length; i++) {
arguments.callee(aObj[i]);
pieces.push(",");
}
if (aObj.length > 0)
pieces.pop(); // drop the trailing colon
pieces.push("]");
}
else if (typeof aObj == "object") {
pieces.push("{");
for (var key in aObj) {
// allow callers to pass objects containing private data which
// they don't want the JSON string to contain (so they don't
// have to manually pre-process the object)
if (aKeysToDrop && aKeysToDrop.indexOf(key) != -1)
continue;
arguments.callee(key.toString());
pieces.push(":");
arguments.callee(aObj[key]);
pieces.push(",");
}
if (pieces[pieces.length - 1] == ",")
pieces.pop(); // drop the trailing colon
pieces.push("}");
}
else {
throw new TypeError("No JSON representation for this object!");
}
}
append_piece(aJSObject);
return pieces.join("");
},
/**
* Converts a JSON string into a JavaScript object.
*
* @param aJSONString is the string to be converted
* @return a JavaScript object for the given JSON representation
*/
fromString: function JSON_fromString(aJSONString) {
if (!this.isMostlyHarmless(aJSONString))
throw new SyntaxError("No valid JSON string!");
var s = new Components.utils.Sandbox("about:blank");
return Components.utils.evalInSandbox("(" + aJSONString + ")", s);
},
/**
* Checks whether the given string contains potentially harmful
* content which might be executed during its evaluation
* (no parser, thus not 100% safe! Best to use a Sandbox for evaluation)
*
* @param aString is the string to be tested
* @return a boolean
*/
isMostlyHarmless: function JSON_isMostlyHarmless(aString) {
const maybeHarmful = /[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/;
const jsonStrings = /"(\\.|[^"\\\n\r])*"/g;
return !maybeHarmful.test(aString.replace(jsonStrings, ""));
}
};

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

@ -56,7 +56,7 @@ REQUIRES = xpcom \
CPPSRCS = mozJSComponentLoader.cpp mozJSSubScriptLoader.cpp
EXTRA_JS_MODULES = XPCOMUtils.jsm JSON.jsm ISO8601DateUtils.jsm
EXTRA_JS_MODULES = XPCOMUtils.jsm ISO8601DateUtils.jsm
include $(topsrcdir)/config/rules.mk

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

@ -1,131 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Simon Bünzli <zeniko@gmail.com>
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
function run_test() {
// converts an object to a JSON string and tests its integrity
function toJSONString(a) {
var res = JSONModule.toString(a);
if (!JSONModule.isMostlyHarmless(res))
throw new SyntaxError("Invalid JSON string: " + res);
return res;
}
// ensures that an object can't be converted to a JSON string
function isInvalidType(a) {
try {
JSONModule.toString(a);
return false;
} catch (ex) {
return ex.name == "TypeError";
}
}
// ensures that a string can't be converted back to a JavaScript object
function isInvalidSyntax(a) {
try {
JSONModule.fromString(a);
return false;
} catch (ex) {
return ex.name == "SyntaxError";
}
}
Components.utils.import("resource://gre/modules/JSON.jsm");
do_check_eq(typeof(JSONModule), "object");
// some of the tests are adapted from /testing/mochitest/tests/test_Base.js
do_check_eq(toJSONString(true), "true");
do_check_eq(toJSONString(false), "false");
do_check_eq(toJSONString(1), "1");
do_check_eq(toJSONString(1.23), "1.23");
do_check_eq(toJSONString(1.23e-45), "1.23e-45");
do_check_true(isInvalidType(Infinity));
do_check_true(isInvalidType(NaN));
//XXXzeniko: using € instead of \u20ac fails because of encoding issues
do_check_eq(toJSONString("Foo-Bar \b\t\n\f\r\"\\ \x01\u20ac"),
'"Foo-Bar \\b\\t\\n\\f\\r\\"\\\\ \\u0001\\u20ac"');
do_check_eq(toJSONString(null), "null");
do_check_true(isInvalidType(undefined));
do_check_eq(toJSONString([1, "2", 3.3]), '[1,"2",3.3]');
// duck-typed Array (since we'll never really get something instanceof Array)
do_check_eq(toJSONString({ 0: 0, 1: "1", 2: -2.2, length: 3 }), '[0,"1",-2.2]');
var obj = { a: 1, b: "2", c: [-3e+30] };
do_check_eq(toJSONString(obj), '{"a":1,"b":"2","c":[-3e+30]}');
do_check_eq(JSONModule.toString(obj, ["b", "c"] /* keys to drop */), '{"a":1}');
do_check_true(isInvalidType(function() { }));
// make sure that toJSONString actually works...
do_check_eq(toJSONString(obj), JSONModule.toString(obj));
do_check_eq(JSONModule.fromString("true"), true);
do_check_eq(JSONModule.fromString("false"), false);
do_check_eq(JSONModule.fromString("1"), 1);
do_check_eq(JSONModule.fromString('"2.2"'), "2.2");
do_check_eq(JSONModule.fromString("1.23e-45"), 1.23e-45);
do_check_true(isInvalidSyntax("NaN"));
do_check_eq(JSONModule.fromString('"Foo-Bar \\b\\t\\n\\f\\r\\"\\\\ \\u0001\\u20ac"'),
"Foo-Bar \b\t\n\f\r\"\\ \x01\u20ac");
do_check_true(isInvalidSyntax('"multi\nline"'));
do_check_eq(JSONModule.fromString("null"), null);
do_check_true(isInvalidSyntax("."));
var res = JSONModule.fromString('[1,"2",3.3]');
do_check_eq(res.length, 3);
do_check_eq(res[2], 3.3);
// res is an instance of the sandbox's array
do_check_false(res instanceof Array);
res = JSONModule.fromString(toJSONString(obj));
do_check_eq(res.a, obj.a);
do_check_eq(res.b, obj.b);
do_check_eq(res.c.length, obj.c.length);
do_check_eq(res.c[0], obj.c[0]);
// those would throw on JSONModule.fromString if there's no object |a|
do_check_true(JSONModule.isMostlyHarmless("a"));
do_check_true(JSONModule.isMostlyHarmless("a[0]"));
do_check_true(JSONModule.isMostlyHarmless('a["alert(\\"P0wn3d!\\");"]'));
do_check_false(JSONModule.isMostlyHarmless('(function() { alert("P0wn3d!"); })()'));
do_check_false(JSONModule.isMostlyHarmless('{ get a() { return "P0wn3d!"; } }'));
}