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