From 7f56bf947599b20e2cf50018e160e602d5516e5f Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Sat, 28 Jun 2008 02:05:48 +0000 Subject: [PATCH] * libs/http: prepare support for RFC2616 / 14.24 - 14.28 --- libs/http/luasrc/http/protocol/conditionals.lua | 111 ++++++++++++++++++++++++ libs/httpd/luasrc/httpd/handler/file.lua | 18 ++-- 2 files changed, 118 insertions(+), 11 deletions(-) create mode 100644 libs/http/luasrc/http/protocol/conditionals.lua diff --git a/libs/http/luasrc/http/protocol/conditionals.lua b/libs/http/luasrc/http/protocol/conditionals.lua new file mode 100644 index 000000000..0bff274cd --- /dev/null +++ b/libs/http/luasrc/http/protocol/conditionals.lua @@ -0,0 +1,111 @@ +--[[ + +HTTP protocol implementation for LuCI - RFC2616 / 14.19, 14.24 - 14.28 +(c) 2008 Freifunk Leipzig / Jo-Philipp Wich + +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 diff --git a/libs/httpd/luasrc/httpd/handler/file.lua b/libs/httpd/luasrc/httpd/handler/file.lua index e6311e839..f553e8292 100644 --- a/libs/httpd/luasrc/httpd/handler/file.lua +++ b/libs/httpd/luasrc/httpd/handler/file.lua @@ -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 -- 2.11.0