-- TODO: function incomplete yet local function file_exists(filename) local file = io.open(filename, "r") if file then io.close(file) return true else return false end end function request.process() local success, error_info = xpcall( function() if request._route.static then local f = assert(io.open(WEBMCP_BASE_PATH .. "static/" .. request._route.static, "r")) local d = f:read("*a") f:close() slot.put_into("data", d) slot.set_layout(nil, "application/octet-stream") -- TODO return end -- restore slots if coming from http redirect local tempstore_value = request._http_request.get_params["_tempstore"] if tempstore_value then trace.restore_slots{} local blob = tempstore.pop(tempstore_value) if blob then slot.restore_all(blob) end end if 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 request._http_request.method ~= "POST" then request.set_status("405 Method Not Allowed") request.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_anchor routing_mode = request._http_request.post_params["_webmcp_routing." .. action_status .. ".mode"] routing_module = request._http_request.post_params["_webmcp_routing." .. action_status .. ".module"] routing_view = request._http_request.post_params["_webmcp_routing." .. action_status .. ".view"] routing_anchor = request._http_request.post_params["_webmcp_routing." .. action_status .. ".anchor"] if not (routing_mode or routing_module or routing_view) then action_status = "default" routing_mode = request._http_request.post_params["_webmcp_routing.default.mode"] routing_module = request._http_request.post_params["_webmcp_routing.default.module"] routing_view = request._http_request.post_params["_webmcp_routing.default.view"] routing_anchor = request._http_request.post_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(request.get_param_strings{ method="POST", include_internal=true }) 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 = request._http_request.post_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 -- TODO: extend trace system to generally monitor execution time -- 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._status then request._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 request._http_request:send_status("303 See Other") request._http_request:send_header("Connection", "close") -- TODO: extend moonbridge request._http_request:send_header( "Location", 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 } ) request._http_request:finish() end if not success or not redirect_data then request._http_request:send_status(request._status or "200 OK") request._http_request:send_header("Connection", "close") -- TODO: extend moonbridge for i, header in ipairs(request._response_headers) do request._http_request:send_header(header[1], header[2]) end request._http_request:send_header("Content-Type", slot.get_content_type()) request._http_request:send_data(slot.render_layout()) request._http_request:finish() end end