* 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:
parent
00aceaf624
commit
e08b97565f
4 changed files with 66 additions and 29 deletions
|
@ -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",
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue