webmcp
changeset 203:c6ef9991b911
Removed CGI support; Created draft for new MCP program to be used with "Moonbridge Network Server for Lua Applications"
author | jbe |
---|---|
date | Fri Jan 09 01:57:20 2015 +0100 (2015-01-09) |
parents | eceb6f56e9ed |
children | b059efd81649 |
files | Makefile framework/bin/mcp.lua framework/cgi-bin/webmcp-wrapper.lua framework/cgi-bin/webmcp.lua framework/env/__init.lua libraries/rocketcgi/rocketcgi.lua |
line diff
1.1 --- a/Makefile Mon Aug 25 20:00:01 2014 +0200 1.2 +++ b/Makefile Fri Jan 09 01:57:20 2015 +0100 1.3 @@ -30,7 +30,6 @@ 1.4 ln -s -f ../../libraries/mondelefant/mondelefant_native.so framework/lib/ 1.5 ln -s -f ../../libraries/mondelefant/mondelefant_atom_connector.lua framework/lib/ 1.6 ln -s -f ../../libraries/multirand/multirand.so framework/lib/ 1.7 - ln -s -f ../../libraries/rocketcgi/rocketcgi.lua framework/lib/ 1.8 ln -s -f ../../libraries/nihil/nihil.lua framework/lib/ 1.9 ln -s -f ../../libraries/luatex/luatex.lua framework/lib/ 1.10
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/framework/bin/mcp.lua Fri Jan 09 01:57:20 2015 +0100 2.3 @@ -0,0 +1,420 @@ 2.4 +#!/usr/bin/env moonbridge 2.5 + 2.6 +WEBMCP_VERSION = "2.0.0_devel" 2.7 + 2.8 +-- check if interactive mode 2.9 +if listen then -- defined by moonbridge 2.10 + WEBMCP_MODE = "listen" 2.11 +else 2.12 + WEBMCP_MODE = "interactive" 2.13 +end 2.14 + 2.15 +-- store extra command line arguments 2.16 +local extraargs = {select(3, ...)} 2.17 + 2.18 +-- determine framework and bath path from command line arguments 2.19 +-- or print usage synopsis (if applicable) 2.20 +do 2.21 + local arg1, arg2 = ... 2.22 + local helpout 2.23 + if 2.24 + arg1 == "-h" or arg1 == "--help" or 2.25 + arg2 == "-h" or arg2 == "--help" 2.26 + then 2.27 + helpout = io.stdout 2.28 + elseif 2.29 + (WEBMCP_MODE == "listen" and (#extraargs < 2 or #extraargs % 2 ~= 0)) or 2.30 + (WEBMCP_MODE == "interactive" and arg2 == nil) 2.31 + then 2.32 + helpout = io.stderr 2.33 + end 2.34 + helpout:write("Usage: moonbridge -- mcp.lua <framework path> <app base path> <app name 1> <config name 1> [<app name 2> <config name 2> ...]\n") 2.35 + helpout:write(" or: lua -i mcp.lua <framework path> <app base path> [<config name>]\n") 2.36 + if helpout then 2.37 + if helpout == io.stderr then 2.38 + return 1 2.39 + else 2.40 + return 0 2.41 + end 2.42 + end 2.43 + local function append_trailing_slash(str) 2.44 + return string.sub(str, "([^/])$", function(last) return last .. "/" end) 2.45 + end 2.46 + WEBMCP_FRAMEWORK_PATH = append_trailing_slash(arg1) 2.47 + WEBMCP_BASE_PATH = append_trailing_slash(arg2) 2.48 +end 2.49 + 2.50 +-- setup search paths for libraries 2.51 +do 2.52 + package.path = WEBMCP_FRAMEWORK_PATH .. "lib/?.lua;" .. package.path 2.53 + -- find out which file name extension shared libraries have 2.54 + local slib_exts = {} 2.55 + for ext in string.gmatch(package.cpath, "%?%.([A-Za-z0-9_-]+)") do 2.56 + slib_exts[ext] = true 2.57 + end 2.58 + local paths = {} 2.59 + for ext in pairs(slib_exts) do 2.60 + paths[#paths+1] = WEBMCP_FRAMEWORK_PATH .. "accelerator/?." .. ext 2.61 + end 2.62 + for ext in pairs(slib_exts) do 2.63 + paths[#paths+1] = WEBMCP_FRAMEWORK_PATH .. "lib/?." .. ext 2.64 + end 2.65 + paths[#paths+1] = package.cpath 2.66 + package.cpath = table.concat(paths, ";") 2.67 +end 2.68 + 2.69 +-- autoloader system for WebMCP environment "$WEBMCP_FRAMEWORK_PATH/env/", 2.70 +-- application environment extensions "$WEBMCP_BASE_PATH/env/" 2.71 +-- and models "$WEBMCP_BASE_PATH/model/" 2.72 +do 2.73 + local weakkey_mt = { __mode = "k" } 2.74 + local autoloader_category = setmetatable({}, weakkey_mt) 2.75 + local autoloader_path = setmetatable({}, weakkey_mt) 2.76 + local autoloader_mt = {} 2.77 + local function install_autoloader(self, category, path) 2.78 + autoloader_category[self] = category 2.79 + autoloader_path[self] = path 2.80 + setmetatable(self, autoloader_mt) 2.81 + end 2.82 + local function try_exec(filename) 2.83 + local file = io.open(filename, "r") 2.84 + if file then 2.85 + local filedata = file:read("*a") 2.86 + io.close(file) 2.87 + local func, errmsg = load(filedata, "=" .. filename) 2.88 + if func then 2.89 + func() 2.90 + return true 2.91 + else 2.92 + error(errmsg, 0) 2.93 + end 2.94 + else 2.95 + return false 2.96 + end 2.97 + end 2.98 + local function compose_path_string(base, path, key) 2.99 + if #path == 0 then 2.100 + return base .. "/" .. key 2.101 + else 2.102 + return base .. table.concat(path, "/") .. "/" .. key 2.103 + end 2.104 + end 2.105 + function autoloader_mt.__index(self, key) 2.106 + local category, base_path, merge_base_path, file_key 2.107 + local merge = false 2.108 + if 2.109 + string.find(key, "^[a-z_][A-Za-z0-9_]*$") and 2.110 + not string.find(key, "^__") 2.111 + then 2.112 + category = "env" 2.113 + base_path = WEBMCP_FRAMEWORK_PATH .. "env/" 2.114 + merge = true 2.115 + merge_base_path = WEBMCP_BASE_PATH .. "env/" 2.116 + file_key = key 2.117 + elseif string.find(key, "^[A-Z][A-Za-z0-9]*$") then 2.118 + category = "model" 2.119 + base_path = WEBMCP_BASE_PATH .. "model/" 2.120 + local first = true 2.121 + file_key = string.gsub(key, "[A-Z]", 2.122 + function(c) 2.123 + if first then 2.124 + first = false 2.125 + return string.lower(c) 2.126 + else 2.127 + return "_" .. string.lower(c) 2.128 + end 2.129 + end 2.130 + ) 2.131 + else 2.132 + return 2.133 + end 2.134 + local required_category = autoloader_category[self] 2.135 + if required_category and required_category ~= category then return end 2.136 + local path = autoloader_path[self] 2.137 + local path_string = compose_path_string(base_path, path, file_key) 2.138 + local merge_path_string 2.139 + if merge then 2.140 + merge_path_string = compose_path_string( 2.141 + merge_base_path, path, file_key 2.142 + ) 2.143 + end 2.144 + local function try_dir(dirname) 2.145 + local dir = io.open(dirname) 2.146 + if dir then 2.147 + io.close(dir) 2.148 + local obj = {} 2.149 + local sub_path = {} 2.150 + for i = 1, #path do sub_path[i] = path[i] end 2.151 + sub_path[#path+1] = file_key 2.152 + install_autoloader(obj, category, sub_path) 2.153 + rawset(self, key, obj) 2.154 + try_exec(path_string .. "/__init.lua") 2.155 + if merge then try_exec(merge_path_string .. "/__init.lua") end 2.156 + return true 2.157 + else 2.158 + return false 2.159 + end 2.160 + end 2.161 + if merge and try_exec(merge_path_string .. ".lua") then 2.162 + elseif merge and try_dir(merge_path_string .. "/") then 2.163 + elseif try_exec(path_string .. ".lua") then 2.164 + elseif try_dir(path_string .. "/") then 2.165 + else end 2.166 + return rawget(self, key) 2.167 + end 2.168 + install_autoloader(_G, nil, {}) 2.169 + try_exec(WEBMCP_FRAMEWORK_PATH .. "env/__init.lua") 2.170 + try_exec(WEBMCP_BASE_PATH .. "env/__init.lua") 2.171 +end 2.172 + 2.173 +-- prohibit (unintended) definition of new global variables 2.174 +_ENV = setmetatable({}, { 2.175 + __index = _G, 2.176 + __newindex = function() 2.177 + error("Setting of global variable prohibited") 2.178 + end 2.179 +}) 2.180 + 2.181 +-- interactive console mode 2.182 +if WEBMCP_MODE == "interactive" then 2.183 + trace.disable() -- avoids memory leakage (TODO: needs general solution for moonbridge?) 2.184 + local config_name = select(3, ...) 2.185 + if config_name then 2.186 + execute.config(config_name) 2.187 + end 2.188 + return 2.189 +end 2.190 + 2.191 +-- TODO: moonbridge support below this line and in env/request and env/slot 2.192 + 2.193 +local success, error_info = xpcall( 2.194 + function() 2.195 + 2.196 + -- execute configuration file 2.197 + do 2.198 + local config_name = request.get_config_name() 2.199 + if config_name then 2.200 + execute.config(config_name) 2.201 + end 2.202 + end 2.203 + 2.204 + -- restore slots if coming from http redirect 2.205 + if cgi.params.tempstore then 2.206 + trace.restore_slots{} 2.207 + local blob = tempstore.pop(cgi.params.tempstore) 2.208 + if blob then slot.restore_all(blob) end 2.209 + end 2.210 + 2.211 + local function file_exists(filename) 2.212 + local file = io.open(filename, "r") 2.213 + if file then 2.214 + io.close(file) 2.215 + return true 2.216 + else 2.217 + return false 2.218 + end 2.219 + end 2.220 + 2.221 + if request.is_404() then 2.222 + request.set_status("404 Not Found") 2.223 + if request.get_404_route() then 2.224 + request.forward(request.get_404_route()) 2.225 + else 2.226 + error("No 404 page set.") 2.227 + end 2.228 + elseif request.get_action() then 2.229 + trace.request{ 2.230 + module = request.get_module(), 2.231 + action = request.get_action() 2.232 + } 2.233 + if 2.234 + request.get_404_route() and 2.235 + not file_exists( 2.236 + encode.action_file_path{ 2.237 + module = request.get_module(), 2.238 + action = request.get_action() 2.239 + } 2.240 + ) 2.241 + then 2.242 + request.set_status("404 Not Found") 2.243 + request.forward(request.get_404_route()) 2.244 + else 2.245 + if cgi.method ~= "POST" then 2.246 + request.set_status("405 Method Not Allowed") 2.247 + cgi.add_header("Allow: POST") 2.248 + error("Tried to invoke an action with a GET request.") 2.249 + end 2.250 + local action_status = execute.filtered_action{ 2.251 + module = request.get_module(), 2.252 + action = request.get_action(), 2.253 + } 2.254 + if not request.is_rerouted() then 2.255 + local routing_mode, routing_module, routing_view 2.256 + routing_mode = cgi.params["_webmcp_routing." .. action_status .. ".mode"] 2.257 + routing_module = cgi.params["_webmcp_routing." .. action_status .. ".module"] 2.258 + routing_view = cgi.params["_webmcp_routing." .. action_status .. ".view"] 2.259 + routing_anchor = cgi.params["_webmcp_routing." .. action_status .. ".anchor"] 2.260 + if not (routing_mode or routing_module or routing_view) then 2.261 + action_status = "default" 2.262 + routing_mode = cgi.params["_webmcp_routing.default.mode"] 2.263 + routing_module = cgi.params["_webmcp_routing.default.module"] 2.264 + routing_view = cgi.params["_webmcp_routing.default.view"] 2.265 + routing_anchor = cgi.params["_webmcp_routing.default.anchor"] 2.266 + end 2.267 + assert(routing_module, "Routing information has no module.") 2.268 + assert(routing_view, "Routing information has no view.") 2.269 + if routing_mode == "redirect" then 2.270 + local routing_params = {} 2.271 + for key, value in pairs(cgi.params) do 2.272 + local status, stripped_key = string.match( 2.273 + key, "^_webmcp_routing%.([^%.]*)%.params%.(.*)$" 2.274 + ) 2.275 + if status == action_status then 2.276 + routing_params[stripped_key] = value 2.277 + end 2.278 + end 2.279 + request.redirect{ 2.280 + module = routing_module, 2.281 + view = routing_view, 2.282 + id = cgi.params["_webmcp_routing." .. action_status .. ".id"], 2.283 + params = routing_params, 2.284 + anchor = routing_anchor 2.285 + } 2.286 + elseif routing_mode == "forward" then 2.287 + request.forward{ module = routing_module, view = routing_view } 2.288 + else 2.289 + error("Missing or unknown routing mode in request parameters.") 2.290 + end 2.291 + end 2.292 + end 2.293 + else 2.294 + -- no action 2.295 + trace.request{ 2.296 + module = request.get_module(), 2.297 + view = request.get_view() 2.298 + } 2.299 + if 2.300 + request.get_404_route() and 2.301 + not file_exists( 2.302 + encode.view_file_path{ 2.303 + module = request.get_module(), 2.304 + view = request.get_view() 2.305 + } 2.306 + ) 2.307 + then 2.308 + request.set_status("404 Not Found") 2.309 + request.forward(request.get_404_route()) 2.310 + end 2.311 + end 2.312 + 2.313 + if not request.get_redirect_data() then 2.314 + request.process_forward() 2.315 + local view = request.get_view() 2.316 + if string.find(view, "^_") then 2.317 + error("Tried to call a private view (prefixed with underscore).") 2.318 + end 2.319 + execute.filtered_view{ 2.320 + module = request.get_module(), 2.321 + view = view, 2.322 + } 2.323 + end 2.324 + 2.325 + -- force error due to missing absolute base URL until its too late to display error message 2.326 + --if request.get_redirect_data() then 2.327 + -- request.get_absolute_baseurl() 2.328 + --end 2.329 + 2.330 + end, 2.331 + 2.332 + function(errobj) 2.333 + return { 2.334 + errobj = errobj, 2.335 + stacktrace = string.gsub( 2.336 + debug.traceback('', 2), 2.337 + "^\r?\n?stack traceback:\r?\n?", "" 2.338 + ) 2.339 + } 2.340 + end 2.341 +) 2.342 + 2.343 +if not success then trace.error{} end 2.344 + 2.345 +-- laufzeitermittlung 2.346 +trace.exectime{ real = extos.monotonic_hires_time(), cpu = os.clock() } 2.347 + 2.348 +slot.select('trace', trace.render) -- render trace information 2.349 + 2.350 +local redirect_data = request.get_redirect_data() 2.351 + 2.352 +-- log error and switch to error layout, unless success 2.353 +if not success then 2.354 + local errobj = error_info.errobj 2.355 + local stacktrace = error_info.stacktrace 2.356 + if not request.get_status() and not request.get_json_request_slots() then 2.357 + request.set_status("500 Internal Server Error") 2.358 + end 2.359 + slot.set_layout('system_error') 2.360 + slot.select('system_error', function() 2.361 + if getmetatable(errobj) == mondelefant.errorobject_metatable then 2.362 + slot.put( 2.363 + "<p>Database error of class <b>", 2.364 + encode.html(errobj.code), 2.365 + "</b> occured:<br/><b>", 2.366 + encode.html(errobj.message), 2.367 + "</b></p>" 2.368 + ) 2.369 + else 2.370 + slot.put("<p><b>", encode.html(tostring(errobj)), "</b></p>") 2.371 + end 2.372 + slot.put("<p>Stack trace follows:<br/>") 2.373 + slot.put(encode.html_newlines(encode.html(stacktrace))) 2.374 + slot.put("</p>") 2.375 + end) 2.376 +elseif redirect_data then 2.377 + local redirect_params = {} 2.378 + for key, value in pairs(redirect_data.params) do 2.379 + redirect_params[key] = value 2.380 + end 2.381 + local slot_dump = slot.dump_all() 2.382 + if slot_dump ~= "" then 2.383 + redirect_params.tempstore = tempstore.save(slot_dump) 2.384 + end 2.385 + local json_request_slots = request.get_json_request_slots() 2.386 + if json_request_slots then 2.387 + redirect_params["_webmcp_json_slots[]"] = json_request_slots 2.388 + end 2.389 + cgi.redirect( 2.390 + encode.url{ 2.391 + base = request.get_absolute_baseurl(), 2.392 + module = redirect_data.module, 2.393 + view = redirect_data.view, 2.394 + id = redirect_data.id, 2.395 + params = redirect_params, 2.396 + anchor = redirect_data.anchor 2.397 + } 2.398 + ) 2.399 + cgi.send_data() 2.400 +end 2.401 + 2.402 +if not success or not redirect_data then 2.403 + 2.404 + local http_status = request.get_status() 2.405 + if http_status then 2.406 + cgi.set_status(http_status) 2.407 + end 2.408 + 2.409 + local json_request_slots = request.get_json_request_slots() 2.410 + if json_request_slots then 2.411 + cgi.set_content_type('application/json') 2.412 + local data = {} 2.413 + for idx, slot_ident in ipairs(json_request_slots) do 2.414 + data[slot_ident] = slot.get_content(slot_ident) 2.415 + end 2.416 + cgi.send_data(encode.json(data)) 2.417 + else 2.418 + cgi.set_content_type(slot.get_content_type()) 2.419 + cgi.send_data(slot.render_layout()) 2.420 + end 2.421 +end 2.422 + 2.423 +exit()
3.1 --- a/framework/cgi-bin/webmcp-wrapper.lua Mon Aug 25 20:00:01 2014 +0200 3.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 3.3 @@ -1,23 +0,0 @@ 3.4 -#!/usr/bin/env lua 3.5 - 3.6 -local func, errmsg = loadfile('webmcp.lua') 3.7 - 3.8 -if func then 3.9 - local result 3.10 - result, errmsg = pcall(func) 3.11 - if result then 3.12 - errmsg = nil 3.13 - end 3.14 -end 3.15 - 3.16 -if errmsg and not (cgi and cgi.data_sent) then 3.17 - print('Status: 500 Internal Server Error') 3.18 - print('Content-type: text/plain') 3.19 - print() 3.20 - print('500 Internal Server Error') 3.21 - print() 3.22 - print(errmsg) 3.23 - print() 3.24 - print('(caught by webmcp-wrapper.lua)') 3.25 - os.exit(1) 3.26 -end
4.1 --- a/framework/cgi-bin/webmcp.lua Mon Aug 25 20:00:01 2014 +0200 4.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 4.3 @@ -1,489 +0,0 @@ 4.4 -#!/usr/bin/env lua 4.5 - 4.6 -_WEBMCP_VERSION = "1.2.6" 4.7 - 4.8 --- Lua 5.1 compatibility 4.9 -if not table.unpack then 4.10 - table.unpack = unpack 4.11 -end 4.12 -do 4.13 - local old_load = load 4.14 - function load(ld, ...) 4.15 - if type(ld) == "string" then 4.16 - local done = false 4.17 - local func = function() 4.18 - if not done then 4.19 - done = true 4.20 - return ld 4.21 - end 4.22 - end 4.23 - return old_load(func, ...) 4.24 - else 4.25 - return old_load(ld, ...) 4.26 - end 4.27 - end 4.28 -end 4.29 - 4.30 --- include "../lib/" in search path for libraries 4.31 -if not WEBMCP_PATH then 4.32 - WEBMCP_PATH = "../" 4.33 -end 4.34 -do 4.35 - package.path = WEBMCP_PATH .. 'lib/?.lua;' .. package.path 4.36 - -- find out which file name extension shared libraries have 4.37 - local slib_exts = {} 4.38 - for ext in string.gmatch(package.cpath, "%?%.([A-Za-z0-9_-]+)") do 4.39 - slib_exts[ext] = true 4.40 - end 4.41 - local paths = {} 4.42 - for ext in pairs(slib_exts) do 4.43 - paths[#paths+1] = WEBMCP_PATH .. "accelerator/?." .. ext 4.44 - end 4.45 - for ext in pairs(slib_exts) do 4.46 - paths[#paths+1] = WEBMCP_PATH .. "lib/?." .. ext 4.47 - end 4.48 - paths[#paths+1] = package.cpath 4.49 - package.cpath = table.concat(paths, ";") 4.50 -end 4.51 - 4.52 --- load os extensions for lua 4.53 --- (should happen as soon as possible due to run time measurement) 4.54 -extos = require 'extos' 4.55 - 4.56 --- load nihil library 4.57 -nihil = require 'nihil' 4.58 - 4.59 --- load random generator library 4.60 -multirand = require 'multirand' 4.61 - 4.62 --- load rocketcgi library and map it to cgi, unless interactive 4.63 -do 4.64 - local option = os.getenv("WEBMCP_INTERACTIVE") 4.65 - if option and option ~= "" and option ~= "0" then 4.66 - cgi = nil 4.67 - else 4.68 - rocketcgi = require 'rocketcgi' -- TODO: no "rocketcgi" alias 4.69 - cgi = rocketcgi 4.70 - end 4.71 -end 4.72 - 4.73 --- load database access library with object relational mapper 4.74 -mondelefant = require 'mondelefant' 4.75 -mondelefant.connection_prototype.error_objects = true 4.76 - 4.77 --- load type system "atom" 4.78 -atom = require 'atom' 4.79 - 4.80 --- load JSON library 4.81 -json = require 'json' 4.82 - 4.83 --- load mondelefant atom connector 4.84 -require 'mondelefant_atom_connector' 4.85 - 4.86 ---[[-- 4.87 -cloned_table = -- newly generated table 4.88 -table.new( 4.89 - table_or_nil -- keys of a given table will be copied to the new table 4.90 -) 4.91 - 4.92 -If a table is given, then a cloned table is returned. 4.93 -If nil is given, then a new empty table is returned. 4.94 - 4.95 ---]]-- 4.96 -function table.new(tbl) 4.97 - new_tbl = {} 4.98 - if tbl then 4.99 - for key, value in pairs(tbl) do 4.100 - new_tbl[key] = value 4.101 - end 4.102 - end 4.103 - return new_tbl 4.104 -end 4.105 ---//-- 4.106 - 4.107 ---[[-- 4.108 -at_exit( 4.109 - func -- function to be called before the process is ending 4.110 -) 4.111 - 4.112 -Registers a function to be called before the CGI process is exiting. 4.113 ---]]-- 4.114 -do 4.115 - local exit_handlers = {} 4.116 - function at_exit(func) 4.117 - table.insert(exit_handlers, func) 4.118 - end 4.119 - function exit(code) 4.120 - for i = #exit_handlers, 1, -1 do 4.121 - exit_handlers[i]() 4.122 - end 4.123 - os.exit(code) 4.124 - end 4.125 -end 4.126 ---//-- 4.127 - 4.128 ---[[-- 4.129 -app -- table to store an application state 4.130 - 4.131 -'app' is a global table for storing any application state data 4.132 ---]]-- 4.133 -app = {} 4.134 ---//-- 4.135 - 4.136 ---[[-- 4.137 -config -- table to store application configuration 4.138 - 4.139 -'config' is a global table, which can be modified by a config file of an application to modify the behaviour of that application. 4.140 ---]]-- 4.141 -config = {} 4.142 ---//-- 4.143 - 4.144 --- autoloader system for WebMCP environment "../env/", 4.145 --- application environment extensions "$WEBMCP_APP_BASE/env/" 4.146 --- and models "$WEBMCP_APP_BASE/model/" 4.147 -do 4.148 - local app_base = os.getenv("WEBMCP_APP_BASEPATH") 4.149 - if not app_base then 4.150 - error( 4.151 - "Failed to initialize autoloader " .. 4.152 - "due to unset WEBMCP_APP_BASEPATH environment variable." 4.153 - ) 4.154 - end 4.155 - local weakkey_mt = { __mode = "k" } 4.156 - local autoloader_category = setmetatable({}, weakkey_mt) 4.157 - local autoloader_path = setmetatable({}, weakkey_mt) 4.158 - local autoloader_mt = {} 4.159 - local function install_autoloader(self, category, path) 4.160 - autoloader_category[self] = category 4.161 - autoloader_path[self] = path 4.162 - setmetatable(self, autoloader_mt) 4.163 - end 4.164 - local function try_exec(filename) 4.165 - local file = io.open(filename, "r") 4.166 - if file then 4.167 - local filedata = file:read("*a") 4.168 - io.close(file) 4.169 - local func, errmsg = load(filedata, "=" .. filename) 4.170 - if func then 4.171 - func() 4.172 - return true 4.173 - else 4.174 - error(errmsg, 0) 4.175 - end 4.176 - else 4.177 - return false 4.178 - end 4.179 - end 4.180 - local function compose_path_string(base, path, key) 4.181 - return string.gsub( 4.182 - base .. table.concat(path, "/") .. "/" .. key, "/+", "/" 4.183 - ) 4.184 - end 4.185 - function autoloader_mt.__index(self, key) 4.186 - local category, base_path, merge_base_path, file_key 4.187 - local merge = false 4.188 - if 4.189 - string.find(key, "^[a-z_][A-Za-z0-9_]*$") and 4.190 - not string.find(key, "^__") 4.191 - then 4.192 - category = "env" 4.193 - base_path = WEBMCP_PATH .. "/env/" 4.194 - merge = true 4.195 - merge_base_path = app_base .. "/env/" 4.196 - file_key = key 4.197 - elseif string.find(key, "^[A-Z][A-Za-z0-9]*$") then 4.198 - category = "model" 4.199 - base_path = app_base .. "/model/" 4.200 - local first = true 4.201 - file_key = string.gsub(key, "[A-Z]", 4.202 - function(c) 4.203 - if first then 4.204 - first = false 4.205 - return string.lower(c) 4.206 - else 4.207 - return "_" .. string.lower(c) 4.208 - end 4.209 - end 4.210 - ) 4.211 - else 4.212 - return 4.213 - end 4.214 - local required_category = autoloader_category[self] 4.215 - if required_category and required_category ~= category then return end 4.216 - local path = autoloader_path[self] 4.217 - local path_string = compose_path_string(base_path, path, file_key) 4.218 - local merge_path_string 4.219 - if merge then 4.220 - merge_path_string = compose_path_string( 4.221 - merge_base_path, path, file_key 4.222 - ) 4.223 - end 4.224 - local function try_dir(dirname) 4.225 - local dir = io.open(dirname) 4.226 - if dir then 4.227 - io.close(dir) 4.228 - local obj = {} 4.229 - local sub_path = {} 4.230 - for i, v in ipairs(path) do sub_path[i] = v end 4.231 - table.insert(sub_path, file_key) 4.232 - install_autoloader(obj, category, sub_path) 4.233 - rawset(self, key, obj) 4.234 - try_exec(path_string .. "/__init.lua") 4.235 - if merge then try_exec(merge_path_string .. "/__init.lua") end 4.236 - return true 4.237 - else 4.238 - return false 4.239 - end 4.240 - end 4.241 - if merge and try_exec(merge_path_string .. ".lua") then 4.242 - elseif merge and try_dir(merge_path_string .. "/") then 4.243 - elseif try_exec(path_string .. ".lua") then 4.244 - elseif try_dir(path_string .. "/") then 4.245 - else end 4.246 - return rawget(self, key) 4.247 - end 4.248 - install_autoloader(_G, nil, {}) 4.249 - try_exec(WEBMCP_PATH .. "env/__init.lua") 4.250 -end 4.251 - 4.252 --- interactive console mode 4.253 -if not cgi then 4.254 - trace.disable() -- avoids memory leakage 4.255 - local config_name = request.get_config_name() 4.256 - if config_name then 4.257 - execute.config(config_name) 4.258 - end 4.259 - return 4.260 -end 4.261 - 4.262 -local success, error_info = xpcall( 4.263 - function() 4.264 - 4.265 - -- execute configuration file 4.266 - do 4.267 - local config_name = request.get_config_name() 4.268 - if config_name then 4.269 - execute.config(config_name) 4.270 - end 4.271 - end 4.272 - 4.273 - -- restore slots if coming from http redirect 4.274 - if cgi.params.tempstore then 4.275 - trace.restore_slots{} 4.276 - local blob = tempstore.pop(cgi.params.tempstore) 4.277 - if blob then slot.restore_all(blob) end 4.278 - end 4.279 - 4.280 - local function file_exists(filename) 4.281 - local file = io.open(filename, "r") 4.282 - if file then 4.283 - io.close(file) 4.284 - return true 4.285 - else 4.286 - return false 4.287 - end 4.288 - end 4.289 - 4.290 - if request.is_404() then 4.291 - request.set_status("404 Not Found") 4.292 - if request.get_404_route() then 4.293 - request.forward(request.get_404_route()) 4.294 - else 4.295 - error("No 404 page set.") 4.296 - end 4.297 - elseif request.get_action() then 4.298 - trace.request{ 4.299 - module = request.get_module(), 4.300 - action = request.get_action() 4.301 - } 4.302 - if 4.303 - request.get_404_route() and 4.304 - not file_exists( 4.305 - encode.action_file_path{ 4.306 - module = request.get_module(), 4.307 - action = request.get_action() 4.308 - } 4.309 - ) 4.310 - then 4.311 - request.set_status("404 Not Found") 4.312 - request.forward(request.get_404_route()) 4.313 - else 4.314 - if cgi.method ~= "POST" then 4.315 - request.set_status("405 Method Not Allowed") 4.316 - cgi.add_header("Allow: POST") 4.317 - error("Tried to invoke an action with a GET request.") 4.318 - end 4.319 - local action_status = execute.filtered_action{ 4.320 - module = request.get_module(), 4.321 - action = request.get_action(), 4.322 - } 4.323 - if not request.is_rerouted() then 4.324 - local routing_mode, routing_module, routing_view 4.325 - routing_mode = cgi.params["_webmcp_routing." .. action_status .. ".mode"] 4.326 - routing_module = cgi.params["_webmcp_routing." .. action_status .. ".module"] 4.327 - routing_view = cgi.params["_webmcp_routing." .. action_status .. ".view"] 4.328 - routing_anchor = cgi.params["_webmcp_routing." .. action_status .. ".anchor"] 4.329 - if not (routing_mode or routing_module or routing_view) then 4.330 - action_status = "default" 4.331 - routing_mode = cgi.params["_webmcp_routing.default.mode"] 4.332 - routing_module = cgi.params["_webmcp_routing.default.module"] 4.333 - routing_view = cgi.params["_webmcp_routing.default.view"] 4.334 - routing_anchor = cgi.params["_webmcp_routing.default.anchor"] 4.335 - end 4.336 - assert(routing_module, "Routing information has no module.") 4.337 - assert(routing_view, "Routing information has no view.") 4.338 - if routing_mode == "redirect" then 4.339 - local routing_params = {} 4.340 - for key, value in pairs(cgi.params) do 4.341 - local status, stripped_key = string.match( 4.342 - key, "^_webmcp_routing%.([^%.]*)%.params%.(.*)$" 4.343 - ) 4.344 - if status == action_status then 4.345 - routing_params[stripped_key] = value 4.346 - end 4.347 - end 4.348 - request.redirect{ 4.349 - module = routing_module, 4.350 - view = routing_view, 4.351 - id = cgi.params["_webmcp_routing." .. action_status .. ".id"], 4.352 - params = routing_params, 4.353 - anchor = routing_anchor 4.354 - } 4.355 - elseif routing_mode == "forward" then 4.356 - request.forward{ module = routing_module, view = routing_view } 4.357 - else 4.358 - error("Missing or unknown routing mode in request parameters.") 4.359 - end 4.360 - end 4.361 - end 4.362 - else 4.363 - -- no action 4.364 - trace.request{ 4.365 - module = request.get_module(), 4.366 - view = request.get_view() 4.367 - } 4.368 - if 4.369 - request.get_404_route() and 4.370 - not file_exists( 4.371 - encode.view_file_path{ 4.372 - module = request.get_module(), 4.373 - view = request.get_view() 4.374 - } 4.375 - ) 4.376 - then 4.377 - request.set_status("404 Not Found") 4.378 - request.forward(request.get_404_route()) 4.379 - end 4.380 - end 4.381 - 4.382 - if not request.get_redirect_data() then 4.383 - request.process_forward() 4.384 - local view = request.get_view() 4.385 - if string.find(view, "^_") then 4.386 - error("Tried to call a private view (prefixed with underscore).") 4.387 - end 4.388 - execute.filtered_view{ 4.389 - module = request.get_module(), 4.390 - view = view, 4.391 - } 4.392 - end 4.393 - 4.394 - -- force error due to missing absolute base URL until its too late to display error message 4.395 - --if request.get_redirect_data() then 4.396 - -- request.get_absolute_baseurl() 4.397 - --end 4.398 - 4.399 - end, 4.400 - 4.401 - function(errobj) 4.402 - return { 4.403 - errobj = errobj, 4.404 - stacktrace = string.gsub( 4.405 - debug.traceback('', 2), 4.406 - "^\r?\n?stack traceback:\r?\n?", "" 4.407 - ) 4.408 - } 4.409 - end 4.410 -) 4.411 - 4.412 -if not success then trace.error{} end 4.413 - 4.414 --- laufzeitermittlung 4.415 -trace.exectime{ real = extos.monotonic_hires_time(), cpu = os.clock() } 4.416 - 4.417 -slot.select('trace', trace.render) -- render trace information 4.418 - 4.419 -local redirect_data = request.get_redirect_data() 4.420 - 4.421 --- log error and switch to error layout, unless success 4.422 -if not success then 4.423 - local errobj = error_info.errobj 4.424 - local stacktrace = error_info.stacktrace 4.425 - if not request.get_status() and not request.get_json_request_slots() then 4.426 - request.set_status("500 Internal Server Error") 4.427 - end 4.428 - slot.set_layout('system_error') 4.429 - slot.select('system_error', function() 4.430 - if getmetatable(errobj) == mondelefant.errorobject_metatable then 4.431 - slot.put( 4.432 - "<p>Database error of class <b>", 4.433 - encode.html(errobj.code), 4.434 - "</b> occured:<br/><b>", 4.435 - encode.html(errobj.message), 4.436 - "</b></p>" 4.437 - ) 4.438 - else 4.439 - slot.put("<p><b>", encode.html(tostring(errobj)), "</b></p>") 4.440 - end 4.441 - slot.put("<p>Stack trace follows:<br/>") 4.442 - slot.put(encode.html_newlines(encode.html(stacktrace))) 4.443 - slot.put("</p>") 4.444 - end) 4.445 -elseif redirect_data then 4.446 - local redirect_params = {} 4.447 - for key, value in pairs(redirect_data.params) do 4.448 - redirect_params[key] = value 4.449 - end 4.450 - local slot_dump = slot.dump_all() 4.451 - if slot_dump ~= "" then 4.452 - redirect_params.tempstore = tempstore.save(slot_dump) 4.453 - end 4.454 - local json_request_slots = request.get_json_request_slots() 4.455 - if json_request_slots then 4.456 - redirect_params["_webmcp_json_slots[]"] = json_request_slots 4.457 - end 4.458 - cgi.redirect( 4.459 - encode.url{ 4.460 - base = request.get_absolute_baseurl(), 4.461 - module = redirect_data.module, 4.462 - view = redirect_data.view, 4.463 - id = redirect_data.id, 4.464 - params = redirect_params, 4.465 - anchor = redirect_data.anchor 4.466 - } 4.467 - ) 4.468 - cgi.send_data() 4.469 -end 4.470 - 4.471 -if not success or not redirect_data then 4.472 - 4.473 - local http_status = request.get_status() 4.474 - if http_status then 4.475 - cgi.set_status(http_status) 4.476 - end 4.477 - 4.478 - local json_request_slots = request.get_json_request_slots() 4.479 - if json_request_slots then 4.480 - cgi.set_content_type('application/json') 4.481 - local data = {} 4.482 - for idx, slot_ident in ipairs(json_request_slots) do 4.483 - data[slot_ident] = slot.get_content(slot_ident) 4.484 - end 4.485 - cgi.send_data(encode.json(data)) 4.486 - else 4.487 - cgi.set_content_type(slot.get_content_type()) 4.488 - cgi.send_data(slot.render_layout()) 4.489 - end 4.490 -end 4.491 - 4.492 -exit()
5.1 --- a/framework/env/__init.lua Mon Aug 25 20:00:01 2014 +0200 5.2 +++ b/framework/env/__init.lua Fri Jan 09 01:57:20 2015 +0100 5.3 @@ -1,3 +1,4 @@ 5.4 +-- string localization function 5.5 function _(text, replacements) 5.6 local text = locale._get_translation_table()[text] or text 5.7 if replacements then 5.8 @@ -14,3 +15,35 @@ 5.9 return text 5.10 end 5.11 end 5.12 + 5.13 +--[[-- 5.14 +cloned_table = -- newly generated table 5.15 +table.new( 5.16 + table_or_nil -- keys of a given table will be copied to the new table 5.17 +) 5.18 + 5.19 +If a table is given, then a cloned table is returned. 5.20 +If nil is given, then a new empty table is returned. 5.21 + 5.22 +--]]-- 5.23 +function table.new(tbl) 5.24 + new_tbl = {} 5.25 + if tbl then 5.26 + for key, value in pairs(tbl) do 5.27 + new_tbl[key] = value 5.28 + end 5.29 + end 5.30 + return new_tbl 5.31 +end 5.32 +--//-- 5.33 + 5.34 +-- load libraries 5.35 +extos = require 'extos' 5.36 +nihil = require 'nihil' 5.37 +multirand = require 'multirand' 5.38 +mondelefant = require 'mondelefant' 5.39 +mondelefant.connection_prototype.error_objects = true 5.40 +atom = require 'atom' 5.41 +json = require 'json' 5.42 +require 'mondelefant_atom_connector' 5.43 +
6.1 --- a/libraries/rocketcgi/rocketcgi.lua Mon Aug 25 20:00:01 2014 +0200 6.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 6.3 @@ -1,313 +0,0 @@ 6.4 -#!/usr/bin/env lua 6.5 - 6.6 -local assert = assert 6.7 -local collectgarbage = collectgarbage 6.8 -local error = error 6.9 -local getmetatable = getmetatable 6.10 -local ipairs = ipairs 6.11 -local next = next 6.12 -local pairs = pairs 6.13 -local print = print 6.14 -local rawequal = rawequal 6.15 -local rawget = rawget 6.16 -local rawlen = rawlen 6.17 -local rawset = rawset 6.18 -local select = select 6.19 -local setmetatable = setmetatable 6.20 -local tonumber = tonumber 6.21 -local tostring = tostring 6.22 -local type = type 6.23 - 6.24 -local io = io 6.25 -local math = math 6.26 -local os = os 6.27 -local string = string 6.28 -local table = table 6.29 - 6.30 -local _M = {} 6.31 -if _ENV then 6.32 - _ENV = _M 6.33 -else 6.34 - _G[...] = _M 6.35 - setfenv(1, _M) 6.36 -end 6.37 - 6.38 -data_sent = false 6.39 - 6.40 ---[[-- 6.41 -rocketcgi.add_header( 6.42 - string_part1, -- string 6.43 - string_part2, -- optional second part of string to be concatted 6.44 - ... 6.45 -) 6.46 - 6.47 -Sends a header line to the browser. Multiple arguments are concatted to form a single string. 6.48 - 6.49 ---]]-- 6.50 -function add_header(...) 6.51 - if data_sent then 6.52 - error("Can not add header after data has been sent.", 2) 6.53 - end 6.54 - io.stdout:write(...) 6.55 - io.stdout:write("\r\n") 6.56 -end 6.57 ---//-- 6.58 - 6.59 ---[[-- 6.60 -rocketcgi.send_data( 6.61 - string_part1, -- string 6.62 - string_part2, -- optional second part of string to be concatted 6.63 - ... 6.64 -) 6.65 - 6.66 -Sends document data to the browser. Multiple arguments are concatted to form a single string. 6.67 - 6.68 ---]]-- 6.69 -function send_data(...) 6.70 - if not data_sent then 6.71 - io.stdout:write("\r\n") 6.72 - data_sent = true 6.73 - end 6.74 - io.stdout:write(...) 6.75 -end 6.76 ---//-- 6.77 - 6.78 ---[[-- 6.79 -rocketcgi.set_status( 6.80 - status -- Status code and description, e.g. "404 Not Found" 6.81 -) 6.82 - 6.83 -Sends a header line to the browser, indicating a given HTTP status. 6.84 - 6.85 ---]]-- 6.86 -function set_status(status) 6.87 - add_header("Status: ", status) 6.88 -end 6.89 ---//-- 6.90 - 6.91 ---[[-- 6.92 -rocketcgi.redirect( 6.93 - status -- Absolute URL to redirect the browser to 6.94 -) 6.95 - 6.96 -Redirects the browser to the given absolute URL, using a 303 Redirect. 6.97 - 6.98 ---]]-- 6.99 -function redirect(location) 6.100 - set_status("303 See Other") 6.101 - add_header("Location: ", location) 6.102 -end 6.103 ---//-- 6.104 - 6.105 ---[[-- 6.106 -rocketcgi.set_content_type( 6.107 - content_type -- MIME content type 6.108 -) 6.109 - 6.110 -Sends a header line specifying the content-type to the browser. 6.111 - 6.112 ---]]-- 6.113 -function set_content_type(content_type) 6.114 - add_header("Content-Type: ", content_type) 6.115 -end 6.116 ---//-- 6.117 - 6.118 ---[[-- 6.119 -rocketcgi.set_cookie{ 6.120 - name = name, -- name of cookie 6.121 - value = value, -- value of cookie 6.122 - domain = domain, -- domain where cookie is transmitted 6.123 - path = path, -- path where cookie is transmitted 6.124 - secure = secure -- boolean, indicating if cookie should only be transmitted over HTTPS 6.125 -} 6.126 - 6.127 -Sends a header line setting a cookie. NOTE: Currently only session cookies are supported. 6.128 - 6.129 ---]]-- 6.130 -function set_cookie(args) 6.131 - assert(string.find(args.name, "^[0-9A-Za-z%%._~-]+$"), "Illegal cookie name") 6.132 - assert(string.find(args.value, "^[0-9A-Za-z%%._~-]+$"), "Illegal cookie value") 6.133 - local parts = {"Set-Cookie: " .. args.name .. "=" .. args.value} 6.134 - if args.domain then 6.135 - assert( 6.136 - string.find(args.path, "^[0-9A-Za-z%%/._~-]+$"), 6.137 - "Illegal cookie domain" 6.138 - ) 6.139 - parts[#parts+1] = "domain=" .. args.domain 6.140 - end 6.141 - if args.path then 6.142 - assert( 6.143 - string.find(args.path, "^[0-9A-Za-z%%/._~-]+$"), 6.144 - "Illegal cookie path" 6.145 - ) 6.146 - parts[#parts+1] = "path=" .. args.path 6.147 - end 6.148 - if args.secure then 6.149 - parts[#parts+1] = "secure" 6.150 - end 6.151 - add_header(table.concat(parts, "; ")) 6.152 -end 6.153 ---//-- 6.154 - 6.155 -method = os.getenv("REQUEST_METHOD") or false 6.156 -query = os.getenv("QUERY_STRING") or false 6.157 -cookie_data = os.getenv("HTTP_COOKIE") or false 6.158 -post_data = io.stdin:read("*a") or false 6.159 -post_contenttype = os.getenv("CONTENT_TYPE") or false 6.160 -params = {} 6.161 -get_params = {} 6.162 -cookies = {} 6.163 -post_params = {} 6.164 -post_filenames = {} 6.165 -post_types = {} 6.166 - 6.167 -local urldecode 6.168 -do 6.169 - local b0 = string.byte("0") 6.170 - local b9 = string.byte("9") 6.171 - local bA = string.byte("A") 6.172 - local bF = string.byte("F") 6.173 - local ba = string.byte("a") 6.174 - local bf = string.byte("f") 6.175 - function urldecode(str) 6.176 - return ( 6.177 - string.gsub( 6.178 - string.gsub(str, "%+", " "), 6.179 - "%%([0-9A-Fa-f][0-9A-Fa-f])", 6.180 - function(hex) 6.181 - local n1, n2 = string.byte(hex, 1, 2) 6.182 - if n1 >= b0 and n1 <= b9 then n1 = n1 - b0 6.183 - elseif n1 >= bA and n1 <= bF then n1 = n1 - bA + 10 6.184 - elseif n1 >= ba and n1 <= bf then n1 = n1 - ba + 10 6.185 - else return end 6.186 - if n2 >= b0 and n2 <= b9 then n2 = n2 - b0 6.187 - elseif n2 >= bA and n2 <= bF then n2 = n2 - bA + 10 6.188 - elseif n2 >= ba and n2 <= bf then n2 = n2 - ba + 10 6.189 - else return end 6.190 - return string.char(n1 * 16 + n2) 6.191 - end 6.192 - ) 6.193 - ) 6.194 - end 6.195 -end 6.196 - 6.197 -local function proc_param(tbl, key, value) 6.198 - if string.find(key, "%[%]$") then 6.199 - if tbl[key] then 6.200 - table.insert(tbl[key], value) 6.201 - else 6.202 - local list = { value } 6.203 - params[key] = list 6.204 - tbl[key] = list 6.205 - end 6.206 - else 6.207 - params[key] = value 6.208 - tbl[key] = value 6.209 - end 6.210 -end 6.211 - 6.212 -local function read_urlencoded_form(tbl, data) 6.213 - for rawkey, rawvalue in string.gmatch(data, "([^=&]*)=([^=&]*)") do 6.214 - proc_param(tbl, urldecode(rawkey), urldecode(rawvalue)) 6.215 - end 6.216 -end 6.217 - 6.218 -if query then 6.219 - read_urlencoded_form(get_params, query) 6.220 -end 6.221 - 6.222 -if cookie_data then 6.223 - for rawkey, rawvalue in string.gmatch(cookie_data, "([^=; ]*)=([^=; ]*)") do 6.224 - cookies[urldecode(rawkey)] = urldecode(rawvalue) 6.225 - end 6.226 -end 6.227 - 6.228 -if post_contenttype and ( 6.229 - post_contenttype == "application/x-www-form-urlencoded" or 6.230 - string.match(post_contenttype, "^application/x%-www%-form%-urlencoded[ ;]") 6.231 -) then 6.232 - read_urlencoded_form(post_params, post_data) 6.233 -elseif post_contenttype then 6.234 - local boundary = string.match( 6.235 - post_contenttype, 6.236 - '^multipart/form%-data[ \t]*;[ \t]*boundary="([^"]+)"' 6.237 - ) or string.match( 6.238 - post_contenttype, 6.239 - '^multipart/form%-data[ \t]*;[ \t]*boundary=([^"; \t]+)' 6.240 - ) 6.241 - if boundary then 6.242 - local parts = {} 6.243 - do 6.244 - local boundary = "\r\n--" .. boundary 6.245 - local post_data = "\r\n" .. post_data 6.246 - local pos1, pos2 = string.find(post_data, boundary, 1, true) 6.247 - while true do 6.248 - local ind = string.sub(post_data, pos2 + 1, pos2 + 2) 6.249 - if ind == "\r\n" then 6.250 - local pos3, pos4 = string.find(post_data, boundary, pos2 + 1, true) 6.251 - if pos3 then 6.252 - parts[#parts + 1] = string.sub(post_data, pos2 + 3, pos3 - 1) 6.253 - else 6.254 - error("Illegal POST data.") 6.255 - end 6.256 - pos1, pos2 = pos3, pos4 6.257 - elseif ind == "--" then 6.258 - break 6.259 - else 6.260 - error("Illegal POST data.") 6.261 - end 6.262 - end 6.263 - end 6.264 - for i, part in ipairs(parts) do 6.265 - local pos = 1 6.266 - local name, filename, contenttype 6.267 - while true do 6.268 - local header 6.269 - do 6.270 - local oldpos = pos 6.271 - pos = string.find(part, "\r\n", oldpos, true) 6.272 - if not pos then 6.273 - error("Illegal POST data.") 6.274 - end 6.275 - if pos == oldpos then break end 6.276 - header = string.sub(part, oldpos, pos - 1) 6.277 - pos = pos + 2 6.278 - end 6.279 - if string.find( 6.280 - string.lower(header), 6.281 - "^content%-disposition:[ \t]*form%-data[ \t]*;" 6.282 - ) then 6.283 - -- TODO: handle all cases correctly 6.284 - name = string.match(header, ';[ \t]*name="([^"]*)"') or 6.285 - string.match(header, ';[ \t]*name=([^"; \t]+)') 6.286 - filename = string.match(header, ';[ \t]*filename="([^"]*)"') or 6.287 - string.match(header, ';[ \t]*filename=([^"; \t]+)') 6.288 - else 6.289 - local dummy, subpos = string.find( 6.290 - string.lower(header), 6.291 - "^content%-type:[ \t]*" 6.292 - ) 6.293 - if subpos then 6.294 - contenttype = string.sub(header, subpos + 1, #header) 6.295 - end 6.296 - end 6.297 - end 6.298 - local content = string.sub(part, pos + 2, #part) 6.299 - if not name then 6.300 - error("Illegal POST data.") 6.301 - end 6.302 - proc_param(post_params, name, content) 6.303 - post_filenames[name] = filename 6.304 - post_types[name] = contenttype 6.305 - end 6.306 - end 6.307 -end 6.308 - 6.309 -if post_data and #post_data > 262144 then 6.310 - post_data = nil 6.311 - collectgarbage("collect") 6.312 -else 6.313 - --post_data = nil --allow access to "post_data" for usual requests 6.314 -end 6.315 - 6.316 -return _M