932d25472145a9086560c4fe97c31925022ba9ad
[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_files_dir", module:get_option_string("http_path", "www_files"));
16
17 -- TODO: Should we read this from /etc/mime.types if it exists? (startup time...?)
18 local mime_map = {
19         html = "text/html";
20         htm = "text/html";
21         xml = "text/xml";
22         xsl = "text/xml";
23         txt = "text/plain; charset=utf-8";
24         js = "text/javascript";
25         css = "text/css";
26 };
27
28 local function preprocess_path(path)
29         if path:sub(1,1) ~= "/" then
30                 path = "/"..path;
31         end
32         local level = 0;
33         for component in path:gmatch("([^/]+)/") do
34                 if component == ".." then
35                         level = level - 1;
36                 elseif component ~= "." then
37                         level = level + 1;
38                 end
39                 if level < 0 then
40                         return nil;
41                 end
42         end
43         return path;
44 end
45
46 function serve_file(event, path)
47         local response = event.response;
48         path = path and preprocess_path(path);
49         if not path then
50                 return 400;
51         end
52         local full_path = http_base..path;
53         if stat(full_path, "mode") == "directory" then
54                 if stat(full_path.."/index.html", "mode") == "file" then
55                         return serve_file(event, path.."/index.html");
56                 end
57                 return 403;
58         end
59         local f, err = open(full_path, "rb");
60         if not f then
61                 module:log("warn", "Failed to open file: %s", err);
62                 return 404;
63         end
64         local data = f:read("*a");
65         f:close();
66         if not data then
67                 return 403;
68         end
69         local ext = path:match("%.([^.]*)$");
70         response.headers.content_type = mime_map[ext]; -- Content-Type should be nil when not known
71         return response:send(data);
72 end
73
74 module:provides("http", {
75         route = {
76                 ["/*"] = serve_file;
77         };
78 });
79