* libs/http: fix header handling in conditionals.lua

* libs/httpd:	add support for RFC2616 / 14.24 - 14.28 in file handler, add Date and Expires headers to luci handler
This commit is contained in:
Jo-Philipp Wich 2008-06-28 16:12:37 +00:00
parent 00aceaf624
commit e08b97565f
4 changed files with 66 additions and 29 deletions

View file

@ -160,7 +160,7 @@ process_states['magic'] = function( msg, chunk, err )
end end
end end
end end
-- Can't handle it -- Can't handle it
return nil, "Invalid HTTP message magic" return nil, "Invalid HTTP message magic"
end end
@ -533,7 +533,7 @@ function header_source( sock )
local chunk, err, part = sock:receive("*l") local chunk, err, part = sock:receive("*l")
-- Line too long -- Line too long
if chunk == nil then if chunk == nil then
if err ~= "timeout" then if err ~= "timeout" then
return nil, part return nil, part
and "Line exceeds maximum allowed length["..part.."]" and "Line exceeds maximum allowed length["..part.."]"
@ -779,11 +779,13 @@ end
-- Status codes -- Status codes
statusmsg = { statusmsg = {
[200] = "OK", [200] = "OK",
[304] = "Not Modified",
[400] = "Bad Request", [400] = "Bad Request",
[403] = "Forbidden", [403] = "Forbidden",
[404] = "Not Found", [404] = "Not Found",
[405] = "Method Not Allowed", [405] = "Method Not Allowed",
[411] = "Length Required", [411] = "Length Required",
[412] = "Precondition Failed",
[500] = "Internal Server Error", [500] = "Internal Server Error",
[503] = "Server Unavailable", [503] = "Server Unavailable",
} }

View file

@ -21,7 +21,7 @@ local date = require("luci.http.protocol.date")
-- 14.19 / ETag -- 14.19 / ETag
function mk_etag( stat ) function mk_etag( stat )
if stat ~= nil then if stat ~= nil then
return string.format( "%x-%x-%x", stat.ino, stat.size, stat.mtime ) return string.format( '"%x-%x-%x"', stat.ino, stat.size, stat.mtime )
end end
end end
@ -56,7 +56,10 @@ function if_modified_since( req, stat )
return true return true
end end
return false, 304 return false, 304, {
["ETag"] = mk_etag( stat );
["Last-Modified"] = date.to_http( stat.mtime )
}
end end
return true return true
@ -74,10 +77,10 @@ function if_none_match( req, stat )
if req.request_method == "get" or if req.request_method == "get" or
req.request_method == "head" req.request_method == "head"
then then
h['ETag'] = mk_etag( stat ) return false, 304, {
h['Last-Modified'] = date.to_http( stat.mtime ) ["ETag"] = mk_etag( stat );
["Last-Modified"] = date.to_http( stat.mtime )
return false, 304 }
else else
return false, 412 return false, 412
end end

View file

@ -31,10 +31,11 @@ function Simple.__init__(self, docroot, dirlist)
self.dirlist = dirlist and true or false self.dirlist = dirlist and true or false
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
end end
function Simple.getfile(self, uri) function Simple.getfile(self, uri)
local file = self.docroot .. uri:gsub("%.%./", "") local file = self.docroot .. uri:gsub("%.%./+", "")
local stat = luci.fs.stat(file) local stat = luci.fs.stat(file)
return file, stat return file, stat
@ -47,18 +48,45 @@ function Simple.handle_get(self, request, sourcein, sinkerr)
if stat.type == "regular" then if stat.type == "regular" then
-- Generate Entity Tag -- Generate Entity Tag
local etag = luci.http.protocol.conditionals.mk_etag( stat ) local etag = self.cond.mk_etag( stat )
-- Send Response -- Check conditionals
return Response( local ok, code, hdrs
200, {
["Date"] = self.date.to_http( os.time() ); ok, code, hdrs = self.cond.if_modified_since( request, stat )
["Last-Modified"] = self.date.to_http( stat.mtime ); if ok then
["Content-Type"] = self.mime.to_mime( file ); ok, code, hdrs = self.cond.if_match( request, stat )
["Content-Length"] = stat.size; if ok then
["ETag"] = etag; ok, code, hdrs = self.cond.if_unmodified_since( request, stat )
} if ok then
), ltn12.source.file(io.open(file)) 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))
else
return Response( code, hdrs or { } ),
ltn12.source.empty()
end
else
return Response( code, hdrs or { } ),
ltn12.source.empty()
end
else
return Response( code, hdrs or { } ),
ltn12.source.empty()
end
else
return Response( code, hdrs or { } ),
ltn12.source.empty()
end
else else
return self:failure(403, "Unable to transmit " .. stat.type .. " " .. file) return self:failure(403, "Unable to transmit " .. stat.type .. " " .. file)
end end

View file

@ -1,7 +1,7 @@
--[[ --[[
HTTP server implementation for LuCI - luci handler HTTP server implementation for LuCI - luci handler
(c) 2008 Steven Barth <steven@midlink.org> (c) 2008 Steven Barth <steven@midlink.org>
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -17,6 +17,7 @@ module("luci.httpd.handler.luci", package.seeall)
require("luci.dispatcher") require("luci.dispatcher")
require("luci.http") require("luci.http")
require("luci.http.protocol.date")
require("ltn12") require("ltn12")
Luci = luci.util.class(luci.httpd.module.Handler) Luci = luci.util.class(luci.httpd.module.Handler)
@ -35,37 +36,37 @@ function Luci.handle_post(self, ...)
return self:handle_get(...) return self:handle_get(...)
end end
function Luci.handle_get(self, request, sourcein, sinkerr) function Luci.handle_get(self, request, sourcein, sinkerr)
local r = luci.http.Request( local r = luci.http.Request(
request.env, request.env,
sourcein, sourcein,
sinkerr sinkerr
) )
local res, id, data1, data2 = true, 0, nil, nil local res, id, data1, data2 = true, 0, nil, nil
local headers = {} local headers = {}
local status = 200 local status = 200
local x = coroutine.create(luci.dispatcher.httpdispatch) local x = coroutine.create(luci.dispatcher.httpdispatch)
while not id or id < 3 do while not id or id < 3 do
coroutine.yield() coroutine.yield()
res, id, data1, data2 = coroutine.resume(x, r) res, id, data1, data2 = coroutine.resume(x, r)
if not res then if not res then
status = 500 status = 500
headers["Content-Type"] = "text/plain" headers["Content-Type"] = "text/plain"
local err = {id} local err = {id}
return Response( status, headers ), function() return table.remove(err) end return Response( status, headers ), function() return table.remove(err) end
end end
if id == 1 then if id == 1 then
status = data1 status = data1
elseif id == 2 then elseif id == 2 then
headers[data1] = data2 headers[data1] = data2
end end
end end
local function iter() local function iter()
local res, id, data = coroutine.resume(x) local res, id, data = coroutine.resume(x)
if not res then if not res then
@ -78,6 +79,9 @@ function Luci.handle_get(self, request, sourcein, sinkerr)
return data return data
end end
end end
headers["Expires"] = luci.http.protocol.date.to_http( os.time() )
headers["Date"] = headers["Expires"]
return Response(status, headers), iter return Response(status, headers), iter
end end