* libs/http: fix header handling in conditionals.lua
authorJo-Philipp Wich <jow@openwrt.org>
Sat, 28 Jun 2008 16:12:37 +0000 (16:12 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Sat, 28 Jun 2008 16:12:37 +0000 (16:12 +0000)
* libs/httpd: add support for RFC2616 / 14.24 - 14.28 in file handler, add Date and Expires headers to luci handler

libs/http/luasrc/http/protocol.lua
libs/http/luasrc/http/protocol/conditionals.lua
libs/httpd/luasrc/httpd/handler/file.lua
libs/httpd/luasrc/httpd/handler/luci.lua

index 205869a..67b4258 100644 (file)
@@ -160,7 +160,7 @@ process_states['magic'] = function( msg, chunk, err )
                        end
                end
        end
                        end
                end
        end
-       
+
        -- Can't handle it
        return nil, "Invalid HTTP message magic"
 end
        -- Can't handle it
        return nil, "Invalid HTTP message magic"
 end
@@ -533,7 +533,7 @@ function header_source( sock )
                local chunk, err, part = sock:receive("*l")
 
                -- Line too long
                local chunk, err, part = sock:receive("*l")
 
                -- Line too long
-               if chunk == nil then 
+               if chunk == nil then
                        if err ~= "timeout" then
                                return nil, part
                                        and "Line exceeds maximum allowed length["..part.."]"
                        if err ~= "timeout" then
                                return nil, part
                                        and "Line exceeds maximum allowed length["..part.."]"
@@ -779,11 +779,13 @@ end
 -- Status codes
 statusmsg = {
        [200] = "OK",
 -- Status codes
 statusmsg = {
        [200] = "OK",
+       [304] = "Not Modified",
        [400] = "Bad Request",
        [403] = "Forbidden",
        [404] = "Not Found",
        [405] = "Method Not Allowed",
        [411] = "Length Required",
        [400] = "Bad Request",
        [403] = "Forbidden",
        [404] = "Not Found",
        [405] = "Method Not Allowed",
        [411] = "Length Required",
+       [412] = "Precondition Failed",
        [500] = "Internal Server Error",
        [503] = "Server Unavailable",
 }
        [500] = "Internal Server Error",
        [503] = "Server Unavailable",
 }
index 0bff274..36f323a 100644 (file)
@@ -21,7 +21,7 @@ local date = require("luci.http.protocol.date")
 -- 14.19 / ETag
 function mk_etag( stat )
        if stat ~= nil then
 -- 14.19 / ETag
 function mk_etag( stat )
        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
                end
 
                        return true
                end
 
-               return false, 304
+               return false, 304, {
+                       ["ETag"]          = mk_etag( stat );
+                       ["Last-Modified"] = date.to_http( stat.mtime )
+               }
        end
 
        return true
        end
 
        return true
@@ -74,10 +77,10 @@ function if_none_match( req, stat )
                                if req.request_method == "get"  or
                                   req.request_method == "head"
                                then
                                if req.request_method == "get"  or
                                   req.request_method == "head"
                                then
-                                       h['ETag']          = mk_etag( stat )
-                                       h['Last-Modified'] = date.to_http( stat.mtime )
-
-                                       return false, 304
+                                       return false, 304, {
+                                               ["ETag"]          = mk_etag( stat );
+                                               ["Last-Modified"] = date.to_http( stat.mtime )
+                                       }
                                else
                                        return false, 412
                                end
                                else
                                        return false, 412
                                end
index f553e82..790ebdd 100644 (file)
@@ -31,10 +31,11 @@ function Simple.__init__(self, docroot, dirlist)
        self.dirlist = dirlist and true or false
        self.mime    = luci.http.protocol.mime
        self.date    = luci.http.protocol.date
        self.dirlist = dirlist and true or false
        self.mime    = luci.http.protocol.mime
        self.date    = luci.http.protocol.date
+       self.cond    = luci.http.protocol.conditionals
 end
 
 function Simple.getfile(self, uri)
 end
 
 function Simple.getfile(self, uri)
-       local file = self.docroot .. uri:gsub("%.%./", "")
+       local file = self.docroot .. uri:gsub("%.%./+", "")
        local stat = luci.fs.stat(file)
 
        return file, stat
        local stat = luci.fs.stat(file)
 
        return file, stat
@@ -47,18 +48,45 @@ function Simple.handle_get(self, request, sourcein, sinkerr)
                if stat.type == "regular" then
 
                        -- Generate Entity Tag
                if stat.type == "regular" then
 
                        -- Generate Entity Tag
-                       local etag = luci.http.protocol.conditionals.mk_etag( stat )
-
-                       -- 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 etag = self.cond.mk_etag( stat )
+
+                       -- Check conditionals
+                       local ok, code, hdrs
+
+                       ok, code, hdrs = self.cond.if_modified_since( request, stat )
+                       if ok then
+                               ok, code, hdrs = self.cond.if_match( request, stat )
+                               if ok then
+                                       ok, code, hdrs = self.cond.if_unmodified_since( request, stat )
+                                       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))
+                                               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
                        return self:failure(403, "Unable to transmit " .. stat.type .. " " .. file)
                end
                else
                        return self:failure(403, "Unable to transmit " .. stat.type .. " " .. file)
                end
index 49a9abc..4a83de1 100644 (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");
 you may not use this file except in compliance with the License.
 
 Licensed under the Apache License, Version 2.0 (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.http")
 
 require("luci.dispatcher")
 require("luci.http")
+require("luci.http.protocol.date")
 require("ltn12")
 
 Luci = luci.util.class(luci.httpd.module.Handler)
 require("ltn12")
 
 Luci = luci.util.class(luci.httpd.module.Handler)
@@ -35,37 +36,37 @@ function Luci.handle_post(self, ...)
        return self:handle_get(...)
 end
 
        return self:handle_get(...)
 end
 
-function Luci.handle_get(self, request, sourcein, sinkerr)     
+function Luci.handle_get(self, request, sourcein, sinkerr)
        local r = luci.http.Request(
                request.env,
                sourcein,
                sinkerr
        )
        local r = luci.http.Request(
                request.env,
                sourcein,
                sinkerr
        )
-               
+
        local res, id, data1, data2 = true, 0, nil, nil
        local headers = {}
        local status = 200
        local res, id, data1, data2 = true, 0, nil, nil
        local headers = {}
        local status = 200
-       
+
        local x = coroutine.create(luci.dispatcher.httpdispatch)
        while not id or id < 3 do
                coroutine.yield()
        local x = coroutine.create(luci.dispatcher.httpdispatch)
        while not id or id < 3 do
                coroutine.yield()
-               
+
                res, id, data1, data2 = coroutine.resume(x, r)
                res, id, data1, data2 = coroutine.resume(x, r)
-               
+
                if not res then
                        status = 500
                        headers["Content-Type"] = "text/plain"
                        local err = {id}
                        return Response( status, headers ), function() return table.remove(err) end
                end
                if not res then
                        status = 500
                        headers["Content-Type"] = "text/plain"
                        local err = {id}
                        return Response( status, headers ), function() return table.remove(err) end
                end
-               
+
                if id == 1 then
                        status = data1
                elseif id == 2 then
                        headers[data1] = data2
                end
        end
                if id == 1 then
                        status = data1
                elseif id == 2 then
                        headers[data1] = data2
                end
        end
-       
+
        local function iter()
                local res, id, data = coroutine.resume(x)
                if not res then
        local function iter()
                local res, id, data = coroutine.resume(x)
                if not res then
@@ -78,6 +79,9 @@ function Luci.handle_get(self, request, sourcein, sinkerr)
                        return data
                end
        end
                        return data
                end
        end
-       
+
+       headers["Expires"] = luci.http.protocol.date.to_http( os.time() )
+       headers["Date"]    = headers["Expires"]
+
        return Response(status, headers), iter
 end
        return Response(status, headers), iter
 end