# HG changeset patch # User jbe # Date 1420765040 -3600 # Node ID c6ef9991b9116f63d5d41e57eb998c57fd18d39e # Parent eceb6f56e9ed85d5c35c6ba0e85812feabaa6475 Removed CGI support; Created draft for new MCP program to be used with "Moonbridge Network Server for Lua Applications" diff -r eceb6f56e9ed -r c6ef9991b911 Makefile --- a/Makefile Mon Aug 25 20:00:01 2014 +0200 +++ b/Makefile Fri Jan 09 01:57:20 2015 +0100 @@ -30,7 +30,6 @@ ln -s -f ../../libraries/mondelefant/mondelefant_native.so framework/lib/ ln -s -f ../../libraries/mondelefant/mondelefant_atom_connector.lua framework/lib/ ln -s -f ../../libraries/multirand/multirand.so framework/lib/ - ln -s -f ../../libraries/rocketcgi/rocketcgi.lua framework/lib/ ln -s -f ../../libraries/nihil/nihil.lua framework/lib/ ln -s -f ../../libraries/luatex/luatex.lua framework/lib/ diff -r eceb6f56e9ed -r c6ef9991b911 framework/bin/mcp.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/framework/bin/mcp.lua Fri Jan 09 01:57:20 2015 +0100 @@ -0,0 +1,420 @@ +#!/usr/bin/env moonbridge + +WEBMCP_VERSION = "2.0.0_devel" + +-- check if interactive mode +if listen then -- defined by moonbridge + WEBMCP_MODE = "listen" +else + WEBMCP_MODE = "interactive" +end + +-- store extra command line arguments +local extraargs = {select(3, ...)} + +-- determine framework and bath path from command line arguments +-- or print usage synopsis (if applicable) +do + local arg1, arg2 = ... + local helpout + if + arg1 == "-h" or arg1 == "--help" or + arg2 == "-h" or arg2 == "--help" + then + helpout = io.stdout + elseif + (WEBMCP_MODE == "listen" and (#extraargs < 2 or #extraargs % 2 ~= 0)) or + (WEBMCP_MODE == "interactive" and arg2 == nil) + then + helpout = io.stderr + end + helpout:write("Usage: moonbridge -- mcp.lua [ ...]\n") + helpout:write(" or: lua -i mcp.lua []\n") + if helpout then + if helpout == io.stderr then + return 1 + else + return 0 + end + end + local function append_trailing_slash(str) + return string.sub(str, "([^/])$", function(last) return last .. "/" end) + end + WEBMCP_FRAMEWORK_PATH = append_trailing_slash(arg1) + WEBMCP_BASE_PATH = append_trailing_slash(arg2) +end + +-- setup search paths for libraries +do + package.path = WEBMCP_FRAMEWORK_PATH .. "lib/?.lua;" .. package.path + -- find out which file name extension shared libraries have + local slib_exts = {} + for ext in string.gmatch(package.cpath, "%?%.([A-Za-z0-9_-]+)") do + slib_exts[ext] = true + end + local paths = {} + for ext in pairs(slib_exts) do + paths[#paths+1] = WEBMCP_FRAMEWORK_PATH .. "accelerator/?." .. ext + end + for ext in pairs(slib_exts) do + paths[#paths+1] = WEBMCP_FRAMEWORK_PATH .. "lib/?." .. ext + end + paths[#paths+1] = package.cpath + package.cpath = table.concat(paths, ";") +end + +-- autoloader system for WebMCP environment "$WEBMCP_FRAMEWORK_PATH/env/", +-- application environment extensions "$WEBMCP_BASE_PATH/env/" +-- and models "$WEBMCP_BASE_PATH/model/" +do + local weakkey_mt = { __mode = "k" } + local autoloader_category = setmetatable({}, weakkey_mt) + local autoloader_path = setmetatable({}, weakkey_mt) + local autoloader_mt = {} + local function install_autoloader(self, category, path) + autoloader_category[self] = category + autoloader_path[self] = path + setmetatable(self, autoloader_mt) + end + local function try_exec(filename) + local file = io.open(filename, "r") + if file then + local filedata = file:read("*a") + io.close(file) + local func, errmsg = load(filedata, "=" .. filename) + if func then + func() + return true + else + error(errmsg, 0) + end + else + return false + end + end + local function compose_path_string(base, path, key) + if #path == 0 then + return base .. "/" .. key + else + return base .. table.concat(path, "/") .. "/" .. key + end + end + function autoloader_mt.__index(self, key) + local category, base_path, merge_base_path, file_key + local merge = false + if + string.find(key, "^[a-z_][A-Za-z0-9_]*$") and + not string.find(key, "^__") + then + category = "env" + base_path = WEBMCP_FRAMEWORK_PATH .. "env/" + merge = true + merge_base_path = WEBMCP_BASE_PATH .. "env/" + file_key = key + elseif string.find(key, "^[A-Z][A-Za-z0-9]*$") then + category = "model" + base_path = WEBMCP_BASE_PATH .. "model/" + local first = true + file_key = string.gsub(key, "[A-Z]", + function(c) + if first then + first = false + return string.lower(c) + else + return "_" .. string.lower(c) + end + end + ) + else + return + end + local required_category = autoloader_category[self] + if required_category and required_category ~= category then return end + local path = autoloader_path[self] + local path_string = compose_path_string(base_path, path, file_key) + local merge_path_string + if merge then + merge_path_string = compose_path_string( + merge_base_path, path, file_key + ) + end + local function try_dir(dirname) + local dir = io.open(dirname) + if dir then + io.close(dir) + local obj = {} + local sub_path = {} + for i = 1, #path do sub_path[i] = path[i] end + sub_path[#path+1] = file_key + install_autoloader(obj, category, sub_path) + rawset(self, key, obj) + try_exec(path_string .. "/__init.lua") + if merge then try_exec(merge_path_string .. "/__init.lua") end + return true + else + return false + end + end + if merge and try_exec(merge_path_string .. ".lua") then + elseif merge and try_dir(merge_path_string .. "/") then + elseif try_exec(path_string .. ".lua") then + elseif try_dir(path_string .. "/") then + else end + return rawget(self, key) + end + install_autoloader(_G, nil, {}) + try_exec(WEBMCP_FRAMEWORK_PATH .. "env/__init.lua") + try_exec(WEBMCP_BASE_PATH .. "env/__init.lua") +end + +-- prohibit (unintended) definition of new global variables +_ENV = setmetatable({}, { + __index = _G, + __newindex = function() + error("Setting of global variable prohibited") + end +}) + +-- interactive console mode +if WEBMCP_MODE == "interactive" then + trace.disable() -- avoids memory leakage (TODO: needs general solution for moonbridge?) + local config_name = select(3, ...) + if config_name then + execute.config(config_name) + end + return +end + +-- TODO: moonbridge support below this line and in env/request and env/slot + +local success, error_info = xpcall( + function() + + -- execute configuration file + do + local config_name = request.get_config_name() + if config_name then + execute.config(config_name) + end + end + + -- restore slots if coming from http redirect + if cgi.params.tempstore then + trace.restore_slots{} + local blob = tempstore.pop(cgi.params.tempstore) + if blob then slot.restore_all(blob) end + end + + local function file_exists(filename) + local file = io.open(filename, "r") + if file then + io.close(file) + return true + else + return false + end + end + + if request.is_404() then + request.set_status("404 Not Found") + if request.get_404_route() then + request.forward(request.get_404_route()) + else + error("No 404 page set.") + end + elseif request.get_action() then + trace.request{ + module = request.get_module(), + action = request.get_action() + } + if + request.get_404_route() and + not file_exists( + encode.action_file_path{ + module = request.get_module(), + action = request.get_action() + } + ) + then + request.set_status("404 Not Found") + request.forward(request.get_404_route()) + else + if cgi.method ~= "POST" then + request.set_status("405 Method Not Allowed") + cgi.add_header("Allow: POST") + error("Tried to invoke an action with a GET request.") + end + local action_status = execute.filtered_action{ + module = request.get_module(), + action = request.get_action(), + } + if not request.is_rerouted() then + local routing_mode, routing_module, routing_view + routing_mode = cgi.params["_webmcp_routing." .. action_status .. ".mode"] + routing_module = cgi.params["_webmcp_routing." .. action_status .. ".module"] + routing_view = cgi.params["_webmcp_routing." .. action_status .. ".view"] + routing_anchor = cgi.params["_webmcp_routing." .. action_status .. ".anchor"] + if not (routing_mode or routing_module or routing_view) then + action_status = "default" + routing_mode = cgi.params["_webmcp_routing.default.mode"] + routing_module = cgi.params["_webmcp_routing.default.module"] + routing_view = cgi.params["_webmcp_routing.default.view"] + routing_anchor = cgi.params["_webmcp_routing.default.anchor"] + end + assert(routing_module, "Routing information has no module.") + assert(routing_view, "Routing information has no view.") + if routing_mode == "redirect" then + local routing_params = {} + for key, value in pairs(cgi.params) do + local status, stripped_key = string.match( + key, "^_webmcp_routing%.([^%.]*)%.params%.(.*)$" + ) + if status == action_status then + routing_params[stripped_key] = value + end + end + request.redirect{ + module = routing_module, + view = routing_view, + id = cgi.params["_webmcp_routing." .. action_status .. ".id"], + params = routing_params, + anchor = routing_anchor + } + elseif routing_mode == "forward" then + request.forward{ module = routing_module, view = routing_view } + else + error("Missing or unknown routing mode in request parameters.") + end + end + end + else + -- no action + trace.request{ + module = request.get_module(), + view = request.get_view() + } + if + request.get_404_route() and + not file_exists( + encode.view_file_path{ + module = request.get_module(), + view = request.get_view() + } + ) + then + request.set_status("404 Not Found") + request.forward(request.get_404_route()) + end + end + + if not request.get_redirect_data() then + request.process_forward() + local view = request.get_view() + if string.find(view, "^_") then + error("Tried to call a private view (prefixed with underscore).") + end + execute.filtered_view{ + module = request.get_module(), + view = view, + } + end + + -- force error due to missing absolute base URL until its too late to display error message + --if request.get_redirect_data() then + -- request.get_absolute_baseurl() + --end + + end, + + function(errobj) + return { + errobj = errobj, + stacktrace = string.gsub( + debug.traceback('', 2), + "^\r?\n?stack traceback:\r?\n?", "" + ) + } + end +) + +if not success then trace.error{} end + +-- laufzeitermittlung +trace.exectime{ real = extos.monotonic_hires_time(), cpu = os.clock() } + +slot.select('trace', trace.render) -- render trace information + +local redirect_data = request.get_redirect_data() + +-- log error and switch to error layout, unless success +if not success then + local errobj = error_info.errobj + local stacktrace = error_info.stacktrace + if not request.get_status() and not request.get_json_request_slots() then + request.set_status("500 Internal Server Error") + end + slot.set_layout('system_error') + slot.select('system_error', function() + if getmetatable(errobj) == mondelefant.errorobject_metatable then + slot.put( + "

Database error of class ", + encode.html(errobj.code), + " occured:
", + encode.html(errobj.message), + "

" + ) + else + slot.put("

", encode.html(tostring(errobj)), "

") + end + slot.put("

Stack trace follows:
") + slot.put(encode.html_newlines(encode.html(stacktrace))) + slot.put("

") + end) +elseif redirect_data then + local redirect_params = {} + for key, value in pairs(redirect_data.params) do + redirect_params[key] = value + end + local slot_dump = slot.dump_all() + if slot_dump ~= "" then + redirect_params.tempstore = tempstore.save(slot_dump) + end + local json_request_slots = request.get_json_request_slots() + if json_request_slots then + redirect_params["_webmcp_json_slots[]"] = json_request_slots + end + cgi.redirect( + encode.url{ + base = request.get_absolute_baseurl(), + module = redirect_data.module, + view = redirect_data.view, + id = redirect_data.id, + params = redirect_params, + anchor = redirect_data.anchor + } + ) + cgi.send_data() +end + +if not success or not redirect_data then + + local http_status = request.get_status() + if http_status then + cgi.set_status(http_status) + end + + local json_request_slots = request.get_json_request_slots() + if json_request_slots then + cgi.set_content_type('application/json') + local data = {} + for idx, slot_ident in ipairs(json_request_slots) do + data[slot_ident] = slot.get_content(slot_ident) + end + cgi.send_data(encode.json(data)) + else + cgi.set_content_type(slot.get_content_type()) + cgi.send_data(slot.render_layout()) + end +end + +exit() diff -r eceb6f56e9ed -r c6ef9991b911 framework/cgi-bin/webmcp-wrapper.lua --- a/framework/cgi-bin/webmcp-wrapper.lua Mon Aug 25 20:00:01 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -#!/usr/bin/env lua - -local func, errmsg = loadfile('webmcp.lua') - -if func then - local result - result, errmsg = pcall(func) - if result then - errmsg = nil - end -end - -if errmsg and not (cgi and cgi.data_sent) then - print('Status: 500 Internal Server Error') - print('Content-type: text/plain') - print() - print('500 Internal Server Error') - print() - print(errmsg) - print() - print('(caught by webmcp-wrapper.lua)') - os.exit(1) -end diff -r eceb6f56e9ed -r c6ef9991b911 framework/cgi-bin/webmcp.lua --- a/framework/cgi-bin/webmcp.lua Mon Aug 25 20:00:01 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,489 +0,0 @@ -#!/usr/bin/env lua - -_WEBMCP_VERSION = "1.2.6" - --- Lua 5.1 compatibility -if not table.unpack then - table.unpack = unpack -end -do - local old_load = load - function load(ld, ...) - if type(ld) == "string" then - local done = false - local func = function() - if not done then - done = true - return ld - end - end - return old_load(func, ...) - else - return old_load(ld, ...) - end - end -end - --- include "../lib/" in search path for libraries -if not WEBMCP_PATH then - WEBMCP_PATH = "../" -end -do - package.path = WEBMCP_PATH .. 'lib/?.lua;' .. package.path - -- find out which file name extension shared libraries have - local slib_exts = {} - for ext in string.gmatch(package.cpath, "%?%.([A-Za-z0-9_-]+)") do - slib_exts[ext] = true - end - local paths = {} - for ext in pairs(slib_exts) do - paths[#paths+1] = WEBMCP_PATH .. "accelerator/?." .. ext - end - for ext in pairs(slib_exts) do - paths[#paths+1] = WEBMCP_PATH .. "lib/?." .. ext - end - paths[#paths+1] = package.cpath - package.cpath = table.concat(paths, ";") -end - --- load os extensions for lua --- (should happen as soon as possible due to run time measurement) -extos = require 'extos' - --- load nihil library -nihil = require 'nihil' - --- load random generator library -multirand = require 'multirand' - --- load rocketcgi library and map it to cgi, unless interactive -do - local option = os.getenv("WEBMCP_INTERACTIVE") - if option and option ~= "" and option ~= "0" then - cgi = nil - else - rocketcgi = require 'rocketcgi' -- TODO: no "rocketcgi" alias - cgi = rocketcgi - end -end - --- load database access library with object relational mapper -mondelefant = require 'mondelefant' -mondelefant.connection_prototype.error_objects = true - --- load type system "atom" -atom = require 'atom' - --- load JSON library -json = require 'json' - --- load mondelefant atom connector -require 'mondelefant_atom_connector' - ---[[-- -cloned_table = -- newly generated table -table.new( - table_or_nil -- keys of a given table will be copied to the new table -) - -If a table is given, then a cloned table is returned. -If nil is given, then a new empty table is returned. - ---]]-- -function table.new(tbl) - new_tbl = {} - if tbl then - for key, value in pairs(tbl) do - new_tbl[key] = value - end - end - return new_tbl -end ---//-- - ---[[-- -at_exit( - func -- function to be called before the process is ending -) - -Registers a function to be called before the CGI process is exiting. ---]]-- -do - local exit_handlers = {} - function at_exit(func) - table.insert(exit_handlers, func) - end - function exit(code) - for i = #exit_handlers, 1, -1 do - exit_handlers[i]() - end - os.exit(code) - end -end ---//-- - ---[[-- -app -- table to store an application state - -'app' is a global table for storing any application state data ---]]-- -app = {} ---//-- - ---[[-- -config -- table to store application configuration - -'config' is a global table, which can be modified by a config file of an application to modify the behaviour of that application. ---]]-- -config = {} ---//-- - --- autoloader system for WebMCP environment "../env/", --- application environment extensions "$WEBMCP_APP_BASE/env/" --- and models "$WEBMCP_APP_BASE/model/" -do - local app_base = os.getenv("WEBMCP_APP_BASEPATH") - if not app_base then - error( - "Failed to initialize autoloader " .. - "due to unset WEBMCP_APP_BASEPATH environment variable." - ) - end - local weakkey_mt = { __mode = "k" } - local autoloader_category = setmetatable({}, weakkey_mt) - local autoloader_path = setmetatable({}, weakkey_mt) - local autoloader_mt = {} - local function install_autoloader(self, category, path) - autoloader_category[self] = category - autoloader_path[self] = path - setmetatable(self, autoloader_mt) - end - local function try_exec(filename) - local file = io.open(filename, "r") - if file then - local filedata = file:read("*a") - io.close(file) - local func, errmsg = load(filedata, "=" .. filename) - if func then - func() - return true - else - error(errmsg, 0) - end - else - return false - end - end - local function compose_path_string(base, path, key) - return string.gsub( - base .. table.concat(path, "/") .. "/" .. key, "/+", "/" - ) - end - function autoloader_mt.__index(self, key) - local category, base_path, merge_base_path, file_key - local merge = false - if - string.find(key, "^[a-z_][A-Za-z0-9_]*$") and - not string.find(key, "^__") - then - category = "env" - base_path = WEBMCP_PATH .. "/env/" - merge = true - merge_base_path = app_base .. "/env/" - file_key = key - elseif string.find(key, "^[A-Z][A-Za-z0-9]*$") then - category = "model" - base_path = app_base .. "/model/" - local first = true - file_key = string.gsub(key, "[A-Z]", - function(c) - if first then - first = false - return string.lower(c) - else - return "_" .. string.lower(c) - end - end - ) - else - return - end - local required_category = autoloader_category[self] - if required_category and required_category ~= category then return end - local path = autoloader_path[self] - local path_string = compose_path_string(base_path, path, file_key) - local merge_path_string - if merge then - merge_path_string = compose_path_string( - merge_base_path, path, file_key - ) - end - local function try_dir(dirname) - local dir = io.open(dirname) - if dir then - io.close(dir) - local obj = {} - local sub_path = {} - for i, v in ipairs(path) do sub_path[i] = v end - table.insert(sub_path, file_key) - install_autoloader(obj, category, sub_path) - rawset(self, key, obj) - try_exec(path_string .. "/__init.lua") - if merge then try_exec(merge_path_string .. "/__init.lua") end - return true - else - return false - end - end - if merge and try_exec(merge_path_string .. ".lua") then - elseif merge and try_dir(merge_path_string .. "/") then - elseif try_exec(path_string .. ".lua") then - elseif try_dir(path_string .. "/") then - else end - return rawget(self, key) - end - install_autoloader(_G, nil, {}) - try_exec(WEBMCP_PATH .. "env/__init.lua") -end - --- interactive console mode -if not cgi then - trace.disable() -- avoids memory leakage - local config_name = request.get_config_name() - if config_name then - execute.config(config_name) - end - return -end - -local success, error_info = xpcall( - function() - - -- execute configuration file - do - local config_name = request.get_config_name() - if config_name then - execute.config(config_name) - end - end - - -- restore slots if coming from http redirect - if cgi.params.tempstore then - trace.restore_slots{} - local blob = tempstore.pop(cgi.params.tempstore) - if blob then slot.restore_all(blob) end - end - - local function file_exists(filename) - local file = io.open(filename, "r") - if file then - io.close(file) - return true - else - return false - end - end - - if request.is_404() then - request.set_status("404 Not Found") - if request.get_404_route() then - request.forward(request.get_404_route()) - else - error("No 404 page set.") - end - elseif request.get_action() then - trace.request{ - module = request.get_module(), - action = request.get_action() - } - if - request.get_404_route() and - not file_exists( - encode.action_file_path{ - module = request.get_module(), - action = request.get_action() - } - ) - then - request.set_status("404 Not Found") - request.forward(request.get_404_route()) - else - if cgi.method ~= "POST" then - request.set_status("405 Method Not Allowed") - cgi.add_header("Allow: POST") - error("Tried to invoke an action with a GET request.") - end - local action_status = execute.filtered_action{ - module = request.get_module(), - action = request.get_action(), - } - if not request.is_rerouted() then - local routing_mode, routing_module, routing_view - routing_mode = cgi.params["_webmcp_routing." .. action_status .. ".mode"] - routing_module = cgi.params["_webmcp_routing." .. action_status .. ".module"] - routing_view = cgi.params["_webmcp_routing." .. action_status .. ".view"] - routing_anchor = cgi.params["_webmcp_routing." .. action_status .. ".anchor"] - if not (routing_mode or routing_module or routing_view) then - action_status = "default" - routing_mode = cgi.params["_webmcp_routing.default.mode"] - routing_module = cgi.params["_webmcp_routing.default.module"] - routing_view = cgi.params["_webmcp_routing.default.view"] - routing_anchor = cgi.params["_webmcp_routing.default.anchor"] - end - assert(routing_module, "Routing information has no module.") - assert(routing_view, "Routing information has no view.") - if routing_mode == "redirect" then - local routing_params = {} - for key, value in pairs(cgi.params) do - local status, stripped_key = string.match( - key, "^_webmcp_routing%.([^%.]*)%.params%.(.*)$" - ) - if status == action_status then - routing_params[stripped_key] = value - end - end - request.redirect{ - module = routing_module, - view = routing_view, - id = cgi.params["_webmcp_routing." .. action_status .. ".id"], - params = routing_params, - anchor = routing_anchor - } - elseif routing_mode == "forward" then - request.forward{ module = routing_module, view = routing_view } - else - error("Missing or unknown routing mode in request parameters.") - end - end - end - else - -- no action - trace.request{ - module = request.get_module(), - view = request.get_view() - } - if - request.get_404_route() and - not file_exists( - encode.view_file_path{ - module = request.get_module(), - view = request.get_view() - } - ) - then - request.set_status("404 Not Found") - request.forward(request.get_404_route()) - end - end - - if not request.get_redirect_data() then - request.process_forward() - local view = request.get_view() - if string.find(view, "^_") then - error("Tried to call a private view (prefixed with underscore).") - end - execute.filtered_view{ - module = request.get_module(), - view = view, - } - end - - -- force error due to missing absolute base URL until its too late to display error message - --if request.get_redirect_data() then - -- request.get_absolute_baseurl() - --end - - end, - - function(errobj) - return { - errobj = errobj, - stacktrace = string.gsub( - debug.traceback('', 2), - "^\r?\n?stack traceback:\r?\n?", "" - ) - } - end -) - -if not success then trace.error{} end - --- laufzeitermittlung -trace.exectime{ real = extos.monotonic_hires_time(), cpu = os.clock() } - -slot.select('trace', trace.render) -- render trace information - -local redirect_data = request.get_redirect_data() - --- log error and switch to error layout, unless success -if not success then - local errobj = error_info.errobj - local stacktrace = error_info.stacktrace - if not request.get_status() and not request.get_json_request_slots() then - request.set_status("500 Internal Server Error") - end - slot.set_layout('system_error') - slot.select('system_error', function() - if getmetatable(errobj) == mondelefant.errorobject_metatable then - slot.put( - "

Database error of class ", - encode.html(errobj.code), - " occured:
", - encode.html(errobj.message), - "

" - ) - else - slot.put("

", encode.html(tostring(errobj)), "

") - end - slot.put("

Stack trace follows:
") - slot.put(encode.html_newlines(encode.html(stacktrace))) - slot.put("

") - end) -elseif redirect_data then - local redirect_params = {} - for key, value in pairs(redirect_data.params) do - redirect_params[key] = value - end - local slot_dump = slot.dump_all() - if slot_dump ~= "" then - redirect_params.tempstore = tempstore.save(slot_dump) - end - local json_request_slots = request.get_json_request_slots() - if json_request_slots then - redirect_params["_webmcp_json_slots[]"] = json_request_slots - end - cgi.redirect( - encode.url{ - base = request.get_absolute_baseurl(), - module = redirect_data.module, - view = redirect_data.view, - id = redirect_data.id, - params = redirect_params, - anchor = redirect_data.anchor - } - ) - cgi.send_data() -end - -if not success or not redirect_data then - - local http_status = request.get_status() - if http_status then - cgi.set_status(http_status) - end - - local json_request_slots = request.get_json_request_slots() - if json_request_slots then - cgi.set_content_type('application/json') - local data = {} - for idx, slot_ident in ipairs(json_request_slots) do - data[slot_ident] = slot.get_content(slot_ident) - end - cgi.send_data(encode.json(data)) - else - cgi.set_content_type(slot.get_content_type()) - cgi.send_data(slot.render_layout()) - end -end - -exit() diff -r eceb6f56e9ed -r c6ef9991b911 framework/env/__init.lua --- a/framework/env/__init.lua Mon Aug 25 20:00:01 2014 +0200 +++ b/framework/env/__init.lua Fri Jan 09 01:57:20 2015 +0100 @@ -1,3 +1,4 @@ +-- string localization function function _(text, replacements) local text = locale._get_translation_table()[text] or text if replacements then @@ -14,3 +15,35 @@ return text end end + +--[[-- +cloned_table = -- newly generated table +table.new( + table_or_nil -- keys of a given table will be copied to the new table +) + +If a table is given, then a cloned table is returned. +If nil is given, then a new empty table is returned. + +--]]-- +function table.new(tbl) + new_tbl = {} + if tbl then + for key, value in pairs(tbl) do + new_tbl[key] = value + end + end + return new_tbl +end +--//-- + +-- load libraries +extos = require 'extos' +nihil = require 'nihil' +multirand = require 'multirand' +mondelefant = require 'mondelefant' +mondelefant.connection_prototype.error_objects = true +atom = require 'atom' +json = require 'json' +require 'mondelefant_atom_connector' + diff -r eceb6f56e9ed -r c6ef9991b911 libraries/rocketcgi/rocketcgi.lua --- a/libraries/rocketcgi/rocketcgi.lua Mon Aug 25 20:00:01 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,313 +0,0 @@ -#!/usr/bin/env lua - -local assert = assert -local collectgarbage = collectgarbage -local error = error -local getmetatable = getmetatable -local ipairs = ipairs -local next = next -local pairs = pairs -local print = print -local rawequal = rawequal -local rawget = rawget -local rawlen = rawlen -local rawset = rawset -local select = select -local setmetatable = setmetatable -local tonumber = tonumber -local tostring = tostring -local type = type - -local io = io -local math = math -local os = os -local string = string -local table = table - -local _M = {} -if _ENV then - _ENV = _M -else - _G[...] = _M - setfenv(1, _M) -end - -data_sent = false - ---[[-- -rocketcgi.add_header( - string_part1, -- string - string_part2, -- optional second part of string to be concatted - ... -) - -Sends a header line to the browser. Multiple arguments are concatted to form a single string. - ---]]-- -function add_header(...) - if data_sent then - error("Can not add header after data has been sent.", 2) - end - io.stdout:write(...) - io.stdout:write("\r\n") -end ---//-- - ---[[-- -rocketcgi.send_data( - string_part1, -- string - string_part2, -- optional second part of string to be concatted - ... -) - -Sends document data to the browser. Multiple arguments are concatted to form a single string. - ---]]-- -function send_data(...) - if not data_sent then - io.stdout:write("\r\n") - data_sent = true - end - io.stdout:write(...) -end ---//-- - ---[[-- -rocketcgi.set_status( - status -- Status code and description, e.g. "404 Not Found" -) - -Sends a header line to the browser, indicating a given HTTP status. - ---]]-- -function set_status(status) - add_header("Status: ", status) -end ---//-- - ---[[-- -rocketcgi.redirect( - status -- Absolute URL to redirect the browser to -) - -Redirects the browser to the given absolute URL, using a 303 Redirect. - ---]]-- -function redirect(location) - set_status("303 See Other") - add_header("Location: ", location) -end ---//-- - ---[[-- -rocketcgi.set_content_type( - content_type -- MIME content type -) - -Sends a header line specifying the content-type to the browser. - ---]]-- -function set_content_type(content_type) - add_header("Content-Type: ", content_type) -end ---//-- - ---[[-- -rocketcgi.set_cookie{ - name = name, -- name of cookie - value = value, -- value of cookie - domain = domain, -- domain where cookie is transmitted - path = path, -- path where cookie is transmitted - secure = secure -- boolean, indicating if cookie should only be transmitted over HTTPS -} - -Sends a header line setting a cookie. NOTE: Currently only session cookies are supported. - ---]]-- -function set_cookie(args) - assert(string.find(args.name, "^[0-9A-Za-z%%._~-]+$"), "Illegal cookie name") - assert(string.find(args.value, "^[0-9A-Za-z%%._~-]+$"), "Illegal cookie value") - local parts = {"Set-Cookie: " .. args.name .. "=" .. args.value} - if args.domain then - assert( - string.find(args.path, "^[0-9A-Za-z%%/._~-]+$"), - "Illegal cookie domain" - ) - parts[#parts+1] = "domain=" .. args.domain - end - if args.path then - assert( - string.find(args.path, "^[0-9A-Za-z%%/._~-]+$"), - "Illegal cookie path" - ) - parts[#parts+1] = "path=" .. args.path - end - if args.secure then - parts[#parts+1] = "secure" - end - add_header(table.concat(parts, "; ")) -end ---//-- - -method = os.getenv("REQUEST_METHOD") or false -query = os.getenv("QUERY_STRING") or false -cookie_data = os.getenv("HTTP_COOKIE") or false -post_data = io.stdin:read("*a") or false -post_contenttype = os.getenv("CONTENT_TYPE") or false -params = {} -get_params = {} -cookies = {} -post_params = {} -post_filenames = {} -post_types = {} - -local urldecode -do - local b0 = string.byte("0") - local b9 = string.byte("9") - local bA = string.byte("A") - local bF = string.byte("F") - local ba = string.byte("a") - local bf = string.byte("f") - function urldecode(str) - return ( - string.gsub( - string.gsub(str, "%+", " "), - "%%([0-9A-Fa-f][0-9A-Fa-f])", - function(hex) - local n1, n2 = string.byte(hex, 1, 2) - if n1 >= b0 and n1 <= b9 then n1 = n1 - b0 - elseif n1 >= bA and n1 <= bF then n1 = n1 - bA + 10 - elseif n1 >= ba and n1 <= bf then n1 = n1 - ba + 10 - else return end - if n2 >= b0 and n2 <= b9 then n2 = n2 - b0 - elseif n2 >= bA and n2 <= bF then n2 = n2 - bA + 10 - elseif n2 >= ba and n2 <= bf then n2 = n2 - ba + 10 - else return end - return string.char(n1 * 16 + n2) - end - ) - ) - end -end - -local function proc_param(tbl, key, value) - if string.find(key, "%[%]$") then - if tbl[key] then - table.insert(tbl[key], value) - else - local list = { value } - params[key] = list - tbl[key] = list - end - else - params[key] = value - tbl[key] = value - end -end - -local function read_urlencoded_form(tbl, data) - for rawkey, rawvalue in string.gmatch(data, "([^=&]*)=([^=&]*)") do - proc_param(tbl, urldecode(rawkey), urldecode(rawvalue)) - end -end - -if query then - read_urlencoded_form(get_params, query) -end - -if cookie_data then - for rawkey, rawvalue in string.gmatch(cookie_data, "([^=; ]*)=([^=; ]*)") do - cookies[urldecode(rawkey)] = urldecode(rawvalue) - end -end - -if post_contenttype and ( - post_contenttype == "application/x-www-form-urlencoded" or - string.match(post_contenttype, "^application/x%-www%-form%-urlencoded[ ;]") -) then - read_urlencoded_form(post_params, post_data) -elseif post_contenttype then - local boundary = string.match( - post_contenttype, - '^multipart/form%-data[ \t]*;[ \t]*boundary="([^"]+)"' - ) or string.match( - post_contenttype, - '^multipart/form%-data[ \t]*;[ \t]*boundary=([^"; \t]+)' - ) - if boundary then - local parts = {} - do - local boundary = "\r\n--" .. boundary - local post_data = "\r\n" .. post_data - local pos1, pos2 = string.find(post_data, boundary, 1, true) - while true do - local ind = string.sub(post_data, pos2 + 1, pos2 + 2) - if ind == "\r\n" then - local pos3, pos4 = string.find(post_data, boundary, pos2 + 1, true) - if pos3 then - parts[#parts + 1] = string.sub(post_data, pos2 + 3, pos3 - 1) - else - error("Illegal POST data.") - end - pos1, pos2 = pos3, pos4 - elseif ind == "--" then - break - else - error("Illegal POST data.") - end - end - end - for i, part in ipairs(parts) do - local pos = 1 - local name, filename, contenttype - while true do - local header - do - local oldpos = pos - pos = string.find(part, "\r\n", oldpos, true) - if not pos then - error("Illegal POST data.") - end - if pos == oldpos then break end - header = string.sub(part, oldpos, pos - 1) - pos = pos + 2 - end - if string.find( - string.lower(header), - "^content%-disposition:[ \t]*form%-data[ \t]*;" - ) then - -- TODO: handle all cases correctly - name = string.match(header, ';[ \t]*name="([^"]*)"') or - string.match(header, ';[ \t]*name=([^"; \t]+)') - filename = string.match(header, ';[ \t]*filename="([^"]*)"') or - string.match(header, ';[ \t]*filename=([^"; \t]+)') - else - local dummy, subpos = string.find( - string.lower(header), - "^content%-type:[ \t]*" - ) - if subpos then - contenttype = string.sub(header, subpos + 1, #header) - end - end - end - local content = string.sub(part, pos + 2, #part) - if not name then - error("Illegal POST data.") - end - proc_param(post_params, name, content) - post_filenames[name] = filename - post_types[name] = contenttype - end - end -end - -if post_data and #post_data > 262144 then - post_data = nil - collectgarbage("collect") -else - --post_data = nil --allow access to "post_data" for usual requests -end - -return _M