* libs/http: removed protocol.filter, added mimetypes to protocol.mime
* libs/httpd: handle missing permissions correctly, perform urldecode on request uri and urlencode on generated links, added css
This commit is contained in:
parent
9926128741
commit
d7697624c4
4 changed files with 80 additions and 109 deletions
|
@ -16,7 +16,6 @@ $Id$
|
||||||
module("luci.http.protocol", package.seeall)
|
module("luci.http.protocol", package.seeall)
|
||||||
|
|
||||||
local ltn12 = require("luci.ltn12")
|
local ltn12 = require("luci.ltn12")
|
||||||
require("luci.http.protocol.filter")
|
|
||||||
|
|
||||||
HTTP_MAX_CONTENT = 1024*4 -- 4 kB maximum content size
|
HTTP_MAX_CONTENT = 1024*4 -- 4 kB maximum content size
|
||||||
HTTP_URLENC_MAXKEYLEN = 1024 -- maximum allowd size of urlencoded parameter names
|
HTTP_URLENC_MAXKEYLEN = 1024 -- maximum allowd size of urlencoded parameter names
|
||||||
|
@ -31,7 +30,7 @@ function urldecode( str )
|
||||||
end
|
end
|
||||||
|
|
||||||
if type(str) == "string" then
|
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
|
end
|
||||||
|
|
||||||
return str
|
return str
|
||||||
|
@ -84,7 +83,7 @@ function urlencode( str )
|
||||||
|
|
||||||
if type(str) == "string" then
|
if type(str) == "string" then
|
||||||
str = str:gsub(
|
str = str:gsub(
|
||||||
"([^a-zA-Z0-9$_%-%.+!*'(),])",
|
"([^a-zA-Z0-9$_%-%.%+!*'(),])",
|
||||||
__chrenc
|
__chrenc
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -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
|
|
|
@ -25,13 +25,41 @@ MIME_TYPES = {
|
||||||
["css"] = "text/css";
|
["css"] = "text/css";
|
||||||
["htm"] = "text/html";
|
["htm"] = "text/html";
|
||||||
["html"] = "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";
|
["gif"] = "image/gif";
|
||||||
["png"] = "image/png";
|
["png"] = "image/png";
|
||||||
["jpg"] = "image/jpeg";
|
["jpg"] = "image/jpeg";
|
||||||
["jpeg"] = "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
|
||||||
|
|
|
@ -30,6 +30,7 @@ function Simple.__init__(self, docroot, dirlist)
|
||||||
luci.httpd.module.Handler.__init__(self)
|
luci.httpd.module.Handler.__init__(self)
|
||||||
self.docroot = docroot
|
self.docroot = docroot
|
||||||
self.dirlist = dirlist and true or false
|
self.dirlist = dirlist and true or false
|
||||||
|
self.proto = luci.http.protocol
|
||||||
self.mime = luci.http.protocol.mime
|
self.mime = luci.http.protocol.mime
|
||||||
self.date = luci.http.protocol.date
|
self.date = luci.http.protocol.date
|
||||||
self.cond = luci.http.protocol.conditionals
|
self.cond = luci.http.protocol.conditionals
|
||||||
|
@ -43,7 +44,7 @@ function Simple.getfile(self, uri)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Simple.handle_get(self, request, sourcein, sinkerr)
|
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 then
|
||||||
if stat.type == "regular" then
|
if stat.type == "regular" then
|
||||||
|
@ -62,16 +63,22 @@ function Simple.handle_get(self, request, sourcein, sinkerr)
|
||||||
if ok then
|
if ok then
|
||||||
ok, code, hdrs = self.cond.if_none_match( request, stat )
|
ok, code, hdrs = self.cond.if_none_match( request, stat )
|
||||||
if ok then
|
if ok then
|
||||||
-- Send Response
|
local f, err = io.open(file)
|
||||||
return Response(
|
|
||||||
200, {
|
if f then
|
||||||
["Date"] = self.date.to_http( os.time() );
|
-- Send Response
|
||||||
["Last-Modified"] = self.date.to_http( stat.mtime );
|
return Response(
|
||||||
["Content-Type"] = self.mime.to_mime( file );
|
200, {
|
||||||
["Content-Length"] = stat.size;
|
["Date"] = self.date.to_http( os.time() );
|
||||||
["ETag"] = etag;
|
["Last-Modified"] = self.date.to_http( stat.mtime );
|
||||||
}
|
["Content-Type"] = self.mime.to_mime( file );
|
||||||
), ltn12.source.file(io.open(file))
|
["Content-Length"] = stat.size;
|
||||||
|
["ETag"] = etag;
|
||||||
|
}
|
||||||
|
), ltn12.source.file(f)
|
||||||
|
else
|
||||||
|
return self:failure( 403, err:gsub("^.+: ", "") )
|
||||||
|
end
|
||||||
else
|
else
|
||||||
return Response( code, hdrs or { } )
|
return Response( code, hdrs or { } )
|
||||||
end
|
end
|
||||||
|
@ -88,6 +95,7 @@ function Simple.handle_get(self, request, sourcein, sinkerr)
|
||||||
elseif stat.type == "directory" then
|
elseif stat.type == "directory" then
|
||||||
|
|
||||||
local ruri = request.request_uri:gsub("/$","")
|
local ruri = request.request_uri:gsub("/$","")
|
||||||
|
local duri = self.proto.urldecode( ruri )
|
||||||
local root = self.docroot:gsub("/$","")
|
local root = self.docroot:gsub("/$","")
|
||||||
|
|
||||||
-- check for index files
|
-- 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
|
-- try to find an index file and redirect to it
|
||||||
for i, candidate in ipairs( index_candidates ) do
|
for i, candidate in ipairs( index_candidates ) do
|
||||||
local istat = luci.fs.stat(
|
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" ' ..
|
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ' ..
|
||||||
'"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n' ..
|
'"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n' ..
|
||||||
'<html xmlns="http://www.w3.org/1999/xhtml" ' ..
|
'<html xmlns="http://www.w3.org/1999/xhtml" ' ..
|
||||||
'xml:lang="en" lang="en">\n' ..
|
'xml:lang="en" lang="en">\n' ..
|
||||||
'<head>\n' ..
|
'<head>\n' ..
|
||||||
'<title>Index of %s/</title>\n' ..
|
'<title>Index of %s/</title>\n' ..
|
||||||
'</head><body><h1>Index of %s/</h1><hr /><ul>',
|
'<style type="text/css"><!--\n' ..
|
||||||
ruri, ruri
|
'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 )
|
local estat = luci.fs.stat( file .. "/" .. e )
|
||||||
|
|
||||||
if estat.type == "directory" then
|
if estat.type == "directory" then
|
||||||
html = html .. string.format(
|
html = html .. string.format(
|
||||||
'<li><p><a href="%s/%s/">%s/</a> ' ..
|
'<li><p><a href="%s/%s/">%s/</a> ' ..
|
||||||
'<small>(directory)</small><br />' ..
|
'<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 )
|
self.date.to_http( estat.mtime )
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
html = html .. string.format(
|
html = html .. string.format(
|
||||||
'<li><p><a href="%s/%s">%s</a> ' ..
|
'<li><p><a href="%s/%s">%s</a> ' ..
|
||||||
'<small>(%s)</small><br />' ..
|
'<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 )
|
estat.size, self.date.to_http( estat.mtime )
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -152,7 +177,7 @@ function Simple.handle_get(self, request, sourcein, sinkerr)
|
||||||
return Response(
|
return Response(
|
||||||
200, {
|
200, {
|
||||||
["Date"] = self.date.to_http( os.time() );
|
["Date"] = self.date.to_http( os.time() );
|
||||||
["Content-Type"] = "text/html";
|
["Content-Type"] = "text/html; charset=ISO-8859-15";
|
||||||
}
|
}
|
||||||
), ltn12.source.string(html)
|
), ltn12.source.string(html)
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in a new issue