mirror of
https://github.com/coolsnowwolf/luci
synced 2025-01-08 11:27:28 +08:00
add luci-lib-httpprotoutils
This commit is contained in:
parent
3a2a6186ed
commit
411f655970
14
libs/luci-lib-httpprotoutils/Makefile
Normal file
14
libs/luci-lib-httpprotoutils/Makefile
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#
|
||||||
|
# Copyright (C) 2018 The LuCI Team <luci@lists.subsignal.org>
|
||||||
|
#
|
||||||
|
# This is free software, licensed under the Apache License, Version 2.0 .
|
||||||
|
#
|
||||||
|
|
||||||
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
|
LUCI_TITLE:=HTTP protocol utility functions
|
||||||
|
LUCI_DEPENDS:=+luci-base
|
||||||
|
|
||||||
|
include ../../luci.mk
|
||||||
|
|
||||||
|
# call BuildPackage - OpenWrt buildroot signature
|
110
libs/luci-lib-httpprotoutils/luasrc/http/conditionals.lua
Normal file
110
libs/luci-lib-httpprotoutils/luasrc/http/conditionals.lua
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
|
||||||
|
-- Licensed to the public under the Apache License 2.0.
|
||||||
|
|
||||||
|
-- This class provides basic ETag handling and implements most of the
|
||||||
|
-- conditional HTTP/1.1 headers specified in RFC2616 Sct. 14.24 - 14.28 .
|
||||||
|
module("luci.http.conditionals", package.seeall)
|
||||||
|
|
||||||
|
local date = require("luci.http.date")
|
||||||
|
|
||||||
|
|
||||||
|
function mk_etag( stat )
|
||||||
|
if stat ~= nil then
|
||||||
|
return string.format( '"%x-%x-%x"', stat.ino, stat.size, stat.mtime )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Test whether the given message object contains an "If-Match" header and
|
||||||
|
-- compare it against the given stat object.
|
||||||
|
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
|
||||||
|
|
||||||
|
-- Test whether the given message object contains an "If-Modified-Since" header
|
||||||
|
-- and compare it against the given stat object.
|
||||||
|
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, {
|
||||||
|
["ETag"] = mk_etag( stat );
|
||||||
|
["Date"] = date.to_http( os.time() );
|
||||||
|
["Last-Modified"] = date.to_http( stat.mtime )
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Test whether the given message object contains an "If-None-Match" header and
|
||||||
|
-- compare it against the given stat object.
|
||||||
|
function if_none_match( req, stat )
|
||||||
|
local h = req.headers
|
||||||
|
local etag = mk_etag( stat )
|
||||||
|
local method = req.env and req.env.REQUEST_METHOD or "GET"
|
||||||
|
|
||||||
|
-- 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 method == "GET" or method == "HEAD" then
|
||||||
|
return false, 304, {
|
||||||
|
["ETag"] = etag;
|
||||||
|
["Date"] = date.to_http( os.time() );
|
||||||
|
["Last-Modified"] = date.to_http( stat.mtime )
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false, 412
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The If-Range header is currently not implemented due to the lack of general
|
||||||
|
-- byte range stuff in luci.http.protocol . This function will always return
|
||||||
|
-- false, 412 to indicate a failed precondition.
|
||||||
|
function if_range( req, stat )
|
||||||
|
-- Sorry, no subranges (yet)
|
||||||
|
return false, 412
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Test whether the given message object contains an "If-Unmodified-Since"
|
||||||
|
-- header and compare it against the given stat object.
|
||||||
|
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
|
85
libs/luci-lib-httpprotoutils/luasrc/http/conditionals.luadoc
Normal file
85
libs/luci-lib-httpprotoutils/luasrc/http/conditionals.luadoc
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
---[[
|
||||||
|
LuCI http protocol implementation - HTTP/1.1 bits.
|
||||||
|
|
||||||
|
This class provides basic ETag handling and implements most of the
|
||||||
|
conditional HTTP/1.1 headers specified in RFC2616 Sct. 14.24 - 14.28 .
|
||||||
|
]]
|
||||||
|
module "luci.http.conditionals"
|
||||||
|
|
||||||
|
---[[
|
||||||
|
Implement 14.19 / ETag.
|
||||||
|
|
||||||
|
@class function
|
||||||
|
@name mk_etag
|
||||||
|
@param stat A file.stat structure
|
||||||
|
@return String containing the generated tag suitable for ETag headers
|
||||||
|
]]
|
||||||
|
|
||||||
|
---[[
|
||||||
|
14.24 / If-Match
|
||||||
|
|
||||||
|
Test whether the given message object contains an "If-Match" header and
|
||||||
|
compare it against the given stat object.
|
||||||
|
@class function
|
||||||
|
@name if_match
|
||||||
|
@param req HTTP request message object
|
||||||
|
@param stat A file.stat object
|
||||||
|
@return Boolean indicating whether the precondition is ok
|
||||||
|
@return Alternative status code if the precondition failed
|
||||||
|
]]
|
||||||
|
|
||||||
|
---[[
|
||||||
|
14.25 / If-Modified-Since
|
||||||
|
|
||||||
|
Test whether the given message object contains an "If-Modified-Since" header
|
||||||
|
and compare it against the given stat object.
|
||||||
|
@class function
|
||||||
|
@name if_modified_since
|
||||||
|
@param req HTTP request message object
|
||||||
|
@param stat A file.stat object
|
||||||
|
@return Boolean indicating whether the precondition is ok
|
||||||
|
@return Alternative status code if the precondition failed
|
||||||
|
@return Table containing extra HTTP headers if the precondition failed
|
||||||
|
]]
|
||||||
|
|
||||||
|
---[[
|
||||||
|
14.26 / If-None-Match
|
||||||
|
|
||||||
|
Test whether the given message object contains an "If-None-Match" header and
|
||||||
|
compare it against the given stat object.
|
||||||
|
@class function
|
||||||
|
@name if_none_match
|
||||||
|
@param req HTTP request message object
|
||||||
|
@param stat A file.stat object
|
||||||
|
@return Boolean indicating whether the precondition is ok
|
||||||
|
@return Alternative status code if the precondition failed
|
||||||
|
@return Table containing extra HTTP headers if the precondition failed
|
||||||
|
]]
|
||||||
|
|
||||||
|
---[[
|
||||||
|
14.27 / If-Range
|
||||||
|
|
||||||
|
The If-Range header is currently not implemented due to the lack of general
|
||||||
|
byte range stuff in luci.http.protocol . This function will always return
|
||||||
|
false, 412 to indicate a failed precondition.
|
||||||
|
@class function
|
||||||
|
@name if_range
|
||||||
|
@param req HTTP request message object
|
||||||
|
@param stat A file.stat object
|
||||||
|
@return Boolean indicating whether the precondition is ok
|
||||||
|
@return Alternative status code if the precondition failed
|
||||||
|
]]
|
||||||
|
|
||||||
|
---[[
|
||||||
|
14.28 / If-Unmodified-Since
|
||||||
|
|
||||||
|
Test whether the given message object contains an "If-Unmodified-Since"
|
||||||
|
header and compare it against the given stat object.
|
||||||
|
@class function
|
||||||
|
@name if_unmodified_since
|
||||||
|
@param req HTTP request message object
|
||||||
|
@param stat A file.stat object
|
||||||
|
@return Boolean indicating whether the precondition is ok
|
||||||
|
@return Alternative status code if the precondition failed
|
||||||
|
]]
|
||||||
|
|
87
libs/luci-lib-httpprotoutils/luasrc/http/date.lua
Normal file
87
libs/luci-lib-httpprotoutils/luasrc/http/date.lua
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
|
||||||
|
-- Licensed to the public under the Apache License 2.0.
|
||||||
|
|
||||||
|
-- This class contains functions to parse, compare and format http dates.
|
||||||
|
module("luci.http.date", package.seeall)
|
||||||
|
|
||||||
|
require("luci.sys.zoneinfo")
|
||||||
|
|
||||||
|
|
||||||
|
MONTHS = {
|
||||||
|
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
|
||||||
|
"Sep", "Oct", "Nov", "Dec"
|
||||||
|
}
|
||||||
|
|
||||||
|
function tz_offset(tz)
|
||||||
|
|
||||||
|
if type(tz) == "string" then
|
||||||
|
|
||||||
|
-- check for a numeric identifier
|
||||||
|
local s, v = tz:match("([%+%-])([0-9]+)")
|
||||||
|
if s == '+' then s = 1 else s = -1 end
|
||||||
|
if v then v = tonumber(v) end
|
||||||
|
|
||||||
|
if s and v then
|
||||||
|
return s * 60 * ( math.floor( v / 100 ) * 60 + ( v % 100 ) )
|
||||||
|
|
||||||
|
-- lookup symbolic tz
|
||||||
|
elseif luci.sys.zoneinfo.OFFSET[tz:lower()] then
|
||||||
|
return luci.sys.zoneinfo.OFFSET[tz:lower()]
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- bad luck
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function to_unix(date)
|
||||||
|
|
||||||
|
local wd, day, mon, yr, hr, min, sec, tz = date:match(
|
||||||
|
"([A-Z][a-z][a-z]), ([0-9]+) " ..
|
||||||
|
"([A-Z][a-z][a-z]) ([0-9]+) " ..
|
||||||
|
"([0-9]+):([0-9]+):([0-9]+) " ..
|
||||||
|
"([A-Z0-9%+%-]+)"
|
||||||
|
)
|
||||||
|
|
||||||
|
if day and mon and yr and hr and min and sec then
|
||||||
|
-- find month
|
||||||
|
local month = 1
|
||||||
|
for i = 1, 12 do
|
||||||
|
if MONTHS[i] == mon then
|
||||||
|
month = i
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- convert to epoch time
|
||||||
|
return tz_offset(tz) + os.time( {
|
||||||
|
year = yr,
|
||||||
|
month = month,
|
||||||
|
day = day,
|
||||||
|
hour = hr,
|
||||||
|
min = min,
|
||||||
|
sec = sec
|
||||||
|
} )
|
||||||
|
end
|
||||||
|
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function to_http(time)
|
||||||
|
return os.date( "%a, %d %b %Y %H:%M:%S GMT", time )
|
||||||
|
end
|
||||||
|
|
||||||
|
function compare(d1, d2)
|
||||||
|
|
||||||
|
if d1:match("[^0-9]") then d1 = to_unix(d1) end
|
||||||
|
if d2:match("[^0-9]") then d2 = to_unix(d2) end
|
||||||
|
|
||||||
|
if d1 == d2 then
|
||||||
|
return 0
|
||||||
|
elseif d1 < d2 then
|
||||||
|
return -1
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
46
libs/luci-lib-httpprotoutils/luasrc/http/date.luadoc
Normal file
46
libs/luci-lib-httpprotoutils/luasrc/http/date.luadoc
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
---[[
|
||||||
|
LuCI http protocol implementation - date helper class.
|
||||||
|
|
||||||
|
This class contains functions to parse, compare and format http dates.
|
||||||
|
]]
|
||||||
|
module "luci.http.date"
|
||||||
|
|
||||||
|
---[[
|
||||||
|
Return the time offset in seconds between the UTC and given time zone.
|
||||||
|
|
||||||
|
@class function
|
||||||
|
@name tz_offset
|
||||||
|
@param tz Symbolic or numeric timezone specifier
|
||||||
|
@return Time offset to UTC in seconds
|
||||||
|
]]
|
||||||
|
|
||||||
|
---[[
|
||||||
|
Parse given HTTP date string and convert it to unix epoch time.
|
||||||
|
|
||||||
|
@class function
|
||||||
|
@name to_unix
|
||||||
|
@param data String containing the date
|
||||||
|
@return Unix epoch time
|
||||||
|
]]
|
||||||
|
|
||||||
|
---[[
|
||||||
|
Convert the given unix epoch time to valid HTTP date string.
|
||||||
|
|
||||||
|
@class function
|
||||||
|
@name to_http
|
||||||
|
@param time Unix epoch time
|
||||||
|
@return String containing the formatted date
|
||||||
|
]]
|
||||||
|
|
||||||
|
---[[
|
||||||
|
Compare two dates which can either be unix epoch times or HTTP date strings.
|
||||||
|
|
||||||
|
@class function
|
||||||
|
@name compare
|
||||||
|
@param d1 The first date or epoch time to compare
|
||||||
|
@param d2 The first date or epoch time to compare
|
||||||
|
@return -1 - if d1 is lower then d2
|
||||||
|
@return 0 - if both dates are equal
|
||||||
|
@return 1 - if d1 is higher then d2
|
||||||
|
]]
|
||||||
|
|
78
libs/luci-lib-httpprotoutils/luasrc/http/mime.lua
Normal file
78
libs/luci-lib-httpprotoutils/luasrc/http/mime.lua
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
|
||||||
|
-- Licensed to the public under the Apache License 2.0.
|
||||||
|
|
||||||
|
-- This class provides functions to guess mime types from file extensions and
|
||||||
|
-- vice versa.
|
||||||
|
module("luci.http.mime", package.seeall)
|
||||||
|
|
||||||
|
require("luci.util")
|
||||||
|
|
||||||
|
MIME_TYPES = {
|
||||||
|
["txt"] = "text/plain";
|
||||||
|
["js"] = "text/javascript";
|
||||||
|
["css"] = "text/css";
|
||||||
|
["htm"] = "text/html";
|
||||||
|
["html"] = "text/html";
|
||||||
|
["patch"] = "text/x-patch";
|
||||||
|
["c"] = "text/x-csrc";
|
||||||
|
["h"] = "text/x-chdr";
|
||||||
|
["o"] = "text/x-object";
|
||||||
|
["ko"] = "text/x-object";
|
||||||
|
|
||||||
|
["bmp"] = "image/bmp";
|
||||||
|
["gif"] = "image/gif";
|
||||||
|
["png"] = "image/png";
|
||||||
|
["jpg"] = "image/jpeg";
|
||||||
|
["jpeg"] = "image/jpeg";
|
||||||
|
["svg"] = "image/svg+xml";
|
||||||
|
|
||||||
|
["zip"] = "application/zip";
|
||||||
|
["pdf"] = "application/pdf";
|
||||||
|
["xml"] = "application/xml";
|
||||||
|
["xsl"] = "application/xml";
|
||||||
|
["doc"] = "application/msword";
|
||||||
|
["ppt"] = "application/vnd.ms-powerpoint";
|
||||||
|
["xls"] = "application/vnd.ms-excel";
|
||||||
|
["odt"] = "application/vnd.oasis.opendocument.text";
|
||||||
|
["odp"] = "application/vnd.oasis.opendocument.presentation";
|
||||||
|
["pl"] = "application/x-perl";
|
||||||
|
["sh"] = "application/x-shellscript";
|
||||||
|
["php"] = "application/x-php";
|
||||||
|
["deb"] = "application/x-deb";
|
||||||
|
["iso"] = "application/x-cd-image";
|
||||||
|
["tgz"] = "application/x-compressed-tar";
|
||||||
|
|
||||||
|
["mp3"] = "audio/mpeg";
|
||||||
|
["ogg"] = "audio/x-vorbis+ogg";
|
||||||
|
["wav"] = "audio/x-wav";
|
||||||
|
|
||||||
|
["mpg"] = "video/mpeg";
|
||||||
|
["mpeg"] = "video/mpeg";
|
||||||
|
["avi"] = "video/x-msvideo";
|
||||||
|
}
|
||||||
|
|
||||||
|
-- "application/octet-stream" if the extension is unknown.
|
||||||
|
function to_mime(filename)
|
||||||
|
if type(filename) == "string" then
|
||||||
|
local ext = filename:match("[^%.]+$")
|
||||||
|
|
||||||
|
if ext and MIME_TYPES[ext:lower()] then
|
||||||
|
return MIME_TYPES[ext:lower()]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return "application/octet-stream"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- given mime-type is unknown.
|
||||||
|
function to_ext(mimetype)
|
||||||
|
if type(mimetype) == "string" then
|
||||||
|
for ext, type in luci.util.kspairs( MIME_TYPES ) do
|
||||||
|
if type == mimetype then
|
||||||
|
return ext
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
34
libs/luci-lib-httpprotoutils/luasrc/http/mime.luadoc
Normal file
34
libs/luci-lib-httpprotoutils/luasrc/http/mime.luadoc
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
---[[
|
||||||
|
LuCI http protocol implementation - mime helper class.
|
||||||
|
|
||||||
|
This class provides functions to guess mime types from file extensions and
|
||||||
|
vice versa.
|
||||||
|
]]
|
||||||
|
module "luci.http.mime"
|
||||||
|
|
||||||
|
---[[
|
||||||
|
MIME mapping table containg extension - mimetype relations.
|
||||||
|
|
||||||
|
@class table
|
||||||
|
]]
|
||||||
|
|
||||||
|
---[[
|
||||||
|
Extract extension from a filename and return corresponding mime-type or
|
||||||
|
|
||||||
|
"application/octet-stream" if the extension is unknown.
|
||||||
|
@class function
|
||||||
|
@name to_mime
|
||||||
|
@param filename The filename for which the mime type is guessed
|
||||||
|
@return String containign the determined mime type
|
||||||
|
]]
|
||||||
|
|
||||||
|
---[[
|
||||||
|
Return corresponding extension for a given mime type or nil if the
|
||||||
|
|
||||||
|
given mime-type is unknown.
|
||||||
|
@class function
|
||||||
|
@name to_ext
|
||||||
|
@param mimetype The mimetype to retrieve the extension from
|
||||||
|
@return String with the extension or nil for unknown type
|
||||||
|
]]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user