* libs/http: prepare support for RFC2616 / 14.24 - 14.28
authorJo-Philipp Wich <jow@openwrt.org>
Sat, 28 Jun 2008 02:05:48 +0000 (02:05 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Sat, 28 Jun 2008 02:05:48 +0000 (02:05 +0000)
libs/http/luasrc/http/protocol/conditionals.lua [new file with mode: 0644]
libs/httpd/luasrc/httpd/handler/file.lua

diff --git a/libs/http/luasrc/http/protocol/conditionals.lua b/libs/http/luasrc/http/protocol/conditionals.lua
new file mode 100644 (file)
index 0000000..0bff274
--- /dev/null
@@ -0,0 +1,111 @@
+--[[
+
+HTTP protocol implementation for LuCI - RFC2616 / 14.19, 14.24 - 14.28
+(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.conditionals", package.seeall)
+
+local date = require("luci.http.protocol.date")
+
+
+-- 14.19 / ETag
+function mk_etag( stat )
+       if stat ~= nil then
+               return string.format( "%x-%x-%x", stat.ino, stat.size, stat.mtime )
+       end
+end
+
+-- 14.24 / If-Match
+function if_match( req, stat )
+       local h    = req.headers
+       local etag = mk_etag( stat )
+
+       -- Check for matching resource
+       if type(h['If-Match']) == "string" then
+               for ent in h['If-Match']:gmatch("([^, ]+)") do
+                       if ( ent == '*' or ent == etag ) and stat ~= nil then
+                               return true
+                       end
+               end
+
+               return false, 412
+       end
+
+       return true
+end
+
+-- 14.25 / If-Modified-Since
+function if_modified_since( req, stat )
+       local h = req.headers
+
+       -- Compare mtimes
+       if type(h['If-Modified-Since']) == "string" then
+               local since = date.to_unix( h['If-Modified-Since'] )
+
+               if stat == nil or since < stat.mtime then
+                       return true
+               end
+
+               return false, 304
+       end
+
+       return true
+end
+
+-- 14.26 / If-None-Match
+function if_none_match( req, stat )
+       local h    = req.headers
+       local etag = mk_etag( stat )
+
+       -- Check for matching resource
+       if type(h['If-None-Match']) == "string" then
+               for ent in h['If-None-Match']:gmatch("([^, ]+)") do
+                       if ( ent == '*' or ent == etag ) and stat ~= nil 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
+                               else
+                                       return false, 412
+                               end
+                       end
+               end
+       end
+
+       return true
+end
+
+-- 14.27 / If-Range
+function if_range( req, stat )
+       -- Sorry, no subranges (yet)
+       return false, 412
+end
+
+-- 14.28 / If-Unmodified-Since
+function if_unmodified_since( req, stat )
+       local h = req.headers
+
+       -- Compare mtimes
+       if type(h['If-Unmodified-Since']) == "string" then
+               local since = date.to_unix( h['If-Unmodified-Since'] )
+
+               if stat ~= nil and since <= stat.mtime then
+                       return false, 412
+               end
+       end
+
+       return true
+end
index e6311e839f1946a8462990567dd01854c8c46e11..f553e8292a81384f50b1a98f5389b5f1597893e1 100644 (file)
@@ -18,6 +18,7 @@ module("luci.httpd.handler.file", package.seeall)
 require("luci.httpd.module")
 require("luci.http.protocol.date")
 require("luci.http.protocol.mime")
+require("luci.http.protocol.conditionals")
 require("luci.fs")
 require("ltn12")
 
@@ -39,28 +40,23 @@ function Simple.getfile(self, uri)
        return file, stat
 end
 
-
-function Simple._mk_etag(self, stat)
-       return string.format( "%x-%x-%x", stat.ino, stat.size, stat.mtime )
-end
-
-function Simple._cmp_etag(self, stat, etag)
-       return ( self:_mk_etag(stat) == etag )
-end
-
-
 function Simple.handle_get(self, request, sourcein, sinkerr)
        local file, stat = self:getfile(request.env.PATH_INFO)
 
        if stat then
                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"]           = self:_mk_etag( stat );
+                                       ["ETag"]           = etag;
                                }
                        ), ltn12.source.file(io.open(file))
                else