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