mod_httpserver: Rename to mod_http_files
[prosody.git] / plugins / mod_http_files.lua
1 -- Prosody IM
2 -- Copyright (C) 2008-2010 Matthew Wild
3 -- Copyright (C) 2008-2010 Waqas Hussain
4 -- 
5 -- This project is MIT/X11 licensed. Please see the
6 -- COPYING file in the source package for more information.
7 --
8
9 module:depends("http");
10 local lfs = require "lfs";
11
12 local open = io.open;
13 local stat = lfs.attributes;
14
15 local http_base = module:get_option_string("http_path", "www_files");
16
17 local response_400 = "<h1>Bad Request</h1>Sorry, we didn't understand your request :(";
18 local response_403 = "<h1>Forbidden</h1>You don't have permission to view the contents of this directory :(";
19 local response_404 = "<h1>Page Not Found</h1>Sorry, we couldn't find what you were looking for :(";
20
21 -- TODO: Should we read this from /etc/mime.types if it exists? (startup time...?)
22 local mime_map = {
23         html = "text/html";
24         htm = "text/html";
25         xml = "text/xml";
26         xsl = "text/xml";
27         txt = "text/plain; charset=utf-8";
28         js = "text/javascript";
29         css = "text/css";
30 };
31
32 local function preprocess_path(path)
33         if path:sub(1,1) ~= "/" then
34                 path = "/"..path;
35         end
36         local level = 0;
37         for component in path:gmatch("([^/]+)/") do
38                 if component == ".." then
39                         level = level - 1;
40                 elseif component ~= "." then
41                         level = level + 1;
42                 end
43                 if level < 0 then
44                         return nil;
45                 end
46         end
47         return path;
48 end
49
50 function serve_file(request, path)
51         local response = request.response;
52         path = path and preprocess_path(path);
53         if not path then
54                 response.status = 400;
55                 return response:send(response_400);
56         end
57         local full_path = http_base..path;
58         if stat(full_path, "mode") == "directory" then
59                 if stat(full_path.."/index.html", "mode") == "file" then
60                         return serve_file(request, path.."/index.html");
61                 end
62                 response.status = 403;
63                 return response:send(response_403);
64         end
65         local f, err = open(full_path, "rb");
66         if not f then
67                 response.status = 404;
68                 return response:send(response_404.."<br/>"..tostring(err));
69         end
70         local data = f:read("*a");
71         f:close();
72         if not data then
73                 response.status = 403;
74                 return response:send(response_403);
75         end
76         local ext = path:match("%.([^.]*)$");
77         response.headers.content_type = mime_map[ext]; -- Content-Type should be nil when not known
78         return response:send(data);
79 end
80
81 module:provides("http", {
82         route = {
83                 ["/*"] = serve_file;
84         };
85 });
86