webmcp
view framework/env/request/process.lua @ 229:bf690b4be420
Workaround for postfork-loading of multirand library
| author | jbe | 
|---|---|
| date | Fri Feb 27 22:45:36 2015 +0100 (2015-02-27) | 
| parents | 32ec28229bb5 | 
| children | d5cba50e16ae | 
 line source
     1 -- TODO: function incomplete yet
     3 local function file_exists(filename)
     4   local file = io.open(filename, "r")
     5   if file then
     6     io.close(file)
     7     return true
     8   else
     9     return false
    10   end
    11 end
    13 function request.process()
    15   local success, error_info = xpcall(
    16     function()
    18       -- restore slots if coming from http redirect
    19       local tempstore_value = request._http_request.get_params["_tempstore"]
    20       if tempstore_value then
    21         trace.restore_slots{}
    22         local blob = tempstore.pop(tempstore_value)
    23         if blob then slot.restore_all(blob) end
    24       end
    26       if request.get_action() then
    27         trace.request{
    28           module = request.get_module(),
    29           action = request.get_action()
    30         }
    31         if
    32           request.get_404_route() and
    33           not file_exists(
    34             encode.action_file_path{
    35               module = request.get_module(),
    36               action = request.get_action()
    37             }
    38           )
    39         then
    40           request.set_status("404 Not Found")
    41           request.forward(request.get_404_route())
    42         else
    43           if request._http_request.method ~= "POST" then
    44             request.set_status("405 Method Not Allowed")
    45             request.add_header("Allow", "POST")
    46             error("Tried to invoke an action with a GET request.")
    47           end
    48           local action_status = execute.filtered_action{
    49             module = request.get_module(),
    50             action = request.get_action(),
    51           }
    52           if not request.is_rerouted() then
    53             local routing_mode, routing_module, routing_view
    54             routing_mode   = request._http_request.post_params["_webmcp_routing." .. action_status .. ".mode"]
    55             routing_module = request._http_request.post_params["_webmcp_routing." .. action_status .. ".module"]
    56             routing_view   = request._http_request.post_params["_webmcp_routing." .. action_status .. ".view"]
    57             routing_anchor = request._http_request.post_params["_webmcp_routing." .. action_status .. ".anchor"]
    58             if not (routing_mode or routing_module or routing_view) then
    59               action_status = "default"
    60               routing_mode   = request._http_request.post_params["_webmcp_routing.default.mode"]
    61               routing_module = request._http_request.post_params["_webmcp_routing.default.module"]
    62               routing_view   = request._http_request.post_params["_webmcp_routing.default.view"]
    63               routing_anchor = request._http_request.post_params["_webmcp_routing.default.anchor"]
    64             end
    65             assert(routing_module, "Routing information has no module.")
    66             assert(routing_view,   "Routing information has no view.")
    67             if routing_mode == "redirect" then
    68               local routing_params = {}
    69               for key, value in request.get_param_strings{ method="POST", include_internal=true } do
    70                 local status, stripped_key = string.match(
    71                   key, "^_webmcp_routing%.([^%.]*)%.params%.(.*)$"
    72                 )
    73                 if status == action_status then
    74                   routing_params[stripped_key] = value
    75                 end
    76               end
    77               request.redirect{
    78                 module = routing_module,
    79                 view   = routing_view,
    80                 id     = request._http_request.post_params["_webmcp_routing." .. action_status .. ".id"],
    81                 params = routing_params,
    82                 anchor = routing_anchor
    83               }
    84             elseif routing_mode == "forward" then
    85               request.forward{ module = routing_module, view = routing_view }
    86             else
    87               error("Missing or unknown routing mode in request parameters.")
    88             end
    89           end
    90         end
    91       else
    92         -- no action
    93         trace.request{
    94           module = request.get_module(),
    95           view   = request.get_view()
    96         }
    97         if
    98           request.get_404_route() and
    99           not file_exists(
   100             encode.view_file_path{
   101               module = request.get_module(),
   102               view   = request.get_view()
   103             }
   104           )
   105         then
   106           request.set_status("404 Not Found")
   107           request.forward(request.get_404_route())
   108         end
   109       end
   111       if not request.get_redirect_data() then
   112         request.process_forward()
   113         local view = request.get_view()
   114         if string.find(view, "^_") then
   115           error("Tried to call a private view (prefixed with underscore).")
   116         end
   117         execute.filtered_view{
   118           module = request.get_module(),
   119           view   = view,
   120         }
   121       end
   123       -- force error due to missing absolute base URL until its too late to display error message
   124       --if request.get_redirect_data() then
   125       --  request.get_absolute_baseurl()
   126       --end
   128     end,
   130     function(errobj)
   131       return {
   132         errobj = errobj,
   133         stacktrace = string.gsub(
   134           debug.traceback('', 2),
   135           "^\r?\n?stack traceback:\r?\n?", ""
   136         )
   137       }
   138     end
   139   )
   141   if not success then trace.error{} end
   143   -- TODO: extend trace system to generally monitor execution time
   144   -- trace.exectime{ real = extos.monotonic_hires_time(), cpu = os.clock() }
   146   slot.select('trace', trace.render)  -- render trace information
   148   local redirect_data = request.get_redirect_data()
   150   -- log error and switch to error layout, unless success
   151   if not success then
   152     local errobj     = error_info.errobj
   153     local stacktrace = error_info.stacktrace
   154     if not request._status then
   155       request._status = "500 Internal Server Error"
   156     end
   157     slot.set_layout('system_error')
   158     slot.select('system_error', function()
   159       if getmetatable(errobj) == mondelefant.errorobject_metatable then
   160         slot.put(
   161           "<p>Database error of class <b>",
   162           encode.html(errobj.code),
   163           "</b> occured:<br/><b>",
   164           encode.html(errobj.message),
   165           "</b></p>"
   166         )
   167       else
   168         slot.put("<p><b>", encode.html(tostring(errobj)), "</b></p>")
   169       end
   170       slot.put("<p>Stack trace follows:<br/>")
   171       slot.put(encode.html_newlines(encode.html(stacktrace)))
   172       slot.put("</p>")
   173     end)
   174   elseif redirect_data then
   175     local redirect_params = {}
   176     for key, value in pairs(redirect_data.params) do
   177       redirect_params[key] = value
   178     end
   179     local slot_dump = slot.dump_all()
   180     if slot_dump ~= "" then
   181       redirect_params.tempstore = tempstore.save(slot_dump)
   182     end
   183     request._http_request:send_status("303 See Other")
   184     request._http_request:send_header(
   185       "Location",
   186       encode.url{
   187         base   = request.get_absolute_baseurl(),
   188         module = redirect_data.module,
   189         view   = redirect_data.view,
   190         id     = redirect_data.id,
   191         params = redirect_params,
   192         anchor = redirect_data.anchor
   193       }
   194     )
   195     request._http_request:finish()
   196   end
   198   if not success or not redirect_data then
   200     request._http_request:send_status(request._status or "200 OK")
   201     for i, header in ipairs(request._response_headers) do
   202       request._http_request:send_header(header[1], header[2])
   203     end
   204     request._http_request:send_header("Content-Type", slot.get_content_type())
   205     request._http_request:send_data(slot.render_layout())
   206     request._http_request:finish()
   207   end
   209 end
