-- lib/supple/request.lua -- -- Sandbox (for) Untrusted Procedure Partitioning (in) Lua Engine -- -- Request/response serialisation/deserialisation including contextual object -- management and organisation. -- -- Copyright 2012 Daniel Silverstone -- -- For licence terms, see COPYING -- local capi = require 'supple.capi' local objects = require 'supple.objects' local tconcat = table.concat local ipairs = ipairs local select = select local loadstring = loadstring local load = load local setfenv = setfenv local function serialise_error(errstr, traceback) return tconcat { "error=true,", ("message=%q,"):format(errstr), ("traceback=%q"):format(traceback) } end local function _serialise_object(obj, ret) ret[#ret+1] = "{" local comma = "" if obj.type then ret[#ret+1] = ("type=%q"):format(obj.type) comma = "," end ret[#ret+1] = ("%stag=%q"):format(comma, obj.tag) if obj.methods then ret[#ret+1] = ",methods={" comma = "" for _, meth in ipairs(obj.methods) do ret[#ret+1] = ("%s%q"):format(comma, meth) comma = "," end ret[#ret+1] = "}" end ret[#ret+1] = "}" end local function serialise_request(obj, method, ...) assert(capi.rawtype(obj) == "string") assert(capi.rawtype(method) == "string") local args = { n = select("#", ...), ... } local ret = { ("object=%q,"):format(obj), ("method=%q,"):format(method), ("args={n=%d"):format(args.n) } for i = 1, args.n do local v = objects.give(args[i]) if capi.rawtype(v) == "string" then ret[#ret+1] = (",%q"):format(v) elseif capi.rawtype(v) == "table" then ret[#ret+1] = "," _serialise_object(v, ret) else ret[#ret+1] = "," .. tostring(v) end end ret[#ret+1] = "}" return tconcat(ret) end local function serialise_response(...) local args = { n = select("#", ...), ... } local ret = { "error=false,", ("results={n=%d"):format(args.n) } for i = 1, args.n do local v = objects.give(args[i]) if capi.rawtype(v) == "string" then ret[#ret+1] = (",%q"):format(v) elseif capi.rawtype(v) == "table" then ret[#ret+1] = "," _serialise_object(v, ret) else ret[#ret+1] = "," .. tostring(v) end end ret[#ret+1] = "}" return tconcat(ret) end local function deserialise_entity(entity) local str = ("return {%s}"):format(entity) local fn if setfenv ~= nil then fn = setfenv(assert(loadstring(str, "@supple-transfer")), {}) else fn = load(str, "@supple-transfer", "t", {}) end local res = fn() local walk = res.args or res.results if walk then assert(walk.n, "Elements missing 'n'") for i = 1, walk.n do walk[i] = objects.receive(walk[i]) end end return res end return { error = serialise_error, request = serialise_request, response = serialise_response, deserialise = deserialise_entity, }