| 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@215 | 13 function request.default_router(path) | 
| jbe@212 | 14   request._http_request = http_request | 
| jbe@215 | 15   local path = http_request.path | 
| jbe@215 | 16   local function parse_path() | 
| jbe@215 | 17     if not path then | 
| jbe@215 | 18       return | 
| jbe@215 | 19     end | 
| jbe@215 | 20     if path == "/" then | 
| jbe@215 | 21       return {module = "index", view = "index"} | 
| jbe@215 | 22     end | 
| jbe@215 | 23     module = string.match(path, "^/([^/]+)/$") | 
| jbe@215 | 24     if module then | 
| jbe@215 | 25       return {module = module, view = "index"} | 
| jbe@215 | 26     end | 
| jbe@215 | 27     module, action = string.match(path, "^/([^/]+)/([^/.]+)$") | 
| jbe@215 | 28     if module then | 
| jbe@215 | 29       return {module = module, action = action} | 
| jbe@215 | 30     end | 
| jbe@215 | 31     module, view, suffix = string.match(path, "^/([^/]+)/([^/.]+)%.([^/]+)$") | 
| jbe@215 | 32     if module then | 
| jbe@215 | 33       return {module = module, view = view, suffix = suffix} | 
| jbe@215 | 34     end | 
| jbe@215 | 35     module, view, id, suffix = string.match(path, "^/([^/]+)/([^/]+)/([^/.]+)%.([^/]+)$") | 
| jbe@215 | 36     if module then | 
| jbe@215 | 37       return {module = module, view = view, id = id, suffix = suffix} | 
| jbe@215 | 38     end | 
| jbe@215 | 39   end | 
| jbe@215 | 40   request._data = parse_path() | 
| jbe@215 | 41   if path then | 
| jbe@215 | 42     local elements = {} | 
| jbe@215 | 43     for match in string.gmatch(path, "/") do | 
| jbe@215 | 44       elements[#elements+1] = "../" | 
| jbe@215 | 45     end | 
| jbe@215 | 46     elements[#elements] = nil | 
| jbe@215 | 47     if #elements > 0 then | 
| jbe@215 | 48       request._relative_baseurl = table.concat(elements) | 
| jbe@215 | 49     else | 
| jbe@215 | 50       request._relative_baseurl = "./" | 
| jbe@215 | 51     end | 
| jbe@215 | 52   end | 
| jbe@210 | 53   local success, error_info = xpcall( | 
| jbe@210 | 54     function() | 
| jbe@210 | 55 | 
| jbe@210 | 56       -- restore slots if coming from http redirect | 
| jbe@215 | 57       local tempstore_value = request.get_param{method = "GET", name = "_tempstore"} | 
| jbe@215 | 58       if tempstore_value then | 
| jbe@210 | 59         trace.restore_slots{} | 
| jbe@215 | 60         local blob = tempstore.pop(tempstore_value) | 
| jbe@210 | 61         if blob then slot.restore_all(blob) end | 
| jbe@210 | 62       end | 
| jbe@210 | 63 | 
| jbe@210 | 64 | 
| jbe@210 | 65       if request.is_404() then | 
| jbe@210 | 66         request.set_status("404 Not Found") | 
| jbe@210 | 67         if request.get_404_route() then | 
| jbe@210 | 68           request.forward(request.get_404_route()) | 
| jbe@210 | 69         else | 
| jbe@210 | 70           error("No 404 page set.") | 
| jbe@210 | 71         end | 
| jbe@210 | 72       elseif request.get_action() then | 
| jbe@210 | 73         trace.request{ | 
| jbe@210 | 74           module = request.get_module(), | 
| jbe@210 | 75           action = request.get_action() | 
| jbe@210 | 76         } | 
| jbe@210 | 77         if | 
| jbe@210 | 78           request.get_404_route() and | 
| jbe@210 | 79           not file_exists( | 
| jbe@210 | 80             encode.action_file_path{ | 
| jbe@210 | 81               module = request.get_module(), | 
| jbe@210 | 82               action = request.get_action() | 
| jbe@210 | 83             } | 
| jbe@210 | 84           ) | 
| jbe@210 | 85         then | 
| jbe@210 | 86           request.set_status("404 Not Found") | 
| jbe@210 | 87           request.forward(request.get_404_route()) | 
| jbe@210 | 88         else | 
| jbe@210 | 89           if cgi.method ~= "POST" then | 
| jbe@210 | 90             request.set_status("405 Method Not Allowed") | 
| jbe@210 | 91             cgi.add_header("Allow: POST") | 
| jbe@210 | 92             error("Tried to invoke an action with a GET request.") | 
| jbe@210 | 93           end | 
| jbe@210 | 94           local action_status = execute.filtered_action{ | 
| jbe@210 | 95             module = request.get_module(), | 
| jbe@210 | 96             action = request.get_action(), | 
| jbe@210 | 97           } | 
| jbe@210 | 98           if not request.is_rerouted() then | 
| jbe@210 | 99             local routing_mode, routing_module, routing_view | 
| jbe@210 | 100             routing_mode   = cgi.params["_webmcp_routing." .. action_status .. ".mode"] | 
| jbe@210 | 101             routing_module = cgi.params["_webmcp_routing." .. action_status .. ".module"] | 
| jbe@210 | 102             routing_view   = cgi.params["_webmcp_routing." .. action_status .. ".view"] | 
| jbe@210 | 103             routing_anchor = cgi.params["_webmcp_routing." .. action_status .. ".anchor"] | 
| jbe@210 | 104             if not (routing_mode or routing_module or routing_view) then | 
| jbe@210 | 105               action_status = "default" | 
| jbe@210 | 106               routing_mode   = cgi.params["_webmcp_routing.default.mode"] | 
| jbe@210 | 107               routing_module = cgi.params["_webmcp_routing.default.module"] | 
| jbe@210 | 108               routing_view   = cgi.params["_webmcp_routing.default.view"] | 
| jbe@210 | 109               routing_anchor = cgi.params["_webmcp_routing.default.anchor"] | 
| jbe@210 | 110             end | 
| jbe@210 | 111             assert(routing_module, "Routing information has no module.") | 
| jbe@210 | 112             assert(routing_view,   "Routing information has no view.") | 
| jbe@210 | 113             if routing_mode == "redirect" then | 
| jbe@210 | 114               local routing_params = {} | 
| jbe@210 | 115               for key, value in pairs(cgi.params) do | 
| jbe@210 | 116                 local status, stripped_key = string.match( | 
| jbe@210 | 117                   key, "^_webmcp_routing%.([^%.]*)%.params%.(.*)$" | 
| jbe@210 | 118                 ) | 
| jbe@210 | 119                 if status == action_status then | 
| jbe@210 | 120                   routing_params[stripped_key] = value | 
| jbe@210 | 121                 end | 
| jbe@210 | 122               end | 
| jbe@210 | 123               request.redirect{ | 
| jbe@210 | 124                 module = routing_module, | 
| jbe@210 | 125                 view   = routing_view, | 
| jbe@210 | 126                 id     = cgi.params["_webmcp_routing." .. action_status .. ".id"], | 
| jbe@210 | 127                 params = routing_params, | 
| jbe@210 | 128                 anchor = routing_anchor | 
| jbe@210 | 129               } | 
| jbe@210 | 130             elseif routing_mode == "forward" then | 
| jbe@210 | 131               request.forward{ module = routing_module, view = routing_view } | 
| jbe@210 | 132             else | 
| jbe@210 | 133               error("Missing or unknown routing mode in request parameters.") | 
| jbe@210 | 134             end | 
| jbe@210 | 135           end | 
| jbe@210 | 136         end | 
| jbe@210 | 137       else | 
| jbe@210 | 138         -- no action | 
| jbe@210 | 139         trace.request{ | 
| jbe@210 | 140           module = request.get_module(), | 
| jbe@210 | 141           view   = request.get_view() | 
| jbe@210 | 142         } | 
| jbe@210 | 143         if | 
| jbe@210 | 144           request.get_404_route() and | 
| jbe@210 | 145           not file_exists( | 
| jbe@210 | 146             encode.view_file_path{ | 
| jbe@210 | 147               module = request.get_module(), | 
| jbe@210 | 148               view   = request.get_view() | 
| jbe@210 | 149             } | 
| jbe@210 | 150           ) | 
| jbe@210 | 151         then | 
| jbe@210 | 152           request.set_status("404 Not Found") | 
| jbe@210 | 153           request.forward(request.get_404_route()) | 
| jbe@210 | 154         end | 
| jbe@210 | 155       end | 
| jbe@210 | 156 | 
| jbe@210 | 157       if not request.get_redirect_data() then | 
| jbe@210 | 158         request.process_forward() | 
| jbe@210 | 159         local view = request.get_view() | 
| jbe@210 | 160         if string.find(view, "^_") then | 
| jbe@210 | 161           error("Tried to call a private view (prefixed with underscore).") | 
| jbe@210 | 162         end | 
| jbe@210 | 163         execute.filtered_view{ | 
| jbe@210 | 164           module = request.get_module(), | 
| jbe@210 | 165           view   = view, | 
| jbe@210 | 166         } | 
| jbe@210 | 167       end | 
| jbe@210 | 168 | 
| jbe@210 | 169       -- force error due to missing absolute base URL until its too late to display error message | 
| jbe@210 | 170       --if request.get_redirect_data() then | 
| jbe@210 | 171       --  request.get_absolute_baseurl() | 
| jbe@210 | 172       --end | 
| jbe@210 | 173 | 
| jbe@210 | 174     end, | 
| jbe@210 | 175 | 
| jbe@210 | 176     function(errobj) | 
| jbe@210 | 177       return { | 
| jbe@210 | 178         errobj = errobj, | 
| jbe@210 | 179         stacktrace = string.gsub( | 
| jbe@210 | 180           debug.traceback('', 2), | 
| jbe@210 | 181           "^\r?\n?stack traceback:\r?\n?", "" | 
| jbe@210 | 182         ) | 
| jbe@210 | 183       } | 
| jbe@210 | 184     end | 
| jbe@210 | 185   ) | 
| jbe@210 | 186 | 
| jbe@210 | 187   if not success then trace.error{} end | 
| jbe@210 | 188 | 
| jbe@210 | 189   -- laufzeitermittlung | 
| jbe@210 | 190   trace.exectime{ real = extos.monotonic_hires_time(), cpu = os.clock() } | 
| jbe@210 | 191 | 
| jbe@210 | 192   slot.select('trace', trace.render)  -- render trace information | 
| jbe@210 | 193 | 
| jbe@210 | 194   local redirect_data = request.get_redirect_data() | 
| jbe@210 | 195 | 
| jbe@210 | 196   -- log error and switch to error layout, unless success | 
| jbe@210 | 197   if not success then | 
| jbe@210 | 198     local errobj     = error_info.errobj | 
| jbe@210 | 199     local stacktrace = error_info.stacktrace | 
| jbe@210 | 200     if not request.get_status() and not request.get_json_request_slots() then | 
| jbe@210 | 201       request.set_status("500 Internal Server Error") | 
| jbe@210 | 202     end | 
| jbe@210 | 203     slot.set_layout('system_error') | 
| jbe@210 | 204     slot.select('system_error', function() | 
| jbe@210 | 205       if getmetatable(errobj) == mondelefant.errorobject_metatable then | 
| jbe@210 | 206         slot.put( | 
| jbe@210 | 207           "<p>Database error of class <b>", | 
| jbe@210 | 208           encode.html(errobj.code), | 
| jbe@210 | 209           "</b> occured:<br/><b>", | 
| jbe@210 | 210           encode.html(errobj.message), | 
| jbe@210 | 211           "</b></p>" | 
| jbe@210 | 212         ) | 
| jbe@210 | 213       else | 
| jbe@210 | 214         slot.put("<p><b>", encode.html(tostring(errobj)), "</b></p>") | 
| jbe@210 | 215       end | 
| jbe@210 | 216       slot.put("<p>Stack trace follows:<br/>") | 
| jbe@210 | 217       slot.put(encode.html_newlines(encode.html(stacktrace))) | 
| jbe@210 | 218       slot.put("</p>") | 
| jbe@210 | 219     end) | 
| jbe@210 | 220   elseif redirect_data then | 
| jbe@210 | 221     local redirect_params = {} | 
| jbe@210 | 222     for key, value in pairs(redirect_data.params) do | 
| jbe@210 | 223       redirect_params[key] = value | 
| jbe@210 | 224     end | 
| jbe@210 | 225     local slot_dump = slot.dump_all() | 
| jbe@210 | 226     if slot_dump ~= "" then | 
| jbe@210 | 227       redirect_params.tempstore = tempstore.save(slot_dump) | 
| jbe@210 | 228     end | 
| jbe@210 | 229     local json_request_slots = request.get_json_request_slots() | 
| jbe@210 | 230     if json_request_slots then | 
| jbe@210 | 231       redirect_params["_webmcp_json_slots[]"] = json_request_slots | 
| jbe@210 | 232     end | 
| jbe@210 | 233     cgi.redirect( | 
| jbe@210 | 234       encode.url{ | 
| jbe@210 | 235         base   = request.get_absolute_baseurl(), | 
| jbe@210 | 236         module = redirect_data.module, | 
| jbe@210 | 237         view   = redirect_data.view, | 
| jbe@210 | 238         id     = redirect_data.id, | 
| jbe@210 | 239         params = redirect_params, | 
| jbe@210 | 240         anchor = redirect_data.anchor | 
| jbe@210 | 241       } | 
| jbe@210 | 242     ) | 
| jbe@210 | 243     cgi.send_data() | 
| jbe@210 | 244   end | 
| jbe@210 | 245 | 
| jbe@210 | 246   if not success or not redirect_data then | 
| jbe@210 | 247 | 
| jbe@210 | 248     local http_status = request.get_status() | 
| jbe@210 | 249     if http_status then | 
| jbe@210 | 250       cgi.set_status(http_status) | 
| jbe@210 | 251     end | 
| jbe@210 | 252 | 
| jbe@210 | 253     local json_request_slots = request.get_json_request_slots() | 
| jbe@210 | 254     if json_request_slots then | 
| jbe@210 | 255       cgi.set_content_type('application/json') | 
| jbe@210 | 256       local data = {} | 
| jbe@210 | 257       for idx, slot_ident in ipairs(json_request_slots) do | 
| jbe@210 | 258         data[slot_ident] = slot.get_content(slot_ident) | 
| jbe@210 | 259       end | 
| jbe@210 | 260       cgi.send_data(encode.json(data)) | 
| jbe@210 | 261     else | 
| jbe@210 | 262       cgi.set_content_type(slot.get_content_type()) | 
| jbe@210 | 263       cgi.send_data(slot.render_layout()) | 
| jbe@210 | 264     end | 
| jbe@210 | 265   end | 
| jbe@210 | 266 | 
| jbe@210 | 267 end |