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