From 250399c9230ea972f6bf374fb9951b6cb35320f2 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Fri, 6 Oct 2006 15:50:26 +0000 Subject: r19142: ensure no race conditions during installation by having same name in source and swat directory; install new apps and services (This used to be commit a2b996317f81aa61d7d5bf427003399560e64f77) --- jsonrpc/json.esp | 269 ----------------------- jsonrpc/json_auth.esp | 13 -- jsonrpc/jsondate.esp | 200 ----------------- jsonrpc/qooxdoo/test.esp | 236 --------------------- jsonrpc/request.esp | 483 ------------------------------------------ services/json.esp | 269 +++++++++++++++++++++++ services/json_auth.esp | 13 ++ services/jsondate.esp | 200 +++++++++++++++++ services/qooxdoo/test.esp | 236 +++++++++++++++++++++ services/request.esp | 483 ++++++++++++++++++++++++++++++++++++++++++ source4/script/installswat.sh | 12 ++ 11 files changed, 1213 insertions(+), 1201 deletions(-) delete mode 100644 jsonrpc/json.esp delete mode 100644 jsonrpc/json_auth.esp delete mode 100644 jsonrpc/jsondate.esp delete mode 100644 jsonrpc/qooxdoo/test.esp delete mode 100644 jsonrpc/request.esp create mode 100644 services/json.esp create mode 100644 services/json_auth.esp create mode 100644 services/jsondate.esp create mode 100644 services/qooxdoo/test.esp create mode 100644 services/request.esp diff --git a/jsonrpc/json.esp b/jsonrpc/json.esp deleted file mode 100644 index 6c59db0fca..0000000000 --- a/jsonrpc/json.esp +++ /dev/null @@ -1,269 +0,0 @@ -<% - -/* - * Copyright: - * (C) 2006 by Derrell Lipman - * All rights reserved - * - * License: - * LGPL 2.1: http://creativecommons.org/licenses/LGPL/2.1/ - */ - -/* - * This module provides a JSON encoder. - */ - - -/* escape a string as required by json */ -function _escape(s) -{ - var i; - var arr = new Array(); - - for (i = 0; i < strlen(s); i++) - { - var c = substr(s, i, 1); - if (c == '\x00') - { - arr[i] = '\\u0000'; - } - if (Json._internal.convert[c] != undefined) - { - arr[i] = Json._internal.convert[c]; - } - else - { - arr[i] = c; - } - } - - if (arr.length == 0) - { - return ""; - } - - return join("", arr); -} - -/* encode an arbitrary object. called recursively, for object and array */ -function _encode(o) -{ - var type = nativeTypeOf(o); - - if (type == "undefined") - { - return "null"; /* you really shouldn't count on this! */ - } - else if (type == "null") - { - return "null"; - } - else if (type == "boolean") - { - if (o) - { - return "true"; - } - else - { - return "false"; - } - } - else if (type == "c_function" || - type == "js_function" || - type == "string_c_function") - { - /* no output */ - } - else if (type == "float" || - type == "integer" || - type == "integer64") - { - return o + 0; - } - else if (type == "pointer") - { - var x = "" + o; - return '"' + substr(x, 16, strlen(x) - 16 - 1) + '"'; - } - else if (type == "object") - { - var buf; - - /* Is this an array or an ordinary object? */ - if (o["length"] != undefined) - { - var i; - - /* Assume it's an array if there's a length field */ - buf = "["; - for (i = 0; i < o.length; i++) - { - /* - * NOTE: We don't support sparse arrays nor associative - * arrays. Should we later want to do either, we're supposed - * to send it as an object rather than as an array. - */ - if (i > 0) - { - buf = buf + ","; - } - buf = buf + this.encode(o[i]); - } - buf = buf + "]"; - } - else if (o["__type"] == "_JSON_Date") - { - buf = "" + o.encoding(); - } - else - { - /* No length field, so it must be an ordinary object */ - var key; - var first = true; - - buf = "{"; - for (key in o) - { - if (! first) - { - buf = buf + ","; - } - buf = buf + '"' + key + '":' + this.encode(o[key]); - first = false; - } - buf = buf + "}"; - } - - return buf; - } - else if (type == "string") - { - return '"' + this._internal.escape(o) + '"'; - } - else - { - return '{ "unknown_object":"' + type + '"}'; - } -} - -/* Allocate the public Json access object */ -Json = new Object(); - -/* Json.encode(): encode an arbitrary object */ -Json.encode = _encode; -_encode = null; - -/* Json.decode(): decode a string into its object form */ -Json.decode = literal_to_var; - -/* Internal stuff, not for external access */ -Json._internal = new Object(); - -Json._internal.escape = _escape; -_escape = null; - -Json._internal.convert = new Object(); -Json._internal.convert['\b'] = '\\b'; -Json._internal.convert['\t'] = '\\t'; -Json._internal.convert['\n'] = '\\n'; -Json._internal.convert['\f'] = '\\f'; -Json._internal.convert['\r'] = '\\r'; -Json._internal.convert['"'] = '\\"'; -Json._internal.convert['\\'] = '\\\\'; -Json._internal.convert['\x01'] = '\\u0001'; -Json._internal.convert['\x02'] = '\\u0002'; -Json._internal.convert['\x03'] = '\\u0003'; -Json._internal.convert['\x04'] = '\\u0004'; -Json._internal.convert['\x05'] = '\\u0005'; -Json._internal.convert['\x06'] = '\\u0006'; -Json._internal.convert['\x07'] = '\\u0007'; -Json._internal.convert['\x08'] = '\\u0008'; -Json._internal.convert['\x09'] = '\\u0009'; -Json._internal.convert['\x0a'] = '\\u000a'; -Json._internal.convert['\x0b'] = '\\u000b'; -Json._internal.convert['\x0c'] = '\\u000c'; -Json._internal.convert['\x0d'] = '\\u000d'; -Json._internal.convert['\x0e'] = '\\u000e'; -Json._internal.convert['\x0f'] = '\\u000f'; -Json._internal.convert['\x10'] = '\\u0010'; -Json._internal.convert['\x11'] = '\\u0011'; -Json._internal.convert['\x12'] = '\\u0012'; -Json._internal.convert['\x13'] = '\\u0013'; -Json._internal.convert['\x14'] = '\\u0014'; -Json._internal.convert['\x15'] = '\\u0015'; -Json._internal.convert['\x16'] = '\\u0016'; -Json._internal.convert['\x17'] = '\\u0017'; -Json._internal.convert['\x18'] = '\\u0018'; -Json._internal.convert['\x19'] = '\\u0019'; -Json._internal.convert['\x1a'] = '\\u001a'; -Json._internal.convert['\x1b'] = '\\u001b'; -Json._internal.convert['\x1c'] = '\\u001c'; -Json._internal.convert['\x1d'] = '\\u001d'; -Json._internal.convert['\x1e'] = '\\u001e'; -Json._internal.convert['\x1f'] = '\\u001f'; -/* - * At some point, we probably want to add \x80-\xff as well, and it's then - * probably more efficient to generate these strings dynamically. (Even now - * it may be, but this was the the way I started, and so it remains.) - */ - - -/* Test it */ -/* -libinclude("base.js"); -function testFormat() -{ - var test = new Object(); - test.int = 23; - test.str = "hello world"; - test.float = 223.1; - test.bool = true; - test.array = new Array(); - test.array[0] = "hello"; - test.array[1] = "world"; - test.obj = new Object(); - test.obj.int = 1000; - test.obj.array = new Array(); - test.obj.array[0] = 42; - test.obj.array[1] = 223; - printf("%s\n", Json.encode(test)); -} -testFormat(); -*/ - -/* -libinclude("base.js"); -function testParse() -{ - var s; - - s = '{ "x" : 23 }'; - obj = Json.decode(s); - printf("Decode/encode of\n\t%s\nyielded\n\t%s\n\n", s, Json.encode(obj)); - - s = '{ "x" : [ 23, 42] }'; - obj = Json.decode(s); - printf("Decode/encode of\n\t%s\nyielded\n\t%s\n\n", s, Json.encode(obj)); - - s = '[ 13, 19, { "x" : [ 23, 42] }, 223 ]'; - obj = Json.decode(s); - printf("Decode/encode of\n\t%s\nyielded\n\t%s\n\n", s, Json.encode(obj)); - - s = '{ "x" : [ "hi" ] }'; - obj = Json.decode(s); - printf("Decode/encode of\n\t%s\nyielded\n\t%s\n\n", s, Json.encode(obj)); - - s = '[ 13, 19, { "x" : [ 23, 42, { "y":{"a":"hello", "b":"world", "c":[1,2,3]}}] }, 223 ]'; - obj = Json.decode(s); - printf("Decode/encode of\n\t%s\nyielded\n\t%s\n\n", s, Json.encode(obj)); -} -testParse(); -*/ - -/* - * Local Variables: - * mode: c - * End: - */ -%> diff --git a/jsonrpc/json_auth.esp b/jsonrpc/json_auth.esp deleted file mode 100644 index 2d58b6e2af..0000000000 --- a/jsonrpc/json_auth.esp +++ /dev/null @@ -1,13 +0,0 @@ -<% -/* Return true to allow access; false otherwise */ -function json_authenticate(serviceComponents, method) -{ - return true; -} - -/* - * Local Variables: - * mode: c - * End: - */ -%> diff --git a/jsonrpc/jsondate.esp b/jsonrpc/jsondate.esp deleted file mode 100644 index 3467228df6..0000000000 --- a/jsonrpc/jsondate.esp +++ /dev/null @@ -1,200 +0,0 @@ -<% -/* - * Copyright: - * (C) 2006 by Derrell Lipman - * All rights reserved - * - * License: - * LGPL 2.1: http://creativecommons.org/licenses/LGPL/2.1/ - */ - -/* - * Date class for JSON-RPC - */ - - -function _JSON_Date_create(secondsSinceEpoch) -{ - var o = new Object(); - o.__type = "_JSON_Date"; - - function _setUtcDateTimeFields(year, month, day, hour, minute, second, millisecond) - { - this.year = year + 0; - this.month = month + 0; - this.day = day + 0; - this.hour = hour + 0; - this.minute = minute + 0; - this.second = second + 0; - this.millisecond = millisecond + 0; - } - - o.setUtcYear = _setUtcDateTimeFields; - - function _setUtcYear(year) - { - this.year = year + 0; - } - o.setUtcYear = _setUtcYear; - - function _setUtcMonth(month) - { - this.month = month + 0; - } - o.setUtcMonth = _setUtcMonth; - - function _setUtcDay(day) - { - this.day = day + 0; - } - o.setUtcDay = _setUtcDay; - - function _setUtcHour(hour) - { - this.hour = hour + 0; - } - o.setUtcHour = _setUtcHour; - - function _setUtcMinute(minute) - { - this.minute = minute + 0; - } - o.setUtcMinute = _setUtcMinute; - - function _setUtcSecond(second) - { - this.second = second + 0; - } - o.setUtcSecond = _setUtcSecond; - - function _setUtcMillisecond(millisecond) - { - this.millisecond = millisecond + 0; - } - o.setUtcMillisecond = _setUtcMillisecond; - - function _setEpochTime(secondsSinceEpoch) - { - var microseconds = 0; - - if (typeof(secondsSinceEpoch) != "number") - { - var currentTime = gettimeofday(); - secondsSinceEpoch = currentTime.sec; - microseconds = currentTime.usec; - } - - var tm = gmtime(secondsSinceEpoch); - - this.year = 1900 + tm.tm_year; - this.month = tm.tm_mon; - this.day = tm.tm_mday; - this.hour = tm.tm_hour; - this.minute = tm.tm_min; - this.second = tm.tm_sec; - this.millisecond = 0; - } - o.setEpochTime = _setEpochTime; - - function _getUtcYear() - { - return this.year; - } - o.getUtcYear = _getUtcYear; - - function _getUtcMonth() - { - return this.month; - } - o.getUtcMonth = _getUtcMonth; - - function _getUtcDay() - { - return this.day; - } - o.getUtcDay = _getUtcDay; - - function _getUtcHour() - { - return this.hour; - } - o.getUtcHour = _getUtcHour; - - function _getUtcMinute() - { - return this.minute; - } - o.getUtcMinute = _getUtcMinute; - - function _getUtcSecond() - { - return this.second; - } - o.getUtcSecond = _getUtcSecond; - - function _getUtcMillisecond() - { - return this.millisecond; - } - o.getUtcMillisecond = _getUtcMillisecond; - - function _getEpochTime() - { - var tm = new Object(); - tm.tm_sec = this.second; - tm.tm_min = this.minute; - tm.tm_hour = this.hour; - tm.tm_mday = -1; - tm.tm_mon = this.month; - tm.tm_year = this.year; - tm.tm_wday = -1; - tm.tm_yday = -1; - tm.isdst = 0; - return gmmktime(tm); - } - o.getEpochTime = _getEpochTime; - - function _encoding() - { - /* Encode the date in a well-documented fashion */ - return sprintf("new Date(Date.UTC(%d,%d,%d,%d,%d,%d,%d))", - this.year, - this.month, - this.day, - this.hour, - this.minute, - this.second, - this.millisecond); - } - o.encoding = _encoding; - - if (! secondsSinceEpoch) - { - var now = gettimeofday(); - o.setEpochTime(now.sec); - } - else - { - o.setEpochTime(secondsSinceEpoch); - } - o.year = 0; - o.month = 0; - o.day = 0; - o.hour = 0; - o.minute = 0; - o.second = 0; - o.millisecond = 0; - return o; -} - -JSON_Date = new Object(); -JSON_Date.create = _JSON_Date_create; -_JSON_Date_create = null; - - -/* - * Local Variables: - * mode: c - * End: - */ -%> diff --git a/jsonrpc/qooxdoo/test.esp b/jsonrpc/qooxdoo/test.esp deleted file mode 100644 index e8686dcc25..0000000000 --- a/jsonrpc/qooxdoo/test.esp +++ /dev/null @@ -1,236 +0,0 @@ -<% -/* - * Copyright: - * (C) 2006 by Derrell Lipman - * All rights reserved - * - * License: - * LGPL 2.1: http://creativecommons.org/licenses/LGPL/2.1/ - */ - -/* - * This is the standard qooxdoo test class. There are tests for each of the - * primitive types here, along with standard named tests "echo", "sink" and - * "sleep". - */ - -/** - * Echo the (one and only) parameter. - * - * @param params - * An array containing the parameters to this method - * - * @param error - * An object of class JsonRpcError. - * - * @return - * Success: The object containing the result of the method; - * Failure: null - */ -function _echo(params, error) -{ - if (params.length != 1) - { - error.setError(JsonRpcError_ParameterMismatch, - "Expected 1 parameter; got " + params.length); - return error; - } - return "Client said: [" + params[0] + "]"; -} -jsonrpc.method.echo = _echo; - -/** - * Sink all data and never return. - * - * @param params - * An array containing the parameters to this method (none expected) - * - * @param error - * An object of class JsonRpcError. - * - * @return - * "Never" - */ -function _sink(params, error) -{ - /* We're never supposed to return. Just sleep for a very long time. */ - sleep(240); -} -jsonrpc.method.sink = _sink; - -/** - * Sleep for the number of seconds specified by the parameter. - * - * @param params - * An array containing the parameters to this method (one expected) - * - * @param error - * An object of class JsonRpcError. - * - * @return - * Success: The object containing the result of the method; - * Failure: null - */ -function _sleep(params, error) -{ - if (params.length != 1) - { - error.setError(JsonRpcError_ParameterMismatch, - "Expected 1 parameter; got " + params.length); - return error; - } - - sleep(params[0]); - return params[0]; -} -jsonrpc.method.sleep = _sleep; - -/*************************************************************************/ - -/* - * The remainder of the functions test each individual primitive type, and - * test echoing arbitrary types. Hopefully the name is self-explanatory. - */ - -function _getInteger(params, error) -{ - return 1; -} -jsonrpc.method.getInteger = _getInteger; - -function _getFloat(params, error) -{ - return 1/3; -} -jsonrpc.method.getFloat = _getFloat; - -function _getString(params, error) -{ - return "Hello world"; -} -jsonrpc.method.getString = _getString; - -function _getBadString(params, error) -{ - return ""; -} -jsonrpc.method.getBadString = _getBadString; - -function _getArrayInteger(params, error) -{ - return new Array(1, 2, 3, 4); -} -jsonrpc.method.getArrayInteger = _getArrayInteger; - -function _getArrayString(params, error) -{ - return new Array("one", "two", "three", "four"); -} -jsonrpc.method.getArrayString = _getArrayString; - -function _getObject(params, error) -{ - o = new Object(); // some arbitrary object - o.something = 23; - o.garbage = 'lkasjdff;lajsdfkl;sadf'; - return o; -} -jsonrpc.method.getObject = _getObject; - -function _getTrue(params, error) -{ - return true; -} -jsonrpc.method.getTrue = _getTrue; - -function _getFalse(params, error) -{ - return false; -} -jsonrpc.method.getFalse = _getFalse; - -function _getNull(params, error) -{ - return null; -} -jsonrpc.method.getNull = _getNull; - -function _isInteger(params, error) -{ - var type = nativeTypeOf(params[0]); - return type == "integer" || type == "integer64"; -} -jsonrpc.method.isInteger = _isInteger; - -function _isFloat(params, error) -{ - return nativeTypeOf(params[0]) == "float"; -} -jsonrpc.method.isFloat = _isFloat; - -function _isString(params, error) -{ - return nativeTypeOf(params[0]) == "string"; -} -jsonrpc.method.isString = _isString; - -function _isBoolean(params, error) -{ - return nativeTypeOf(params[0]) == "boolean"; -} -jsonrpc.method.isBoolean = _isBoolean; - -function _isArray(params, error) -{ - return nativeTypeOf(params[0]) == "object" && params.length != undefined; -} -jsonrpc.method.isArray = _isArray; - -function _isObject(params, error) -{ - return nativeTypeOf(params[0]) == "object"; -} -jsonrpc.method.isObject = _isObject; - -function _isNull(params, error) -{ - return nativeTypeOf(params[0]) == "null"; -} -jsonrpc.method.isNull = _isNull; - -function _getParams(params, error) -{ - return params; -} -jsonrpc.method.getParams = _getParams; - -function _getParam(params, error) -{ - return params[0]; -} -jsonrpc.method.getParam = _getParam; - -function _getCurrentTimestamp() -{ - now = gettimeofday(); - obj = new Object(); - obj.now = now.sec; - obj.json = JSON_Date.create(now); - return obj; -} -jsonrpc.method.getCurrentTimestamp = _getCurrentTimestamp; - -function _getError(params, error) -{ - error.setError(23, "This is an application-provided error"); - return error; -} -jsonrpc.method.getError = _getError; - - -/* - * Local Variables: - * mode: c - * End: - */ -%> diff --git a/jsonrpc/request.esp b/jsonrpc/request.esp deleted file mode 100644 index 1cd22a71a8..0000000000 --- a/jsonrpc/request.esp +++ /dev/null @@ -1,483 +0,0 @@ -<% - -/* - * Copyright: - * (C) 2006 by Derrell Lipman - * All rights reserved - * - * License: - * LGPL 2.1: http://creativecommons.org/licenses/LGPL/2.1/ - */ - -/* - * This is a simple JSON-RPC server. - */ - -/* Bring in the json format/parse functions */ -jsonrpc_include("json.esp"); - -/* Bring in the date class */ -jsonrpc_include("jsondate.esp"); - -/* Load the authentication script */ -jsonrpc_include("json_auth.esp"); - - -/* bring the string functions into the global frame */ -string_init(global); - -/* Bring the system functions into the global frame */ -sys_init(global); - -function printf() -{ - print(vsprintf(arguments)); -} - - -/* - * All of our manipulation of JSON RPC methods will be through this object. - * Each class of methods will assign to here, and all of the constants will - * also be in this object. - */ -jsonrpc = new Object(); -jsonrpc.Constant = new Object(); -jsonrpc.Constant.ErrorOrigin = new Object(); /* error origins */ -jsonrpc.Constant.ErrorCode = new Object(); /* server-generated error codes */ -jsonrpc.method = new Object(); /* methods available in requested class */ - - -/* - * ScriptTransport constants - */ -jsonrpc.Constant.ScriptTransport = new Object(); -jsonrpc.Constant.ScriptTransport.NotInUse = -1; - - -/* - * JSON-RPC error origin constants - */ -jsonrpc.Constant.ErrorOrigin.Server = 1; -jsonrpc.Constant.ErrorOrigin.Application = 2; -jsonrpc.Constant.ErrorOrigin.Transport = 3; -jsonrpc.Constant.ErrorOrigin.Client = 4; - - - -/* - * JSON-RPC server-generated error code constants - */ - -/** - * Error code, value 0: Unknown Error - * - * The default error code, used only when no specific error code is passed to - * the JsonRpcError constructor. This code should generally not be used. - */ -jsonrpc.Constant.ErrorCode.Unknown = 0; - -/** - * Error code, value 1: Illegal Service - * - * The service name contains illegal characters or is otherwise deemed - * unacceptable to the JSON-RPC server. - */ -jsonrpc.Constant.ErrorCode.IllegalService = 1; - -/** - * Error code, value 2: Service Not Found - * - * The requested service does not exist at the JSON-RPC server. - */ -jsonrpc.Constant.ErrorCode.ServiceNotFound = 2; - -/** - * Error code, value 3: Class Not Found - * - * If the JSON-RPC server divides service methods into subsets (classes), this - * indicates that the specified class was not found. This is slightly more - * detailed than "Method Not Found", but that error would always also be legal - * (and true) whenever this one is returned. (Not used in this implementation) - */ -jsonrpc.Constant.ErrorCode.ClassNotFound = 3; // not used in this implementation - -/** - * Error code, value 4: Method Not Found - * - * The method specified in the request is not found in the requested service. - */ -jsonrpc.Constant.ErrorCode.MethodNotFound = 4; - -/** - * Error code, value 5: Parameter Mismatch - * - * If a method discovers that the parameters (arguments) provided to it do not - * match the requisite types for the method's parameters, it should return - * this error code to indicate so to the caller. - */ -jsonrpc.Constant.ErrorCode.PaameterMismatch = 5; - -/** - * Error code, value 6: Permission Denied - * - * A JSON-RPC service provider can require authentication, and that - * authentication can be implemented such the method takes authentication - * parameters, or such that a method or class of methods requires prior - * authentication. If the caller has not properly authenticated to use the - * requested method, this error code is returned. - */ -jsonrpc.Constant.ErrorCode.PermissionDenied = 6; - -/* - * Error code, value 7: Unexpected Output - * - * The called method illegally generated output to the browser, which would - * have preceeded the JSON-RPC data. - */ -jsonrpc.Constant.ErrorCode.UnexpectedOutput = 7; - - - - - - - -function sendReply(reply, scriptTransportId) -{ - /* If not using ScriptTransport... */ - if (scriptTransportId == jsonrpc.Constant.ScriptTransport.NotInUse) - { - /* ... then just output the reply. */ - write(reply); - } - else - { - /* Otherwise, we need to add a call to a qooxdoo-specific function */ - reply = - "qx.io.remote.ScriptTransport._requestFinished(" + - scriptTransportId + ", " + reply + - ");"; - write(reply); - } -} - - -function _jsonValidRequest(req) -{ - if (req == undefined) - { - return false; - } - - if (typeof(req) != "object") - { - return false; - } - - if (req["id"] == undefined) - { - return false; - } - - if (req["service"] == undefined) - { - return false; - } - - if (req["method"] == undefined) - { - return false; - } - - if (req["params"] == undefined) - { - return false; - } - - return true; -} -jsonrpc.validRequest = _jsonValidRequest; -_jsonValidRequest = null; - -/* - * class JsonRpcError - * - * This class allows service methods to easily provide error information for - * return via JSON-RPC. - */ -function _JsonRpcError_create(origin, code, message) -{ - var o = new Object(); - - o.data = new Object(); - o.data.origin = origin; - o.data.code = code; - o.data.message = message; - o.scriptTransportId = jsonrpc.Constant.ScriptTransport.NotInUse; - o.__type = "_JsonRpcError"; - - function _origin(origin) - { - this.data.origin = origin; - } - o.setOrigin = _origin; - - function _setError(code, message) - { - this.data.code = code; - this.data.message = message; - } - o.setError = _setError; - - function _setId(id) - { - this.id = id; - } - o.setId = _setId; - - function _setScriptTransportId(id) - { - this.scriptTransportId = id; - } - o.setScriptTransportId = _setScriptTransportId; - - function _Send() - { - var error = this; - var id = this.id; - var ret = new Object(); - ret.error = this.data; - ret.id = this.id; - sendReply(Json.encode(ret), this.scriptTransportId); - } - o.Send = _Send; - - return o; -} - -jsonrpc.createError = _JsonRpcError_create; -_JsonRpcError_create = null; - -/* - * 'input' is the user-provided json-encoded request - * 'jsonInput' is that request, decoded into its object form - */ -var input; -var jsonInput = null; - -/* Allocate a generic error object */ -error = jsonrpc.createError(jsonrpc.Constant.ErrorOrigin.Server, - jsonrpc.Constant.ErrorCode.Unknown, - "Unknown error"); - -/* Assume (default) we're not using ScriptTransport */ -scriptTransportId = jsonrpc.Constant.ScriptTransport.NotInUse; - -/* What type of request did we receive? */ -if (request["REQUEST_METHOD"] == "POST" && - request["CONTENT_TYPE"] == "text/json") -{ - /* We found literal POSTed json-rpc data (we hope) */ - input = request["POST_DATA"]; - jsonInput = Json.decode(input); -} -else if (request["REQUEST_METHOD"] == "GET" && - form["_ScriptTransport_id"] != undefined && - form["_ScriptTransport_data"] != undefined) -{ - /* We have what looks like a valid ScriptTransport request */ - scriptTransportId = form["_ScriptTransport_id"]; - error.setScriptTransportId(scriptTransportId); - input = form["_ScriptTransport_data"]; - jsonInput = Json.decode(input); -} - -/* Ensure that this was a JSON-RPC service request */ -if (! jsonrpc.validRequest(jsonInput)) -{ - /* - * This request was not issued with JSON-RPC so echo the error rather than - * issuing a JsonRpcError response. - */ - write("JSON-RPC request expected; service, method or params missing
"); - return; -} - -/* - * Ok, it looks like JSON-RPC, so we'll return an Error object if we encounter - * errors from here on out. - */ -error.setId(jsonInput.id); - -/* Service and method names may contain these characters */ -var nameChars = - "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; - -/* The first letter of service and method names must be a letter */ -var nameFirstLetter = - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - -/* - * Ensure the method name is kosher. A meethod name should be: - * - * - first character is in [a-zA-Z] - * - other characters are in [_a-zA-Z0-9] - */ - -/* First check for legal characters */ -if (strspn(jsonInput.method, nameChars) != strlen(jsonInput.method)) -{ - /* There's some illegal character in the service name */ - error.setError(JsonRpcError.MethodNotFound, - "Illegal character found in method name."); - error.Send(); - return; -} - -/* Now ensure that it begins with a letter */ -if (strspn(substr(jsonInput.method, 0, 1), nameFirstLetter) != 1) -{ - error.setError(jsonrpc.Constant.ErrorCode.MethodNotFound, - "The method name does not begin with a letter"); - error.Send(); - return; -} - -/* - * Ensure the requested service name is kosher. A service name should be: - * - * - a dot-separated sequences of strings; no adjacent dots - * - first character of each string is in [a-zA-Z] - * - other characters are in [_a-zA-Z0-9] - */ - -/* First check for legal characters */ -if (strspn(jsonInput.service, "." + nameChars) != strlen(jsonInput.service)) -{ - /* There's some illegal character in the service name */ - error.setError(JsonRpcError.IllegalService, - "Illegal character found in service name."); - error.Send(); - return; -} - -/* - * Now ensure there are no double dots. - * - * Frustration with ejs. Result must be NULL, but we can't use the === - * operator: strstr() === null so we have to use typeof. If the result isn't - * null, then it'll be a number and therefore not type "pointer". - */ -if (typeof(strstr(jsonInput.service, "..")) != "pointer") -{ - error.setError(JsonRpcError.IllegalService, - "Illegal use of two consecutive dots in service name"); - error.Send(); - return; -} - -/* Explode the service name into its dot-separated parts */ -var serviceComponents = split(".", jsonInput.service); - -/* Ensure that each component begins with a letter */ -for (var i = 0; i < serviceComponents.length; i++) -{ - if (strspn(substr(serviceComponents[i], 0, 1), nameFirstLetter) != 1) - { - error.setError(jsonrpc.Constant.ErrorCode.IllegalService, - "A service name component does not begin with a letter"); - error.Send(); - return; - } -} - -/* - * Now replace all dots with slashes so we can locate the service script. We - * also retain the split components of the path, as the class name of the - * service is the last component of the path. - */ -var servicePath = join("/", serviceComponents) + ".esp"; - -/* Load the requested class */ -if (jsonrpc_include(servicePath)) -{ - /* Couldn't find the requested service */ - error.setError(jsonrpc.Constant.ErrorCode.ServiceNotFound, - "Service class `" + servicePath + "` does not exist."); - error.Send(); - return; -} - -/* - * Find the requested method. - * - * What we really want to do here, and could do in any reasonable language, - * is: - * - * method = jsonrpc.method[jsonInput.method]; - * if (method && typeof(method) == "function") ... - * - * The following completely unreasonable sequence of commands is because: - * - * (a) ejs evaluates all OR'ed expressions even if an early one is false, and - * barfs on the typeof(method) call if method is undefined - * - * (b) ejs does not allow comparing against the string "function"!!! What - * the hell is special about that particular string??? - * - * E-gad. What a mess. - */ -var method = jsonrpc.method[jsonInput.method]; -var valid = (method != undefined); -if (valid) -{ - var type = typeof(method); - if (substr(type, 0, 1) != 'f' || substr(type, 1) != "unction") - { - valid = false; - } -} - -if (! valid) -{ - error.setError(jsonrpc.Constant.ErrorCode.MethodNotFound, - "Method `" + method + "` not found."); - error.Send(); - return; -} - -/* Ensure the logged-in user is allowed to issue the requested method */ -if (! json_authenticate(serviceComponents, method)) -{ - error.setError(jsonrpc.Constant.ErrorCode.PermissionDenied, - "Permission denied"); - error.Send(); - return; -} - -/* Most errors from here on out will be Application-generated */ -error.setOrigin(jsonrpc.Constant.ErrorOrigin.Application); - -/* Call the requested method passing it the provided params */ -var retval = method(jsonInput.params, error); - -/* See if the result of the function was actually an error object */ -if (retval["__type"] == "_JsonRpcError") -{ - /* Yup, it was. Return the error */ - retval.Send(); - return; -} - -/* Give 'em what they came for! */ -var ret = new Object(); -ret.result = retval; -ret.id = jsonInput.id; -sendReply(Json.encode(ret), scriptTransportId); - -/* - * Local Variables: - * mode: c - * End: - */ -%> diff --git a/services/json.esp b/services/json.esp new file mode 100644 index 0000000000..6c59db0fca --- /dev/null +++ b/services/json.esp @@ -0,0 +1,269 @@ +<% + +/* + * Copyright: + * (C) 2006 by Derrell Lipman + * All rights reserved + * + * License: + * LGPL 2.1: http://creativecommons.org/licenses/LGPL/2.1/ + */ + +/* + * This module provides a JSON encoder. + */ + + +/* escape a string as required by json */ +function _escape(s) +{ + var i; + var arr = new Array(); + + for (i = 0; i < strlen(s); i++) + { + var c = substr(s, i, 1); + if (c == '\x00') + { + arr[i] = '\\u0000'; + } + if (Json._internal.convert[c] != undefined) + { + arr[i] = Json._internal.convert[c]; + } + else + { + arr[i] = c; + } + } + + if (arr.length == 0) + { + return ""; + } + + return join("", arr); +} + +/* encode an arbitrary object. called recursively, for object and array */ +function _encode(o) +{ + var type = nativeTypeOf(o); + + if (type == "undefined") + { + return "null"; /* you really shouldn't count on this! */ + } + else if (type == "null") + { + return "null"; + } + else if (type == "boolean") + { + if (o) + { + return "true"; + } + else + { + return "false"; + } + } + else if (type == "c_function" || + type == "js_function" || + type == "string_c_function") + { + /* no output */ + } + else if (type == "float" || + type == "integer" || + type == "integer64") + { + return o + 0; + } + else if (type == "pointer") + { + var x = "" + o; + return '"' + substr(x, 16, strlen(x) - 16 - 1) + '"'; + } + else if (type == "object") + { + var buf; + + /* Is this an array or an ordinary object? */ + if (o["length"] != undefined) + { + var i; + + /* Assume it's an array if there's a length field */ + buf = "["; + for (i = 0; i < o.length; i++) + { + /* + * NOTE: We don't support sparse arrays nor associative + * arrays. Should we later want to do either, we're supposed + * to send it as an object rather than as an array. + */ + if (i > 0) + { + buf = buf + ","; + } + buf = buf + this.encode(o[i]); + } + buf = buf + "]"; + } + else if (o["__type"] == "_JSON_Date") + { + buf = "" + o.encoding(); + } + else + { + /* No length field, so it must be an ordinary object */ + var key; + var first = true; + + buf = "{"; + for (key in o) + { + if (! first) + { + buf = buf + ","; + } + buf = buf + '"' + key + '":' + this.encode(o[key]); + first = false; + } + buf = buf + "}"; + } + + return buf; + } + else if (type == "string") + { + return '"' + this._internal.escape(o) + '"'; + } + else + { + return '{ "unknown_object":"' + type + '"}'; + } +} + +/* Allocate the public Json access object */ +Json = new Object(); + +/* Json.encode(): encode an arbitrary object */ +Json.encode = _encode; +_encode = null; + +/* Json.decode(): decode a string into its object form */ +Json.decode = literal_to_var; + +/* Internal stuff, not for external access */ +Json._internal = new Object(); + +Json._internal.escape = _escape; +_escape = null; + +Json._internal.convert = new Object(); +Json._internal.convert['\b'] = '\\b'; +Json._internal.convert['\t'] = '\\t'; +Json._internal.convert['\n'] = '\\n'; +Json._internal.convert['\f'] = '\\f'; +Json._internal.convert['\r'] = '\\r'; +Json._internal.convert['"'] = '\\"'; +Json._internal.convert['\\'] = '\\\\'; +Json._internal.convert['\x01'] = '\\u0001'; +Json._internal.convert['\x02'] = '\\u0002'; +Json._internal.convert['\x03'] = '\\u0003'; +Json._internal.convert['\x04'] = '\\u0004'; +Json._internal.convert['\x05'] = '\\u0005'; +Json._internal.convert['\x06'] = '\\u0006'; +Json._internal.convert['\x07'] = '\\u0007'; +Json._internal.convert['\x08'] = '\\u0008'; +Json._internal.convert['\x09'] = '\\u0009'; +Json._internal.convert['\x0a'] = '\\u000a'; +Json._internal.convert['\x0b'] = '\\u000b'; +Json._internal.convert['\x0c'] = '\\u000c'; +Json._internal.convert['\x0d'] = '\\u000d'; +Json._internal.convert['\x0e'] = '\\u000e'; +Json._internal.convert['\x0f'] = '\\u000f'; +Json._internal.convert['\x10'] = '\\u0010'; +Json._internal.convert['\x11'] = '\\u0011'; +Json._internal.convert['\x12'] = '\\u0012'; +Json._internal.convert['\x13'] = '\\u0013'; +Json._internal.convert['\x14'] = '\\u0014'; +Json._internal.convert['\x15'] = '\\u0015'; +Json._internal.convert['\x16'] = '\\u0016'; +Json._internal.convert['\x17'] = '\\u0017'; +Json._internal.convert['\x18'] = '\\u0018'; +Json._internal.convert['\x19'] = '\\u0019'; +Json._internal.convert['\x1a'] = '\\u001a'; +Json._internal.convert['\x1b'] = '\\u001b'; +Json._internal.convert['\x1c'] = '\\u001c'; +Json._internal.convert['\x1d'] = '\\u001d'; +Json._internal.convert['\x1e'] = '\\u001e'; +Json._internal.convert['\x1f'] = '\\u001f'; +/* + * At some point, we probably want to add \x80-\xff as well, and it's then + * probably more efficient to generate these strings dynamically. (Even now + * it may be, but this was the the way I started, and so it remains.) + */ + + +/* Test it */ +/* +libinclude("base.js"); +function testFormat() +{ + var test = new Object(); + test.int = 23; + test.str = "hello world"; + test.float = 223.1; + test.bool = true; + test.array = new Array(); + test.array[0] = "hello"; + test.array[1] = "world"; + test.obj = new Object(); + test.obj.int = 1000; + test.obj.array = new Array(); + test.obj.array[0] = 42; + test.obj.array[1] = 223; + printf("%s\n", Json.encode(test)); +} +testFormat(); +*/ + +/* +libinclude("base.js"); +function testParse() +{ + var s; + + s = '{ "x" : 23 }'; + obj = Json.decode(s); + printf("Decode/encode of\n\t%s\nyielded\n\t%s\n\n", s, Json.encode(obj)); + + s = '{ "x" : [ 23, 42] }'; + obj = Json.decode(s); + printf("Decode/encode of\n\t%s\nyielded\n\t%s\n\n", s, Json.encode(obj)); + + s = '[ 13, 19, { "x" : [ 23, 42] }, 223 ]'; + obj = Json.decode(s); + printf("Decode/encode of\n\t%s\nyielded\n\t%s\n\n", s, Json.encode(obj)); + + s = '{ "x" : [ "hi" ] }'; + obj = Json.decode(s); + printf("Decode/encode of\n\t%s\nyielded\n\t%s\n\n", s, Json.encode(obj)); + + s = '[ 13, 19, { "x" : [ 23, 42, { "y":{"a":"hello", "b":"world", "c":[1,2,3]}}] }, 223 ]'; + obj = Json.decode(s); + printf("Decode/encode of\n\t%s\nyielded\n\t%s\n\n", s, Json.encode(obj)); +} +testParse(); +*/ + +/* + * Local Variables: + * mode: c + * End: + */ +%> diff --git a/services/json_auth.esp b/services/json_auth.esp new file mode 100644 index 0000000000..2d58b6e2af --- /dev/null +++ b/services/json_auth.esp @@ -0,0 +1,13 @@ +<% +/* Return true to allow access; false otherwise */ +function json_authenticate(serviceComponents, method) +{ + return true; +} + +/* + * Local Variables: + * mode: c + * End: + */ +%> diff --git a/services/jsondate.esp b/services/jsondate.esp new file mode 100644 index 0000000000..3467228df6 --- /dev/null +++ b/services/jsondate.esp @@ -0,0 +1,200 @@ +<% +/* + * Copyright: + * (C) 2006 by Derrell Lipman + * All rights reserved + * + * License: + * LGPL 2.1: http://creativecommons.org/licenses/LGPL/2.1/ + */ + +/* + * Date class for JSON-RPC + */ + + +function _JSON_Date_create(secondsSinceEpoch) +{ + var o = new Object(); + o.__type = "_JSON_Date"; + + function _setUtcDateTimeFields(year, month, day, hour, minute, second, millisecond) + { + this.year = year + 0; + this.month = month + 0; + this.day = day + 0; + this.hour = hour + 0; + this.minute = minute + 0; + this.second = second + 0; + this.millisecond = millisecond + 0; + } + + o.setUtcYear = _setUtcDateTimeFields; + + function _setUtcYear(year) + { + this.year = year + 0; + } + o.setUtcYear = _setUtcYear; + + function _setUtcMonth(month) + { + this.month = month + 0; + } + o.setUtcMonth = _setUtcMonth; + + function _setUtcDay(day) + { + this.day = day + 0; + } + o.setUtcDay = _setUtcDay; + + function _setUtcHour(hour) + { + this.hour = hour + 0; + } + o.setUtcHour = _setUtcHour; + + function _setUtcMinute(minute) + { + this.minute = minute + 0; + } + o.setUtcMinute = _setUtcMinute; + + function _setUtcSecond(second) + { + this.second = second + 0; + } + o.setUtcSecond = _setUtcSecond; + + function _setUtcMillisecond(millisecond) + { + this.millisecond = millisecond + 0; + } + o.setUtcMillisecond = _setUtcMillisecond; + + function _setEpochTime(secondsSinceEpoch) + { + var microseconds = 0; + + if (typeof(secondsSinceEpoch) != "number") + { + var currentTime = gettimeofday(); + secondsSinceEpoch = currentTime.sec; + microseconds = currentTime.usec; + } + + var tm = gmtime(secondsSinceEpoch); + + this.year = 1900 + tm.tm_year; + this.month = tm.tm_mon; + this.day = tm.tm_mday; + this.hour = tm.tm_hour; + this.minute = tm.tm_min; + this.second = tm.tm_sec; + this.millisecond = 0; + } + o.setEpochTime = _setEpochTime; + + function _getUtcYear() + { + return this.year; + } + o.getUtcYear = _getUtcYear; + + function _getUtcMonth() + { + return this.month; + } + o.getUtcMonth = _getUtcMonth; + + function _getUtcDay() + { + return this.day; + } + o.getUtcDay = _getUtcDay; + + function _getUtcHour() + { + return this.hour; + } + o.getUtcHour = _getUtcHour; + + function _getUtcMinute() + { + return this.minute; + } + o.getUtcMinute = _getUtcMinute; + + function _getUtcSecond() + { + return this.second; + } + o.getUtcSecond = _getUtcSecond; + + function _getUtcMillisecond() + { + return this.millisecond; + } + o.getUtcMillisecond = _getUtcMillisecond; + + function _getEpochTime() + { + var tm = new Object(); + tm.tm_sec = this.second; + tm.tm_min = this.minute; + tm.tm_hour = this.hour; + tm.tm_mday = -1; + tm.tm_mon = this.month; + tm.tm_year = this.year; + tm.tm_wday = -1; + tm.tm_yday = -1; + tm.isdst = 0; + return gmmktime(tm); + } + o.getEpochTime = _getEpochTime; + + function _encoding() + { + /* Encode the date in a well-documented fashion */ + return sprintf("new Date(Date.UTC(%d,%d,%d,%d,%d,%d,%d))", + this.year, + this.month, + this.day, + this.hour, + this.minute, + this.second, + this.millisecond); + } + o.encoding = _encoding; + + if (! secondsSinceEpoch) + { + var now = gettimeofday(); + o.setEpochTime(now.sec); + } + else + { + o.setEpochTime(secondsSinceEpoch); + } + o.year = 0; + o.month = 0; + o.day = 0; + o.hour = 0; + o.minute = 0; + o.second = 0; + o.millisecond = 0; + return o; +} + +JSON_Date = new Object(); +JSON_Date.create = _JSON_Date_create; +_JSON_Date_create = null; + + +/* + * Local Variables: + * mode: c + * End: + */ +%> diff --git a/services/qooxdoo/test.esp b/services/qooxdoo/test.esp new file mode 100644 index 0000000000..e8686dcc25 --- /dev/null +++ b/services/qooxdoo/test.esp @@ -0,0 +1,236 @@ +<% +/* + * Copyright: + * (C) 2006 by Derrell Lipman + * All rights reserved + * + * License: + * LGPL 2.1: http://creativecommons.org/licenses/LGPL/2.1/ + */ + +/* + * This is the standard qooxdoo test class. There are tests for each of the + * primitive types here, along with standard named tests "echo", "sink" and + * "sleep". + */ + +/** + * Echo the (one and only) parameter. + * + * @param params + * An array containing the parameters to this method + * + * @param error + * An object of class JsonRpcError. + * + * @return + * Success: The object containing the result of the method; + * Failure: null + */ +function _echo(params, error) +{ + if (params.length != 1) + { + error.setError(JsonRpcError_ParameterMismatch, + "Expected 1 parameter; got " + params.length); + return error; + } + return "Client said: [" + params[0] + "]"; +} +jsonrpc.method.echo = _echo; + +/** + * Sink all data and never return. + * + * @param params + * An array containing the parameters to this method (none expected) + * + * @param error + * An object of class JsonRpcError. + * + * @return + * "Never" + */ +function _sink(params, error) +{ + /* We're never supposed to return. Just sleep for a very long time. */ + sleep(240); +} +jsonrpc.method.sink = _sink; + +/** + * Sleep for the number of seconds specified by the parameter. + * + * @param params + * An array containing the parameters to this method (one expected) + * + * @param error + * An object of class JsonRpcError. + * + * @return + * Success: The object containing the result of the method; + * Failure: null + */ +function _sleep(params, error) +{ + if (params.length != 1) + { + error.setError(JsonRpcError_ParameterMismatch, + "Expected 1 parameter; got " + params.length); + return error; + } + + sleep(params[0]); + return params[0]; +} +jsonrpc.method.sleep = _sleep; + +/*************************************************************************/ + +/* + * The remainder of the functions test each individual primitive type, and + * test echoing arbitrary types. Hopefully the name is self-explanatory. + */ + +function _getInteger(params, error) +{ + return 1; +} +jsonrpc.method.getInteger = _getInteger; + +function _getFloat(params, error) +{ + return 1/3; +} +jsonrpc.method.getFloat = _getFloat; + +function _getString(params, error) +{ + return "Hello world"; +} +jsonrpc.method.getString = _getString; + +function _getBadString(params, error) +{ + return ""; +} +jsonrpc.method.getBadString = _getBadString; + +function _getArrayInteger(params, error) +{ + return new Array(1, 2, 3, 4); +} +jsonrpc.method.getArrayInteger = _getArrayInteger; + +function _getArrayString(params, error) +{ + return new Array("one", "two", "three", "four"); +} +jsonrpc.method.getArrayString = _getArrayString; + +function _getObject(params, error) +{ + o = new Object(); // some arbitrary object + o.something = 23; + o.garbage = 'lkasjdff;lajsdfkl;sadf'; + return o; +} +jsonrpc.method.getObject = _getObject; + +function _getTrue(params, error) +{ + return true; +} +jsonrpc.method.getTrue = _getTrue; + +function _getFalse(params, error) +{ + return false; +} +jsonrpc.method.getFalse = _getFalse; + +function _getNull(params, error) +{ + return null; +} +jsonrpc.method.getNull = _getNull; + +function _isInteger(params, error) +{ + var type = nativeTypeOf(params[0]); + return type == "integer" || type == "integer64"; +} +jsonrpc.method.isInteger = _isInteger; + +function _isFloat(params, error) +{ + return nativeTypeOf(params[0]) == "float"; +} +jsonrpc.method.isFloat = _isFloat; + +function _isString(params, error) +{ + return nativeTypeOf(params[0]) == "string"; +} +jsonrpc.method.isString = _isString; + +function _isBoolean(params, error) +{ + return nativeTypeOf(params[0]) == "boolean"; +} +jsonrpc.method.isBoolean = _isBoolean; + +function _isArray(params, error) +{ + return nativeTypeOf(params[0]) == "object" && params.length != undefined; +} +jsonrpc.method.isArray = _isArray; + +function _isObject(params, error) +{ + return nativeTypeOf(params[0]) == "object"; +} +jsonrpc.method.isObject = _isObject; + +function _isNull(params, error) +{ + return nativeTypeOf(params[0]) == "null"; +} +jsonrpc.method.isNull = _isNull; + +function _getParams(params, error) +{ + return params; +} +jsonrpc.method.getParams = _getParams; + +function _getParam(params, error) +{ + return params[0]; +} +jsonrpc.method.getParam = _getParam; + +function _getCurrentTimestamp() +{ + now = gettimeofday(); + obj = new Object(); + obj.now = now.sec; + obj.json = JSON_Date.create(now); + return obj; +} +jsonrpc.method.getCurrentTimestamp = _getCurrentTimestamp; + +function _getError(params, error) +{ + error.setError(23, "This is an application-provided error"); + return error; +} +jsonrpc.method.getError = _getError; + + +/* + * Local Variables: + * mode: c + * End: + */ +%> diff --git a/services/request.esp b/services/request.esp new file mode 100644 index 0000000000..1cd22a71a8 --- /dev/null +++ b/services/request.esp @@ -0,0 +1,483 @@ +<% + +/* + * Copyright: + * (C) 2006 by Derrell Lipman + * All rights reserved + * + * License: + * LGPL 2.1: http://creativecommons.org/licenses/LGPL/2.1/ + */ + +/* + * This is a simple JSON-RPC server. + */ + +/* Bring in the json format/parse functions */ +jsonrpc_include("json.esp"); + +/* Bring in the date class */ +jsonrpc_include("jsondate.esp"); + +/* Load the authentication script */ +jsonrpc_include("json_auth.esp"); + + +/* bring the string functions into the global frame */ +string_init(global); + +/* Bring the system functions into the global frame */ +sys_init(global); + +function printf() +{ + print(vsprintf(arguments)); +} + + +/* + * All of our manipulation of JSON RPC methods will be through this object. + * Each class of methods will assign to here, and all of the constants will + * also be in this object. + */ +jsonrpc = new Object(); +jsonrpc.Constant = new Object(); +jsonrpc.Constant.ErrorOrigin = new Object(); /* error origins */ +jsonrpc.Constant.ErrorCode = new Object(); /* server-generated error codes */ +jsonrpc.method = new Object(); /* methods available in requested class */ + + +/* + * ScriptTransport constants + */ +jsonrpc.Constant.ScriptTransport = new Object(); +jsonrpc.Constant.ScriptTransport.NotInUse = -1; + + +/* + * JSON-RPC error origin constants + */ +jsonrpc.Constant.ErrorOrigin.Server = 1; +jsonrpc.Constant.ErrorOrigin.Application = 2; +jsonrpc.Constant.ErrorOrigin.Transport = 3; +jsonrpc.Constant.ErrorOrigin.Client = 4; + + + +/* + * JSON-RPC server-generated error code constants + */ + +/** + * Error code, value 0: Unknown Error + * + * The default error code, used only when no specific error code is passed to + * the JsonRpcError constructor. This code should generally not be used. + */ +jsonrpc.Constant.ErrorCode.Unknown = 0; + +/** + * Error code, value 1: Illegal Service + * + * The service name contains illegal characters or is otherwise deemed + * unacceptable to the JSON-RPC server. + */ +jsonrpc.Constant.ErrorCode.IllegalService = 1; + +/** + * Error code, value 2: Service Not Found + * + * The requested service does not exist at the JSON-RPC server. + */ +jsonrpc.Constant.ErrorCode.ServiceNotFound = 2; + +/** + * Error code, value 3: Class Not Found + * + * If the JSON-RPC server divides service methods into subsets (classes), this + * indicates that the specified class was not found. This is slightly more + * detailed than "Method Not Found", but that error would always also be legal + * (and true) whenever this one is returned. (Not used in this implementation) + */ +jsonrpc.Constant.ErrorCode.ClassNotFound = 3; // not used in this implementation + +/** + * Error code, value 4: Method Not Found + * + * The method specified in the request is not found in the requested service. + */ +jsonrpc.Constant.ErrorCode.MethodNotFound = 4; + +/** + * Error code, value 5: Parameter Mismatch + * + * If a method discovers that the parameters (arguments) provided to it do not + * match the requisite types for the method's parameters, it should return + * this error code to indicate so to the caller. + */ +jsonrpc.Constant.ErrorCode.PaameterMismatch = 5; + +/** + * Error code, value 6: Permission Denied + * + * A JSON-RPC service provider can require authentication, and that + * authentication can be implemented such the method takes authentication + * parameters, or such that a method or class of methods requires prior + * authentication. If the caller has not properly authenticated to use the + * requested method, this error code is returned. + */ +jsonrpc.Constant.ErrorCode.PermissionDenied = 6; + +/* + * Error code, value 7: Unexpected Output + * + * The called method illegally generated output to the browser, which would + * have preceeded the JSON-RPC data. + */ +jsonrpc.Constant.ErrorCode.UnexpectedOutput = 7; + + + + + + + +function sendReply(reply, scriptTransportId) +{ + /* If not using ScriptTransport... */ + if (scriptTransportId == jsonrpc.Constant.ScriptTransport.NotInUse) + { + /* ... then just output the reply. */ + write(reply); + } + else + { + /* Otherwise, we need to add a call to a qooxdoo-specific function */ + reply = + "qx.io.remote.ScriptTransport._requestFinished(" + + scriptTransportId + ", " + reply + + ");"; + write(reply); + } +} + + +function _jsonValidRequest(req) +{ + if (req == undefined) + { + return false; + } + + if (typeof(req) != "object") + { + return false; + } + + if (req["id"] == undefined) + { + return false; + } + + if (req["service"] == undefined) + { + return false; + } + + if (req["method"] == undefined) + { + return false; + } + + if (req["params"] == undefined) + { + return false; + } + + return true; +} +jsonrpc.validRequest = _jsonValidRequest; +_jsonValidRequest = null; + +/* + * class JsonRpcError + * + * This class allows service methods to easily provide error information for + * return via JSON-RPC. + */ +function _JsonRpcError_create(origin, code, message) +{ + var o = new Object(); + + o.data = new Object(); + o.data.origin = origin; + o.data.code = code; + o.data.message = message; + o.scriptTransportId = jsonrpc.Constant.ScriptTransport.NotInUse; + o.__type = "_JsonRpcError"; + + function _origin(origin) + { + this.data.origin = origin; + } + o.setOrigin = _origin; + + function _setError(code, message) + { + this.data.code = code; + this.data.message = message; + } + o.setError = _setError; + + function _setId(id) + { + this.id = id; + } + o.setId = _setId; + + function _setScriptTransportId(id) + { + this.scriptTransportId = id; + } + o.setScriptTransportId = _setScriptTransportId; + + function _Send() + { + var error = this; + var id = this.id; + var ret = new Object(); + ret.error = this.data; + ret.id = this.id; + sendReply(Json.encode(ret), this.scriptTransportId); + } + o.Send = _Send; + + return o; +} + +jsonrpc.createError = _JsonRpcError_create; +_JsonRpcError_create = null; + +/* + * 'input' is the user-provided json-encoded request + * 'jsonInput' is that request, decoded into its object form + */ +var input; +var jsonInput = null; + +/* Allocate a generic error object */ +error = jsonrpc.createError(jsonrpc.Constant.ErrorOrigin.Server, + jsonrpc.Constant.ErrorCode.Unknown, + "Unknown error"); + +/* Assume (default) we're not using ScriptTransport */ +scriptTransportId = jsonrpc.Constant.ScriptTransport.NotInUse; + +/* What type of request did we receive? */ +if (request["REQUEST_METHOD"] == "POST" && + request["CONTENT_TYPE"] == "text/json") +{ + /* We found literal POSTed json-rpc data (we hope) */ + input = request["POST_DATA"]; + jsonInput = Json.decode(input); +} +else if (request["REQUEST_METHOD"] == "GET" && + form["_ScriptTransport_id"] != undefined && + form["_ScriptTransport_data"] != undefined) +{ + /* We have what looks like a valid ScriptTransport request */ + scriptTransportId = form["_ScriptTransport_id"]; + error.setScriptTransportId(scriptTransportId); + input = form["_ScriptTransport_data"]; + jsonInput = Json.decode(input); +} + +/* Ensure that this was a JSON-RPC service request */ +if (! jsonrpc.validRequest(jsonInput)) +{ + /* + * This request was not issued with JSON-RPC so echo the error rather than + * issuing a JsonRpcError response. + */ + write("JSON-RPC request expected; service, method or params missing
"); + return; +} + +/* + * Ok, it looks like JSON-RPC, so we'll return an Error object if we encounter + * errors from here on out. + */ +error.setId(jsonInput.id); + +/* Service and method names may contain these characters */ +var nameChars = + "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + +/* The first letter of service and method names must be a letter */ +var nameFirstLetter = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +/* + * Ensure the method name is kosher. A meethod name should be: + * + * - first character is in [a-zA-Z] + * - other characters are in [_a-zA-Z0-9] + */ + +/* First check for legal characters */ +if (strspn(jsonInput.method, nameChars) != strlen(jsonInput.method)) +{ + /* There's some illegal character in the service name */ + error.setError(JsonRpcError.MethodNotFound, + "Illegal character found in method name."); + error.Send(); + return; +} + +/* Now ensure that it begins with a letter */ +if (strspn(substr(jsonInput.method, 0, 1), nameFirstLetter) != 1) +{ + error.setError(jsonrpc.Constant.ErrorCode.MethodNotFound, + "The method name does not begin with a letter"); + error.Send(); + return; +} + +/* + * Ensure the requested service name is kosher. A service name should be: + * + * - a dot-separated sequences of strings; no adjacent dots + * - first character of each string is in [a-zA-Z] + * - other characters are in [_a-zA-Z0-9] + */ + +/* First check for legal characters */ +if (strspn(jsonInput.service, "." + nameChars) != strlen(jsonInput.service)) +{ + /* There's some illegal character in the service name */ + error.setError(JsonRpcError.IllegalService, + "Illegal character found in service name."); + error.Send(); + return; +} + +/* + * Now ensure there are no double dots. + * + * Frustration with ejs. Result must be NULL, but we can't use the === + * operator: strstr() === null so we have to use typeof. If the result isn't + * null, then it'll be a number and therefore not type "pointer". + */ +if (typeof(strstr(jsonInput.service, "..")) != "pointer") +{ + error.setError(JsonRpcError.IllegalService, + "Illegal use of two consecutive dots in service name"); + error.Send(); + return; +} + +/* Explode the service name into its dot-separated parts */ +var serviceComponents = split(".", jsonInput.service); + +/* Ensure that each component begins with a letter */ +for (var i = 0; i < serviceComponents.length; i++) +{ + if (strspn(substr(serviceComponents[i], 0, 1), nameFirstLetter) != 1) + { + error.setError(jsonrpc.Constant.ErrorCode.IllegalService, + "A service name component does not begin with a letter"); + error.Send(); + return; + } +} + +/* + * Now replace all dots with slashes so we can locate the service script. We + * also retain the split components of the path, as the class name of the + * service is the last component of the path. + */ +var servicePath = join("/", serviceComponents) + ".esp"; + +/* Load the requested class */ +if (jsonrpc_include(servicePath)) +{ + /* Couldn't find the requested service */ + error.setError(jsonrpc.Constant.ErrorCode.ServiceNotFound, + "Service class `" + servicePath + "` does not exist."); + error.Send(); + return; +} + +/* + * Find the requested method. + * + * What we really want to do here, and could do in any reasonable language, + * is: + * + * method = jsonrpc.method[jsonInput.method]; + * if (method && typeof(method) == "function") ... + * + * The following completely unreasonable sequence of commands is because: + * + * (a) ejs evaluates all OR'ed expressions even if an early one is false, and + * barfs on the typeof(method) call if method is undefined + * + * (b) ejs does not allow comparing against the string "function"!!! What + * the hell is special about that particular string??? + * + * E-gad. What a mess. + */ +var method = jsonrpc.method[jsonInput.method]; +var valid = (method != undefined); +if (valid) +{ + var type = typeof(method); + if (substr(type, 0, 1) != 'f' || substr(type, 1) != "unction") + { + valid = false; + } +} + +if (! valid) +{ + error.setError(jsonrpc.Constant.ErrorCode.MethodNotFound, + "Method `" + method + "` not found."); + error.Send(); + return; +} + +/* Ensure the logged-in user is allowed to issue the requested method */ +if (! json_authenticate(serviceComponents, method)) +{ + error.setError(jsonrpc.Constant.ErrorCode.PermissionDenied, + "Permission denied"); + error.Send(); + return; +} + +/* Most errors from here on out will be Application-generated */ +error.setOrigin(jsonrpc.Constant.ErrorOrigin.Application); + +/* Call the requested method passing it the provided params */ +var retval = method(jsonInput.params, error); + +/* See if the result of the function was actually an error object */ +if (retval["__type"] == "_JsonRpcError") +{ + /* Yup, it was. Return the error */ + retval.Send(); + return; +} + +/* Give 'em what they came for! */ +var ret = new Object(); +ret.result = retval; +ret.id = jsonInput.id; +sendReply(Json.encode(ret), scriptTransportId); + +/* + * Local Variables: + * mode: c + * End: + */ +%> diff --git a/source4/script/installswat.sh b/source4/script/installswat.sh index 4304e3e490..72dfc2f456 100644 --- a/source4/script/installswat.sh +++ b/source4/script/installswat.sh @@ -19,6 +19,7 @@ installdir() { done } +installdir `find . -name '*.html'` installdir `find . -name '*.js'` installdir `find . -name '*.esp'` installdir `find . -name '*.css'` @@ -33,5 +34,16 @@ The swat files have been installed. ====================================================================== EOF +cd $SRCDIR/.. || exit 1 + +installdir `find services -name '*.esp'` + +cat << EOF +====================================================================== +The JSON-RPC services have been installed. +====================================================================== +EOF + + exit 0 -- cgit