* libs/http: removed protocol.filter, added mimetypes to protocol.mime
authorJo-Philipp Wich <jow@openwrt.org>
Mon, 30 Jun 2008 11:52:23 +0000 (11:52 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Mon, 30 Jun 2008 11:52:23 +0000 (11:52 +0000)
* libs/httpd: handle missing permissions correctly, perform urldecode on request uri and urlencode on generated links, added css

libs/http/luasrc/http/protocol.lua
libs/http/luasrc/http/protocol/filter.lua [deleted file]
libs/http/luasrc/http/protocol/mime.lua
libs/httpd/luasrc/httpd/handler/file.lua

index ac58578..93851fb 100644 (file)
@@ -16,7 +16,6 @@ $Id$
 module("luci.http.protocol", package.seeall)
 
 local ltn12 = require("luci.ltn12")
 module("luci.http.protocol", package.seeall)
 
 local ltn12 = require("luci.ltn12")
-require("luci.http.protocol.filter")
 
 HTTP_MAX_CONTENT      = 1024*4         -- 4 kB maximum content size
 HTTP_URLENC_MAXKEYLEN = 1024           -- maximum allowd size of urlencoded parameter names
 
 HTTP_MAX_CONTENT      = 1024*4         -- 4 kB maximum content size
 HTTP_URLENC_MAXKEYLEN = 1024           -- maximum allowd size of urlencoded parameter names
@@ -31,7 +30,7 @@ function urldecode( str )
        end
 
        if type(str) == "string" then
        end
 
        if type(str) == "string" then
-               str = str:gsub( "+", " " ):gsub( "%%([a-fA-F0-9][a-fA-F0-9])", __chrdec )
+               str = str:gsub( "%%([a-fA-F0-9][a-fA-F0-9])", __chrdec )
        end
 
        return str
        end
 
        return str
@@ -84,7 +83,7 @@ function urlencode( str )
 
        if type(str) == "string" then
                str = str:gsub(
 
        if type(str) == "string" then
                str = str:gsub(
-                       "([^a-zA-Z0-9$_%-%.+!*'(),])",
+                       "([^a-zA-Z0-9$_%-%.%+!*'(),])",
                        __chrenc
                )
        end
                        __chrenc
                )
        end
diff --git a/libs/http/luasrc/http/protocol/filter.lua b/libs/http/luasrc/http/protocol/filter.lua
deleted file mode 100644 (file)
index de106aa..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
---[[
-
-HTTP protocol implementation for LuCI - filter implementation
-(c) 2008 Freifunk Leipzig / Jo-Philipp Wich <xm@leipzig.freifunk.net>
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-        http://www.apache.org/licenses/LICENSE-2.0
-
-$Id$
-
-]]--
-
-module("luci.http.protocol.filter", package.seeall)
-
-local ltn12 = require("luci.ltn12")
-
-
--- Factory that produces a filter which normalizes chunked transfer encoding
-function decode_chunked()
-
-       local length = 0
-       local read   = 0
-
-       return ltn12.filter.cycle(
-               function( chunk, ctx )
-
-                       if chunk ~= nil then
-
-                               -- EOF
-                               if ctx == nil then
-                                       if ( length - read ) > 0 then
-                                               return nil, "Unexpected EOF"
-                                       else
-                                               return ""
-                                       end
-                               end
-
-                               chunk = ctx .. chunk
-
-                               local buf = ""
-                               while true do
-
-                                       if read == length then
-
-                                               -- Find chunk length indicator
-                                               local spos, epos = chunk:find("^\r?\n?[a-fA-F0-9]+ *\r\n")
-                                               if spos and spos == 1 then
-                                                       read   = 0
-                                                       length = tonumber(
-                                                               chunk:sub( 1, epos ):gsub( "[^a-fA-F0-9]", "" ), 16
-                                                       )
-
-                                                       -- Check for end of chunk
-                                                       if length > 0 then
-                                                               chunk = chunk:sub( epos + 1, #chunk )
-                                                       else
-                                                               return buf, ""
-                                                       end
-                                               else
-                                                       return "", nil
-                                               end
-                                       else
-                                               if ( read + #chunk ) <= length then
-                                                       read = read + #chunk
-                                                       return buf .. chunk, ""
-                                               else
-                                                       local rest = length - read
-                                                       read  = read + rest
-                                                       buf   = buf .. chunk:sub( 1, rest )
-                                                       chunk = chunk:sub( rest + 1, #chunk )
-                                               end
-                                       end
-                               end
-                       end
-               end,
-               ""
-       )
-end
index 7f09f94..9fb8d25 100644 (file)
@@ -25,13 +25,41 @@ MIME_TYPES = {
     ["css"]   = "text/css";
     ["htm"]   = "text/html";
     ["html"]  = "text/html";
     ["css"]   = "text/css";
     ["htm"]   = "text/html";
     ["html"]  = "text/html";
+    ["patch"] = "text/x-patch";
+    ["c"]     = "text/x-csrc";
+    ["h"]     = "text/x-chdr";
+    ["o"]     = "text/x-object";
+    ["ko"]    = "text/x-object";
 
 
+    ["bmp"]   = "image/bmp";
     ["gif"]   = "image/gif";
     ["png"]   = "image/png";
     ["jpg"]   = "image/jpeg";
     ["jpeg"]  = "image/jpeg";
     ["gif"]   = "image/gif";
     ["png"]   = "image/png";
     ["jpg"]   = "image/jpeg";
     ["jpeg"]  = "image/jpeg";
+    ["svg"]   = "image/svg+xml";
 
 
+    ["zip"]   = "application/zip";
+    ["pdf"]   = "application/pdf";
     ["xml"]   = "application/xml";
     ["xml"]   = "application/xml";
+    ["doc"]   = "application/msword";
+    ["ppt"]   = "application/vnd.ms-powerpoint";
+    ["xls"]   = "application/vnd.ms-excel";
+    ["odt"]   = "application/vnd.oasis.opendocument.text";
+    ["odp"]   = "application/vnd.oasis.opendocument.presentation";
+    ["pl"]    = "application/x-perl";
+    ["sh"]    = "application/x-shellscript";
+    ["php"]   = "application/x-php";
+    ["deb"]   = "application/x-deb";
+    ["iso"]   = "application/x-cd-image";
+    ["tgz"]   = "application/x-compressed-tar";
+
+    ["mp3"]   = "audio/mpeg";
+    ["ogg"]   = "audio/x-vorbis+ogg";
+    ["wav"]   = "audio/x-wav";
+
+    ["mpg"]   = "video/mpeg";
+    ["mpeg"]  = "video/mpeg";
+    ["avi"]   = "video/x-msvideo";
 }
 
 -- extract extension from a filename and return corresponding mime-type or
 }
 
 -- extract extension from a filename and return corresponding mime-type or
index 8028263..4cbfa41 100644 (file)
@@ -30,6 +30,7 @@ function Simple.__init__(self, docroot, dirlist)
        luci.httpd.module.Handler.__init__(self)
        self.docroot = docroot
        self.dirlist = dirlist and true or false
        luci.httpd.module.Handler.__init__(self)
        self.docroot = docroot
        self.dirlist = dirlist and true or false
+       self.proto   = luci.http.protocol
        self.mime    = luci.http.protocol.mime
        self.date    = luci.http.protocol.date
        self.cond    = luci.http.protocol.conditionals
        self.mime    = luci.http.protocol.mime
        self.date    = luci.http.protocol.date
        self.cond    = luci.http.protocol.conditionals
@@ -43,7 +44,7 @@ function Simple.getfile(self, uri)
 end
 
 function Simple.handle_get(self, request, sourcein, sinkerr)
 end
 
 function Simple.handle_get(self, request, sourcein, sinkerr)
-       local file, stat = self:getfile(request.env.PATH_INFO)
+       local file, stat = self:getfile( self.proto.urldecode( request.env.PATH_INFO ) )
 
        if stat then
                if stat.type == "regular" then
 
        if stat then
                if stat.type == "regular" then
@@ -62,16 +63,22 @@ function Simple.handle_get(self, request, sourcein, sinkerr)
                                        if ok then
                                                ok, code, hdrs = self.cond.if_none_match( request, stat )
                                                if ok then
                                        if ok then
                                                ok, code, hdrs = self.cond.if_none_match( request, stat )
                                                if ok then
-                                                       -- Send Response
-                                                       return Response(
-                                                               200, {
-                                                                       ["Date"]           = self.date.to_http( os.time() );
-                                                                       ["Last-Modified"]  = self.date.to_http( stat.mtime );
-                                                                       ["Content-Type"]   = self.mime.to_mime( file );
-                                                                       ["Content-Length"] = stat.size;
-                                                                       ["ETag"]           = etag;
-                                                               }
-                                                       ), ltn12.source.file(io.open(file))
+                                                       local f, err = io.open(file)
+
+                                                       if f then
+                                                               -- Send Response
+                                                               return Response(
+                                                                       200, {
+                                                                               ["Date"]           = self.date.to_http( os.time() );
+                                                                               ["Last-Modified"]  = self.date.to_http( stat.mtime );
+                                                                               ["Content-Type"]   = self.mime.to_mime( file );
+                                                                               ["Content-Length"] = stat.size;
+                                                                               ["ETag"]           = etag;
+                                                                       }
+                                                               ), ltn12.source.file(f)
+                                                       else
+                                                               return self:failure( 403, err:gsub("^.+: ", "") )
+                                                       end
                                                else
                                                        return Response( code, hdrs or { } )
                                                end
                                                else
                                                        return Response( code, hdrs or { } )
                                                end
@@ -88,6 +95,7 @@ function Simple.handle_get(self, request, sourcein, sinkerr)
                elseif stat.type == "directory" then
 
                        local ruri = request.request_uri:gsub("/$","")
                elseif stat.type == "directory" then
 
                        local ruri = request.request_uri:gsub("/$","")
+                       local duri = self.proto.urldecode( ruri )
                        local root = self.docroot:gsub("/$","")
 
                        -- check for index files
                        local root = self.docroot:gsub("/$","")
 
                        -- check for index files
@@ -99,7 +107,7 @@ function Simple.handle_get(self, request, sourcein, sinkerr)
                        -- try to find an index file and redirect to it
                        for i, candidate in ipairs( index_candidates ) do
                                local istat = luci.fs.stat(
                        -- try to find an index file and redirect to it
                        for i, candidate in ipairs( index_candidates ) do
                                local istat = luci.fs.stat(
-                                       root .. "/" .. ruri .. "/" .. candidate
+                                       root .. "/" .. duri .. "/" .. candidate
                                )
 
                                if istat ~= nil and istat.type == "regular" then
                                )
 
                                if istat ~= nil and istat.type == "regular" then
@@ -111,36 +119,53 @@ function Simple.handle_get(self, request, sourcein, sinkerr)
 
 
                        local html = string.format(
 
 
                        local html = string.format(
-                               '<?xml version="1.0" encoding="UTF-8"?>\n' ..
+                               '<?xml version="1.0" encoding="ISO-8859-15"?>\n' ..
                                '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" '  ..
                                        '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n' ..
                                '<html xmlns="http://www.w3.org/1999/xhtml" '                ..
                                        'xml:lang="en" lang="en">\n'                             ..
                                '<head>\n'                                                   ..
                                '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" '  ..
                                        '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n' ..
                                '<html xmlns="http://www.w3.org/1999/xhtml" '                ..
                                        'xml:lang="en" lang="en">\n'                             ..
                                '<head>\n'                                                   ..
-                               '<title>Index of %s/</title>\n'                               ..
-                               '</head><body><h1>Index of %s/</h1><hr /><ul>',
-                                       ruri, ruri
+                               '<title>Index of %s/</title>\n'                              ..
+                               '<style type="text/css"><!--\n'                              ..
+                                       'body { background-color:#FFFFFF; color:#000000 } '      ..
+                                       'li { border-bottom:1px dotted #CCCCCC; padding:3px } '  ..
+                                       'small { font-size:60%%; color:#999999 } '               ..
+                                       'p { margin:0 }'                                         ..
+                               '\n--></style></head><body><h1>Index of %s/</h1><hr /><ul>',
+                                       duri, duri
                        )
 
                        )
 
-                       for i, e in luci.util.vspairs( luci.fs.dir( file ) ) do
+                       local entries = luci.fs.dir( file )
 
 
-                               if e ~= '.' then
+                       for i, e in luci.util.spairs(
+                               entries, function(a,b)
+                                       if entries[a] == '..' then
+                                               return true
+                                       elseif entries[b] == '..' then
+                                               return false
+                                       else
+                                               return ( entries[a] < entries[b] )
+                                       end
+                               end
+                       ) do
+                               if e ~= '.' and ( e == '..' or e:sub(1,1) ~= '.' ) then
                                        local estat = luci.fs.stat( file .. "/" .. e )
 
                                        if estat.type == "directory" then
                                                html = html .. string.format(
                                        local estat = luci.fs.stat( file .. "/" .. e )
 
                                        if estat.type == "directory" then
                                                html = html .. string.format(
-                                                       '<li><p><a href="%s/%s/">%s/</a> '                         ..
-                                                       '<small>(directory)</small><br />'                              ..
+                                                       '<li><p><a href="%s/%s/">%s/</a> '               ..
+                                                       '<small>(directory)</small><br />'               ..
                                                        '<small>Changed: %s</small></li>',
                                                        '<small>Changed: %s</small></li>',
-                                                               ruri, e, e,
+                                                               ruri, self.proto.urlencode( e ), e,
                                                                self.date.to_http( estat.mtime )
                                                )
                                        else
                                                html = html .. string.format(
                                                                self.date.to_http( estat.mtime )
                                                )
                                        else
                                                html = html .. string.format(
-                                                       '<li><p><a href="%s/%s">%s</a> '                         ..
-                                                       '<small>(%s)</small><br />'                              ..
+                                                       '<li><p><a href="%s/%s">%s</a> '                 ..
+                                                       '<small>(%s)</small><br />'                      ..
                                                        '<small>Size: %i Bytes | Changed: %s</small></li>',
                                                        '<small>Size: %i Bytes | Changed: %s</small></li>',
-                                                               ruri, e, e, self.mime.to_mime( e ),
+                                                               ruri, self.proto.urlencode( e ), e,
+                                                               self.mime.to_mime( e ),
                                                                estat.size, self.date.to_http( estat.mtime )
                                                )
                                        end
                                                                estat.size, self.date.to_http( estat.mtime )
                                                )
                                        end
@@ -152,7 +177,7 @@ function Simple.handle_get(self, request, sourcein, sinkerr)
                        return Response(
                                200, {
                                        ["Date"]         = self.date.to_http( os.time() );
                        return Response(
                                200, {
                                        ["Date"]         = self.date.to_http( os.time() );
-                                       ["Content-Type"] = "text/html";
+                                       ["Content-Type"] = "text/html; charset=ISO-8859-15";
                                }
                        ), ltn12.source.string(html)
                else
                                }
                        ), ltn12.source.string(html)
                else