http.lua
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:9k
源码类别:

midi

开发平台:

Unix_Linux

  1. --[==========================================================================[
  2.  http.lua: HTTP interface module for VLC
  3. --[==========================================================================[
  4.  Copyright (C) 2007 the VideoLAN team
  5.  $Id$
  6.  Authors: Antoine Cellerier <dionoea at videolan dot org>
  7.  This program is free software; you can redistribute it and/or modify
  8.  it under the terms of the GNU General Public License as published by
  9.  the Free Software Foundation; either version 2 of the License, or
  10.  (at your option) any later version.
  11.  This program is distributed in the hope that it will be useful,
  12.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  GNU General Public License for more details.
  15.  You should have received a copy of the GNU General Public License
  16.  along with this program; if not, write to the Free Software
  17.  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  18. --]==========================================================================]
  19. --[==========================================================================[
  20. Configuration options:
  21.  * host: A host to listen on.
  22.  * dir: Directory to use as the http interface's root.
  23.  * no_error_detail: If set, do not print the Lua error message when generating
  24.                     a page fails.
  25.  * no_index: If set, don't build directory indexes
  26. --]==========================================================================]
  27. require "common"
  28. vlc.msg.info("Lua HTTP interface")
  29. open_tag = "<?vlc"
  30. close_tag = "?>"
  31. function escape(s)
  32.     return (string.gsub(s,"([%^%$%%%.%[%]%*%+%-%?])","%%%1"))
  33. end
  34. function process_raw(filename)
  35.     local input = io.open(filename):read("*a")
  36.     -- find the longest [===[ or ]=====] type sequence and make sure that
  37.     -- we use one that's longer.
  38.     local str="X"
  39.     for str2 in string.gmatch(input,"[%[%]]=*[%[%]]") do
  40.         if #str < #str2 then str = str2 end
  41.     end
  42.     str=string.rep("=",#str-1)
  43.     --[[ FIXME:
  44.     <?xml version="1.0" encoding="charset" standalone="yes" ?> is still a problem. The closing '?>' needs to be printed using '?<?vlc print ">" ?>' to prevent a parse error.
  45.     --]]
  46.     local code0 = string.gsub(input,escape(close_tag)," print(["..str.."[")
  47.     local code1 = string.gsub(code0,escape(open_tag),"]"..str.."]) ")
  48.     local code = "print(["..str.."["..code1.."]"..str.."])"
  49.     --[[ Uncomment to debug
  50.     if string.match(filename,"vlm_cmd.xml$") then
  51.     io.write(code)
  52.     io.write("n")
  53.     end
  54.     --]]
  55.     return assert(loadstring(code,filename))
  56. end
  57. function process(filename)
  58.     local mtime = 0    -- vlc.net.stat(filename).modification_time
  59.     local func = false -- process_raw(filename)
  60.     return function(...)
  61.         local new_mtime = vlc.net.stat(filename).modification_time
  62.         if new_mtime ~= mtime then
  63.             -- Re-read the file if it changed
  64.             if mtime == 0 then
  65.                 vlc.msg.dbg("Loading `"..filename.."'")
  66.             else
  67.                 vlc.msg.dbg("Reloading `"..filename.."'")
  68.             end
  69.             func = process_raw(filename)
  70.             mtime = new_mtime
  71.         end
  72.         return func(...)
  73.     end
  74. end
  75. function callback_error(path,url,msg)
  76.     local url = url or "&lt;page unknown&gt;"
  77.     return  [[<html xmlns="http://www.w3.org/1999/xhtml">
  78. <head>
  79. <title>Error loading ]]..url..[[</title>
  80. </head>
  81. <body>
  82. <h1>Error loading ]]..url..[[</h1><pre>]]..(config.no_error_detail and "Remove configuration option `no_error_detail' on the server to get more information." or tostring(msg))..[[</pre>
  83. <p>
  84. <a href="http://www.videolan.org/">VideoLAN</a><br/>
  85. <a href="http://www.lua.org/manual/5.1/">Lua 5.1 Reference Manual</a>
  86. </p>
  87. </body>
  88. </html>]]
  89. end
  90. function dirlisting(url,listing,acl_)
  91.     local list = {}
  92.     for _,f in ipairs(listing) do
  93.         if not string.match(f,"^%.") then
  94.             table.insert(list,"<li><a href='"..f.."'>"..f.."</a></li>")
  95.         end
  96.     end
  97.     list = table.concat(list)
  98.     local function callback()
  99.         return [[<html xmlns="http://www.w3.org/1999/xhtml">
  100. <head>
  101. <title>Directory listing ]]..url..[[</title>
  102. </head>
  103. <body>
  104. <h1>Directory listing ]]..url..[[</h1><ul>]]..list..[[</ul>
  105. </body>
  106. </html>]]
  107.     end
  108.     return h:file(url,"text/html",nil,nil,acl_,callback,nil)
  109. end
  110. function file(h,path,url,acl_,mime)
  111.     local generate_page = process(path)
  112.     local callback = function(data,request)
  113.         -- FIXME: I'm sure that we could define a real sandbox
  114.         -- redefine print
  115.         local page = {}
  116.         local function pageprint(...)
  117.             for i=1,select("#",...) do
  118.                 if i== 1 then
  119.                     table.insert(page,tostring(select(i,...)))
  120.                 else
  121.                     table.insert(page," "..tostring(select(i,...)))
  122.                 end
  123.             end
  124.         end
  125.         _G._GET = parse_url_request(request)
  126.         local oldprint = print
  127.         print = pageprint
  128.         local ok, msg = pcall(generate_page)
  129.         -- reset
  130.         print = oldprint
  131.         if not ok then
  132.             return callback_error(path,url,msg)
  133.         end
  134.         return table.concat(page)
  135.     end
  136.     return h:file(url or path,mime,nil,nil,acl_,callback,nil)
  137. end
  138. function rawfile(h,path,url,acl_)
  139.     local filename = path
  140.     local mtime = 0    -- vlc.net.stat(filename).modification_time
  141.     local page = false -- io.open(filename):read("*a")
  142.     local callback = function(data,request)
  143.         local new_mtime = vlc.net.stat(filename).modification_time
  144.         if mtime ~= new_mtime then
  145.             -- Re-read the file if it changed
  146.             if mtime == 0 then
  147.                 vlc.msg.dbg("Loading `"..filename.."'")
  148.             else
  149.                 vlc.msg.dbg("Reloading `"..filename.."'")
  150.             end
  151.             page = io.open(filename):read("*a")
  152.             mtime = new_mtime
  153.         end
  154.         return page
  155.     end
  156.     return h:file(url or path,nil,nil,nil,acl_,callback,nil)
  157. end
  158. function parse_url_request(request)
  159.     if not request then return {} end
  160.     t = {}
  161.     for k,v in string.gmatch(request,"([^=&]+)=?([^=&]*)") do
  162.         local k_ = vlc.strings.decode_uri(k)
  163.         local v_ = vlc.strings.decode_uri(v)
  164.         if t[k_] ~= nil then
  165.             local t2
  166.             if type(t[k_]) ~= "table" then
  167.                 t2 = {}
  168.                 table.insert(t2,t[k_])
  169.                 t[k_] = t2
  170.             else
  171.                 t2 = t[k_]
  172.             end
  173.             table.insert(t2,v_)
  174.         else
  175.             t[k_] = v_
  176.         end
  177.     end
  178.     return t
  179. end
  180. local function find_datadir(name)
  181.     local list = vlc.misc.datadir_list(name)
  182.     for _, l in ipairs(list) do
  183.         local s = vlc.net.stat(l)
  184.         if s then
  185.             return l
  186.         end
  187.     end
  188.     error("Unable to find the `"..name.."' directory.")
  189. end
  190. http_dir = config.dir or find_datadir("http")
  191. do
  192.     local oldpath = package.path
  193.     package.path = http_dir.."/?.lua"
  194.     local ok, err = pcall(require,"custom")
  195.     if not ok then
  196.         vlc.msg.warn("Couldn't load "..http_dir.."/custom.lua")
  197.     else
  198.         vlc.msg.dbg("Loaded "..http_dir.."/custom.lua")
  199.     end
  200.     package.path = oldpath
  201. end
  202. local files = {}
  203. local mimes = {
  204.     txt = "text/plain",
  205.     html = "text/html",
  206.     xml = "text/xml",
  207.     js = "text/javascript",
  208.     css = "text/css",
  209.     png = "image/png",
  210.     ico = "image/x-icon",
  211. }
  212. local function load_dir(dir,root,parent_acl)
  213.     local root = root or "/"
  214.     local has_index = false
  215.     local my_acl = parent_acl
  216.     do
  217.         local af = dir.."/.hosts"
  218.         local s = vlc.net.stat(af)
  219.         if s and s.type == "file" then
  220.             -- We found an acl
  221.             my_acl = vlc.acl(false)
  222.             my_acl:load_file(af)
  223.         end
  224.     end
  225.     local d = vlc.net.opendir(dir)
  226.     for _,f in ipairs(d) do
  227.         if not string.match(f,"^%.") then
  228.             local s = vlc.net.stat(dir.."/"..f)
  229.             if s.type == "file" then
  230.                 local url
  231.                 if f == "index.html" then
  232.                     url = root
  233.                     has_index = true
  234.                 else
  235.                     url = root..f
  236.                 end
  237.                 local ext = string.match(f,"%.([^%.]-)$")
  238.                 local mime = mimes[ext]
  239.                 -- print(url,mime)
  240.                 if mime and string.match(mime,"^text/") then
  241.                     table.insert(files,file(h,dir.."/"..f,url,my_acl and my_acl.private,mime))
  242.                 else
  243.                     table.insert(files,rawfile(h,dir.."/"..f,url,my_acl and my_acl.private))
  244.                 end
  245.             elseif s.type == "dir" then
  246.                 load_dir(dir.."/"..f,root..f.."/",my_acl)
  247.             end
  248.         end
  249.     end
  250.     if not has_index and not config.no_index then
  251.         -- print("Adding index for", root)
  252.         table.insert(files,dirlisting(root,d,my_acl and my_acl.private))
  253.     end
  254. end
  255. local u = vlc.net.url_parse( config.host or "localhost:8080" )
  256. h = vlc.httpd(u.host,u.port)
  257. load_dir( http_dir )
  258. while not vlc.misc.lock_and_wait() do end -- everything happens in callbacks
  259. -- FIXME: We shouldn't need to do this ourselves.
  260. for i=1,#files do
  261.     getmetatable(files[i]).__gc(files[i])
  262.     files[i] = nil
  263. end