diff options
Diffstat (limited to 'share/server/util.js')
-rw-r--r-- | share/server/util.js | 150 |
1 files changed, 84 insertions, 66 deletions
diff --git a/share/server/util.js b/share/server/util.js index bd4abc1d..b55480b9 100644 --- a/share/server/util.js +++ b/share/server/util.js @@ -10,22 +10,80 @@ // License for the specific language governing permissions and limitations under // the License. +var resolveModule = function(names, mod, root) { + if (names.length == 0) { + if (typeof mod.current != "string") { + throw ["error","invalid_require_path", + 'Must require a JavaScript string, not: '+(typeof mod.current)]; + } + return { + current : mod.current, + parent : mod.parent, + id : mod.id, + exports : {} + } + } + // we need to traverse the path + var n = names.shift(); + if (n == '..') { + if (!(mod.parent && mod.parent.parent)) { + throw ["error", "invalid_require_path", 'Object has no parent '+JSON.stringify(mod.current)]; + } + return resolveModule(names, { + id : mod.id.slice(0, mod.id.lastIndexOf('/')), + parent : mod.parent.parent.parent, + current : mod.parent.parent.current + }); + } else if (n == '.') { + if (!mod.parent) { + throw ["error", "invalid_require_path", 'Object has no parent '+JSON.stringify(mod.current)]; + } + return resolveModule(names, { + parent : mod.parent.parent, + current : mod.parent.current, + id : mod.id + }); + } else if (root) { + mod = {current : root}; + } + if (!mod.current[n]) { + throw ["error", "invalid_require_path", 'Object has no property "'+n+'". '+JSON.stringify(mod.current)]; + } + return resolveModule(names, { + current : mod.current[n], + parent : mod, + id : mod.id ? mod.id + '/' + n : n + }); +}; + var Couch = { // moving this away from global so we can move to json2.js later toJSON : function (val) { - if (typeof(val) == "undefined") { - throw "Cannot encode 'undefined' value as JSON"; - } - if (typeof(val) == "xml") { // E4X support - val = val.toXMLString(); - } - if (val === null) { return "null"; } - return (Couch.toJSON.dispatcher[val.constructor.name])(val); + return JSON.stringify(val); }, - compileFunction : function(source) { + compileFunction : function(source, ddoc) { if (!source) throw(["error","not_found","missing function"]); try { - var functionObject = sandbox ? evalcx(source, sandbox) : eval(source); + if (sandbox) { + if (ddoc) { + var require = function(name, module) { + module = module || {}; + var newModule = resolveModule(name.split('/'), module, ddoc); + var s = "function (module, exports, require) { " + newModule.current + " }"; + try { + var func = sandbox ? evalcx(s, sandbox) : eval(s); + func.apply(sandbox, [newModule, newModule.exports, function(name) {return require(name, newModule)}]); + } catch(e) { + throw ["error","compilation_error","Module require('"+name+"') raised error "+e.toSource()]; + } + return newModule.exports; + } + sandbox.require = require; + } + var functionObject = evalcx(source, sandbox); + } else { + var functionObject = eval(source); + } } catch (err) { throw(["error", "compilation_error", err.toSource() + " (" + source + ")"]); }; @@ -38,64 +96,20 @@ var Couch = { }, recursivelySeal : function(obj) { // seal() is broken in current Spidermonkey - seal(obj); + try { + seal(obj); + } catch (x) { + // Sealing of arrays broken in some SpiderMonkey versions. + // https://bugzilla.mozilla.org/show_bug.cgi?id=449657 + } for (var propname in obj) { - if (typeof doc[propname] == "object") { - recursivelySeal(doc[propname]); + if (typeof obj[propname] == "object") { + arguments.callee(obj[propname]); } } } } -Couch.toJSON.subs = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', - '\r': '\\r', '"' : '\\"', '\\': '\\\\'}; -Couch.toJSON.dispatcher = { - "Array": function(v) { - var buf = []; - for (var i = 0; i < v.length; i++) { - buf.push(Couch.toJSON(v[i])); - } - return "[" + buf.join(",") + "]"; - }, - "Boolean": function(v) { - return v.toString(); - }, - "Date": function(v) { - var f = function(n) { return n < 10 ? '0' + n : n }; - return '"' + v.getUTCFullYear() + '-' + - f(v.getUTCMonth() + 1) + '-' + - f(v.getUTCDate()) + 'T' + - f(v.getUTCHours()) + ':' + - f(v.getUTCMinutes()) + ':' + - f(v.getUTCSeconds()) + 'Z"'; - }, - "Number": function(v) { - return isFinite(v) ? v.toString() : "null"; - }, - "Object": function(v) { - //if (v === null) return "null"; - var buf = []; - for (var k in v) { - if (!v.hasOwnProperty(k) || typeof(k) !== "string" || v[k] === undefined) { - continue; - } - buf.push(Couch.toJSON(k) + ": " + Couch.toJSON(v[k])); - } - return "{" + buf.join(",") + "}"; - }, - "String": function(v) { - if (/["\\\x00-\x1f]/.test(v)) { - v = v.replace(/([\x00-\x1f\\"])/g, function(a, b) { - var c = Couch.toJSON.subs[b]; - if (c) return c; - c = b.charCodeAt(); - return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16); - }); - } - return '"' + v + '"'; - } -}; - // prints the object as JSON, and rescues and logs any toJSON() related errors function respond(obj) { try { @@ -107,11 +121,15 @@ function respond(obj) { }; function log(message) { - // return; // idea: query_server_config option for log level - if (typeof message == "undefined") { - message = "Error: attempting to log message of 'undefined'."; + // idea: query_server_config option for log level + if (typeof message == "xml") { + message = message.toXMLString(); } else if (typeof message != "string") { message = Couch.toJSON(message); } - respond(["log", message]); + respond(["log", String(message)]); }; + +function isArray(obj) { + return toString.call(obj) === "[object Array]"; +} |